Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4....

400
Programiranje Baza Podataka – Kroz programske jezike C i Java – Ajzenhamer Nikola, Vulović Ana

Transcript of Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4....

Page 1: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Programiranje Baza Podataka

– Kroz programske jezike C i Java –

Ajzenhamer Nikola, Vulović Ana

Page 2: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Copyright ©2020 Nikola Ajzenhamer, Ana Vulović[email protected][email protected]

Izdato od strane ”Nikola Ajzenhamer @ MATF”

http://www.math.rs/˜nikola_ajzenhamer/kursevi/pbp/pbp.pdf

Ovo delo je zaštićeno licencom Creative Commons Attribution-NonCommercial 3.0 Un-ported License (”Licenca”). Ovo delo se ne može koristiti osim ako nije u skladu sa Licen-com. Detalji Licence mogu se videti na veb adresi http://creativecommons.org/licenses/by-nc/3.0. Dozvoljeno je umnožavanje, distribucija i javno saopštavanje dela, pod uslovomda se navedu imena autora. Upotreba dela u komercijalne svrhe nije dozvoljena. Prerada,preoblikovanje i upotreba dela u sklopu nekog drugog nije dozvoljena.

Prvo izdanje, April 2020.

Page 3: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Sadržaj

Predgovor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

I Osnovni koncepti programiranja baza podataka

1 Uvod u programiranje DB2 aplikacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131.1 Programiranje na klijentu 141.1.1 Ugnežđen SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141.1.2 Tipovi SQL upita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151.2 Obnavljanje SQL upita 16

II Programiranje baza podataka u programskom jeziku C

2 Baze podataka i programski jezik C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.1 DB2 pretprocesorske naredbe 232.1.1 Naredba INCLUDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242.1.2 Naredbe BEGIN DECLARE SECTION i END DECLARE SECTION . . . . . . . . . . . . . . . . . . . 242.2 DB2 tipovi promenljivih 242.3 Tok pisanja programa 262.4 Prevođenje programa 27

3 Osnovni elementi programiranja baza podataka . . . . . . . . . . . . . . . . . . 313.1 Indikatorske promenljive i naredba SELECT 313.1.1 Alat db2dclgn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

Page 4: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.2 Obrada grešaka 363.2.1 Naredba WHENEVER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.2.2 Obrada grešaka pomoću SQLCA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.3 Izvršavanje SQL naredbi INSERT, UPDATE i DELETE 44

4 Programiranje korišćenjem kursora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514.1 Rad sa kursorima 514.1.1 Deklaracija kursora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524.1.2 Otvaranje kursora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524.1.3 Dohvatanje reda iz kursora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.1.4 Zatvaranje kursora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.2 Korišćenje kursora za čitanje podataka 534.3 Korišćenje kursora za ažuriranje i brisanje podataka 604.4 Ugnežđeni kursori 74

5 Programiranje transakcija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 795.1 Složena SQL naredba 795.2 Tačke čuvanja u okviru transakcija 895.2.1 Kreiranje tačke čuvanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895.3 Pohranjivanje izmena 905.4 Poništavanje izmena 91

6 Rad u višekorisničkom okruženju . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976.1 Aplikacioni proces i konkurentnost 976.2 Katanci 996.2.1 Konverzija katanaca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1006.2.2 Istek vremena i mrtva petlja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016.3 Nivoi izolovanosti 1106.4 Programersko zaključavanje tabela 123

7 Programiranje dinamičkih SQL naredbi . . . . . . . . . . . . . . . . . . . . . . . . . 1277.1 Naredbe za ugnežđavanje dinamičkih SQL naredbi 1277.2 Naredba EXECUTE IMMEDIATE 1287.3 Naredba PREPARE 1307.3.1 Parametarske oznake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1317.4 Naredba EXECUTE 1327.5 SQLDA 1387.5.1 Efekat naredbe EXECUTE na SQLDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1417.5.2 Efekat naredbe DESCRIBE na SQLDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1417.6 Naredba DESCRIBE 1417.6.1 Naredba DESCRIBE INPUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1417.6.2 Naredba DESCRIBE OUTPUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

Page 5: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8 Povezivanje na više baza podataka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1538.1 Osnovno o povezivanju na baze podataka 1538.1.1 Semantika udaljene jedinice posla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1548.1.2 Semantika distribuirane jedinice posla pod upravljanjem aplikacije . . . . . . . . . . . . . . . . 1568.2 Opcije za definisanje semantike konekcije jedinice posla 1578.3 Naredbe za upravljanje konekcijama na baze podataka 1588.3.1 Naredba CONNECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1588.3.2 Naredba SET CONNECTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1608.3.3 Naredba DISCONNECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1608.4 DB2 API za podešavanje konekcije 1618.5 Šabloni za rad, primeri i implementacione napomene 163

III Programiranje baza podataka u programskom jeziku Java

9 Programiranje SQLJ aplikacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1859.1 Baze podataka i programski jezik Java 1859.2 Programiranje SQLJ aplikacija 1869.2.1 Matične promenljive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1889.2.2 Kreiranje konteksta konekcije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1899.2.3 Kreiranje podrazumevanog konteksta konekcije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1909.2.4 Kreiranje konteksta izvršavanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1919.2.5 Zatvaranje konteksta i konekcije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1919.2.6 Obrada SQL grešaka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1929.2.7 Prevođenje SQLJ aplikacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1939.2.8 Primeri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1949.3 Iteratori u SQLJ 2029.3.1 Pozicioni iteratori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2029.3.2 Imenovani iteratori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2059.3.3 Iteratori za ažuriranje i brisanje podataka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2089.3.4 Ugnežđeni iteratori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

10 SQLJ, transakcije i višekorisničko okruženje . . . . . . . . . . . . . . . . . . . . . 21710.1 Ostvarivanje transakcija u SQLJ aplikacijama 21710.1.1 Auto commit mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21710.1.2 Transaction isolation level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21810.1.3 Savepoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21910.2 Rad u višekorisničkom okruženju 220

11 Programiranje JDBC aplikacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23511.1 Kreiranje konekcije 23511.2 Obrada SQL grešaka 23611.3 Upravljanje podacima 23811.3.1 Interfejs Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23811.3.2 Interfejs PreparedStatement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24411.3.3 Rukovanje nedostajućim vrednostima . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251

Page 6: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3.4 Podešavanje kursora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25411.3.5 Ažuriranje redova korišćenjem ResultSet kursora . . . . . . . . . . . . . . . . . . . . . . . . . . 25811.3.6 Brisanje redova korišćenjem ResultSet kursora . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26311.3.7 Ugnežđeni kursori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267

12 Napredni koncepti u JDBC aplikacijama . . . . . . . . . . . . . . . . . . . . . . . . 27112.1 Transakcioni rad 27112.1.1 Auto-Commit Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27112.1.2 Transaction Isolation Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27212.1.3 Savepoints in a Transaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27312.2 Rad u višekorisničkom okruženju 27412.3 Povezivanje na više baza podataka 28512.3.1 Objektno-orijentisani pristup kreiranju JDBC aplikacija . . . . . . . . . . . . . . . . . . . . . . . 293

13 Okruženje za razvoj Hibernate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30313.1 Podešavanje Hibernate projekta 30413.2 Podešavanje konekcije na bazu podataka 30913.3 Skladištenje objekata 31113.4 Omogućavanje skladištenja objekata i OR preslikavanje 31213.5 Dohvatanje jednog sloga 31813.6 Brisanje jednog sloga 31913.7 Složeni ključ 32113.8 Rad sa skupovima slogova 33213.8.1 HQL (Hibernate Query Language) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33213.8.2 Using Native SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33513.9 Asocijativne veze i strani ključevi 34413.9.1 Veza jedan-ka-jedan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34513.9.2 Veza jedan-ka-više/više-ka-jedan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34813.9.3 Veza više-ka-više . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34913.9.4 Strani ključevi u složenim primarnim ključevima . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35013.9.5 Strani ključevi ka složenim ključevima . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35113.9.6 Složeni strani ključevi kao delovi složenih primarnih ključeva . . . . . . . . . . . . . . . . . . . . 35213.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 36813.10.1 Restrikcija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36913.10.2 Ograničavanje skupa rezultata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37013.10.3 Projekcija i agregacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37013.10.4 Spajanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371

Dodatak

A Opis baze VSTUD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i

B Opis baze MSTUD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii

Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix

Page 7: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Indeks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi

Page 8: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 9: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Predgovor

Ovaj tekst predstavlja skriptu za izborni kurs ”Programiranje Baza Podataka”, na 3. i 4.godini smera Informatika na Matematičkom fakultetu Univerziteta u Beogradu. Skripta jekoncipirana na osnovu materijala Nine Radojičić Matić sa časova vežbi. Skripta je pratećimaterijal pre svega studentima koji ovaj kurs slušaju u okviru svojih studija, ali i svimaVama koji biste želeli da se upoznate sa ovom tematikom. Ovaj materijal ne može zamenitipohađanje vežbi niti drugu preporučenu literaturu.

Ovaj tekst je u ranoj fazi formiranja. Ukoliko ste pažljivi čitalac ove skripte, i ukolikouočite bilo kakvu grešku ili propust, možete se javiti autoru putem elektronske pošte naadresu [email protected]. Potrebno je da u naslovu elektronske poruke stavitetekst ”[PBP] Skripta”. Svi komentari, sugestije, kritike, ali i pohvale vezane za ovajmaterijal su dobrodošli.

Autori

Page 10: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 11: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

I

1 Uvod u programiranje DB2 aplikacija . . 131.1 Programiranje na klijentu1.2 Obnavljanje SQL upita

Osnovni konceptiprogramiranja baza podataka

Page 12: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 13: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

1. Uvod u programiranje DB2 aplikacija

DB2 je sistem za upravljanje relacionim bazama podataka (RSUBP) koji nudi veomamoćne softverske alate za programiranje baza podataka. Ovi alati su korisni kako ad-ministratorima baza podataka, tako i programerima aplikacija koje koriste mogućnostirelacionih baza podataka. Pod programiranjem baza podataka možemo smestiti narednedve aktivnosti:

1. Programiranje na serveru kroz pohranjene procedure, okidače i korisnički definisanefunkcije

2. Programiranje na klijentu kroz više programske jezike (često se ovi jezici nazivaju imatični jezici)

Slika 1.1: Dva načina za programiranje baza podataka: programiranje na klijentu (levo) iprogramiranje na serveru (desno).

Page 14: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

14 Glava 1. Uvod u programiranje DB2 aplikacija

Ova dva načina programiranja baza podataka ilustrovani su na slici 1.1. Kao što vidimo,programiranje na klijentu (levo) podrazumeva korišćenje viših programskih jezika kao štosu C, C++, Java, PHP i mnogi drugi, kroz neka razvojna okruženja, da bi se pristupilointerfejsu za programiranje aplikacija (API). Kroz ovaj interfejs se zatim, preko drajverakoji je dostupan programerima, aplikacija povezuje sa RSUBP i izvršava SQL upite. Sadruge strane, programiranje na serveru obuhvata programiranje pohranjenih procedura,korisnički definisanih funkcija i okidača od strane administratora baza podataka, koje sezatim mogu izvršavati.

S obzirom da je cilj ovog kursa da naučimo da programiramo aplikacije napisane u program-skim jezicima C i Java, koje će koristiti DB2 RSUBP za upravljanje podacima, nećemogovoriti o načinima za programiranje na serveru.

1.1 Programiranje na klijentu

Kao što smo napomenuli, programiranje na klijentu podrazumeva da programer razvijaaplikaciju u nekom višem programskom jeziku, a zatim se poveže na DB2 bazu podatakakorišćenjem API-ja za odgovarajući jezik.

Za početak, potrebno je da se upoznamo sa pojmovima SQL-ugnežđena aplikacija, statičkiSQL, dinamički SQL i matična promenljiva.

1.1.1 Ugnežđen SQLDefinicija 1.1.1 — SQL-ugnežđena aplikacija. Za aplikaciju kažemo da je SQL-ugnežđenaukoliko postoji barem jedna SQL naredba koja je ugnežđena u matični jezik, kao štosu C, C++, COBOL, i dr.

SQL-ugnežđene aplikacije mogu da sadrže SQL upite koji su statičke ili dinamičke prirode,o čemu će biti reči u daljem tekstu.

Slika 1.2: Prevođenje SQL-ugnežđenih aplikacija.

Na slici 1.2 možemo videti kako se izvršava prevođenje SQL-ugnežđene aplikacije napisaneu programskom jeziku C. Vidimo da datoteka hello.sqc sadrži ugnežđene SQL upite. Iakoćemo o tome pričati detaljnije uskoro, programski jezik C koristi naredbe EXEC SQL da bi u

Page 15: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

1.1 Programiranje na klijentu 15

fazi pretprocesiranja bile zamenjene konkretnim pozivima funkcija iz DB2 API-ja. U fazipretprocesiranja generišu se dve datoteke — hello.bnd i hello.c — prva sadrži samo SQLupite, a druga sadrži samo C kod. Datoteka hello.bnd se podvrgava procesu vezivanja.

Definicija 1.1.2 — Vezivanje. Vezivanje predstavlja proces kojim se od datoteke sa ek-stenzijom bnd kreira paket koji se čuva u bazi podataka.

Definicija 1.1.3 — Paket. Paket sadrži izvršivu formu svakog SQL upita iz aplikacije.Za svaku SQL naredbu se čuva informacija koji se postojeći indeksi koriste i kako. Usuštini, paket predstavlja pristupni plan podacima i igra ključnu ulogu u komunikacijiklijentske aplikacije i DB2 servera.

Sa druge strane, izvorni kod hello.c se kompilira i povezuje kao i svaki drugi C program.Završna datoteka hello.exe mora da odgovara paketu koji se sačuvao u bazi podataka dabi se uspešno izvršio.

U kodu u datoteci hello.sqc možemo da vidimo nešto što se naziva matična promenljiva.

Definicija 1.1.4 — Matična promenljiva. U pitanju su promenljive koje su definisane uvišem programskom jeziku, a koje se ugnežđavaju u SQL upite da bi se iskoristile njihovevrednosti ili da bi se rezultati upita smestili u njih.

U programskom jeziku se koriste kao i sve druge promenljive, na primer:EXEC SQL BEGIN DECLARE SECTION;char dbname[15];EXEC SQL END DECLARE SECTION;

strcpy(dbname, "vstud");

dok se u ugnežđenom SQL upitu navodi dvotačka ispred naziva, na primer:EXEC SQL CONNECT TO :dbname;

Detaljno ćemo govoriti o matičnim promenljivama i njihovim deklaracijama i upotrebi zasvaki programski jezik zasebno. Za sada, potrebno je da razumemo njihov značaj.

1.1.2 Tipovi SQL upita

Svi SQL upiti se mogu podeliti u dva tipa: statički i dinamički.

Definicija 1.1.5 — Statički SQL upit. Statički SQL upiti su oni gde je SQL struktura upotpunosti poznata u fazi pretprocesiranja.

Na primer, upitSELECT indeks, ime, prezime FROM dosije

je statičkog tipa jer su kolone INDEKS, IME i PREZIME, kao i tabela DOSIJE u potpunostipoznati u fazi pretprocesiranja. Slično, i upitSELECT ime, prezime FROM dosije WHERE indeks = :mojIndeks

je statičkog tipa. U ovom primeru, matična promenljiva mojIndeks se koristi kao deougnežđenog SQL upita. Iako je vrednost ove promenljive nepoznata sve dok program nije

Page 16: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

16 Glava 1. Uvod u programiranje DB2 aplikacija

pokrenut, njen tip je svakako poznat, te DB2 može da izračuna način na koji će se ovaj upitizvršiti (ovo je takođe poznato pod terminom plan izvršavanja upita). Zbog toga, ovakavupit se i dalje smatra za statičkim. Drugim rečima, statički SQL upiti se pretprocesiraju,vezuju i kompiliraju pre nego što se aplikacija pokrene.

Pogledajmo sada naredni SQL upit:SELECT ?, ? FROM ?

U ovom primeru, nazivi kolona i tabele koje se referišu u upitu nisu poznati do fazeizvršavanja. Ovakvi tipovi SQL upita se nazivaju dinamički SQL upiti.

Definicija 1.1.6 — Dinamički SQL upit. Dinamički SQL upiti su oni čiji se plan izvršava-nja može izračunati tek u fazi izvršavanja.

Ipak, neki API-ji, kao JDBC i ODBC, uvek koriste dinamičke SQL upite, bez obzira nanjihovu strukturu. Svi planovi izvršavanja se izračunavaju u fazi pokretanja.

U opštem slučaju, dinamičkim upitima se upravlja kroz naredne dve akcije:

1. Priprema upita — SQL upit se priprema ili kompilira čime se izračunava plan izvr-šavanja da bi se dohvatili podaci

2. Izvršenje upita — SQL upit se izvršava nad RSUBP

Oznaka ? označava nešto što se naziva parametarska oznaka.

Definicija 1.1.7 — Parametarska oznaka. Parametarska oznaka (engl. parameter mar-ker) predstavlja deo upita koji služi kao zamena za jednu konkretnu, unapred poznatuvrednost.

Korišćenjem parametarskih oznaka, program može da pripremi upit samo jednom, a zatimda ga izvrši više puta korišćenjem drugačijih vrednosti na mestu parametarskih oznaka.

Ovo su bile najosnovnije informacije koje treba imati na umu pri programiranju aplikacijakoje koriste relacione baze podataka za skladištenje podataka i njihovu obradu. U nared-nom poglavlju ćemo se detaljnije pozabaviti razvojem aplikacija napisanih u programskomjeziku C koji koriste DB2 sistem za upravljanje relacionim bazama podataka.

1.2 Obnavljanje SQL upita

Ova sekcija služi za obnavljanje gradiva iz relacionih baza podataka. Za svaki primer jepotrebno napisati upit na jeziku SQL koji predstavlja njegovo rešenje.

Primer 1.1 — Čas 01 — 01. Napisati na jeziku SQL upit koji izdvaja studente koji susve do sada upisivane obavezne predmete i položili (ne moraju biti položeni u školskojgodini u kojoj su i upisani) i to sa ocenom barem 8, a da student nijedan ispit nije paou poslednjih 6 godina.

Za studente izdvojiti ime, srednje slovo i prezime u formatu ime srednje_slovo. prezime(na primer, Marko M. Markovic). Srednje slovo se dobija na osnovu imena oca akopostoji u bazi; ukoliko za studenta nije navedeno ime oca koristi se ime majke; ukolikonije navedeno nijedno od ta dva, ne izdvaja se srednje slovo, niti prateća tačka. Ukolikosu imena roditelja u bazi sastavljena samo od belina, smatrati ih nenavedenim.

Page 17: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

1.2 Obnavljanje SQL upita 17

Rešenje.

Kod 1.1: Primeri/cas01/primer1.sqlselect trim(ime) || ' ' || (

casewhen ime_oca is not NULL and length(rtrim(ime_oca)) <> 0

then substr(ime_oca,1,1) || '. 'when ime_majke is not nuLL and length(rtrim(ime_majke)) <> 0

then substr(ime_majke,1,1) || '. 'else ''

end) || prezime ime_i_prezimefrom dosije dwhere not exists (

select ∗from upisan_kurs uk

join obavezan_predmet opon op.id_predmeta = uk.id_predmeta

where uk.indeks = d.indeksand op.id_smera = d.id_smeraand not exists(

select ∗ from ispitwhere indeks = d.indeks

and ocena >= 8and status_prijave = 'o'and id_predmeta = uk.id_predmeta

))and not exists (

select ∗from ispitwhere indeks = d.indeks

and ocena = 5and status_prijave = 'o'and coalesce(datum_usmenog, datum_pismenog) > current_date − 6 year

);

Primer 1.2 — Čas 01 — 02. Napisati na jeziku SQL upit koji pravi statistiku premaimenima studenata: uz ime studenta izdvaja prosečan broj upisivanih godina studenatasa tim imenom izražen na 3 decimale, kao i broj proteklih dana od prvog uspešnogpolaganja nekog studenta sa tim imenom. Rezultat urediti prema imenu leksikografski.

Rešenje.

Kod 1.2: Primeri/cas01/primer2.sqlwith godine as (

select ime, count(∗) godfrom upis_godine ug

join dosije don ug.indeks=d.indeks

group by d.indeks, ime),

prosek_godina as(

select ime, decimal(avg(god∗1.0), 5, 3) prfrom godinegroup by ime

),

Page 18: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

18 Glava 1. Uvod u programiranje DB2 aplikacija

datumi as (select ime, min(coalesce(datum_usmenog, datum_pismenog)) min_datfrom ispit i

join dosije don i.indeks = d.indeks

where ocena > 5and status_prijave='o'

group by ime)

select pp.ime,pp.pr,days(current date) − days(d.min_dat) br_dana

from prosek_godina ppleft join datumi d

on pp.ime = d.imeorder by ime;

Primer 1.3 — Čas 01 — 03. Za svaku pojedinačnu stavku zadatka napisati po jednuSQL naredbu kojom se:

1. pravi tabela upisani_kursevi_2016 koja ima isti skup kolona kao tabelaupisan_kurs, pri čemu:(a) dozvojeno je kreirati tabelu nabrajanjem kolona.(b) nije dozvoljeno kreirati tabelu nabrajanjem kolona.

2. dodaje prethodno napravljenoj tabeli primarni ključ koji čine kolone indeks,id_predmeta, godina, semestar i strani ključevi na tabele dosije i predmet.

3. studentima upisanim na fakultet posle 2011. godine i koji su upisivali, ali nisupoložili predmete čiji nazivi počinju rečju ”Uvod”, upisuju kursevi iz tih predmetau 2016. školskoj godini u 2. semestru unoseći ih u tabelu upisani_kursevi_2016.

4. studentima osnovnih studija svi upisani kursevi u drugom semestru prebacuju uprvi semestar, a ostali se ne diraju. Korisiti činjenicu da su osnovne studije nastepenu I. Uraditi zadatak:(a) bez korišćenja naredbe MERGE.(b) korišćenjem naredbe MERGE.

5. uklanja tabelu upisani_kursevi_2016.

Rešenje.

Kod 1.3: Primeri/cas01/primer3.sql−− 1. (a)

create table upisani_kursevi_2016 (indeks integer not null,id_predmeta integer not null,godina smallint not null,semestar smallint not null

);

−− 1. (b)

create table upisani_kursevi_2016 like upisan_kurs;

−− 2.

ALTER TABLE upisani_kursevi_2016ADD PRIMARY KEY (indeks, id_predmeta, godina, semestar)

Page 19: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

1.2 Obnavljanje SQL upita 19

ADD FOREIGN KEY fk_pred (ID_PREDMETA) REFERENCES predmetADD FOREIGN KEY fk_dos (indeks) REFERENCES dosije;

−− 3.

insert into upisani_kursevi_2016select distinct d.indeks, p.id_predmeta, 2016, 2from dosije d

join upisan_kurs ukon d.indeks = uk.indeks

join predmet pon p.id_predmeta = uk.id_predmeta

where naziv like 'Uvod%'and not exists (

select ∗from ispitwhere ocena > 5

and status_prijave = 'o'and indeks = d.indeksand id_predmeta = p.id_predmeta

)and year(d.datum_upisa) >= 2011;

−− 4. (a)

update upisani_kursevi_2016set semestar = 1where semestar = 2

and indeks in (select indeksfrom dosije d

join smer son d.id_smera = s.id_smera

join nivo_kvalifikacije nkon nk.id_nivoa = s.id_nivoa

where nk.stepen = 'I');

−− 4. (b)

merge into upisani_kursevi_2016 ukusing (

select indeksfrom dosije d

join smer son d.id_smera = s.id_smera

join nivo_kvalifikacije nkon nk.id_nivoa = s.id_nivoa

where nk.stepen = 'I') as pon p.indeks = uk.indekswhen matched and uk.semestar = 2

then update set semestar = 1else ignore;

−− 5.

drop table upisani_kursevi_2016;

Page 20: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 21: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

II 2 Baze podataka i programski jezik C . . . . 232.1 DB2 pretprocesorske naredbe2.2 DB2 tipovi promenljivih2.3 Tok pisanja programa2.4 Prevođenje programa

3 Osnovni elementi programiranja baza poda-taka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.1 Indikatorske promenljive i naredba SELECT3.2 Obrada grešaka3.3 Izvršavanje SQL naredbi INSERT, UPDATE i DELETE

4 Programiranje korišćenjem kursora . . . . . 514.1 Rad sa kursorima4.2 Korišćenje kursora za čitanje podataka4.3 Korišćenje kursora za ažuriranje i brisanje podataka4.4 Ugnežđeni kursori

5 Programiranje transakcija . . . . . . . . . . . . . 795.1 Složena SQL naredba5.2 Tačke čuvanja u okviru transakcija5.3 Pohranjivanje izmena5.4 Poništavanje izmena

6 Rad u višekorisničkom okruženju . . . . . . . 976.1 Aplikacioni proces i konkurentnost6.2 Katanci6.3 Nivoi izolovanosti6.4 Programersko zaključavanje tabela

7 Programiranje dinamičkih SQL naredbi 1277.1 Naredbe za ugnežđavanje dinamičkih SQL naredbi7.2 Naredba EXECUTE IMMEDIATE7.3 Naredba PREPARE7.4 Naredba EXECUTE7.5 SQLDA7.6 Naredba DESCRIBE

8 Povezivanje na više baza podataka . . . . 1538.1 Osnovno o povezivanju na baze podataka8.2 Opcije za definisanje semantike konekcije jedinice posla8.3 Naredbe za upravljanje konekcijama na baze podataka8.4 DB2 API za podešavanje konekcije8.5 Šabloni za rad, primeri i implementacione napomene

Programiranje baza podatakau programskom jeziku C

Page 22: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 23: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

2. Baze podataka i programski jezik C

U ovom poglavlju ćemo se detaljnije upustiti u diskusiju konstrukcije aplikacija, napisanihu programskom jeziku C, koje koriste DB2 RSUBP. S obzirom da pretprostavljamo daimamo podešeno okruženje, govorićemo o prevođenju od izvornog koda do izvršne apli-kacije i uvešćemo elemente neophodne za kompilaciju naših programa, kao što su DB2pretprocesorske naredbe, upravljanje greškama, ugnežđavanje najrazličitijih vrsta upitai druge. Sve ovo će biti demonstrirano kroz veliki broj primera koji podrazumevaju dapostoji baza podataka VSTUD. Opis ove baze podataka možete pronaći u dodatku A. Za-počnimo ovo poglavlje pričom o DB2 pretprocesorskim naredbama.

2.1 DB2 pretprocesorske naredbe

Za početak, potrebno je da razumemo da DB2 očekuje da naši programi budu napisaniu datotekama čije su ekstenzije .sqc. U ovim datotekama se, dakle, nalazi C izvorni kodu kojem su ugnežđeni SQL upiti. Prvi korak jeste da se ovakve izvorne datoteke obradekroz DB2 pretprocesor, čime će se generisati među-datoteke sa ekstenzijama .bnd i .c. Oovome je već bilo reči u prethodnom poglavlju.

Tokom ovog procesa, DB2 pretprocesor prolazi kroz izvorni kod .sqc datoteke i izvršavaodređene akcije kada naiđe na određene DB2 naredbe. Ovakvih naredbi ima dosta, a mićemo objasniti neke od njih.

Sve DB2 procesorske naredbe počinju ključnim rečima EXEC SQL, za kojima slede SQLnaredbe. U daljem tekstu ćemo podrazumevati postojanje ovih ključnih reči ukoliko se nenavedu eksplicitno.

Page 24: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

24 Glava 2. Baze podataka i programski jezik C

2.1.1 Naredba INCLUDE

Naredba INCLUDE služi za uključivanje zaglavlja u izvorni kod programa. Razlikuje se odstandardne C pretprocesorske direktive #include po tome što se izvršava tokom pretpro-cesiranja od strane DB2 pretprocesora. Za razliku od nje, direktiva #include se izvršavatokom prevođenja C programa. Ovo je ključna razlika jer želimo da neka zaglavlja bududostupna pre nego što se dođe do faze prevođenja C programa.

Da bismo mogli da radimo sa SQL upitima, potrebno je da uključimo zaglavlje SQLCA (SQLCommunication Area) i to u fazi DB2 pretprocesiranja, što se čini naredbom:EXEC SQL INCLUDE SQLCA;

Zaglavlje SQLCA predstavlja kolekciju promenljivih koje se ažuriraju pri izvršavanju svakogSQL upita. Kako se budemo susretali sa raznim zahtevima, tako ćemo objašnjavati svakuod neophodnih promenljivih koje su nam dostupne uključivanjem ovog zaglavlja.

2.1.2 Naredbe BEGIN DECLARE SECTION i END DECLARE SECTION

O matičnim promenljivama je takođe bilo reči u uvodnom poglavlju. Da se podsetimo, upitanju su promenljive koje su definisane u višem programskom jeziku, a koje se ugnežđa-vaju u SQL upite da bi se iskoristile njihove vrednosti ili da bi se rezultati upita smestiliu njih.

U programskom jeziku C, da bismo deklarisali ovakve promenljive, potrebno je da njihovedeklaracije smestimo između para naredbi BEGIN DECLARE SECTION i END DECLARE SECTION.Na primer:EXEC SQL BEGIN DECLARE SECTION;sqlint32 primerMaticnePromenljive;EXEC SQL END DECLARE SECTION;

Par ovih naredbi je moguće smestiti na bilo koje mesto u kodu gde bismo mogli da de-klarišemo i standardne C promenljive. U našem slučaju, mi ćemo deklarisati matičnepromenljive u globalnom opsegu, ali, naravno, to ne mora biti slučaj.

Postoje neka pravila koja se moraju ispoštovati pri korišćenju ovih naredbi. NaredbeBEGIN DECLARE SECTION i END DECLARE SECTION moraju biti uparene, i nije ih je mogućeugnežđavati. Takođe, nije moguće ugnežđavati SQL naredbe između para ovih naredbi.Promenljive koje se deklarišu izvan sekcija definisanih parom ovim naredbama ne smejuimati isti identifikator kao i matične promenljive u tim sekcijama. Naravno, sve promen-ljive koje se koriste u SQL upitima moraju biti deklarisane u sekciji definisanoj nekimparom ovih naredbi.

2.2 DB2 tipovi promenljivih

Kao što znamo, programski jezik C definiše određeni broj osnovnih tipova. Neki od ovih ti-pova korespondiraju sa DB2 tipovima kolona u tabelama. U tabeli 2.1 prikazan je preglednekih najčešćih tipova kolona u DB2, kao i odgovarajući C tipovi. Ovi tipovi se mogu ko-ristiti za deklaraciju matičnih promenljivih. Kada DB2 pretprocesor naiđe na deklaracijumatične promenljive, on određuje prikladni SQL tip. RSUBP zatim koristi ovu vrednostza konverziju podataka koji se razmenjuju između aplikacije i njega. Napomenimo da se

Page 25: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

2.2 DB2 tipovi promenljivih 25

tipovi označeni zvezdicom preporučuju u odnosu na druge zbog kompatibilnosti izmeđuoperativnih sistema.

Tabela 2.1: DB2 tipovi kolona i odgovarajući C tipovi.DB2 tip kolone C tip Opis DB2 tipa

SMALLINTshortshort intsqlint16

16-bitni označeni ceo broj

INTEGER

intlonglong intsqlint32*

32-bitni označeni ceo broj

BIGINT

long longlong__int64sqlint64*

64-bitni označeni ceo broj

REAL float Broj u pokretnom zarezujednostruke preciznosti

DOUBLE double Broj u pokretnom zarezu dvostrukepreciznosti

DECIMAL(p,s)Nema precizanekvivalentan tip; koristitidouble

Pakovan decimalni zapis

CHAR(1) char Jedan karakter

CHAR(n)

Nema precizanekvivalentan tip; koristitichar[n+1] gde je ndovoljno veliko da sadržipodatak 1<=n<=254

Niska nepromenljive dužine

VARCHAR(n)

struct tag{short int;char[n] }1<=n<=32672

Niska promenljive dužine bezterminirajuće nule sa 2-bajtnimindikatorom dužine

DATE Nula-terminirajućakarakterna forma

Dopustiti barem 11 karaktera da bise smestio terminirajući karakter

DATE VARCHAR struktuiranaforma Dopustiti barem 10 karaktera

TIME Nula-terminirajućakarakterna forma

Dopustiti barem 9 karaktera da bise smestio terminirajući karakter

TIME VARCHAR struktuiranaforma Dopustiti barem 8 karaktera

TIMESTAMP(p) Nula-terminirajućakarakterna forma

Dopustiti barem 20-33 karaktera dabi se smestio terminirajući karakter

TIMESTAMP(p) VARCHAR struktuiranaforma Dopustiti barem 19-32 karaktera

Page 26: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

26 Glava 2. Baze podataka i programski jezik C

2.3 Tok pisanja programa

Pisanje C programa sa ugnežđenim SQL naredbama obično podrazumeva naredne korake:

1. Uključivanje potrebnih zaglavlja2. Deklaracija matičnih promenljivih3. Povezivanje na bazu podataka4. Izvršavanje SQL naredbi5. Obrada SQL grešaka6. Ostvarivanje transakcija7. Prekidanje konekcije sa bazom podataka

Sada smo u stanju da rešimo prvi zahtev koji je pred nama, uz nekoliko dodatnih napomena.Pogledajmo naredni primer.

Primer 2.1 — Čas 02 — 01. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje maksimalni indeks iz tabele ISPIT.

Rešenje. Potrebno je da pratimo prethodno opisane korake za pisanje C programa. Uovom primeru, ignorisaćemo korake 5 i 6. Na korak ”Obrada SQL grešaka” osvrnućemose kroz samo nekoliko primera, dok ćemo transakcijama i radu sa njima posvetiti posebnupažnju nešto kasnije. Dakle, krenimo redom:

Uključivanje potrebnih zaglavlja

Ovaj korak bi trebalo da nam bude jasan do sada:#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

Deklaracija matičnih promenljivih

Kako je indeks definisan tipom INTEGER, možemo birati neki od tipova int, long, longint ili sqlint32. Pošto je preporučeno koristiti tip sqlint32 zbog kompatibilnosti izmeđuoperativnih sistema različite bit-nosti, matičnu promenljivu koja će sadržati traženi indeksdeklarišemo na sledeći način:EXEC SQL BEGIN DECLARE SECTION;

sqlint32 maxIndeks;

EXEC SQL END DECLARE SECTION;

Ostale korake ćemo izvršavati u funkciji int main().

Povezivanje na bazu podataka

Da bismo se povezali na bazu podataka, koristićemo SQL naredbu oblikaCONNECT TO imeBP USER imeKorisnika USING korisnickaLozinka;

U našem slučaju:EXEC SQL CONNECT TO vstud USER student USING abcdef;

Page 27: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

2.4 Prevođenje programa 27

Izvršavanje SQL naredbi

U ovom koraku je potrebno da napišemo odgovarajući SQL upit za izračunavanje najvećegindeksa iz tabele ISPIT i da rezultat smestimo u prethodno definisanu matičnu promenljivumaxIndeks. Zatim, potrebno je da ispišemo rezultat. To se može uraditi narednim delomkoda:EXEC SQL SELECT MAX(INDEKS) INTO :maxIndeks

FROM ISPIT;

printf("Najveci indeks je %d\n", maxIndeks);

Prekidanje konekcije sa bazom podataka

Prekidanje konekcije je vrlo jednostavno. Dovoljno je izvršiti upit:EXEC SQL CONNECT RESET;

I time smo ispunili zahtev primera. U nastavku je dato celokupno rešenje:

Kod 2.1: Primeri/cas02/primer1.sqc#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

// Deklaracija potrebnih maticnih promenljivihEXEC SQL BEGIN DECLARE SECTION;sqlint32 maxIndeks;EXEC SQL END DECLARE SECTION;

int main(){

// Konekcija na bazuEXEC SQL CONNECT TO vstud user student using abcdef;

// Izdvajamo maksimalni indeks i smestamo u maticnu promenljivu maxIndeksEXEC SQL SELECT MAX(INDEKS) INTO :maxIndeks

FROM ISPIT;

// Ispisujemo podatak koji se sada nalazi u maticnoj promenljivoj maxIndeksprintf("\nNajveci indeks je %d\n", maxIndeks);

// Diskonekcija sa bazeEXEC SQL CONNECT RESET;

return 0;}

2.4 Prevođenje programa

Rešavanjem prethodnog primera smo otvorili novo pitanje — kako se, koristeći precizneinstrukcije, vrši prevođenje ovako napisanih programa. Videli smo kako ovaj proces tečei koji se sve fajlovi konstruišu u ovom procesu, ali nismo govorili o naredbama kojima seovaj proces izvršava.

Proces prevođenja C programa sa ugnežđenim SQL naredbama obično podrazumeva na-redne korake:

Page 28: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

28 Glava 2. Baze podataka i programski jezik C

1. Ostvarivanje konekcije na bazu podataka. Ovo podrazumeva pokretanje naredbe:db2 connect to IMEBAZE user KORISNIK using LOZINKA

2. Pretprocesiranje aplikacije tako što se izvršava PRECOMPILE naredba. Ovo pod-razumeva pokretanje naredbe:db2 precompile IMEDATOTEKE.sqc bindfile

3. Ako je kreirana IMEDATOTEKE.bnd datoteka (korišćenjem BINDFILE opcije u PRE-COMPILE naredbi u koraku 2), vrši se vezivanje te datoteke sa bazom podataka dabi se kreirao aplikacioni paket tako što se izvršava BIND naredba. Ovo podrazumevapokretanje naredbe:db2 bind IMEDATOTEKE.bnd

4. Kompiliranje modifikovanog aplikacionog izvornog koda i izvornih datoteka koji nesadrže ugnežđeni SQL da bi se kreirale objektne datoteke (jedna ili više njih, zavi-sno od modularnosti koda; kod nas će uglavnom biti jedna objektna datoteka poprimeru). Potrebno je kompilatoru specifikovati gde se nalaze zaglavlja koje namDB2 sistem nudi. Ovo podrazumeva pokretanje naredbe:cc −I/opt/ibm/db2/V10.5/include −c IMEDATOTEKE.c

5. Linkovanje aplikacionih objektnih datoteka sa DB2 bibliotekama i bibliotekama ma-tičnog jezika da bi se kreirao izvršni program. Ovo podrazumeva pokretanje naredbe:cc −o IMEDATOTEKE IMEDATOTEKE.o −Wl,−rpath,/opt/ibm/db2/V10.5/lib32 −L/

opt/ibm/db2/V10.5/lib32 −ldb2

S obzirom da je ovaj proces poprilično linearan za svaku aplikaciju koju ćemo pisati (uzjednocifren broj izuzetaka), dobro bi bilo automatizovati ga. U tu svrhu, kreirali smoskript prevodjenje:

Kod 2.2: Primeri/cas02/prevodjenje.sh#!/bin/sh

DB2PATH=/opt/ibm/db2/V10.5EXTRA_LFLAG="−Wl,−rpath,$DB2PATH/lib32"

if (test $# −lt 3)then

db2 connect to $2else

db2 connect to $2 user $3 using $4fi

db2 precompile $1.sqc bindfile

db2 bind $1.bnd

cc −I$DB2PATH/include −c $1.c

cc −o $1 $1.o $EXTRA_LFLAG −L$DB2PATH/lib32 −ldb2

Ovaj skript u svojoj osnovnoj varijanti zahteva 4 argumenta:

1. Naziv datoteke koji se prevodi bez ekstenzije .sqc (u prethodnim koracima vrednostIMEDATOTEKE) — obavezan argument

Page 29: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

2.4 Prevođenje programa 29

2. Naziv baze podataka na koju se vrši konekcija (u prethodnim koracima vrednostIMEBAZE) — obavezan argument

3. Naziv korisnika sa kojim se pristupa bazi podataka (u prethodnim koracima vrednostKORISNIK)

4. Lozinka za pristup bazi podataka za korisnika KORISNIK iz koraka 3 (u prethodnimkoracima vrednost LOZINKA)

Konkretno, prevođenje primera 2.1 se vrši pomoću naredbe:./prevodjenje primer1 vstud student abcdef

Tokom ovog procesa možemo videti da li je došlo do nekih grešaka u fazi prevođenja.Ukoliko je sve prošlo kako treba, kreirana je izvršna datoteka primer koja se pokreće kaoi svaki drugi izvršni C program:./primer1

Page 30: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 31: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3. Osnovni elementi programiranja baza podataka

Do sada smo videli razne elemente programiranja kao što su: uvoženje zaglavlja, matičnepromenljive i rad sa njima i izvršavanje SQL upita. U ovoj sekciji ćemo kroz razne primerevideti još neke elemente.

3.1 Indikatorske promenljive i naredba SELECT

Jedno pitanje koje se prirodno postavlja u radu sa SQL podacima jeste kako se rukujepodacima za koje znamo da mogu imati nedostajuće vrednosti u bazi podataka. Naprimer, u tabeli DOSIJE kolone datum_rodjenja i ime_ocamogu imati nedostajuće vrednosti.Potrebno je da se na neki način indikuje ukoliko se naiđe na vrednost NULL. Za to namsluže indikatorske promenljive.

Kako su ove promenljive deljenje između RSUBP-a i višeg programskog jezika, to je i njihpotrebno deklarisati kao matične promenljive. Ove promenljive uzimaju SQL tip vrednostiSMALLINT, odnosno, možemo koristiti short u C kodu.

Indikatorska promenljiva se u SQL upitu nalazi odmah nakon matične promenljive i odnje je odvojena dvotačkom. Na primer:SELECT nullKolonaINTO :maticnaPromenljiva:indikatorskaPromenljiva...

Ispitivanje da li je neka vrednost NULL ili ne, može se izvršiti proverom vrednosti indika-torske promenljive. Ako je njena vrednost negativan broj, dohvaćena vrednost je NULL iodgovarajuću matičnu promenljivu ne bi trebalo koristiti. U suprotnom, matična promen-ljiva sadrži odgovarajuću vrednost iz tabele. RSUBP neće promeniti vrednost matičnepromenljive u slučaju da je dohvaćena vrednost NULL. Na primer:

Page 32: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

32 Glava 3. Osnovni elementi programiranja baza podataka

if (indikatorskaPromenljiva < 0) {printf("Podatak ne postoji!\n");

}else {

printf("Dohvacen je podatak: %s\n", maticnaPromenljiva);}

Naredni primer ilustruje upotrebu indikatorske promenljive.

Primer 3.1 — Čas 02 — 02. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje indeks, ime, prezime, ime oca (ukoliko je navedeno u bazi) i datumrođenja (ukoliko je navedeno u bazi) za studenta sa maksimalnim indeksom iz tabeleISPIT.

Rešenje.

Kod 3.1: Primeri/cas02/primer2.sqc#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[26];char prezime[26];char ime_oca[51];short ind_ime_oca;char datum_rodjenja[11];short ind_datum_rodjenja;EXEC SQL END DECLARE SECTION;

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;

EXEC SQL SELECT indeks, ime, prezime, ime_oca, datum_rodjenjaINTO :indeks, :ime, :prezime, :ime_oca:ind_ime_oca, :datum_rodjenja:

ind_datum_rodjenjaFROM DOSIJEWHERE INDEKS = (SELECT MAX(INDEKS) FROM DOSIJE);

printf("\nINDEKS:%i IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",indeks, ime, prezime,(ind_ime_oca < 0) ? "null" : ime_oca,(ind_datum_rodjenja < 0) ? "null" : datum_rodjenja);

EXEC SQL CONNECT RESET;

return 0;}

Do sada smo samo smeštali vrednosti iz baze podataka u matične promenljive. Naredniprimer ilustruje upotrebu matične promenljive čija se vrednost koristi u SQL upitu.

Primer 3.2 — Čas 02 — 03. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji koji ispisuje indeks, ime, prezime, ime oca (ukoliko je navedeno u bazi) idatum rođenja (ukoliko je navedeno u bazi) za studenta čiji se broj indeksa učitava sa

Page 33: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.1 Indikatorske promenljive i naredba SELECT 33

standardnog ulaza.

Rešenje.

Kod 3.2: Primeri/cas02/primer3.sqc#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[26];char prezime[26];char ime_oca[51];short ind_ime_oca;char datum_rodjenja[11];short ind_datum_rodjenja;EXEC SQL END DECLARE SECTION;

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;

printf("Unesite broj indeksa:");scanf("%d", &indeks);

EXEC SQL SELECT ime, prezime, ime_oca, datum_rodjenjaINTO :ime, :prezime, :ime_oca:ind_ime_oca, :datum_rodjenja:

ind_datum_rodjenjaFROM DOSIJEWHERE INDEKS = :indeks;

printf("\nINDEKS:%d IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",indeks, ime, prezime,(ind_ime_oca < 0) ? "nepoznato" : ime_oca,(ind_datum_rodjenja < 0) ? "nepoznat" : datum_rodjenja);

EXEC SQL CONNECT RESET;

return 0;}

3.1.1 Alat db2dclgn

Do sada smo mi sami, ručno deklarisali matične promenljive u koje smo upisivali rezultateupita za dohvatanje vrednosti iz baze podataka. Ovo je sasvim u redu ukoliko izdvajamotek nekoliko kolona u finalnom rezultatu. Međutim, ukoliko bismo želeli da izvučemovrednosti iz svih kolona za neku tabelu, za tabele iole visokog stepena, ovaj posao možebiti značajno zamoran.

Na sreću, DB2 sistem nam nudi alat komandne linije koji možemo da koristimo i kojim segeneriše struktura koja odgovara definiciji tabele. U pitanju je alat db2dclgn. Ovaj alatima naredne argumente:

1. −d IMEBAZE — specifikuje bazu podataka koja se koristi2. −t IMETABELE — specifikuje tabelu baze podataka iz argumenta 13. nula ili više dodatnih argumenata

Page 34: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

34 Glava 3. Osnovni elementi programiranja baza podataka

• −i — biće kreirane indikatorske promenljive• −l JEZIK — specifikuje jezik za koji se kreira struktura. Validne vrednosti za

JEZIK su: C, COBOL, JAVA i FORTRAN. Podrazumevana vrednost je C.• −a AKCIJA — specifikuje da li nove deklaracije zamenjuju stare ili se dodaju na

njih. Validne vrednosti za AKCIJA su: ADD i REPLACE. Podrazumevana vrednostje ADD.

Primer upotrebe za tabelu PREDMET baze podataka VSTUD:db2dclgn −d vstud −t predmet −l c −a replace

Ovom naredbom će biti generisana naredna datoteka:

Kod 3.3: Primeri/cas02/predmet.hstruct{sqlint32 id_predmeta;struct{short length;char data[21];

} sifra;struct{short length;char data[201];

} naziv;short broj_semestara;short bodovi;

} predmet;

Ono što je potrebno uraditi jeste unutar sekcije za deklaraciju matičnih promenljivihuključiti generisano zaglavlje:EXEC SQL BEGIN DECLARE SECTION;

EXEC SQL INCLUDE predmet;

EXEC SQL END DECLARE SECTION;

Nakon toga, strukturu predmet možemo koristiti kao bilo koju matičnu promenljivu, naprimer, u SQL upitu:SELECT id_predmeta, trim(sifra) INTO :predmet...

kao i u C delu koda:printf("ID: %i, SIFRA: %s", predmet.id_predmeta, predmet.sifra.data);

Naredni primer ilustruje upotrebu db2dclgn alata.

Primer 3.3 — Čas 02 — 04. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje podatke iz tabele PREDMET za predmet čiji je identifikator 640 ustrukturu generisanu alatom db2dclgn, a zatim ispisati podatke iz strukture na stan-dardni izlaz.

Rešenje. Prvo je neophodno pokrenuti komandu:

Page 35: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.1 Indikatorske promenljive i naredba SELECT 35

db2dclgn −d vstud −t predmet −l c −a replace

Zatim je možemo uključiti i iskoristiti kao u narednom kodu:

Kod 3.4: Primeri/cas02/primer4.sqc#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

// Ukljucujemo zaglavlje predmet.h// u kojem se nalazi maticna promenljiva predmet// generisana alatom db2dclgn.// Ne mozemo ukljuciti zaglavlje pomocu #include C direktive// zato sto nam je promenljiva predmet potrebna u fazi DB2 pretprocesiranja.EXEC SQL BEGIN DECLARE SECTION;EXEC SQL INCLUDE predmet;EXEC SQL END DECLARE SECTION;

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;

EXEC SQL SELECT id_predmeta, trim(sifra), trim(naziv), broj_semestara,bodoviINTO :predmetFROM PREDMETWHERE id_predmeta = 640;

printf("\nID:%d SIFRA:%s NAZIV:%s SEMSLUS:%i BODOVI:%i\n",predmet.id_predmeta, predmet.sifra.data, predmet.naziv.data, predmet.

broj_semestara, predmet.bodovi);

EXEC SQL CONNECT RESET;

return 0;}

Primer 3.4 — Čas 02 — 05. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje podatke iz tabele PREDMET za predmet čiji je identifikator 640 ustrukturu koju je potrebno deklarisati bez upotrebe alata db2dclgn, a zatim ispisatipodatke iz strukture na standardni izlaz.

Rešenje.

Kod 3.5: Primeri/cas02/primer5.sqc#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;struct{

sqlint32 id_predmeta;struct{

short length;char data[20];

} sifra;struct

Page 36: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

36 Glava 3. Osnovni elementi programiranja baza podataka

{short length;char data[200];

} naziv;short broj_semestara;short bodovi;

} predmet;EXEC SQL END DECLARE SECTION;

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;

EXEC SQL SELECT id_predmeta, sifra, naziv, broj_semestara, bodoviINTO :predmetFROM PREDMETWHERE id_predmeta = 640;

printf("\nID:%d SIFRA:%s NAZIV:%s SEMSLUS:%d BODOVI:%d\n",predmet.id_predmeta, predmet.sifra.data, predmet.naziv.data, predmet.

broj_semestara, predmet.bodovi);

EXEC SQL CONNECT RESET;

return 0;}

3.2 Obrada grešaka

Pri radu sa SQL bazom podataka, možemo očekivati da će se potencijalno pojaviti trivrste grešaka:

1. NOT FOUND — ovim upozorenjem se signalizira da se upitom nije pronađen nijedanred u tabeli koji je zadovoljavajući

2. SQLWARNING — ovim upozorenjem se signalizira da postoji neka akcija koja nije oče-kivana ili da potencijalno postoji nekakav propust

3. SQLERROR — ovom greškom se signalizira da postoji veliki problem koji je neophodnorešiti

3.2.1 Naredba WHENEVER

Naredbom WHENEVER se specifikuje šta je potrebno uraditi u slučaju da se pojavi odgova-rajuća vrsta greške. Ova naredba ima tri varijante, za svaku vrstu greške po jednu:WHENEVER NOT FOUND ...WHENEVER SQLWARNING ...WHENEVER SQLERROR ...

Da bismo specifikovali koju je akciju potrebno uraditi, možemo specifikovati neku od na-redne tri klauze:

• CONTINUE — prelazi se na narednu sekvencijalnu instrukciju u programu• GOTO :maticnaLabela ili GO TO :maticnaLabela — tok se prepušta kontroli koja se

identifikuje datom labelom maticnaLabela.

Page 37: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.2 Obrada grešaka 37

• DO — tok se prepušta jednoj od narednih kontrola, u zavisnosti od toga šta sledinakon klauze DO:

– naziv_funkcije()— specifikuje C funkciju koja će biti pozvana. Funkcija moraimati povratni tip void i ne sme primati argumente.

– BREAK — specifikuje C kontrolu break čime se prekida neka od ponavljajućih Ckontrola toka

– CONTINUE — specifikuje C kontroli continue čime se prelazi na narednu iteracijuneke od ponavljajućih C kontrola toka

Svaka izvršni SQL upit u programu je pod opsegom neke WHENEVER naredbe, implicitnoili eksplicitno. SQL upit je pod opsegom poslednje WHENEVER naredbe, za svaku varijantunaredbe, koja je specifikovana do tog upita u izvornom kodu aplikacije. Ako neka varijantaWHENEVER naredbe nije specifikovana do nekog SQL upita, onda se podrazumevano smatrada se koristi klauza CONTINUE.

Naredni primer ilustruje upotrebu WHENEVER naredbe za obradu grešaka.

Primer 3.5 — Čas 02 — 06. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje indeks, ime, prezime, ime oca (ukoliko je navedeno u bazi) i datumrođenja (ukoliko je navedeno u bazi) za studenta čiji se broj indeksa unosi sa standardnogulaza. Obraditi greške korišćenjem SQL naredbe WHENEVER.

Rešenje.

Kod 3.6: Primeri/cas02/primer6.sqc#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

// Deklarisemo akcije za svaki tip greskeEXEC SQL WHENEVER NOT FOUND GO TO :nije_pronadjen_student;EXEC SQL WHENEVER SQLERROR GO TO :greska;EXEC SQL WHENEVER SQLWARNING CONTINUE;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[26];char prezime[26];char ime_oca[51];short ind_ime_oca;char datum_rodjenja[11];short ind_datum_rodjenja;EXEC SQL END DECLARE SECTION;

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;

printf("Unesite broj indeksa:");scanf("%d", &indeks);

EXEC SQL SELECT ime, prezime, ime_oca, datum_rodjenjaINTO :ime, :prezime, :ime_oca:ind_ime_oca, :datum_rodjenja:

ind_datum_rodjenjaFROM DOSIJEWHERE INDEKS = :indeks;

printf("\nINDEKS:%d IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",

Page 38: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

38 Glava 3. Osnovni elementi programiranja baza podataka

indeks, ime, prezime,(ind_ime_oca < 0) ? "nepoznato" : ime_oca,(ind_datum_rodjenja < 0) ? "nepoznat" : datum_rodjenja);

goto exit;

nije_pronadjen_student:printf("Student nije pronadjen!\n");goto exit;

greska:printf("Greska!\n");goto exit;

exit:EXEC SQL CONNECT RESET;return 0;

}

Naredni primer ilustruje promenu WHENEVER NOT FOUND varijante naredbe WHENEVER.

Primer 3.6 — Čas 02 — 07. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje indeks, ime, prezime, ime oca (ukoliko je navedeno u bazi) i datumrođenja (ukoliko je navedeno u bazi) za studenta čiji se indeks unosi na standardnogulaza. Omogućiti da korisnik može dva puta da unese indeks. U slučaju da nije prona-đen student pri prvom unosu, ispisati poruku korisniku da student nije pronađen. Pridrugom unosu, samo nastaviti izvršavanje programa. Obraditi greške korišćenjem SQLnaredbe WHENEVER.

Rešenje.

Kod 3.7: Primeri/cas02/primer7.sqc#include <stdio.h>

EXEC SQL INCLUDE SQLCA;

// Deklarisemo akcije za NOT FOUND i SQLERROR, kao u prethodnom primeru.// Podrazumevano se koristi akcija CONTINUE,// pa zato ne navodimo deklaraciju za SQLWARNING.EXEC SQL WHENEVER NOT FOUND GO TO :nije_pronadjen_student;EXEC SQL WHENEVER SQLERROR GO TO :greska;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[26];char prezime[26];char ime_oca[51];short ind_ime_oca;char dat_rodjenja[11];short ind_dat_rodjenja;EXEC SQL END DECLARE SECTION;

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;

printf("Unesite broj indeksa:");scanf("%d", &indeks);

Page 39: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.2 Obrada grešaka 39

EXEC SQL SELECT ime, prezime, ime_oca, datum_rodjenjaINTO :ime, :prezime, :ime_oca:ind_ime_oca, :dat_rodjenja:

ind_dat_rodjenjaFROM DOSIJEWHERE INDEKS = :indeks;

printf("\nINDEKS:%d IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",indeks, ime, prezime,(ind_ime_oca < 0) ? "nepoznato" : ime_oca,(ind_dat_rodjenja < 0) ? "nepoznat" : dat_rodjenja);

// Menjamo akciju za NOT FOUND.// Ova promena ce biti vidljiva za svaku narednu EXEC SQL naredbu.EXEC SQL WHENEVER NOT FOUND CONTINUE;

printf("Unesite broj indeksa:");scanf("%d", &indeks);

EXEC SQL SELECT ime, prezime, ime_oca, datum_rodjenjaINTO :ime, :prezime, :ime_oca:ind_ime_oca, :dat_rodjenja:

ind_dat_rodjenjaFROM DOSIJEWHERE INDEKS = :indeks;

printf("\nINDEKS:%d IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",indeks, ime, prezime,(ind_ime_oca < 0) ? "nepoznato" : ime_oca,(ind_dat_rodjenja < 0) ? "nepoznat" : dat_rodjenja);

goto exit;

nije_pronadjen_student:printf("Student nije pronadjen!\n");goto exit;

greska:printf("Greska!\n");goto exit;

exit:EXEC SQL CONNECT RESET;return 0;

}

3.2.2 Obrada grešaka pomoću SQLCA

Obrada grešaka pomoću naredbe WHENEVER ima ključni problem — ona se najčešćeoslanja na zastarele C naredbe poput go to i definisane labela, za koje znamo da brzodovode do ”špageti” koda. Ovo se može prevazići korišćenjem klauze DO, a da kod zaobradu greške smestimo u funkciju. Međutim, posledica ovog načina rada jeste mali brojfunkcija čija tela sadrže značajno veliki broj linija koda zbog obrade specifičnih slučajeva(često upotrebom switch naredbe).

DB2 sistem nam nudi pametnije načine za obradu grešaka i u narednim primerima ćemopokazati kako možemo da ih koristimo. U osnovi svih ovih načina nalazi se zaglavljeSQLCA i razne promenljive, strukture i funkcije koje ona nudi. Ovo je moguće tako štoprilikom pretprocesiranja programa, RSUBP umeće deklaracije raznih matičnih promen-

Page 40: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

40 Glava 3. Osnovni elementi programiranja baza podataka

ljivih na mesto INCLUDE SQLCA naredbe. Sistem zatim komunicira sa našim programomkoristeći promenljive za postavljanje zastavica prilikom upozorenja, kodova za greške idrugih informacija za dijagnozu.

Nakon izvršavanja svake SQL naredbe, sistem daje povratni kod kroz matične promenljiveSQLCODE i SQLSTATE. SQLCODE predstavlja celi broj koja na neki način sumira izvršavanjeSQL naredbe, dok je SQLSTATE niska od 5 karaktera, koja detaljnije opisuje česte kodoveza greške među različitim softverskim rešenjima vezane za relacione baze od strane IBM-a.Mi ćemo se najčešće oslanjati na promenljivu SQLCODE prilikom obrade grešaka.

U zavisnosti od vrednosti SQLCODE promenljive, razlikujemo naredna tri slučaja:

• SQLCODE = 0: Naredba se uspešno izvršila i nije došlo do greške.• SQLCODE > 0: Došlo je do nekakvog upozorenja od strane RSUBP, ali naredba je

svakako izvršena. Specijalno, ukoliko je kod upozorenja +100, to znači da nijepronađen željeni podatak u bazi (u slučaju upita koji vraćaju jednu vrednost) ili dase došlo do kraja čitanja (u slučaju upita koji vraćaju više vrednosti).

• SQLCODE < 0: Došlo je do nekakve greške i naredba nije izvršena.

Pređimo sada na razne načine korišćenja ovih informacija. Naredni primer ilustruje obradugreške proverom vrednosti matične promenljive SQLCODE. Obratiti pažnju na definisanjefunkcije void is_error(char ∗), kojom se proverava da li je došlo do greške — u slučajuda postoji greška, program se prekida, dok se u suprotnom nastavlja sa izvršavanjem — injenim pozivima.

Da bismo otkrili šta znaci određena greška, potrebno je da u komandnoj liniji izvršimokomandu:db2 ? sql<KOD GRESKE>

Na primer, ukoliko želimo da vidimo šta znači greška čiji je kod −502, potrebno je daizvršimo:db2 ? sql502

Primer 3.7 — Čas 02 — 08. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje indeks, ime, prezime, ime oca (ukoliko je navedeno u bazi) i da-tum rođenja studenta (ukoliko je navedeno u bazi) za studenta čiji se indeks unosi nastandardnog ulaza. Obraditi greške korišćenjem matične promenljive SQLCODE.

Rešenje.

Kod 3.8: Primeri/cas02/primer8.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[26];char prezime[26];char ime_oca[51];short ind_ime_oca;char datum_rodjenja[11];short ind_datum_rodjenja;

Page 41: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.2 Obrada grešaka 41

EXEC SQL END DECLARE SECTION;

// Deklarisemo funkciju za obradu greske.// Ova funkcija se zove za svaku EXEC SQL naredbu// koja dolazi do izrazaja u fazi izvrsavanja.// Funkcija koristi globalni makro SQLCODE za proveru greske.void is_error(char ∗str){

if(SQLCODE < 0){

printf("Greska %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

printf("Unesite broj indeksa:");scanf("%d", &indeks);

EXEC SQL SELECT ime, prezime, ime_oca, datum_rodjenjaINTO :ime, :prezime, :ime_oca:ind_ime_oca, :datum_rodjenja:

ind_datum_rodjenjaFROM DOSIJEWHERE INDEKS = :indeks;

is_error("Citanje podataka o studentu");

if(SQLCODE == 100){

printf("Nema studenta sa zadatim indeksom.\n");}else{

printf("\nINDEKS:%i IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",indeks, ime, prezime,(ind_ime_oca < 0) ? "nepoznato" : ime_oca,(ind_datum_rodjenja < 0) ? "nepoznat" : datum_rodjenja);

}

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Uključivanjem zaglavlja SQLCA, na raspolaganju nam je globalna promenljiva sqlca čiji jetip dat sa struct sqlca. U okviru ove strukture definisana su razna polja koja možemoiskoristiti u dijagnozi problema. Tako nam je dostupno polje sqlcode koje sadrži vred-nost koda za grešku nakon svake SQL naredbe1. Naredni primer ilustruje korišćenje ovestrukture za ispitivanje grešaka.

1Zapravo, ono što smo do sada zvali ”matična promenljiva” SQLCODE nije ništa drugo do makro zavrednost sqlca.sqlcode.

Page 42: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

42 Glava 3. Osnovni elementi programiranja baza podataka

Primer 3.8 — Čas 02 — 09. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje indeks, ime, prezime, ime oca (ukoliko je navedeno u bazi) i da-tum rođenja studenta (ukoliko je navedeno u bazi) za studenta čiji se indeks unosi nastandardnog ulaza. Obraditi greške korišćenjem matične promenljive sqlca.

Rešenje.

Kod 3.9: Primeri/cas02/primer9.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[26];char prezime[26];char ime_oca[51];short ind_ime_oca;char datum_rodjenja[11];short ind_datum_rodjenja;EXEC SQL END DECLARE SECTION;

// Funkcija koristi globalnu strukturu sqlca za proveru greske.void is_error(char ∗str){

if(sqlca.sqlcode < 0){

printf("Greska %d: %s\n", sqlca.sqlcode, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

printf("Unesite broj indeksa:");scanf("%d", &indeks);

EXEC SQL SELECT trim(ime), trim(prezime), trim(ime_oca), datum_rodjenjaINTO :ime, :prezime, :ime_oca:ind_ime_oca, :datum_rodjenja:

ind_datum_rodjenjaFROM DOSIJEWHERE INDEKS = :indeks;

is_error("Citanje podataka o studentu");

if(sqlca.sqlcode == 100){

printf("Nema studenta sa zadatim indeksom.\n");}else{

printf("\nINDEKS:%d IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",indeks, ime, prezime,(ind_ime_oca < 0) ? "nepoznato" : ime_oca,(ind_datum_rodjenja < 0) ? "nepoznat" : datum_rodjenja);

}

Page 43: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.2 Obrada grešaka 43

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Konstantna provera značenja svakog SQL koda za grešku, bilo pretragom kroz dokumen-taciju ili izvršavanjem komande db2 ? sql<∗> iz komandne linije, može biti mukotrpna.Ono što bismo nekada želeli jeste da naš program odmah ispiše opis greške koji se dogodio.Srećom po nas, ovo je moguće i veoma je jednostavno za uraditi. Ukoliko uključimo za-glavlje sql.h, na raspolaganju će nam biti funkcija sqlaintp, koju možemo da iskoristimoda dohvatimo tekstualni opis greške koja se dogodila. Ova funkcija ima naredna četiriargumenta:

1. char ∗ pBuffer — Karakterni bafer u koji će biti smešten tekstualni opis greške.Ukoliko je veličina bafera manja nego što je dužina opisa, opis će biti skraćen naveličinu bafera i biće postavljena terminirajuća nula.

2. short BufferSize — Veličina bafera koji se prosleđuje kao prvi argument.3. short LineWidth — Najveća veličina svake linije u tekstu opisa. Linije će biti raz-

bijene odgovarajućim karakterom za novi red tako da reči u datoj liniji ostanu cele.Ukoliko prosledimo vrednost 0, poruka neće sadržati karaktere za novi red.

4. struct sqlca ∗ pSqlca — Pokazivač na strukturu sqlca na osnovu koje će funkcijazaključiti do koje greške je došlo.

Naredni primer ilustruje upotrebu ove funkcije.

Primer 3.9 — Čas 02 — 10. Napisati program u programskom jeziku C sa ugnežđe-nim SQL-om koji ispisuje indeks, ime, prezime, ime oca (ukoliko je navedeno u bazi) idatum rodjenja studenta (ukoliko je navedeno u bazi) za studenta ciji se indeks unosina standardnog ulaza. U slučaju pojave greške ili ako student nije pronađen, ispisatiodgovarajuću poruku o grešci.

Rešenje.

Kod 3.10: Primeri/cas02/primer10.sqc#include <stdio.h>#include <stdlib.h>#include <sql.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[26];char prezime[26];char ime_oca[51];short ind_ime_oca;char datum_rodjenja[11];short ind_datum_rodjenja;EXEC SQL END DECLARE SECTION;

// Funkcija koristi globalnu strukturu sqlca za proveru greske,// kao i funkciju sqlaintp za dohvatanje tekstualnog opisa greske.void is_error(char ∗str){

if(sqlca.sqlcode < 0 || sqlca.sqlcode == 100)

Page 44: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

44 Glava 3. Osnovni elementi programiranja baza podataka

{char bafer[1024];short bafer_velicina = sizeof(bafer);short duzina_linije = 50;

sqlaintp(bafer, bafer_velicina, duzina_linije, &sqlca);

printf("Greska %d: %s\n", sqlca.sqlcode, str);printf("%s\n", bafer);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

printf("Unesite broj indeksa:");scanf("%d", &indeks);

EXEC SQL SELECT ime, prezime, ime_oca, datum_rodjenjaINTO :ime, :prezime, :ime_oca:ind_ime_oca, :datum_rodjenja:

ind_datum_rodjenjaFROM DOSIJEWHERE INDEKS = :indeks;

is_error("Citanje podataka o studentu");

printf("\nINDEKS:%d IME:%s PREZIME:%s IME_OCA:%s DAT_RODJENJA:%s\n",indeks, ime, prezime,(ind_ime_oca < 0) ? "nepoznato" : ime_oca,(ind_datum_rodjenja < 0) ? "nepoznat" : datum_rodjenja);

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

3.3 Izvršavanje SQL naredbi INSERT, UPDATE i DELETE

Do sada smo videli primere u kojima smo dohvatali tačno jedan red u tabeli (ili, even-tualno, nijedan), korišćenjem naredbe SELECT. U nastavku slede primeri u kojem ćemodemonstrirati upotrebu naredbi INSERT, UPDATE i DELETE.

Primer 3.10 — Čas 02 — 11. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji se sastoji od naredna tri dela:

1. Sa standardnog ulaza se unose podaci: id_predmeta, sifra, naziv, bodovi ibroj_semestara. Potrebno je uneti te podatke u tabelu PREDMET. Nakon toga,naredbom SELECT proveriti da li podaci dobro uneti i ispisati ih.

2. Izvršiti ažuriranje podataka za uneseni predmet, tako što se broj bodova duplopovećava i nakon čega se podaci izlistavaju ponovo.

3. Obrisati uneseni predmet iz baze.

Rešenje.

Page 45: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.3 Izvršavanje SQL naredbi INSERT, UPDATE i DELETE 45

Kod 3.11: Primeri/cas02/primer11.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 id_predmeta;char sifra[21];char naziv[201];short broj_semestara;short bodovi;EXEC SQL END DECLARE SECTION;

void is_error(char∗ str){

if(SQLCODE < 0){

printf("Greska %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

// Deklaracije funkcija za svaki deo zadatka

void unesi_novi_predmet();void izmeni_novi_predmet();void obrisi_novi_predmet();

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Konekcija na bazu");

unesi_novi_predmet();izmeni_novi_predmet();obrisi_novi_predmet();

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

// Definicije funkcija za svaki deo zadatka

void unesi_novi_predmet(){

printf("Identifikator predmeta:");scanf("%d", &id_predmeta);

printf("Sifra predmeta:");scanf("%s", sifra);

printf("Naziv predmeta:");scanf("%s", naziv);

printf("Semestara slusanja predmeta:");scanf("%hd", &broj_semestara);

Page 46: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

46 Glava 3. Osnovni elementi programiranja baza podataka

printf("Bodovi predmeta:");scanf("%hd", &bodovi);

EXEC SQL INSERT INTO PREDMETVALUES (:id_predmeta, :sifra, :naziv, :broj_semestara, :bodovi);

is_error("Unos podataka o predmetu");

EXEC SQL SELECT id_predmeta, sifra, naziv, broj_semestara, bodoviINTO :id_predmeta, :sifra, :naziv, :broj_semestara, :bodoviFROM PREDMETWHERE id_predmeta = :id_predmeta;

is_error("Izlistavanje podataka");

printf("\nID:%d SIFRA:%s NAZIV:%s SEMSLUS:%hd BODOVI:%hd\n",id_predmeta, sifra, naziv, broj_semestara, bodovi);

}

void izmeni_novi_predmet(){

EXEC SQL UPDATE PREDMETSET BODOVI = BODOVI∗2WHERE id_predmeta = :id_predmeta;

is_error("Azuriranje podataka o predmetu");

EXEC SQL SELECT id_predmeta, sifra, naziv, broj_semestara, bodoviINTO :id_predmeta, :sifra, :naziv, :broj_semestara, :bodoviFROM PREDMETWHERE id_predmeta = :id_predmeta;

is_error("Izlistavanje podataka");

printf("\nID:%d SIFRA:%s NAZIV:%s SEMSLUS:%hd BODOVI:%hd\n",id_predmeta, sifra, naziv, broj_semestara, bodovi);

}

void obrisi_novi_predmet(){

EXEC SQL DELETE FROM PREDMETWHERE id_predmeta = :id_predmeta;

is_error("Brisanje podataka o predmetu");

printf("\nUspesno su obrisani podaci o predmetu\n");}

Primer 3.11 — Čas 03 — 01. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se dodaje u tabelu USLOVNI_PREDMET da je za polaganje predmeta čiji jeidentifikator 720, uslov da se položi predmet čiji je identifikator 655, a zatim obrisatiuneti uslov.

Rešenje.

Kod 3.12: Primeri/cas03/primer1.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗str){

if (SQLCODE < 0){

Page 47: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.3 Izvršavanje SQL naredbi INSERT, UPDATE i DELETE 47

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL INSERT INTO uslovni_predmetvalues (720, 655);

is_error("Insert");

EXEC SQL DELETE FROM uslovni_predmetwhere id_predmeta = 720

and id_uslovnog = 655;is_error("Delete");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 3.12 — Čas 03 — 02. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se u tabelu NIVO_KVALIFIKACIJE dodaje novi nivo čiji se identifikator,naziv i stepen unose sa standardnog ulaza, a zatim obrisati unete podatke.

Rešenje.

Kod 3.13: Primeri/cas03/primer2.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;short id;char naziv[201];char stepen[11];EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

printf("Unesite id nivoa: ");scanf("%hd", &id);

Page 48: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

48 Glava 3. Osnovni elementi programiranja baza podataka

printf("Unesite naziv: ");scanf("%s", naziv);

printf("Unesite stepen: ");scanf("%s", stepen);

printf("Unosimo podatke u tabelu nivo_kvalifikacije. \n");EXEC SQL INSERT INTO nivo_kvalifikacije

values (:id, :naziv, :stepen);is_error("Insert");

printf("Brisemo unete podatke iz tabele nivo_kvalifikacije. \n");EXEC SQL DELETE FROM nivo_kvalifikacije

WHERE id_nivoa = :id;is_error("Delete");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 3.13 — Čas 03 — 03. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se u tabeli USLOVNI_PREDMET brišu svi redovi koji se odnose na predmetekoji su uslovni da bi se položio predmet čiji se identifikator unosi sa standardnog ulaza.

Rešenje.

Kod 3.14: Primeri/cas03/primer3.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 id;EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

printf("Unesite id predmeta: ");scanf("%d", &id);

EXEC SQL DELETE FROM uslovni_predmetWHERE id_predmeta = :id;

is_error("Delete");

EXEC SQL CONNECT RESET;

Page 49: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

3.3 Izvršavanje SQL naredbi INSERT, UPDATE i DELETE 49

is_error("Connect reset");

return 0;}

Primer 3.14 — Čas 03 — 04. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se iz tabele ISPIT brišu svi podaci o studentu sa maksimalnim brojemindeksa.

Rešenje.

Kod 3.15: Primeri/cas03/primer4.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DELETE FROM ispitWHERE indeks = (select max(indeks) from dosije);

is_error("Delete");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Page 50: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 51: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4. Programiranje korišćenjem kursora

Do sada su rezultati naših SQL upita bili kardinalnosti 1. Zbog toga smo mogli da ko-ristimo jednostavnu SELECT INTO naredbu za dohvatanje informacija iz rezultata upita.Ukoliko smo sigurni da će rezultat upita biti jedan red, ovakav način programiranja je pri-hvatljiv. Međutim, ukoliko znamo da se rezultat može sastojati od više redova, potrebannam je drugačiji pristup.

U slučaju da nam je nepoznat broj redova u rezultatu upita, za dohvatanje rezultatamožemo iskoristiti mehanizam zasnovan na kursorima. Kursorima je moguće procesiratisvaki red rezultata, bez obzira na to koliko redova rezultat sadrži. Kursor je imenovanakontrolna struktura koja se koristi od strane aplikativnog programa da ”pokazuje” naspecifičan red u okviru uređenog skupa redova.

4.1 Rad sa kursorima

Rad sa kursorima se najčešće može opisati kroz naredna četiri koraka:

1. Deklaracija kursora:DECLARE ime_kursoraCURSOR FOR upit[(FOR READ ONLY)|(FOR UPDATE OF lista_atributa)][(WITHOUT HOLD)|(WITH HOLD)]

2. Otvaranje kursora:OPEN ime_kursora[USING lista_maticnih_promenljivih]

3. Dohvatanje jednog po jednog reda iz rezultata:FETCH ime_kursoraINTO lista_maticnih_promenljivih

Page 52: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

52 Glava 4. Programiranje korišćenjem kursora

4. Zatvaranje kursora:

CLOSE ime_kursora[WITH RELEASE]

4.1.1 Deklaracija kursora

Promenljiva ime_kursora mora biti jedinstvena u programu. Vrednost upit predstavljaSELECT upit za koji se vezuje kursor. Ne može da sadrži parametarske oznake, ali možesadržati matične promenljive, s tim da deklaracije matičnih promenljivih koje se koristeu upitu moraju biti pre deklaracije kursora. Ukoliko navedemo klauzu FOR READ ONLY,time definišemo kursor koji služi samo za čitanje podataka. Ukoliko želimo da se podacimenjaju pomoću kursora, tada se nakon upit navodi klauza FOR UPDATE OF za kojom sledilista imena atributa koji se mogu menjati kursorom, odvojeni zapetama.

Kursor se implicitno ograničava samo za čitanje (kažemo da je kursor čitajući) ako jeispunjen barem jedan od sledećih uslova:

• Bilo koja FROM klauza koja se nalazi u upit sadrži više od jedne tabele ili sadržipogled koji služi samo za čitanje.

• upit sadrži DISTINCT, VALUES ili ORDER BY klauzu.• upit sadrži agregatne funkcije ili GROUP BY ili HAVING klauzu.• upit sadrži neki skupovni operator, kao što su UNION, INTERSECT i EXCEPT sa izuzet-

kom UNION ALL.

Za kursor kažemo da je brišući ukoliko nije čitajući. Za kursor kažemo da je ažurirajućiukoliko je brišući i kolone koje su proglašene za ažuriranje u FOR UPDATE OF predstavljajuneke od kolona u baznoj tabeli. Za kursor kažemo da je dvosmisleni ukoliko je upitdinamički pripremljen i nije navedena nijedna od klauza FOR READ ONLY ili FOR UPDATE OF.

Navođenjem neke od opcionih klauza WITHOUT HOLD ili WITH HOLD možemo specifikovati dali će se kursor zatvarati ili ne kao posledica operacije pohranjivanja (engl. commit). Navo-đenjem klauze WITHOUT HOLD kursor se ne sprečava da bude zatvoren, što je podrazumevanoponašanje. Navođenjem klauze WITH HOLD kursor održava resursa kroz različite jediniceposla. Kada budemo govorili o transakcijama, definisaćemo preciznije ovo ponašanje.

4.1.2 Otvaranje kursora

Naredbom OPEN se vrši otvaranje kursora i njegovo izvršavanje, zarad dohvatanja redovaiz rezultujuće tabele. Promenljiva ime_kursora mora biti deklarisana naredbom DECLAREkoja se nalazi ispred u programu. Kada se izvrši naredba OPEN, ime_kursora mora biti uzatvorenom stanju (bilo da je eksplicitno zatvoren ili da je samo deklarisan pre otvaranja).

Ukoliko se kursor otvara za pripremljenu SQL naredbu, navođenjem klauze USING možemouvesti vrednosti koje se koriste za zamenu parametarskih oznaka. U slučaju statičke SQLnaredbe pri deklaraciji kursora, klauza USING se može koristiti da se uvedu vrednosti koje ćese koristiti umesto vrednosti matičnih promenljivih koje su korišćene prilikom deklaracijekursora.

Nakon otvaranja kursor je pozicioniran ispred prvog reda rezultujuće tabele.

Page 53: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.2 Korišćenje kursora za čitanje podataka 53

4.1.3 Dohvatanje reda iz kursora

Naredbom FETCH se vrši pozicioniranje kursora na naredni red iz rezultujuće tabele i dode-ljuju se vrednosti iz tog reda ciljanim promenljivama. Promenljiva ime_kursora mora bitideklarisana naredbom DECLARE koja se nalazi ispred u programu. Da bi se izvršila naredbaFETCH, ime_kursora mora biti u otvorenom stanju.

Klauzom INTO se prva vrednost dohvaćenog reda smešta u prvu promenljivu ulista_maticnih_promenljivih, druga vrednost u drugu promenljivu, i tako dalje. Akodođe do greške pri bilo kojoj dodeli vrednosti, ta vrednost se ne dodeljuje promenljivoj,kao ni bilo koja vrednost nakon nje. Sve do tada dodeljene vrednosti ostaju dodeljene.

Otvoreni kursor ima tri moguće pozicije: (1) pre reda, (2) na redu i (3) nakon poslednjegreda. Kursor može biti samo na redu primenom naredbe FETCH. Ako se kursor pozicionirana poslednjem redu rezultujuće tabele ili iza njega, izvršavanje naredne FETCH ima naredneefekte:

• SQLCODE se postavlja na vrednost +100.• Kursor se pozicionira nakon poslednjeg reda.• Vrednosti se ne dodeljuju matičnim promenljivama.

Ako je kursor pozicioniran pre reda, izvršavanjem naredbe FETCH, kursor se pozicionira nataj red, i vrednosti se dodeljuju matičnim promenljivama klauzom INTO. Ako je kursorpozicioniran na redu koji nije poslednji, izvršavanjem naredbe FETCH, kursor se pozicionirana naredni red i vrednosti tog reda se dodeljuju matičnim promenljivama klauzom INTO.Ako je kursor pozicioniran na redu, taj red se naziva tekući red kursora. Kursor na koji sereferiše u naredbama UPDATE ili DELETE mora biti pozicioniran na redu. Moguće je da sedolaskom do greške stanje kursora postavi na nepredvidivo.

4.1.4 Zatvaranje kursora

Naredbom CLOSE se vrši zatvaranje kursora. Ukoliko je rezultujuća tabela kreirana kadaje kursor otvoren, ta tabela se uništava. Promenljiva ime_kursora mora biti deklarisananaredbom DECLARE koja se nalazi ispred u programu. Da bi se izvršila naredba CLOSE,ime_kursora mora biti u otvorenom stanju.

Ukoliko se navede opciona klauza WITH RELEASE, prilikom zatvaranja kursora se pokušavasa oslobađanjem svih katanaca koji su držani od strane kursora. S obzirom da se katancimogu držati drugim operacijama ili procesima, ne znači da će biti nužno i oslobođenizatvaranjem kursora. U katancima će biti više reči u kasnijem tekstu.

Na kraju jedinice posla, svi kursori koji pripadaju procesu aplikacije i koji su deklarisanibez klauze WITH HOLD se implicitno zatvaraju.

4.2 Korišćenje kursora za čitanje podataka

Sada smo spremni za rešavanje primera koji zahtevaju upotrebu kursora. Počnimo sanarednim primerom koji ilustruje čitanje rezultata iz kursora.

Primer 4.1 — Čas 03 — 05. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje identifikator, oznaku, naziv, broj semestara i broj bodova za svaki

Page 54: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

54 Glava 4. Programiranje korišćenjem kursora

od smerova iz tabele SMER.

Page 55: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.2 Korišćenje kursora za čitanje podataka 55

Rešenje.

Kod 4.1: Primeri/cas03/primer5.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_id;char d_oznaka[11];char d_naziv[201];short d_semestara;short d_bodovi;EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

// Konektujemo se na bazu podatakaEXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

// Deklarisemo kursor koji prolazi tabelom smerEXEC SQL DECLARE c_smer CURSOR FOR

select id_smera, oznaka, naziv, semestara, bodovifrom smer;

is_error("Declare cursor");

// Otvaramo kursor, cime se izvrsava upit naveden u deklaracijiEXEC SQL OPEN c_smer;is_error("Open cursor");

// Sve dok ima redova u rezultujucoj tabelifor(;;){

// Citamo red po redEXEC SQL FETCH c_smer

INTO :d_id, :d_oznaka, :d_naziv, :d_semestara, :d_bodovi;is_error("Fetch cursor");

// Ako smo stigli do kraja rezultujuce tabele,// izlazimo iz petljeif (SQLCODE == 100){

break;}

// Inace, stampamo red iz rezultataprintf("ID:%d OZNAKA:%s NAZIV:%.70s "

"SEMESTARA:%hd bodovi:%hd\n",d_id, d_oznaka, d_naziv, d_semestara, d_bodovi);

}

Page 56: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

56 Glava 4. Programiranje korišćenjem kursora

// Zatvaramo kursorEXEC SQL CLOSE c_smer;is_error("Close cursor");

// Raskidamo konekciju sa bazom podatakaEXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Naredni primeri služe za provežbavanje upotrebe čitajućih kursora.

Primer 4.2 — Čas 03 — 06. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se za uneti broj indeksa studenta ispisuju podaci (naziv predmeta, datumpolaganja i ocena) za sve ispite koje je on položio. Nakon toga ispisuje se njegov prosek.

Rešenje.

Kod 4.2: Primeri/cas03/primer6.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_indeks;char d_naziv[201];char d_datum[11];short d_ocena;double d_prosek;EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

// Deklarisemo kursor koji za dati broj indeksa nalazi sve polozene ispiteEXEC SQL DECLARE polozeni_ispiti CURSOR FOR

select naziv, coalesce(datum_usmenog, datum_pismenog), ocenafrom ispit i

join predmet pon i.id_predmeta = p.id_predmeta

where indeks = :d_indeksand ocena > 5and status_prijave = 'o';

is_error("Declare cursor");

printf("Unesite broj indeksa studenta:\n");

Page 57: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.2 Korišćenje kursora za čitanje podataka 57

scanf("%d", &d_indeks);

// Otvaramo kursorEXEC SQL OPEN polozeni_ispiti;is_error("Open cursor");

for(;;){

// Smestamo naredni red rezultata upita u odgovarajuce promenljiveEXEC SQL FETCH polozeni_ispiti

INTO :d_naziv, :d_datum, :d_ocena;is_error("Fetch cursor");

// Ako smo stigli do kraja kursora, izlazimo iz petljeif (SQLCODE == 100){

break;}

// Inace, stampamo naredni ispitprintf("NAZIV:%.70s DATUM:%s OCENA:%hd\n",

d_naziv, d_datum, d_ocena);}

// Zatvaramo kursorEXEC SQL CLOSE polozeni_ispiti;is_error("Close cursor");

// Za datog studenta racunamo prosek ocenaEXEC SQL SELECT coalesce(avg(ocena + 0.0), 5.0) INTO :d_prosek

from ispitwhere indeks = :d_indeks

and ocena > 5and status_prijave = 'o';

is_error("Select into");

printf("Prosek ocena je: %.2f.\n", d_prosek);

// Raskida se konekcija sa bazom podatakaEXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 4.3 — Čas 03 — 07. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje sva ženska imena koja postoje među studentima (zajedno sa brojempojavljivanja) u opadajućem poretku.

Rešenje.

Kod 4.3: Primeri/cas03/primer7.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char ime[51];sqlint32 br;

Page 58: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

58 Glava 4. Programiranje korišćenjem kursora

EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DECLARE zenska_imena CURSOR FORselect ime, count(∗) ukupnofrom dosijewhere pol='z'group by imeorder by ukupno desc;

is_error("Declare cursor");

EXEC SQL OPEN zenska_imena;is_error("Open cursor");

for(;;){

EXEC SQL FETCH zenska_imenaINTO :ime, :br;

is_error("Fetch cursor");

if (SQLCODE == 100){

break;}

printf("Studentkinja sa imenom:%.20s ima:%d\n", ime, br);}

EXEC SQL CLOSE zenska_imena;is_error("Close cursor");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 4.4 — Čas 03 — 08. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje za svakog studenta ime, prezime, poslednji položeni ispit (nazivpredmeta koji je položen), kao i datum polaganja tog ispita.

Rešenje.

Kod 4.4: Primeri/cas03/primer8.sqc#include <stdio.h>#include <stdlib.h>

Page 59: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.2 Korišćenje kursora za čitanje podataka 59

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char ime[51];char prezime[51];char naziv[201];char datum[11];EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DECLARE student_predmet CURSOR FORwith poslednji_ispit as (

select indeks, max(coalesce(datum_usmenog, datum_pismenog))datum_poslednjeg

from ispitwhere ocena > 5

and status_prijave='o'group by indeks

)

select ime, prezime, datum_poslednjeg, nazivfrom poslednji_ispit pi

join dosije don pi.indeks = d.indeks

join ispit ion pi.indeks = i.indeks

join predmet pon p.id_predmeta = i.id_predmeta

where datum_pismenog = datum_poslednjegor datum_usmenog = datum_poslednjegand ocena > 5;

is_error("Declare cursor");

EXEC SQL OPEN student_predmet;is_error("Open cursor");

for(;;){

EXEC SQL FETCH student_predmetINTO :ime, :prezime, :datum, :naziv;

is_error("Fetch cursor");

if (SQLCODE == 100){

break;}

printf("Poslednji ispit studenta %.15s %.15s koji je polozio je %.20s;

Page 60: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

60 Glava 4. Programiranje korišćenjem kursora

""datum polaganja: %.11s\n", ime, prezime, naziv, datum);

}

EXEC SQL CLOSE student_predmet;is_error("Close cursor");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

4.3 Korišćenje kursora za ažuriranje i brisanje podataka

Kao što smo napomenuli, moguće je korišćenje kursora za ažuriranje ili brisanje redova iztabela. U slučaju ažuriranja redova, potrebno je deklarisati koje kolone se mogu menjatipri deklaraciji kursora, a zatim koristiti UPDATE naredbu oblika:UPDATE ime_tabeleSET ime_kolone_1 = vrednost_1,

...ime_kolone_N = vrednost_N

WHERE CURRENT OF ime_kursora;

Očigledno, kolone ime_kolone_1, …, ime_kolone_N moraju biti deklarisane uFOR UPDATE OF klauzi pri deklaraciji kursora ime_kursora. Takođe, tabela ime_tabelemora biti jedina tabela koja se nalazi u FROM klauzi kursora. Na ovaj način će upotrebomopisane naredbe UPDATE biti ažuriran tekući red kursora.

Primer 4.5 — Čas 03 — 09. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se za svaki od smerova iz tabele SMER korisniku postavlja pitanje da li želida uveća broj bodova za 10 i ako je odgovor potvrdan vrši se odgovarajuća promena.

Rešenje.

Kod 4.5: Primeri/cas03/primer9.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_id;char d_oznaka[11];char d_naziv[201];short d_semestara;short d_bodovi;EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}

Page 61: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.3 Korišćenje kursora za ažuriranje i brisanje podataka 61

}

int main(){

// Odgovor od korisnikachar c;

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

// Deklarisemo kursor koji prolazi tabelom smer,// kojim zelimo da menjamo atribut bodoviEXEC SQL DECLARE c_smer CURSOR FOR

select id_smera, oznaka, naziv, semestara, bodovifrom smer// Na ovaj nacin najavljujemo da cemo vrsiti promenu za kolonu "bodovi"for update of bodovi;

is_error("Declare cursor");

EXEC SQL OPEN c_smer;is_error("Open cursor");

for(;;){

EXEC SQL FETCH c_smerINTO :d_id, :d_oznaka, :d_naziv, :d_semestara, :d_bodovi;

is_error("Fetch cursor");

if (SQLCODE == 100){

break;}

printf("Da li zelite da povecate broj bodova za smer %.70s za 10?\n""Unesite d/D ili n/N. \n", d_naziv);

scanf("%c", &c);

// Da bismo procitali i znak za novi redgetchar();

// Ukoliko korisnik zeli izmenuif (c == 'd' || c == 'D'){

EXEC SQL UPDATE smerSET bodovi = bodovi + 10// Na ovaj nacin kazemo da zelimo izmenu// nad trenutnim redom u kursoru c_smerWHERE CURRENT OF c_smer;

is_error("Update");

EXEC SQL select bodovi INTO :d_bodovifrom smerwhere id_smera = :d_id;

is_error("Select into");

printf("Broj bodova je sada %hd\n", d_bodovi);}

}

EXEC SQL CLOSE c_smer;is_error("Close cursor");

Page 62: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

62 Glava 4. Programiranje korišćenjem kursora

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

U slučaju brisanja redova pomoću kursora, nije potrebno deklarisati koje kolone se mogubrisati kao što je to bio slučaj sa ažuriranjem. Potrebno je samo da tabela ime_tabelebude jedina tabela koja se nalazi u FROM klauzi upita kursora ime_kursora, da bi se moglakoristiti DELETE naredba oblika:DELETE FROM ime_tabeleWHERE CURRENT OF ime_kursora;

Primer 4.6 — Čas 03 — 10. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se za sve studente smera Informatika briše iz tabele ISPIT prvi položenispit (ukoliko ima položenih ispita tog studenta).

Rešenje.

Kod 4.6: Primeri/cas03/primer10.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char datum[11];EXEC SQL END DECLARE SECTION;

void is_error(char ∗str){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n", SQLCODE, str);exit(EXIT_FAILURE);

}}

int main(){

// Brojac obrisanih redovaint i = 0;

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DECLARE prvi_ispit CURSOR FORwith pomocna as (

select i.indeks, min(coalesce(datum_usmenog, datum_pismenog))datum_prvog

from ispit ijoin dosije d

on d.indeks = i.indeksjoin smer s

on s.id_smera = d.id_smerawhere s.oznaka = 'I'

Page 63: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.3 Korišćenje kursora za ažuriranje i brisanje podataka 63

and ocena > 5and status_prijave = 'o'

group by i.indeks)

select i.indeks, coalesce(datum_usmenog, datum_pismenog)from ispit iwhere exists (

select ∗from pomocna powhere po.indeks = i.indeks

and po.datum_prvog = coalesce(i.datum_usmenog, i.datum_pismenog)

);is_error("Declare cursor");

EXEC SQL OPEN prvi_ispit;is_error("Open cursor");

for(;;){

EXEC SQL FETCH prvi_ispitINTO :indeks, :datum;

is_error("Fetch cursor");

if (SQLCODE == 100){

break;}

printf("Student sa brojem indeksa %d ima datum polaganja prvog ispita %s...\n""Izbrisacemo to iz tabele ispit!\n", indeks, datum);

// Uvecavamo brojac za jedan++i;

EXEC SQL DELETE FROM ispit// Na ovaj nacin kazemo da zelimo da obrisemo// trenutni red u kursoru prvi_ispitWHERE CURRENT OF prvi_ispit;

is_error("Delete");}

printf("\n\nObrisali smo %d redova.\n", i);

EXEC SQL CLOSE prvi_ispit;is_error("Close cursor");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Naredni zadatak se ostavlja čitaocu za vežbu.

Page 64: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

64 Glava 4. Programiranje korišćenjem kursora

Zadatak 4.1 Napisati program u programskom jeziku C sa ugnežđenim SQL-om kojimse prvo unosi identifikator predmeta sa standardnog ulaza. Za taj predmet se zatimkorisniku nudi da li želi da obriše uslovne predmete za taj predmet i to tako što se zasvaki uslovni predmet nudi da li korisnik hoće da ga obriše ili ne. Odgovori su ’D’ i ’N’.Ukoliko je odgovor ’D’, u tabeli USLOVNI_PREDMET briše se željeni red koji se odnosi napredmet za koje je pitanje postavljeno. ■

Naredni primeri služe za provežbavanje usvojenih znanja iz kursora.

Primer 4.7 — Čas 04 — 01. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji se za sve studente smera Informatika ažurira u tabeli ISPIT prvi položenispit (ukoliko ima položenih ispita za tog studenta) tako što povećava ocenu za 1 (ukolikoje ocena bila 5 ili 10 ostavlja je nepromenjenu).

Rešenje.

Kod 4.7: Primeri/cas04/primer1.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;short ocena;EXEC SQL END DECLARE SECTION;

// Funkcija za obradu greskevoid is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Konekcija na bazu");

// Izdvajamo polja indeks i ocena,// da bismo mogli da ih ispisujemo na standardni izlaz// pre nego sto promenimo podatkeEXEC SQL DECLARE cursorInf CURSOR FOR

select indeks, ocenafrom ispit iwhere i.indeks in (

select indeksfrom dosije d join smer s

on s.id_smera = d.id_smerawhere naziv = 'Informatika'

)and i.ocena > 5and i.status_prijave = 'o'and not exists (

select ∗

Page 65: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.3 Korišćenje kursora za ažuriranje i brisanje podataka 65

from ispit i2where i2.indeks = i.indeks

and i2.ocena > 5and i2.status_prijave = 'o'and coalesce(i2.datum_usmenog, i2.datum_pismenog) <

coalesce(i.datum_usmenog, i.datum_pismenog))for update of ocena;

is_error("Deklarisanje kursora − cursorInf");

EXEC SQL OPEN cursorInf;is_error("Otvaranje kursora − cursorInf");

while(1){

EXEC SQL FETCH cursorInfINTO :indeks, :ocena;

is_error("Dohvatanje iz kursora − cursorInf");

if(SQLCODE == 100){

break;}

printf("Student %d, ocena: %d\n", indeks, ocena);

if(ocena > 5 && ocena < 10){

EXEC SQL UPDATE ispitSET ocena = ocena + 1WHERE current of cursorInf;

is_error("Azuriranje tabele ispit");}

}

EXEC SQL CLOSE cursorInf;is_error("Zatvaranje kursora − cursorInf");

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Primer 4.8 — Čas 04 — 02. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje sve napomene koje se nalaze u tabeli ISPIT, navodeći i broj indeksastudenata.

Rešenje.

Kod 4.8: Primeri/cas04/primer2.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char napomena[1001];short ind_napomena;sqlint32 indeks;EXEC SQL END DECLARE SECTION;

Page 66: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

66 Glava 4. Programiranje korišćenjem kursora

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

EXEC SQL DECLARE kursorNapomene CURSOR FORselect indeks, napomenafrom ispit;

is_error("Deklaracija kursora − kursorNapomene");

EXEC SQL OPEN kursorNapomene;is_error("Otvaranje kursora − kursorNapomene");

while(1){

EXEC SQL FETCH kursorNapomeneINTO :indeks, :napomena:ind_napomena;

is_error("Dohvatanje podataka iz kursora − kursorNapomene");

if(SQLCODE == 100){

break;}

// // U slucaju da zelimo da ispisujemo samo napomene koje postoje:// if(ind_napomena >= 0)// {// printf("Student %d : %.50s\n", indeks, napomena);// }

printf("Student %d : %.50s\n", indeks,(ind_napomena < 0)? "Nema napomene" : napomena);

}

EXEC SQL CLOSE kursorNapomene;is_error("Zatvaranje kursora − kursorNapomene");

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Primer 4.9 — Čas 04 — 03. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se sa standardnog ulaza unosi ime smera, a zatim se ispisuje 10 studenatatog smera koji su najviše padali na ispitima tokom studija. Izdvojiti ime, prezime, brojindeksa i broj padova tokom studija.

Page 67: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.3 Korišćenje kursora za ažuriranje i brisanje podataka 67

Rešenje.

Kod 4.9: Primeri/cas04/primer3.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char naziv_smera[201];char ime[21];char prezime[21];sqlint32 indeks;short br_padova;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

int i;

printf("Unesite naziv smera:\n");

// gets(naziv_smera);fgets(naziv_smera, sizeof(naziv_smera), stdin);

// Uklanjanje novog reda na kraju promenljive naziv_smera:// www.cplusplus.com/reference/cstring/strcspn/naziv_smera[strcspn(naziv_smera, "\n")] = 0;

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

EXEC SQL DECLARE kursorBrojPadova CURSOR FORselect i.indeks, ime, prezime,

sum(casewhen ocena = 5 and status_prijave = 'o'

then 1else 0

end) br_padovafrom ispit i

join dosije don i.indeks = d.indeks

join smer son s.id_smera = d.id_smera

where s.naziv = trim(:naziv_smera)group by i.indeks, ime, prezimeorder by br_padova desc;

is_error("Deklaracija kursora − kursorBrojPadova");

EXEC SQL OPEN kursorBrojPadova;is_error("Otvaranje kursora − kursorBrojPadova");

Page 68: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

68 Glava 4. Programiranje korišćenjem kursora

for(i = 0; i < 10; ++i){

EXEC SQL FETCH kursorBrojPadovaINTO :indeks,:ime, :prezime, :br_padova;

is_error("Dohvatanje podataka iz kursora − kursorBrojPadova");

// I dalje imamo ovu proveru jer ih mozda ima manje od 10if(SQLCODE == 100){

break;}

printf("Student %d, %s %s, broj padanja: %d\n",indeks, ime, prezime, br_padova);

}

EXEC SQL CLOSE kursorBrojPadova;is_error("Zatvaranje kursora − kursorBrojPadova");

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Primer 4.10 — Čas 04 — 04. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji ispisuje za svakog studenta ime, prezime, poslednji položeni ispit (tj. nazivpredmeta koji je položen), kao i datum polaganja tog ispita.

Rešenje.

Kod 4.10: Primeri/cas04/primer4.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char ime[21];char prezime[21];char naziv[201];char datum[11];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud;is_error("konekcija na bazu");

EXEC SQL DECLARE student_predmet CURSOR FOR

Page 69: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.3 Korišćenje kursora za ažuriranje i brisanje podataka 69

with poslednji_ispit as (select indeks,

max(coalesce(datum_usmenog, datum_pismenog)) datum_poslednjegfrom ispitwhere ocena > 5

and status_prijave = 'o'group by indeks

)

select trim(ime), trim(prezime), datum_poslednjeg, trim(naziv)from poslednji_ispit pi

join dosije don pi.indeks = d.indeks

join ispit ion pi.indeks = i.indeks

join predmet pon p.id_predmeta = i.id_predmeta

where datum_pismenog = datum_poslednjegor datum_usmenog = datum_poslednjegand ocena > 5;

is_error("Deklaracija kursora − student_predmet");

EXEC SQL OPEN student_predmet;is_error("Otvaranje kursora − student_predmet");

while(1){

EXEC SQL FETCH student_predmetINTO :ime, :prezime, :datum, :naziv;

is_error("Dohvatanje podataka iz kursora − student_predmet");

if (SQLCODE == 100){

break;}

printf("Poslednji polozeni ispit studenta %.15s %.15s je %.75s\n""Datum polaganja: %.11s\n\n", ime, prezime, naziv, datum);

}

EXEC SQL CLOSE student_predmet;is_error("Zatvaranje kursora − student_predmet");

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Primer 4.11 — Čas 04 — 05. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se brišu sva uspešna polaganja ispita iz barem trećeg pokušaja za studentekoji su upisivali najviše N godina, gde se vrednost za N unosi sa standardnog ulaza.

Rešenje.

Kod 4.11: Primeri/cas04/primer5.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

Page 70: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

70 Glava 4. Programiranje korišćenjem kursora

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_indeks;short br_godina;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

char karakter_za_brisanje;int brojac = 0;

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

EXEC SQL DECLARE studenti CURSOR FORselect indeksfrom ispit iwhere status_prijave = 'o'

and ocena > 5and broj_polaganja >= 3and (

select count(∗)from upis_godinewhere indeks = i.indeks

) >= :br_godina;is_error("Deklaracija kursora − studenti");

printf("Unesi maksimalan broj godina koje je student upisivao\n");scanf("%hd", &br_godina);

EXEC SQL OPEN studenti;is_error("Otvaranje kursora − studenti");

while(1){

EXEC SQL FETCH studentiINTO :d_indeks;

is_error("Dohvatanje podataka iz kursora − studenti");

if (SQLCODE == 100){

break;}

scanf("%c", &karakter_za_brisanje);

printf("Brisemo polaganje studenta sa brojem indeksa %d\n", d_indeks);

EXEC SQL DELETE from ispitWHERE CURRENT OF studenti;

is_error("Brisanje iz kursora − studenti");

Page 71: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.3 Korišćenje kursora za ažuriranje i brisanje podataka 71

++brojac;}

printf("\nIzvestaj: Obrisali smo %d redova.\n", brojac);

// // Alternativno, bez koriscenja kursora,// // mogli smo koristiti DELETE upit,// // bez informacije o broju redova// EXEC SQL DELETE FROM ispit// WHERE status_prijave = 'o'// and ocena > 5// and brojpol >= 3// and exists(// select ∗// from dosije// where indeks = i.indeks// and status='budzet'// )// and (// select count(∗)// from upis_godine// where indeks = i.indeks// ) >= :br_godina;// is_error("Brisanje iz tabele ispit");

EXEC SQL CLOSE studenti;is_error("Zatvaranje kursora − studenti");

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Primer 4.12 — Čas 04 — 06. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji za studenta čiji se broj indeksa zadaje sa standardnog ulaza, ispisuje nazivpredmeta, datum polaganja, ocenu, broj bodova na pismenom i broj bodova na usmenomdelu ispita za svaki ispit koji je student položio. Nakon toga ispisuje se prosečna ocenastudenta.

Rešenje.

Kod 4.12: Primeri/cas04/primer6.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_indeks;char d_ime_i_prezime[41];char d_naziv[201];char d_datum[11];short d_ocena;double d_prosek;short id_prosek;short d_bodovi_pismenog;short d_bodovi_usmenog;short id_bodovi_pismenog;

Page 72: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

72 Glava 4. Programiranje korišćenjem kursora

short id_bodovi_usmenog;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

// Promenljiva koja se koristi kao Bulova vrednost// i oznacava da li se ispisuje prvi ispit ili neint prvi_ispit = 1;

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

EXEC SQL DECLARE polozeni_ispiti CURSOR FORselect rtrim(ime) || ' ' || rtrim(prezime),

rtrim(p.naziv),coalesce(datum_usmenog, datum_pismenog),ocena,bodovi_pismenog,bodovi_usmenog

from dosije djoin ispit i

on d.indeks = i.indeksjoin predmet p

on i.id_predmeta = p.id_predmetawhere d.indeks = :d_indeks

and ocena > 5and status_prijave = 'o';

is_error("Deklaracija kursora − polozeni_ispiti");

printf("Unesite broj indeksa studenta kome se izdaje uverenje ""o polozenim ispitima:\n");

scanf("%d", &d_indeks);

EXEC SQL OPEN polozeni_ispiti;is_error("Otvaranje kursora − polozeni_ispiti");

while(1){

EXEC SQL FETCH polozeni_ispitiINTO :d_ime_i_prezime, :d_naziv, :d_datum, :d_ocena,

:d_bodovi_pismenog:id_bodovi_pismenog,:d_bodovi_usmenog:id_bodovi_usmenog;

is_error("Dohvatanje podataka iz kursora − polozeni_ispiti");

if(SQLCODE == 100){

if(prvi_ispit){

printf("Student sa indeksom %d nema polozenih ispita ""ili ne postoji u bazi!\n", d_indeks);

}break;

Page 73: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.3 Korišćenje kursora za ažuriranje i brisanje podataka 73

}

// Ako je to prvi procitani red ispisujemo podatke o studentu izaglavlje

if(prvi_ispit){

printf("\nStudent: %s indeks: %d\n\n",d_ime_i_prezime, d_indeks);printf("NAZIV "

"DATUM OCENA PISMENI USMENI\n");printf("============================================="

"==============================\n");

prvi_ispit = 0;}

printf("%40s %11s %5d ",d_naziv, d_datum, d_ocena);

if (id_bodovi_pismenog >= 0){

printf("%7d", d_bodovi_pismenog);}else{

printf(" −");}

if (id_bodovi_usmenog >= 0){

printf("%7d\n", d_bodovi_usmenog);}else{

printf(" −\n");}

}

EXEC SQL CLOSE polozeni_ispiti;is_error("Zatvaranje kursora − polozeni_ispiti");

// Za datog studenta racunamo prosek ocenaEXEC SQL SELECT avg(ocena+0.0)

INTO :d_prosek:id_prosekfrom ispitwhere indeks = :d_indeks

and ocena > 5and status_prijave = 'o';

is_error("Racunanje proseka ocena");

if (id_prosek >= 0){

printf("=================================================""=========================\nProsek ocena je: %2f.\n\n", d_prosek);

}

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Page 74: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

74 Glava 4. Programiranje korišćenjem kursora

4.4 Ugnežđeni kursori

Do sada smo videli kako možemo koristiti kursore za upravljanje potencijalno višim brojemredova u rezultatu upita. Obrada ovih redova je do sada obuhvatala jednostavno proce-siranje podataka, poput ispisivanja na standardni izlaz, uz eventualne transformacije iliažuriranje ili brisanje podataka na koje pokazuje kursor.

Međutim, šta raditi ukoliko je potrebno da za svaki red rezultata jednog upita izvršimoakciju nad rezultatom nekog drugog upita? Da li nam kursori u ovakvim situacijama mogupomoći? Odgovor je potvrdan zbog činjenice da je kursore moguće ugnežđavati. Tipičantok rada podrazumeva da se svi kursori prvo deklarišu, a zatim da se procesi otvaranja izatvaranja potkursora izvršavaju nakon dohvatanja podataka iz natkursora. Naredna dvaprimera ilustruju rad sa ugnežđenim kursorima.

Primer 4.13 — Čas 04 — 07. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se formira izveštaj o studentima koji su padali neki ispit koji sadržisledeće informacije: ime, prezime i broj indeksa.Za svaki smer formirati posebnu sekciju izveštaja sa odgovarajućim zaglavljem. Sadržajsvake sekcije urediti po broju indeksa.

Rešenje.

Kod 4.13: Primeri/cas04/primerKursorUKursoru1.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 id_smera;char naziv[201];sqlint32 indeks;char ime[21];char prezime[21];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

EXEC SQL DECLARE smerovi CURSOR FORselect id_smera, nazivfrom smerorder by id_smera;

is_error("Deklaracija kursora − smerovi");

EXEC SQL DECLARE padaliIspit CURSOR FORselect indeks, ime, prezime

Page 75: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.4 Ugnežđeni kursori 75

from dosije dwhere d.id_smera = :id_smera

and exists (select ∗from ispitwhere indeks = d.indeks

and ocena = 5and status_prijave = 'o'

)order by indeks;

is_error("Deklaracija kursora − padaliIspit");

EXEC SQL OPEN smerovi;is_error("Otvaranje kursora − smerovi");

while(1){

EXEC SQL FETCH smeroviINTO :id_smera, :naziv;

is_error("Dohvatanje podataka iz kursora − smerovi");

if(SQLCODE == 100){

break;}

// Stampamo sekciju za smerprintf("\n∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗\nStudenti sa smera %d: %s!\n

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗\n",id_smera, naziv);

EXEC SQL OPEN padaliIspit;is_error("Otvaranje kursora − padaliIspit");

while(1){

EXEC SQL FETCH padaliIspitINTO :indeks, :ime, :prezime;

is_error("Dohvatanje podataka iz kursora − padaliIspit");

if(SQLCODE == 100){

break;}

// Stampamo informacije o studentuprintf("Student %s %s sa brojem indeksa %d\n", ime, prezime, indeks

);}

EXEC SQL CLOSE padaliIspit;is_error("Zatvaranje kursora − padaliIspit");

}

EXEC SQL CLOSE smerovi;is_error("Zatvaranje kursora − padaliIspit");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;

Page 76: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

76 Glava 4. Programiranje korišćenjem kursora

}

Primer 4.14 — Čas 04 — 08. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se za svaki smer pronalazi student koji ima najviše položenih ESPBbodova. Zatim u tabeli ISPIT u napomeni koja se odnosi na poslednji položeni ispittog studenta zapisuje 'Ovo je student koji ima najvise polozenih kredita na svomsmeru'.

Rešenje.

Kod 4.14: Primeri/cas04/primerKursorUKursoru2.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;short suma;sqlint32 id_smera;sqlint32 indeks;char datum[11];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud;is_error("Konekcija na bazu");

EXEC SQL DECLARE najvisePolozenih CURSOR FORwith pomocna as (

select d.id_smera, d.indeks, sum(p.bodovi) sumafrom dosije d

join ispit ion i.indeks = d.indeks

join predmet pon p.id_predmeta = i.id_predmeta

where ocena > 5and status_prijave='o'

group by d.id_smera, d.indeks)

select pom.suma, d.indeks, pom.id_smerafrom pomocna pom

join dosije don d.indeks = pom.indeks

where pom.suma in (select max(suma) from pomocna pom1where pom1.id_smera = pom.id_smera

)order by id_smera;

Page 77: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

4.4 Ugnežđeni kursori 77

is_error("Deklaracija kursora − najvisePolozenih");

EXEC SQL DECLARE poslednji_ispit CURSOR FORwith pomocna as (

select i.indeks,max(coalesce(datum_usmenog, datum_pismenog)) datum_prvog

from ispit ijoin dosije d

on d.indeks = i.indekswhere ocena > 5

and status_prijave = 'o'group by i.indeks

)

select i.indeksfrom ispit iwhere i.indeks = :indeks

and exists (select ∗from pomocna powhere po.indeks = i.indeks

and po.datum_prvog = coalesce(i.datum_usmenog, i.datum_pismenog)

)for update of napomena;

is_error("Deklaracija kursora − poslednji_ispit");

EXEC SQL OPEN najvisePolozenih;is_error("Otvaranje kursora − najvisePolozenih");

while(1){

EXEC SQL FETCH najvisePolozenihINTO :suma, :indeks, :id_smera;

is_error("Dohvatanje podataka iz kursora − najvisePolozenih");

if(SQLCODE == 100){

break;}

// Stampamo informaciju o studentu koji ima najvise kredita na smeruprintf("Student sa brojem indeksa %d na smeru %d ima polozeno %d bodova

!\n",indeks, id_smera, suma);

EXEC SQL OPEN poslednji_ispit;is_error("Otvaranje kursora − poslednji_ispit");

while(1){

EXEC SQL FETCH poslednji_ispitINTO :indeks, :datum;

is_error("Dohvatanje podataka iz kursora − poslednji_ispit");

if(SQLCODE == 100){

break;}

EXEC SQL UPDATE ispit

Page 78: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

78 Glava 4. Programiranje korišćenjem kursora

SET napomena = 'Ovo je student koji ima najvise polozenihkredita na svom smeru'

WHERE CURRENT OF poslednji_ispit;is_error("Azuriranje tabele ispit");

}

EXEC SQL CLOSE poslednji_ispit;is_error("Zatvaranje kursora − poslednji_ispit");

}

EXEC SQL CLOSE najvisePolozenih;is_error("Zatvaranje kursora − najvisePolozenih");

EXEC SQL CONNECT RESET;is_error("Diskonekcija sa baze");

return 0;}

Page 79: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5. Programiranje transakcija

Transakcije predstavljaju izuzetno važan alat za svakog programera koji koristi baze po-dataka u svojim aplikacijama. Svaka iole kompleksnija operacija nad podacima zahtevakorišćenje transakcija da bi se takva operacija uspešno implementirala. Pritom, postojiveliki broj pitanja i potencijalnih problema koji se otvaraju prilikom korišćenja transak-cija. U ovoj sekciji ćemo se upoznati sa različitim naredbama za rad sa transakcijamau DB2 sistemu za upravljanje relacionim bazama podataka. Započnimo ovaj deo tekstanarednom definicijom.

Definicija 5.0.1 — Transakcija. Transakcija (engl. transaction) predstavlja logičku jedi-nicu posla pri radu sa podacima.

Transakcija predstavlja niz radnji koji ne narušava uslove integriteta. Sa stanovišta kori-snika, izvršavanje transakcije je atomično. Po izvršenju kompletne transakcije stanje bazetreba da bude konzistentno, tj. da su ispunjeni uslovi integriteta. Dakle, posmatranakao jedinica posla, transakcija prevodi jedno konzistentno stanje baze u drugo takvo sta-nje baze, dok u međukoracima transakcije konzistentnost podataka može biti i narušena.Transakcija na taj način predstavlja i bezbedno sredstvo za interakciju korisnika sa bazom.

5.1 Složena SQL naredba

U ovoj sekciji ćemo diskutovati o načinima za izvršavanje više SQL naredbi kao jednenaredbe, tzv. složene SQL naredbe. Složene SQL naredbe predstavljaju osnovu rada satransakcijama, o čemu će biti detaljnije reči u nastavku teksta.

Definicija 5.1.1 — Složena SQL naredba. Složena SQL naredba (engl. compound SQL)predstavlja sekvencu SQL naredbi ograđenu odgovarajućim ključnim rečima kojim sedefiniše jedan blok izvršavanja.

Page 80: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

80 Glava 5. Programiranje transakcija

Postoje tri tipa složenih SQL naredbi:

1. Linijske (engl. inline) — Složena SQL linijska naredba je složena SQL naredba kojaje umetnuta linijski tokom faze izvršavanja u okviru druge SQL naredbe. SloženeSQL linijske naredbe imaju svojstvo atomičnosti; ako izvršavanje bilo koje pojedi-načne SQL naredbe podigne grešku, cela naredba se poništava.

2. Ugnežđene (engl. embedded) — Ovaj tip naredbi kombinuje jednu ili više SQL na-redbi (odnosno, podnaredbi) u jedan izvršivi blok.

3. Kompilirane (engl. compiled) — Predstavlja sekvencu SQL naredbi koje se izvršavajusa lokalnim opsegom za promenljive, uslove, kursore i pokazivače na slogove (engl.handle).

Mi ćemo u daljem tekstu razmatrati isključivo složene SQL ugnežđene naredbe, tako dapodrazumevamo ovaj tip kada kažemo ”složena SQL naredba”. Sintaksa ovih naredbi jedata u nastavku:BEGIN COMPOUND (ATOMIC|NOT ATOMIC) STATIC[STOP AFTER FIRST host−variable STATEMENTS]

sql−statement;sql−statement;...sql−statement;

END COMPOUND

U zavisnosti od odabranih vrednosti narednih opcija prilikom deklaracije složene SQLnaredbe, ta naredba može imati različite varijante koji utiču na način izvršavanja:

• Atomičnost — tačno jedna od naredne dve opcije se navode– ATOMIC — Specifikuje da, ako bilo koja od podnaredbi u okviru složene SQL

naredbe bude izvršena neuspešno, onda se sve izmene u bazi podataka koje sunastale efektom bilo koje druge podnaredbe, bilo one uspešne izvršene ili ne,poništavaju.

– NOT ATOMIC — Specifikuje da, bez obzira na neuspešno izvršavanje podnaredbi,složena SQL naredba neće poništiti izmene u bazi podataka koje su nastaleefektom bilo koje druge podnaredbe.

• Statičnost — navodi se naredna naredba– STATIC — Specifikuje da će sve matične promenljive za sve podnaredbe zadržati

njihove originalne vrednosti. Na primer, ukoliko imamo naredbu:SELECT ... INTO :abc ...

koja je praćena naredbomUPDATE T1 SET C1 = 5 WHERE C2 = :abc

onda će naredba UPDATE koristiti vrednost matične promenljive abc koju je tapromenljiva imala na početku bloka koji je definisan složenom SQL naredbom,a ne vrednost koja je dobijena naredbom SELECT. Dodatno, ako se vrednost istepromenljive postavlja od strane više SQL podnaredbi, onda će na kraju blokata promenljiva sadržati vrednost koju je postavila poslednja SQL podnaredba.Napomenimo da u DB2 sistemu nestatičko ponašanje nije podržano. To značida bi trebalo posmatrati kao da se podnaredbe izvršavaju nesekvencijalno ipodnaredbe ne bi trebalo da imaju međuzavisnosti.

Page 81: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.1 Složena SQL naredba 81

• Opcionom klauzom STOP AFTER FIRST specifikujemo da će se izvršiti samo određenibroj podnaredbi. Matična promenljiva host−variable (tipa short) sadrži ceo brojN kojim se specifikuje koliko prvih N podnaredbi će biti izvršeno.

Nakon opisanih opcija, potrebno je navesti nula ili više SQL naredbi sql−statement. SQLnaredbe koje je moguće navesti kao deo složenih SQL naredbi su sve izvršive naredbe, osimnarednih 14 naredbi:

1. CALL2. CLOSE3. CONNECT4. Compound SQL5. DESCRIBE6. DISCONNECT7. EXECUTE IMMEDIATE8. FETCH9. OPEN10. PREPARE11. RELEASE (Connection)12. ROLLBACK13. SET CONNECTION14. SET variable

Ukoliko se naredba COMMIT koristi kao jedna od podnaredbi, onda se ona mora naći kao po-slednja podnaredba. Ukoliko je COMMIT nađe na ovoj poziciji, onda će ona biti izvršena, čaki u situaciji da klauza STOP AFTER FIRST indikuje da se neće sve podnaredbe u okviru slo-žene SQL naredbe izvršiti. Na primer, pretpostavimo da je COMMIT poslednja podnaredbau okviru složene SQL naredbe koja ima 100 podnaredbi. Ukoliko se klauzom STOP AFTERFIRST specifikuje da se izvršava prvih 50 podnaredbi, onda će COMMIT podnaredba bitiizvršena kao 51. podnaredba.

Neka dodatna pravila i napomene koje treba imati u vidu prilikom rada sa složenih SQLnaredbama u DB2 sistemu su sledeće:

• Nije dozvoljeno ugnežđavati kod iz matičnog jezika unutar bloka koji definiše složenaSQL naredba.

• Nije dozvoljeno ugnežđavati složene SQL naredbe u okviru drugih složenih SQLnaredbi.

• Pripremljena COMMIT naredba nije dozvoljena u ATOMIC složenoj SQL naredbi.• Jedna SQLCA se postavlja za celu složenu SQL naredbu. Važe naredna pravila:

– Vrednosti SQLCODE i SQLSTATE koje se postavljaju na kraju složene SQL naredbesu podrazumevano postavljene na osnovu poslednje podnaredbe koja se izvršilau okviru složene SQL naredbe, osim u slučaju opisanom narednom tačkom.

– Ako je sistem signalizirao ”nije pronađen podatak” upozorenje (SQLSTATE 02000, odnosno, SQLCODE +100), onda se tom upozorenju daje prednost u odnosu naostala upozorenja da bi se naredbom WHENEVER NOT FOUND moglo dejstvovati. Uovoj situaciji se polja iz SQLCA koja se eventualno vraćaju aplikaciji postavljajuna osnovu podnaredbe koja je okinula ”nije pronađen podatak” upozorenje.Ukoliko u okviru složene SQL naredbe postoji više podnaredbi koje okidajuovo upozorenje, onda se polja iz SQLCA postavljaju na osnovu poslednje od tihpodnaredbi.

Page 82: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

82 Glava 5. Programiranje transakcija

Pre nego što započnemo sa primerima vezanih za složene SQL naredbe, uvedimo još dveSQL naredbe koje će nam biti neophodne za naredne primere. U pitanju su naredbe COMMITi ROLLBACK, čiji je efekat pohranjivanje, odnosno, poništavanje izmena koje su prethodneSQL naredbe izvršile nad bazom podataka, redom. Više o ovim naredbama će biti reči upodsekciji 5.2.

Primer 5.1 — Čas 05 — 01. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji:

1. Pronalazi i ispisuje najveći indeks iz tabele ISPIT.2. Briše studenta sa pronađenim indeksom iz tabele ISPIT.3. Ponovo pronalazi i ispisuje najveći indeks iz tabele ISPIT.4. Poništava načinjene izmene u bazi podataka naredbom ROLLBACK.5. Konačno, pronalazi i ispisuje najveći indeks iz tabele ISPIT.

Rešenje.

Kod 5.1: Primeri/cas05/rollback.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

// U funkciju za obradu greske dodajemo naredbu ROLLBACK// da bismo ponistili eventualne izmene u bazi podataka// ukoliko zaista dodje do greske.EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud USER student USING abcdef;is_error("Connect");

EXEC SQL SELECT max(indeks) INTO :indeksFROM ispit;

is_error("Select 1");

if(SQLCODE != 100){

printf("Maksimalni indeks je %d.\n", indeks);

// Brisanje studenta sa najvecim indeksom iz tabele ispitEXEC SQL DELETE FROM ispit

WHERE indeks = :indeks;is_error("Delete");

Page 83: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.1 Složena SQL naredba 83

// Ispisivanje najveceg indeksa iz tabele ispitEXEC SQL SELECT max(indeks) INTO :indeks

FROM ispit;is_error("Select 2");

if(SQLCODE != 100){

printf("Maximalni indeks je %d.\n", indeks);}else{

printf("Tabela je prazna!\n");}

// Ponistavamo transakciju naredbom ROLLBACKEXEC SQL ROLLBACK;is_error("Rollback");

printf("Izvrsen je Rollback!\n");

// Ispisujemo najveci indeks ponovoEXEC SQL SELECT max(indeks) INTO :indeks

FROM ispit;is_error("Select 3");

if(SQLCODE != 100){

printf("Maximalni indeks je %d.\n", indeks);}else{

printf("Tabela je prazna!\n");}

}else{

printf("Tabela je prazna!\n");}

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Sada slede primeri korišćenja složenih SQL naredbi. Primetimo da smo, kao i u pret-hodnom primeru, koristili naredbu ROLLBACK u definiciji funkcije is_error da poništimoizmene u bazi podataka u slučaju da dođe do greške.

Primer 5.2 — Čas 05 — 02. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji:

1. Kreira novi ispitni rok samo za predmete iz prvog semestra u 2019. godini čijaje oznaka ”maj” i naziv ”Maj 2019”. Za početak prijavljivanja postaviti današnjidatum i postaviti da prijavljivanje traje 20 dana.

2. Ažurira datum kraja prijavljivanja za prethodno uneti ispitni rok tako što smanjujetrajanje prijavljivanja za 10 dana.

Page 84: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

84 Glava 5. Programiranje transakcija

Obezbediti da se navedene operacije izvrše ili sve ili nijedna.

Rešenje.

Kod 5.2: Primeri/cas05/slozeniSQL/compound1.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

// Funkcija za obradu greskevoid is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL BEGIN COMPOUND ATOMIC STATICINSERT INTO ispitni_rok

VALUES (2019, 'maj', 'Maj 2019', current_date, current_date + 20days, 1);

UPDATE ispitni_rokSET kraj_prijavljivanja = kraj_prijavljivanja − 10 daysWHERE godina = 2019

and oznaka = 'maj';END COMPOUND;

is_error("Compound");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 5.3 — Čas 05 — 03. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji:

1. Kreira novi ispitni rok samo za predmete iz prvog semestra u 2019. godini čijaje oznaka ”apr” i naziv ”April 2019”. Za početak prijavljivanja postaviti današnjidatum i postaviti da prijavljivanje traje 10 dana.

2. Ažurira tip za prethodno uneti ispitni rok na tip ”Z”.

Obezbediti da se navedene operacije izvrše ili sve ili nijedna.

Rešenje.

Kod 5.3: Primeri/cas05/slozeniSQL/compound2.sqc#include <stdio.h>

Page 85: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.1 Složena SQL naredba 85

#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL BEGIN COMPOUND ATOMIC STATICINSERT INTO ispitni_rok

VALUES (2019, 'apr', 'April 2019', current_date, current_date + 10days, 1);

UPDATE ispitni_rok−− Neispravan je tip!−− Ocekujemo da nam izbaci gresku prilikom pokretanja,−− kao i da se ne unese April 2019 u tabelu ISPITNI_ROKSET tip = 'Z'WHERE godina = 2019

AND oznaka = 'apr';

COMMIT;END COMPOUND;is_error("Compound");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 5.4 — Čas 05 — 04. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji:

1. Kreira novi ispitni rok samo za predmete iz prvog semestra u 2019. godini čijaje oznaka ”apr” i naziv ”April 2019”. Za početak prijavljivanja postaviti današnjidatum i postaviti da prijavljivanje traje 10 dana.

2. Ažurira tip za prethodno uneti ispitni rok na tip ”Z”.

Obezbediti da se navedene operacije izvrše zasebno.

Rešenje.

Kod 5.4: Primeri/cas05/slozeniSQL/compound3.sqc#include <stdio.h>#include <stdlib.h>

Page 86: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

86 Glava 5. Programiranje transakcija

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL BEGIN COMPOUND NOT ATOMIC STATICINSERT INTO ispitni_rok

VALUES (2019, 'apr', 'April 2019', current_date, current_date + 10days, 1);

UPDATE ispitni_rokSET tip = 'Z'WHERE godina = 2019

AND oznaka = 'apr';

COMMIT;END COMPOUND;is_error("Compound");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 5.5 — Čas 05 — 05. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji omogućava korisniku da unese nove ispitne rokove samo za predmete izprvog semestra u 2019. godini za svaki mesec od marta do oktobra, sa odgovarajućimoznakama i nazivima. Za svaki ispitni rok postaviti da je datum početka prijavljivanjadanašnji datum pomeren za odgovarajući broj meseci, kao i da prijavljivanje traje 20dana.

Omogućiti da korisnik unese broj ispitnih rokova koji želi da kreira. Minimalni brojispitnih rokova je 0, a maksimalni broj je 6. U zavisnosti od unetog broja, kreiratiodgovarajući broj ispitnih rokova.

Obezbediti da se navedene operacije izvrše zasebno.

Rešenje.

Kod 5.5: Primeri/cas05/slozeniSQL/compound4.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>

EXEC SQL INCLUDE SQLCA;

Page 87: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.1 Složena SQL naredba 87

EXEC SQL BEGIN DECLARE SECTION;short br;EXEC SQL END DECLARE SECTION;

// Ova funkcija predstavlja dodatni kod − samo za znatizeljne// Ne podrazumeva se poznavanje ove funkcije na proverama znanja!void prikazi_sqlstate_za_svaku_podnaredbu();

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

prikazi_sqlstate_za_svaku_podnaredbu();

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

printf("Koliko zelite ispitnih rokova u 2019. godini? ""Maksimum je 6, a minimum je 0. \n");

scanf("%hd", &br);

EXEC SQL BEGIN COMPOUND NOT ATOMIC STATIC STOP AFTER FIRST :br STATEMENTSINSERT INTO ispitni_rok

VALUES (2019, 'mar', 'Mart 2019', current_date, current_date + 20days, 1);

INSERT INTO ispitni_rokVALUES (2019, 'apr', 'April 2019', current_date + 1 month,

current_date + 1 month + 20 days, 1);INSERT INTO ispitni_rok

VALUES (2019, 'maj', 'Maj 2019', current_date + 2 month,current_date + 2 month + 20 days, 1);

INSERT INTO ispitni_rokVALUES (2019, 'jun', 'Jun 2019', current_date + 3 month,

current_date + 3 month + 20 days, 1);INSERT INTO ispitni_rok

VALUES (2019, 'jul', 'Jul 2019', current_date + 4 month,current_date + 4 month + 20 days, 1);

INSERT INTO ispitni_rokVALUES (2019, 'avg', 'Avgust 2019', current_date + 5 month,

current_date + 5 month + 20 days, 1);INSERT INTO ispitni_rok

VALUES (2019, 'sep', 'Septembar 2019', current_date + 6 month,current_date + 6 month + 20 days, 1);

INSERT INTO ispitni_rokVALUES (2019, 'okt', 'Oktobar 2019', current_date + 7 month,

current_date + 7 month + 20 days, 1);COMMIT;

END COMPOUND;is_error("Compound");

EXEC SQL CONNECT RESET;

Page 88: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

88 Glava 5. Programiranje transakcija

is_error("Connect reset");

return 0;}

// Ova funkcija predstavlja dodatni kod − samo za znatizeljne// Ne podrazumeva se poznavanje ove funkcije na proverama znanja!void prikazi_sqlstate_za_svaku_podnaredbu(){

// Kod −1339 oznacava da// barem jedna od podnaredbi u COMPOUND// nije izvrsena uspesnoif (sqlca.sqlcode != −1339){

return;}

// Za dijagnostifikaciju mozemo koristiti nisku sqlca.sqlerrmc// koja ima specijalnu strukturu oblika://// nnnXsssccccc//// gde se podniska Xsssccccc ponavlja najvise 7 puta// a njeno znacenje je:// 1) nnn − Ukupan broj neuspelih podnaredbi.// Ukoliko ih ima vise od 999,// brojanje se resetuje od 0.// 2) X − Token separator X'FF'.// 3) sss − Redni broj podnaredbe koja je proizvela gresku.// 4) ccccc − SQLSTATE greske za tu podnaredbu

// Izdvajamo broj neuspelih naredbichar neuspele_naredbe[4];strncpy(neuspele_naredbe, sqlca.sqlerrmc, 3);neuspele_naredbe[3] = 0;

int broj_neuspesnih_podnaredbi = atoi(neuspele_naredbe);printf("Broj neuspesnih podnaredbi: %d\n", broj_neuspesnih_podnaredbi);

// Alternativno:// broj_neuspesnih_podnaredbi = sqlca.sqlerrd[1];

// Za svaku neuspesnu podnaredbu,// izdvajamo njen redni broj i SQLSTATEint pokazivac = 3,

idx_naredbe = 0;char redni_broj_naredbe[4];char sqlstate_naredbe[6];for(; idx_naredbe < broj_neuspesnih_podnaredbi; ++idx_naredbe){

// Preskacemo token separator++pokazivac;

// Izdvajamo informaciju o rednom broju naredbestrncpy(redni_broj_naredbe, sqlca.sqlerrmc + pokazivac, 3);redni_broj_naredbe[3] = 0;pokazivac += 3;

// Izdvajamo informaciju o SQLSTATEstrncpy(sqlstate_naredbe, sqlca.sqlerrmc + pokazivac, 5);sqlstate_naredbe[5] = 0;

Page 89: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.2 Tačke čuvanja u okviru transakcija 89

pokazivac += 5;

printf("Podnaredba sa rednim brojem %d je prijavila gresku sa SQLSTATEvrednoscu %s\n",atoi(redni_broj_naredbe), sqlstate_naredbe

);}

}

5.2 Tačke čuvanja u okviru transakcija

U prethodnim primerima smo videli da možemo da predstavimo transakcije kao složeneSQL naredbe, a zatim da koristimo specifičnosti složenih SQL naredbi da bismo preciznijedefinisali ponašanje u zavisnosti od toga da li se pojavila greška tokom rada transakcije iline. Preciznije, videli smo kako je moguće poništiti efekat celog izvršavanja programa kaojedinice posla u slučaju pojave greške u nekoj od podnaredbi.

Vrlo često nam je neophodno da imamo precizniju kontrolu nad time šta se tačno poništava,na primer, ukoliko želimo da samo jedan deo transakcije bude poništen, umesto cele trans-akcije. Da bismo postigli takav efekat, potrebne su nam sofisticiranije metode upravljanjatransakcijama. Jedan od takvih metoda podrazumeva korišćenje tačke čuvanja.

Definicija 5.2.1 — Tačka čuvanja. Tačka čuvanja (engl. savepoint) predstavlja mehani-zam za poništavanje preciznog definisanog skupa izvršenih naredbi.

Ukoliko se desi neka greška prilikom izvršavanja transakcije, tačka čuvanja se može koristitida poništi dejstvo naredbi od trenutka kada je tačka čuvanja započeta do trenutka kadaje poništenje akcija zahtevano.

Samim tim, tačka čuvanja omogućava konstruisanje grupe od nekoliko SQL naredbi, gru-pisanih u jedan izvršivi blok, koji se može izvršavati, kao deo jedne transakcije. Ukolikose neka od podnaredbi izvrši sa greškom, taj definisani blok će biti poništen.

5.2.1 Kreiranje tačke čuvanja

Kreiranje tačke čuvanja u izvornom kodu se može izvršiti pozivanjem naredbe SAVEPOINT,čija je sintaksa data sa:SAVEPOINT savepoint−name [UNIQUE]ON ROLLBACK RETAIN CURSORS[ON ROLLBACK RETAIN LOCKS]

Ovom naredbom se kreira nova tačka čuvanja naziva savepoint−name. Ukoliko specifiku-jemo opcionu klauzu UNIQUE, onda navodimo da aplikacija ne želi da iskoristi ovo ime tačkečuvanja dok je tačka čuvanja aktivna u okviru trenutnog nivoa čuvanja. DB2 sistem ćeprijaviti grešku ako pokušamo da kreiramo tačku čuvanja kao jedinstvenu ako već postojitačka čuvanja sa istim imenom, kao i ako pokušamo da kreiramo tačku čuvanja sa imenomkoje je prethodno bilo proglašeno za jedinstveno.

Obaveznom klauzom ON ROLLBACK RETAIN CURSORS se specifikuje ponašanje sistema tokomoperacija poništavanja izmena do ove tačke čuvanja u odnosu na otvorene kursore nakonove SAVEPOINT naredbe. Ovom klauzom se indikuje da, kada god je to moguće, kursori

Page 90: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

90 Glava 5. Programiranje transakcija

bivaju van uticaja operacije poništavanja do tačke čuvanja. Za više detalja o tome kakoponištavanje izmena utiče na kursore, pogledati podsekciju 5.4.

Ukoliko navedemo opcionu klauzu ON ROLLBACK RETAIN LOCKS se specifikuje ponašanje si-stema tokom operacija poništavanja izmena do ove tačke čuvanja u odnosu na katancekoje je aplikacija dobila nakon ove SAVEPOINT naredbe. Ukoliko je navedena, katanci kojeje aplikacija dobila neće biti oslobođeni prilikom takve operacije poništavanja.

Neka dodatna pravila i napomene koje treba imati u vidu prilikom kreiranja tačaka čuvanjau DB2 sistemu su sledeće:

• Novi nivo čuvanja se kreira kada se naredni događaji okinu:– Nova jedinica posla je započela.– Pozvana je procedura koja je definisana klauzom NEW SAVEPOINT LEVEL.– Započeta je atomična složena SQL naredba.

• Nivo čuvanja se završava kada događaj koji je inicirao njegovo kreiranje je završenili uklonjen. Kada se nivo čuvanja završi, sve tačke čuvanja koje se nalaze na tomnivou se oslobađaju. Svi otvoreni kursori, DDL akcije ili modifikacije podataka sunasleđeni od strane roditeljskog nivoa čuvanja (odnosno, nivoa čuvanja u okvirukojeg se trenutni nivo čuvanja završio) i pod uticajem su bilo koje naredbe koja setiče nivoa čuvanja i koja važi u okviru roditeljskog nivoa čuvanja.

5.3 Pohranjivanje izmena

Najosnovnija operacija za upravljanje izmenama koje je napravila jedna jedinica poslai transakcija u okviru nje jeste pohranjivanje izmena (engl. commit), koja se izvršavaizvršavanjem naredbe COMMIT. Sintaksa ove naredbe je data u nastavku:COMMIT [WORK]

Iako naredba pohranjivanja izmena ima jednostavnu sintaksu, njeni efekti su mnogobrojni.Osnovna upotreba naredbe podrazumeva da se jedinica posla, u kojoj je COMMIT naredbaizvršena, završava i nova jedinica posla se inicira. Sve izmene koje su izvršene nekom odnarednih naredbi se pohranjuju u bazi podataka: ALTER, COMMENT, CREATE, DROP, GRANT,LOCK TABLE, REVOKE, SET INTEGRITY, SET Variable, kao i naredbe za izmenu podataka:INSERT, DELETE, MERGE, UPDATE, uključujući i one naredbe koje su ugnežđene u upitima.

Svi katanci koje je jedinica posla dobila nakon njenog iniciranja se oslobađaju, osim neop-hodnih katanaca za otvorene kursore koji su deklarisani klauzom WITH HOLD. Svi otvorenikursori koji nisu deklarisani klauzom WITH HOLD se zatvaraju. Otvoreni kursori koji jesudeklarisani klauzom WITH HOLD ostaju otvoreni, i takvi kursori se pozicioniraju ispred na-rednog logičkog reda rezultujuće tabele (naredba FETCH se mora izvršiti pre nego što seizvrši pozicionirana naredba UPDATE ili DELETE).

Sve tačke čuvanja postavljene u okviru transakcije se oslobađaju.

Neka dodatna pravila i napomene koje treba imati u vidu prilikom poništavanja izmenau DB2 sistemu su sledeće:

• Snažno se preporučuje da svaki aplikacioni proces eksplicitno završi svoju jedinicuposla pre nego li se završi. Ako se aplikacioni program završi bez COMMIT ili ROLLBACKnaredbe, onda će SUBP sam pokušati da izvrši operaciju pohranjivanja ili poništa-vanja u zavisnosti od okruženja aplikacije.

Page 91: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.4 Poništavanje izmena 91

5.4 Poništavanje izmena

Ukoliko želimo da poništimo izmene koje je napravila jedna jedinica posla ili transakcijau okviru nje, možemo koristiti SQL naredbu ROLLBACK. Sintaksa ove naredbe je data unastavku:ROLLBACK [WORK][TO SAVEPOINT [savepoint−name]]

Efekat ove naredbe je da se prekida jedinica posla u kojoj je izvršena naredba ROLLBACKi nova jedinica posla se inicijalizuje. Sve promene koje su se ostvarile u bazi podatakatokom jedinice posla su poništene. U zavisnosti od odabranih vrednosti narednih opcijaprilikom deklaracije naredbe ROLLBACK, ta naredba može imati različite varijante koje utičuna način izvršavanja:

• Navođenjem opcione klauze TO SAVEPOINT, poništavanje se izvršava parcijalno, od-nosno, do poslednje tačke čuvanja. Ukoliko nijedna tačka čuvanja nije aktivna natrenutnom nivou čuvanja, podiže se greška (SQLSTATE 3B502). Nakon uspešnog po-ništavanja, navedena tačka čuvanja savepoint−name nastavlja da postoji, ali svakaugnežđena tačka čuvanja se oslobađa i nadalje ne postoji.Ugnežđene tačke čuvanja, ako postoje, smatraju se za poništene i oslobođene kaodeo poništavanja do navedene tačke čuvanja. Ukoliko savepoint−name nije navedeno,onda se poništavanje vrši do poslednje postavljene tačke čuvanja na tekućem nivoučuvanja.Ako se klauza TO SAVEPOINT ne postavi, onda naredba ROLLBACK poništava čitavutransakciju. Dodatno, sve tačke čuvanja u okviru te transakcije se oslobađaju.Ukoliko se navede savepoint−name, onda će se poništavanje izvršiti do te imenovanetačke čuvanja. Nakon uspešne operacije poništavanja, navedena imenovana tačkačuvanja nastavlja da postoji. Ukoliko ne postoji imenovana tačka čuvanja sa datimnazivom, podiže se greška SQLSTATE 3B001.

Neka dodatna pravila i napomene koje treba imati u vidu prilikom poništavanja izmenau DB2 sistemu su sledeće:

• Svi katanci koji se čuvaju se oslobađaju prilikom izvršavanja naredbe ROLLBACK zatu jedinicu posla. Svi otvoreni kursori se zatvaraju.

• Izvršavanje naredbe ROLLBACK neće uticati na naredbu RELEASE.• Ukoliko se izvršavanje program ne završi normalno, onda je jedinica posla implicitno

poništena.• Uticaj na kursore koji rezultuje iz naredbe ROLLBACK TO SAVEPOINT zavisi od naredbi

u okviru tačke čuvanja:– Ako tačka čuvanja sadrži DDL za koji je kursor zavisan, kursor se označava

za nevalidan. Pokušaji da se takav kursor koristi rezultuju podizanjem greškeSQLSTATE 57007.

– Inače:∗ Ako je kursor referenciran u tački čuvanja, kursor ostaje otvoren i bivapozicioniran ispred narednog logičkog reda rezultujuće tabele. U tom slu-čaju je potrebno izvršiti naredbu FETCH pre nego što se izvrši pozicionirananaredba UPDATE ili DELETE.

∗ Inače, kursor ne potpada pod uticaj naredbe ROLLBACK TO SAVEPOINT (ostajeotvoren i pozicioniran).

Page 92: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

92 Glava 5. Programiranje transakcija

• Naredba ROLLBACK TO SAVEPOINT će obrisati sve privremeno kreirane ili deklarisaneprivremene tabele u okviru tačke čuvanja.

• Svi katanci su sadržani nakon ROLLBACK TO SAVEPOINT naredbe.

Primer 5.6 — Čas 05 — 06. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji:

1. Unosi novi ispitni rok za april u 2019. godini.2. Unosi nove ispitne rokove za mart, maj, jun, jul, avgust, septembar i oktobar u

2019. godini.3. Ispisuje sve ispitne rokove.4. Pita korisnika da li želi da poništi unos ispitnih rokova u koraku 2. Ukoliko korisnik

odgovori potvrdno, odgovarajuće izmene se poništavaju.5. Ispisuje sve ispitne rokove.

Rešenje.

Kod 5.6: Primeri/cas05/tackeCuvanja/savepoint1.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 godina;char oznaka[21],

naziv[51];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

char odgovor_od_korisnika;

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DECLARE ispitniRok CURSOR FORSELECT godina, oznaka, nazivFROM ispitni_rok;

is_error("Declare");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'apr', 'April 2019', current_date, current_date + 20 days

, 1);is_error("Insert into ispitni_rok apr");

// Kreiranje tacke cuvanja − S1EXEC SQL SAVEPOINT S1 ON ROLLBACK RETAIN CURSORS;

Page 93: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.4 Poništavanje izmena 93

is_error("Savepoint");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'mar', 'Mart 2019', current_date − 1 month, current_date

− 1 month + 20 days, 1);is_error("Insert into ispitni_rok mar");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'maj', 'Maj 2019', current_date + 1 month, current_date +

1 month + 20 days, 1);is_error("Insert into ispitni_rok maj");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'jun', 'Jun 2019', current_date + 2 month, current_date +

2 month + 20 days, 1);is_error("Insert into ispitni_rok jun");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'jul', 'Jul 2019', current_date + 3 month, current_date +

3 month + 20 days, 1);is_error("Insert into ispitni_rok jul");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'avg', 'Avgust 2019', current_date + 4 month,

current_date + 4 month + 20 days, 1);is_error("Insert into ispitni_rok avg");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'sep', 'Septembar 2019', current_date + 5 month,

current_date + 5 month + 20 days, 1);is_error("Insert into ispitni_rok sep");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'okt', 'Oktobar 2019', current_date + 6 month,

current_date + 1 month + 20 days, 1);is_error("Insert into ispitni_rok okt");

EXEC SQL OPEN ispitniRok;is_error("Open");

while(1){

EXEC SQL FETCH ispitniRokINTO :godina, :oznaka, :naziv;

is_error("Fetch");

if(SQLCODE == 100){

break;}

printf("Godina %d oznaka: %s i naziv %s \n", godina, oznaka, naziv);}

EXEC SQL CLOSE ispitniRok;is_error("Close");

printf("Da li zelite da ponistite izmene? \n");

odgovor_od_korisnika = getchar();if (odgovor_od_korisnika == 'd' || odgovor_od_korisnika == 'D')

Page 94: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

94 Glava 5. Programiranje transakcija

{// Ponistavanje izmena samo do tacke cuvanja S1EXEC SQL ROLLBACK TO SAVEPOINT S1;is_error("Rollback");

}

EXEC SQL OPEN ispitniRok;is_error("Open");

while(1){

EXEC SQL FETCH ispitniRokINTO :godina, :oznaka, :naziv;

is_error("Fetch");

if(SQLCODE == 100){

break;}

printf("Godina %d oznaka: %s i naziv %s \n", godina, oznaka, naziv);}

EXEC SQL CLOSE ispitniRok;is_error("Close");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 5.7 — Čas 05 — 07. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji:

1. Unosi novi ispitni rok za februar u 2019. godini.2. Unosi nove ispitne rokove za mart, maj i jun u 2019. godini.3. Pita korisnika da li želi da poništi unos ispitnih rokova u koraku 2. Ukoliko korisnik

odgovori potvrdno, odgovarajuće izmene se poništavaju.4. Ispisuje sve ispitne rokove (staviti da svaki ispis ima prefiks "1: ").5. Unosi nove ispitne rokove za avgust, septembar i oktobar u 2019. godini i pohra-

njuje izmene u bazi podataka.6. Ispisuje sve ispitne rokove (staviti da svaki ispis ima prefiks "2: ").

Rešenje.

Kod 5.7: Primeri/cas05/tackeCuvanja/savepoint2.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 godina;char oznaka[21],

naziv[51];EXEC SQL END DECLARE SECTION;

Page 95: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

5.4 Poništavanje izmena 95

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

char odgovor_od_korisnika;

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DECLARE c_ispitni_rok CURSOR FORSELECT godina, oznaka, nazivFROM ispitni_rokWHERE godina = 2019;

is_error("Declare");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'feb', 'Februar 2019', current_date, current_date + 20

days, 1);is_error("Insert into ispitni_rok feb");

EXEC SQL SAVEPOINT S1 ON ROLLBACK RETAIN CURSORS;is_error("Savepoint s1");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'mar', 'Mart 2019', current_date − 1 month, current_date

− 1 month + 20 days, 1);is_error("Insert into ispitni_rok mart");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'maj', 'Maj 2019', current_date + 1 month, current_date +

1 month + 20 days, 1);is_error("Insert into ispitni_rok maj");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'jun', 'Jun 2019', current_date + 2 month, current_date +

2 month + 20 days, 1);is_error("Insert into ispitni_rok jun");

printf("Da li zelite da se poniste izmene? [d/n] \n");

odgovor_od_korisnika = getchar();

if(odgovor_od_korisnika == 'd'){

EXEC SQL ROLLBACK TO SAVEPOINT S1;is_error("Rollback to savepoint");

}

EXEC SQL OPEN c_ispitni_rok;is_error("Open c_ispitni_rok");

while(1)

Page 96: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

96 Glava 5. Programiranje transakcija

{EXEC SQL FETCH c_ispitni_rok

INTO :godina, :oznaka, :naziv;is_error("Fetch c_ispitni_rok");

if(SQLCODE == 100){

break;}

printf("1: Godina %d, oznaka %s, naziv %s\n\n", godina, oznaka, naziv);}

EXEC SQL CLOSE c_ispitni_rok;is_error("Close c_ispitni_rok");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'avg', 'Avgust 2019', current_date + 4 month,

current_date + 4 month + 20 days, 1);is_error("Insert into ispitni_rok avg");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'sep', 'Septembar 2019', current_date + 5 month,

current_date + 5 month + 20 days, 1);is_error("Insert into ispitni_rok sep");

EXEC SQL INSERT INTO ispitni_rokVALUES (2019, 'okt', 'Oktobar 2019', current_date + 6 month,

current_date + 6 month + 20 days, 1);is_error("Insert into ispitni_rok okt");

EXEC SQL COMMIT;is_error("Commit");

EXEC SQL OPEN c_ispitni_rok;is_error("Open c_ispitni_rok");

while(1){

EXEC SQL FETCH c_ispitni_rokINTO :godina, :oznaka, :naziv;

is_error("Fetch c_ispitni_rok");

if(SQLCODE == 100){

break;}

printf("2: Godina %d, oznaka %s, naziv %s\n\n", godina, oznaka, naziv);}

EXEC SQL CLOSE c_ispitni_rok;is_error("Close c_ispitni_rok");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Page 97: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6. Rad u višekorisničkom okruženju

Ovo poglavlje je posvećeno dizajnu aplikacija koje koriste baze podataka, a za koje se oče-kuje da će biti izvršavane u višekorisničkom okruženju. Ovo podrazumeva da je potrebnouvesti dodatne mere u slučaju da više aplikacija želi da pristupi nekom objektu u bazipodataka (na primer, određenom redu ili tabeli).

6.1 Aplikacioni proces i konkurentnost

Svi SQL programi se izvršavaju kao deo aplikacionih procesa ili agenta. Aplikacioni procespodrazumeva izvršavanje jednog ili više programa, i predstavlja jedinicu kojoj SUBP alo-cira resurse i katance. Različiti aplikacioni procesi mogu da povlače sa sobom izvršavanjerazličitih programa ili različita izvršavanja istog programa.

U višekorisničkom okruženju, osnovna pretpostavka je da više od jednog aplikacionogprocesa može da zahteva pristup istim podacima u isto vreme. U tu svrhu, da bi seobezbedio integritet podataka, potrebno je implementirati i koristiti mehanizam poznatpod nazivom zaključavanje.

Definicija 6.1.1 — Zaključavanje. Zaključavanje (engl. locking) predstavlja mehanizamkoji se koristi za održavanje integriteta podataka pod uslovima višekorisničkog okruže-nja.

Korišćenjem zaključavanja se može sprečiti da, na primer, dva aplikaciona procesa izvršeažuriranje istog reda u isto vreme.

SUBP upravlja katancima da bi onemogućio da nepohranjene izmene napravljene odstrane jednog aplikacionog procesa budu vidljive od bilo kog drugog procesa. U trenutkukada se neki proces završi, tada se svi katanci koje je proces dobio od strane RSUBP, idržao ih, oslobađaju. Ipak, aplikacioni proces može da eksplicitno zahteva da se neki kata-

Page 98: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

98 Glava 6. Rad u višekorisničkom okruženju

nac oslobodi ranije. Ovo je omogućeno korišćenjem operacije pohranjivanja izmena, kojaoslobađa katance koji su dobijeni tokom jedinice posla i takođe, pohranjuje sve izmenekoje su obavljene tokom te jedinice posla.

Definicija 6.1.2 — Jedinica posla. Jedinica posla (engl. unit of work, skr. UOW ) pred-stavlja nadoknadivu sekvencu operacija u okviru aplikacionog procesa.

Jedinica posla se inicijalizuje prilikom pokretanja aplikacionog procesa ili kada se pret-hodna jedinica posla završila posledicom operacije koja nije prekid aplikacionog procesa.Jedinica posla se završava operacijom pohranjivanja ili poništavanja izmena ili završet-kom aplikacionog procesa. Operacije pohranjivanja i poništavanja izmena utiču samo daone promene u bazi podataka koje su izvršene tokom te jedinice posla koja se završava.isending.

Direktni pozivi DB2 funkcija i ugnežđeni SQL omogućavaju režim konekcije koji se nazivakonkurentne transakcije (engl. concurrent transactions) kojim se omogućavaju višestrukekonekcije, pri čemu svaka od njih je nezavisna transakcija. Aplikacija može da ima višekonkurentnih konekcija ka istoj bazi podataka.

Slika 6.1: Grafički prikaz jedne jedinice posla tokom vremena. Ova jedinica posla seuspešno izvršila i sve izmene koje predstavljaju deo te jedinice posla se uspešno pohranjujuu bazi podataka.

Slika 6.2: Grafički prikaz jedne jedinice posla tokom vremena. U ovoj jedinici posla jedošlo do greške, čime je neophodno da se izmene koje su načinjene u bazi podataka ponište.

Inicijalizacija i završetak jedinice posla definišu tačke konzistentnosti u okviru aplikacionogprocesa. Razmotrimo primer bankarske transakcije u kojoj se vrši premeštaj sredstava

Page 99: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.2 Katanci 99

sa jednog računa na drugi račun. Takva transakcija podrazumeva da se sredstva prvooduzmu sa prvom računa, a zatim se ona dodaju drugom računu. Nakon prvog koraka(oduzimanja sredstava) podaci su nekonzistentni. Tek nakon izvršavanja drugog koraka(dodavanje sredstava) konzistentnost je obnovljena (slika 6.1). Kada se oba koraka izvrše,može se iskoristiti operacija pohranjivanja izmena da bi se završila jedinica posla, čimeće izmene biti vidljive drugim aplikacionim procesima. Ako dođe do greške pre nego štose jedinica posla uspešno završi, SUBP će poništiti sve nepohranjene izmene da bi vratiostanje baze podataka u konzistentno (slika 6.2).

6.2 Katanci

Kao što smo rekli, katanci predstavljaju osnovni alat za uspostavljanje mehanizma zaklju-čavanja. Svaki katanac ima odgovarajuće karakteristike:

• Režim (engl. mode) — Definiše tip pristupa koji je dozvoljen procesu koji drži ključ,kao i tip pristupa koji je dozvoljen konkurentnim procesima. Ponekad se režimkatanca naziva i stanje (engl. state) katanca.

• Objekat — Definiše resurs nad kojim se primenjuje operacija zaključavanja. Jedinitip objekta koji se može programerski zaključati jeste tabela (za više informacija,videti sekciju 6.4). SUBP ima pravo da postavi katanac na druge objekte u bazipodataka, kao što su: redovi, prostori tabela, blokovi, particije podataka, i dr.

• Trajanje (engl. lock count) — Dužina vremena tokom kojeg je katanac bio držanod strane procesa. Trajanje katanca se određuje nivoom izolovanosti pod kojim senaredba pokreće (za više informacija o nivoima izolovanosti, videti sekciju 6.3).

DB2 sistem nudi podršku za različite vrste katanaca. Mi ćemo prikazati samo najosnovnije,poređane rastuće po restrikciji koju obezbeđuju:

• IN (engl. intent none) — vlasnik katanca može da čita sve podatke u tabeli, uključu-jući i nepotvrđene podatke, ali ne može da ih menja. Druge konkurentne aplikacijemogu da čitaju ili da ažuriraju tabelu. Ne postavljaju se nikakvi katanci na redo-vima.

• IS (engl. intent share) — vlasnik katanca može da čita proizvoljan podatak u tabeliako se S katanac može dobiti na redovima ili stranicama od interesa.

• IX (engl. intent exclusive) — vlasnik katanca može da čita ili menja proizvoljnipodatak u tabeli ako važe naredna dva uslova:

– X katanac se može dobiti na redovima ili stranicama koje želimo da menjamo.– S ili U katanac se može dobiti na redovima koje želimo da čitamo.

• SIX (engl. share with intent exclusive) — vlasnik katanca može da čita sve podatkeiz tabele i da menja redove ako može da dobije X katanac na tim redovima. Začitanje se ne dobijaju katanci na redovima. Druge konkurentne aplikacije mogu dačitaju iz tabele. SIX katanac se dobija ako aplikacija ima IX katanac na tabeli ionda se zahteva S katanac ili obratno.

• S (engl. share) — vlasnik katanca moze da čita proizvoljan podatak u tabeli i nećedobiti katance na redovima ili stranicama.

• U (engl. update) — vlasnik katanca može da čita proizvoljan podatak u tabeli i možeda menja podatke ako se na tabeli može dobiti X katanac. Pritom se ne dobijajunikakvi katanci na redovima ili stranicama.

• X (engl. exclusive) — vlasnik katanca može da čita i da menja proizvoljan podatakiz tabele. Pritom se ne dobijaju nikakvi katanci na redovima ili stranicama.

Page 100: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

100 Glava 6. Rad u višekorisničkom okruženju

• Z (engl. super exclusive) — ovaj katanac se zahteva na tabeli u posebnim prilikama,kao što su recimo menjanje strukture tabele ili njeno brisanje. Nijedna druga apli-kacija (ni ona sa nivoom izolovanosti ”nepohranjeno čitanje” (UR)) ne može da čitaniti da ažurira podatke u tabeli.

Očigledno, primenom različitih vrsta katanaca, može doći do sukoba u smislu da li SUBPtreba da dodeli katanac nekom aplikacionom procesu kada postoji drugi aplikacioni proceskoji već drži katanac nad istim objektom. Samo u slučaju kada su katanci kompatibilniće SUBP dodeliti drugi katanac.

U slučaju da katanci nisu kompatibilni, nije moguće dodeliti traženi katanac aplikacio-nom procesu. Tada taj proces mora da pređe u stanje čekanja dok proces ne oslobodinekompatibilni katanac koji drži, kao i dok se svi ostali nekompatibilni katanci ne oslo-bode. U nekim slučajevima može doći do isteka vremena (engl. timeout) dok zatražilacčeka na katanac. O tome će nešto detaljnije biti reči u nastavku, a za sada će prikazatikompatibilnosti između katanaca u tabeli 6.1.

Tabela 6.1: Tabela kompatibilnosti katanaca. Oznaka N znači da nad resursom nemakatanca, odnosno, da aplikacioni proces ne traži katanac.

Stanje traženog resursaStanje koje je traženo N IN IS S IX SIX U X Z

N da da da da da da da da daIN da da da da da da da da neIS da da da da da da da ne neS da da da da ne ne da ne neIX da da da ne da ne ne ne neSIX da da da ne ne ne ne ne neU da da da da ne ne ne ne neX da da ne ne ne ne ne ne neZ da ne ne ne ne ne ne ne ne

6.2.1 Konverzija katanaca

Definicija 6.2.1 — Konverzija katanca. Promena režima katanca koji se već drži se nazivakonverzija katanca (engl. lock conversion).

Konverzija katanca se ostvaruje u situacijama kada aplikacioni proces pristupa objektunad kojim već drži katanac, a taj pristup zahteva restriktivniji katanac od onog koji seveć drži. Proces nad objektom može da drži najviše jedan katanac u nekom trenutku, alimože da traži različite katance nad istim objektom indirektno kroz izvršavanje naredbi.

Neki režimi katanaca se primenjuju samo za tabele, neki samo za redove, blokove iliparticije podataka. Za redove ili blokove, konverzija se uglavnom izvršava ukoliko se tražikatanac X, a već se drži katanac S ili U.

Katanci IX i S imaju specijalan odnos — nijedan od ova dva katanca se smatra restrik-tivnijim u odnosu na drugi. Ukoliko aplikacioni proces drži jedan od ova dva katanca izahteva drugi, onda će se izvršiti konverzija u katanac SIX. Sve ostale konverzije se vršepo narednom principu:

Page 101: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.2 Katanci 101

Ukoliko je katanac koji se zahteva restriktivniji u odnosu na katanac koji sedrži, onda se katanac koji se drži konvertuje u katanac koji se zahteva.

Naravno, da bi se uspešno izvršila konverzija katanca, nad objektom nad kojim se zahtevanovi katanac ne sme postojati neki drugi katanac koji je nekompatibilan sa njim.

6.2.2 Istek vremena i mrtva petlja

Već smo napomenuli da, ukoliko aplikacija zahteva katanac nad objektom koji je nekom-patibilan sa katancem koji već postoji nad istim objektom, ona ulazi u fazu čekanja dokse taj katanac ne oslobodi. Neka, na primer, jedna transakcija čeka na katanac koji držineka korisnička aplikacija. Ukoliko korisnik koji koristi tu aplikaciju napusti aplikacijubez da dozvoli pohranjivanje izmena, onda se katanac ne oslobađa nad tim objektom itransakcija može da čeka beskonačno dugo.

SUBP ima poseban mehanizam kojim se može sprečiti da aplikacija beskonačno dugočeka na oslobađanje katanca i koji se naziva detekcija isteka vremena (engl. lock timeoutdetection). Ovaj mehanizam se oslanja na korišćenje locktimeout parametra podešavanjabaze podataka i predstavlja najduže vreme koje transakcija može da čeka na oslobađanjekatanca. Podrazumevana vrednost ovog parametra je −1, što znači da je detekcija istekavremena onemogućena. U nastavku ćemo videti kako možemo postaviti vrednost ovogparametra, kao i koje je ponašanje SUBP u slučaju da dođe do isteka vremena, međutim,prvo ćemo diskutovati o situaciji do koje može doći u slučaju da aplikacije mogu da čekajubeskonačno dugo na oslobađanje katanca.

Pretpostavimo da postoje dve aplikacije A i B koje rade konkurentno i da je mehanizamdetekcije isteka vremena onemogućen u SUBP. Aplikacija A se sastoji od dve operacije:prva operacija želi da ažurira red 1 u tabeli 1, a druga operacija želi da ažurira red 2 utabeli 2. Aplikacija B se takođe sastoji od dve operacije: prva operacija želi da ažurirared 2 u tabeli 2, a druga operacija želi da ažurira red 1 u tabeli 1. Pretpostavimo takođeda se operacije dešavaju u (približno) isto vreme. Redosled izvršavanja ovih operacija idobijanja katanaca je sledeći (što je ilustrovano i na slici 6.3):

• U trenutku T1:– Aplikacija A dobija katanac X nad redom 1 u tabeli 1.– Aplikacija B dobija katanac X nad redom 2 u tabeli 2.

• U trenutku T2:– Aplikacija A pokušava da dobije katanac X nad redom 2 u tabeli 2. Taj katanac

je nekompatibilan sa postojećim katancem X koji drži aplikacija B. AplikacijaA prelazi u stanje čekanja.

– Aplikacija B pokušava da dobije katanac X nad redom 1 u tabeli 1. Taj katanacje nekompatibilan sa postojećim katancem X koji drži aplikacija A. AplikacijaB prelazi u stanje čekanja.

• U trenutku TN (N > 2):– Aplikacija A je u stanju čekanja.– Aplikacija B je u stanju čekanja.

Očigledno, počevši od trenutka T3, obe aplikacije će čekati jedna na drugu beskonačnodugo i neće se ”nikad” završiti. Ova pojava se naziva mrtva petlja.

Page 102: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

102 Glava 6. Rad u višekorisničkom okruženju

Definicija 6.2.2 — Mrtva petlja. Mrtva petlja (engl. deadlock) predstavlja pojavu kadadve aplikacije (ili više njih) zaključaju podatak koji je neophodan jedan drugoj, štorezultuje u situaciji da se obe aplikacije blokiraju i nijedna ne može da nastavi sadaljim izvršavanjem.

Slika 6.3: Ilustracija pojave mrtve petlje prilikom izvršavanja dva aplikaciona procesa.

Zbog toga što aplikacije neće ”volonterski” osloboditi katance koje drže nad podacima,da bi se prevazišla mrtva petlja, mora se pristupiti procesu prepoznavanja mrtve petlje.Mehanizam prepoznavanja mrtve petlje nadgleda informacije o agentima koji čekaju nakatance i pokreće se na interval specifikovan kroz parametar dlchktime podešavanja bazepodataka.

Ukoliko mehanizam pronađe mrtvu petlju, onda se nasumično bira jedan od procesa umrtvoj petlji koji se naziva žrtva (engl. victim process), čije će izmene biti poništene.Aplikacija koja pripada procesu žrtvi se podiže i prosleđuje joj se odgovarajući kod kojije ona dužna da obradi. SUBP automatski poništava nepohranjene izmene od straneodabrane aplikacije. Kada je operacija pohranjivanja završena, katanci koji su pripadaliprocesu žrtvi se oslobađaju i ostali procesi u mrtvoj petlji mogu da nastave dalje sa radom.

Postoje dve vrste grešaka koje SUBP može prijaviti aplikaciji u slučaju da dođe do istekavremena, odnosno, ako je aplikacija izabrana za žrtvu prilikom prepoznavanja mrtve petlje:

• Greška −911:– Značenje: Tekuća transakcija se poništava usled mrtve petlje ili isteka vremena.– Uz ovu poruku se prilaže i kod koji preciznije označava razlog zbog kojeg se

došlo do ǧreske. Ovih kodova ima više, a mi ćemo prikazati dva najznačajnija:∗ 2 — Transakcija je poništena usled mrtve petlje.∗ 68 — Transakcija je poništena usled isteka vremena za katanac.

Pokretanjem komande db2 ? sql911 u konzoli je moguće dobiti više informacijao grešci.

• Greška −913:– Značenje: Došlo je do neuspeha pri izvršavanju distribuirane transakcije zbog

mrtve petlje ili isteka vremena.– I uz ovu poruku se prilaže kod koji preciznije označava razlog zbog kojeg se

Page 103: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.2 Katanci 103

došlo do ǧreske. Ovih kodova ima više, a mi ćemo prikazati dva najznačajnija:∗ 2 — Grana transakcije je neuspešna usled mrtve petlje.∗ 68 — Grana transakcije je neuspešna usled isteka vremena za katanac.∗ 80 — Naredba je neuspešna usled isteka vremena.

Pokretanjem komande db2 ? sql913 u konzoli je moguće dobiti više informacijao grešci.

Još jedan mogući način da se izborimo sa mrtvom petljom jeste da specifikujemo najduživremenski period koji aplikacija može da čeka na dobijanje katanca. Specijalni registarCURRENT LOCK TIMEOUT, koji je tipa INTEGER, sadrži broj sekundi pre nego što SUBP vratigrešku koja indikuje da katanac ne može biti dodeljen aplikacionom procesu.

Validne vrednosti za ovaj registar su u opsegu [−1,32767]. Dodatno, specijalnom registruse može postaviti vrednost NULL. Vrednost −1 označava da SUBP neće prijavljivati istekvremena, već da aplikacija mora da čeka na zahtevani katanac dok se nekompatibilnikatanac ne oslobodi ili dok se ne detektuje mrtva petlja. Vrednost 0 označava da aplikacijaneće čekati na katanac, već ukoliko ne može da dobije katanac kada ga zatraži, odmah ćedobiti grešku. Vrednost NULL označava da će SUBP koristiti vrednost koja je postavljenau parametru locktimeout o kojem je bilo reči ranije.

Ukoliko želimo da pročitamo vrednost ovog specijalnog registra, nakon konekcije na bazupodataka potrebno je izvršiti narednu komandu u konzoli:$ db2 values CURRENT LOCK TIMEOUT

Naredba SET CURRENT LOCK TIMEOUT služi za promenu vrednosti specijalnog registra CURRENTLOCK TIMEOUT. Izvršavanje ove naredbe nije pod uticajem kontrole transakcije u pro-gramu. Zbog toga, ukoliko ovu naredbu koristimo u našim aplikacijama, dobra je praksavratiti vrednost na podrazumevanu pre završavanja programa. Sintaksa ove naredbe jedata u nastavku:SET [CURRENT] LOCK TIMEOUT [=](WAIT|NOT WAIT|NULL|[WAIT] integer−constant|host−variable)

Ovoj naredbi je moguće specifikovati naredne vrednosti:

• WAIT — Specifikuje se vrednost −1, što znači da SUBP mora da čeka dok se katanacne oslobodi ili se ne detektuje mrtva petlja

• NOT WAIT — Specifikuje se vrednost 0, što znači da SUBP ne čeka na katance kojise ne mogu dodeliti aplikacijama, već odmah prijavljuje grešku.

• NULL — Specifikuje da vrednost u registru CURRENT LOCK TIMEOUT nije postavljena,čime se efektivno koristi vrednost parametra locktimeout podešavanja baze poda-taka. Vrednost koja se vraća za ovaj specijalni registar se menja pri promeni vred-nosti parametra locktimeout.

• [WAIT] integer−constant — Specifikuje celobrojnu vrednost integer−constant izintervala [−1,32767]. Ako je vrednost u intervalu [1,32767], onda će SUBP čekatitoliko sekundi pre nego što aplikaciji prosledi grešku. Vrednosti −1 i 0 odgovarajuspecifikovanju klauza WAIT i NO WAIT, redom.

• host−variable — Specifikuje celobrojnu vrednost iz intervala [−1,32767] koja senalazi u matičnoj promenljivoj host−variable. Ako je vrednost u intervalu [1,32767],onda će SUBP čekati toliko sekundi pre nego što aplikaciji prosledi grešku. Vrednosti−1 i 0 odgovaraju specifikovanju klauza WAIT i NO WAIT, redom.

Page 104: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

104 Glava 6. Rad u višekorisničkom okruženju

Naredna dva primera ilustruju obradu transakcija u višekorisničkom okruženju korišćenjemznanja iz diskusija u ovom poglavlju.

Primer 6.1 — Čas 05 — 08. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji za svaki predmet omogućuje korisniku da poveća broj semestra u kome sesluša za 1. Ukoliko korisnik želi izmenu, onda ju je potrebno pohraniti u bazi podataka.Napisati program tako da može da radi u višekorisničkom okruženju. Obrada jednogpredmeta predstavlja jednu transakciju. Postaviti istek vremena za zahtevanje katanacana 10 sekundi.

Rešenje.

Kod 6.1: Primeri/cas05/katanci/katanci1.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_id;char d_sifra[21],

d_naziv[201];short d_broj_semestara,

d_bodovi;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("Greska %d: %s\n\n", SQLCODE, err);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

// Niz do sada obradjenih predmeta// i broj elemenata ovog niza#define NAJVISE_PREDMETA 1000sqlint32 obradjeni[NAJVISE_PREDMETA];int poslednji_obradjen = 0;

// Funkcija za ispitivanje da li se identifikator// nalazi u nizu obradjeniint vec_obradjen(sqlint32 id);

// Funkcija za obradu cekanjavoid obradi_cekanje();

int main(){

char odgovor_od_korisnika;

EXEC SQL CONNECT TO vstud USER student USING abcdef;is_error("Connect");

EXEC SQL SET CURRENT LOCK TIMEOUT 10;is_error("Set current lock timeout 10");

Page 105: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.2 Katanci 105

EXEC SQL DECLARE predmeti CURSOR WITH HOLD FORselect id_predmeta, sifra, naziv, broj_semestara, bodovifrom predmet−−limit 10FOR UPDATE OF broj_semestara;

is_error("Declare predmeti");

EXEC SQL OPEN predmeti;is_error("Open predmeti");

for(;;){

EXEC SQL FETCH predmetiINTO :d_id, :d_sifra, :d_naziv, :d_broj_semestara, :d_bodovi;

// Proverava se da li trazeni S katanac ne dovodi do nekog// od problema konkurentog izvrsavanjaif (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();continue;

}

is_error("Fetch predmeti");

// Ako smo naisli na kraj kursora zavrsavamo obraduif (SQLCODE == 100){

break;}

if (!vec_obradjen(d_id)){

printf("Predmet − id = %d sifra = %.5s naziv = %.40s broj_semestara= %d bodovi = %d\n",d_id, d_sifra, d_naziv, d_broj_semestara, d_bodovi);

printf("Da li se zeli promena semestra u kome se slusa ovaj predmet? Odgovoriti sa d ili n.\n");

scanf("%c", &odgovor_od_korisnika);getchar(); // za novi red

if (odgovor_od_korisnika == 'd' || odgovor_od_korisnika == 'D'){

EXEC SQL UPDATE predmetSET broj_semestara = :d_broj_semestara + 1WHERE CURRENT OF predmeti;

// Proverava se da li trazeni X katanac ne dovodi do nekog// od problema konkurentog izvrsavanjaif (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();continue;

}

is_error("Update");

// Provera izvrsenih promenaEXEC SQL SELECT broj_semestara

Page 106: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

106 Glava 6. Rad u višekorisničkom okruženju

INTO :d_broj_semestaraFROM predmetWHERE id_predmeta = :d_id;

// Proverava se da li trazeni S katanac ne dovodi do nekog// od problema konkurentog izvrsavanjaif (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();continue;

}

is_error("Select into");

printf("Semestar u kome se slusa predmet je sada %d\n\n",d_broj_semestara);

}

// Pohranjivanje izmenaEXEC SQL COMMIT;is_error("Commit");

// Evidentiranje obrade u nizobradjeni[poslednji_obradjen] = d_id;++poslednji_obradjen;

}}

EXEC SQL CLOSE predmeti;is_error("Close predmeti");

EXEC SQL SET CURRENT LOCK TIMEOUT NULL;is_error("Set current lock timeout null");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

int vec_obradjen(sqlint32 id){

int j = 0;for (; j < poslednji_obradjen; ++j){

if (obradjeni[j] == id){

return 1;}

}return 0;

}

void obradi_cekanje(){

printf("Objekat je zakljucan od strane druge transakcije.\n""Sacekati neko vreme.\n");

EXEC SQL ROLLBACK;is_error("Rollback");

Page 107: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.2 Katanci 107

EXEC SQL OPEN predmeti;is_error("Open predmeti − obrada cekanja");

}

Primer 6.2 — Čas 05 — 09. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji za svaki predmet omogućuje korisniku da poveća broj semestra u kome sesluša za 1. Ukoliko korisnik želi izmenu, onda ju je potrebno pohraniti u bazi podataka.Dodatno, svaku obradu evidentirati u tabeli obradjeni_predmeti.

Pre početka izvršavanja, kreirati tabelu obradjeni_predmeti koja sadrži identifikatorepredmeta koji su do sada obrađeni. Nakon izvršavanja programa, može se kreiranatabela obrisati.

Napisati program tako da može da radi u višekorisničkom okruženju. Obrada jednogpredmeta predstavlja jednu transakciju. Postaviti istek vremena za zahtevanje katanacana 10 sekundi.

Rešenje.

Kod 6.2: Primeri/cas05/katanci/katanci2.sqc// Potrebno je pozvati narednu naredbu,// pre nego sto se program pokrene:// CREATE TABLE obradjeni_predmeti (predmet integer not null);

// Nakon izvrsavanja programa pozvati narednu naredbu:// DROP TABLE obradjeni_predmeti;

#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_id;char d_sifra[21],

d_naziv[201];short d_broj_semestara,

d_bodovi;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("Greska %d: %s\n\n", SQLCODE, err);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

void obradi_cekanje();

int main(){

char odgovor_od_korisnika;// int broj_obradjenih = 0;

EXEC SQL CONNECT TO vstud user student using abcdef;

Page 108: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

108 Glava 6. Rad u višekorisničkom okruženju

is_error("Connect");

EXEC SQL SET CURRENT LOCK TIMEOUT 10;is_error("Set current lock timeout 10");

EXEC SQL DECLARE predmeti CURSOR WITH HOLD FORselect id_predmeta, sifra, naziv, broj_semestara, bodovifrom predmet pwhere not exists (

select ∗from obradjeni_predmetiwhere predmet = p.id_predmeta

)FOR UPDATE OF broj_semestara;

is_error("Declare predmeti");

EXEC SQL OPEN predmeti;is_error("Open predmeti");

for(;;){

EXEC SQL FETCH predmetiINTO :d_id, :d_sifra, :d_naziv, :d_broj_semestara, :d_bodovi;

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();continue;

}is_error("Fetch predmeti");

if (SQLCODE == 100){

printf("Nema vise predmeta za obradjivanje!\n");break;

}

printf("Predmet − id = %d sifra = %.5s naziv = %.40s ""broj_semestara = %d bodovi = %d\n",d_id, d_sifra, d_naziv, d_broj_semestara, d_bodovi);

printf("Da li se zeli promena semestra ""u kome se slusa ovaj predmet? ""Odgovoriti sa d ili n.\n");

scanf("%c", &odgovor_od_korisnika);getchar(); // novi red

if (odgovor_od_korisnika == 'd' || odgovor_od_korisnika == 'D'){

EXEC SQL UPDATE predmetSET broj_semestara = :d_broj_semestara + 1WHERE CURRENT OF predmeti;

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();continue;

}is_error("Update");

EXEC SQL SELECT broj_semestara

Page 109: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.2 Katanci 109

INTO :d_broj_semestaraFROM predmetWHERE id_predmeta = :d_id;

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();continue;

}is_error("Select into");

printf("Semestar u kome se slusa predmet je sada %d\n\n",d_broj_semestara);

}

EXEC SQL insert into obradjeni_predmetivalues(:d_id);

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();continue;

}is_error("Insert into");

EXEC SQL COMMIT;is_error("Commit");

// ++broj_obradjenih;// if (broj_obradjenih > 10)// {// break;// }

}

EXEC SQL CLOSE predmeti;is_error("Close predmeti");

EXEC SQL SET CURRENT LOCK TIMEOUT NULL;is_error("Set current lock timeout null");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

void obradi_cekanje(){

printf("Objekat je zakljucan od strane druge transakcije.\n""Sacekati neko vreme.\n");

EXEC SQL ROLLBACK;is_error("Rollback");

EXEC SQL OPEN predmeti;is_error("Open predmeti − obrada cekanja");

}

Page 110: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

110 Glava 6. Rad u višekorisničkom okruženju

6.3 Nivoi izolovanosti

U najosnovnijem slučaju, svaka transakcija je u potpunosti izolovana od svih drugih trans-akcija. Međutim, videli smo da ovakva, potpuna izolovanost, može brzo dovesti do pro-blema poput mrtve petlje u konkurentnom sistemu izvršavanja. Zbog toga, da bi sepovećala konkurentnost između aplikacionih procesa, DB2 SUBP definiše različite nivoeizolovanosti na kojima aplikacija može da se izvršava.

Definicija 6.3.1 — Nivo izolovanosti. Nivo izolovanosti (engl. isolation level) koji sepridružuje aplikacionom procesu određuje stepen zaključavanja ili izolacije u kojem supodaci kojima taj proces pristupa, u odnosu na druge konkurentne procese.

Drugim rečima, nivo izolovanosti jednog aplikacionog procesa P specifikuje sledeće:

• Stepen u kojem su redovi koji se čitaju ili ažuriraju od strane procesa P dostupnidrugim konkurentnim aplikacionim procesima.

• Stepen u kojem ažuriranja od strane drugih konkurentnih aplikacionih procesa moguda utiču na izvršavanje procesa P.

DB2 definiše naredna četiri nivoa izolacije:

• Ponovljeno čitanje (engl. Repeatable Read, skr. RR)– Nijedan podatak koji je pročitan od strane procesa P ne sme se menjati od

strane drugih procesa sve do završetka obrade od strane procesa P (čime seobezbeđuje saglasnost podataka u slučaju ponovljenog čitanja).

– Nijedan red promenjen od strane drugog procesa ne može se čitati dok se pro-mene u okviru tog procesa na okončaju.

– Osim već pomenutih ekskluzivnih katanaca, proces na RR nivou izolovanostidobija bar deljive katance na svim podacima kojima pristupa, pri čemu sezaključavanje vrši tako da je proces u potpunosti izolovan od strane ostalihprocesa.

• Stabilno čitanje (engl. Read Stability, skr. RS)– Nijedan podatak koji je pročitan od strane procesa P ne sme se menjati od

strane drugih procesa sve do završetka obrade od strane procesa P.– Nijedan red promenjen od strane drugog procesa ne može se čitati dok se pro-

mene u okviru tog procesa ne okončaju.– Za razliku od RR, na ovom nivou izolacije proces koji izvršava isti upit više puta,

može dobiti neke nove redove u odgovorima (tzv. fantomski redovi) u slučaju dadrugi proces unese nove redove koji zadovoljavaju dati upit i pohrani te izmene.

– Osim ekskluzivnih katanaca, proces na RS nivou izolovanosti dobija bar deljivekatance na svim podacima koji su prihvaćeni. Na primer, neka se izvršavanaredni upit:SELECT ∗FROM SMERWHERE ID_NIVOA = 10

U slučaju RR nivoa izolovanosti izvršavanje ovog upita izazvaće zaključavanjesvih redova tabele SMER, a u slučaju RS nivoa izolovanosti zaključavanje se vršisamo nad onim redovima koji ispunjavaju uslov restrikcije ID_NIVOA = 10.

• Stabilni kursor (engl. cursor stability, skr. CS)– Nijedan red promenjen od strane drugog procesa ne može se čitati dok se pro-

mene u okviru tog procesa na okončaju.

Page 111: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.3 Nivoi izolovanosti 111

– Ovaj nivo izolovanosti obezbeđuje da konkurentni procesi ne mogu menjatisamo trenutno aktivne redove otvorenih kursora posmatranog procesa.

– Redovi koji su ranije pročitani mogu biti menjani.– Bez obzira na razne ekskluzivne katance, ovaj nivo obezbeđuje bar deljive ka-

tance na aktivnim redovima svih kursora.

Page 112: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

112 Glava 6. Rad u višekorisničkom okruženju

• Nepohranjeno čitanje (engl. Uncommitted Read, skr. UR)– Za naredbe SELECT INTO ili FETCH nad kursorom koji služi samo za čitanje, ili

podupite naredbi INSERT ili UPDATE, ili upite koji kao rezultat imaju skalar, ovajnivo omogućava da:∗ Bilo koji red pročitan tokom jedinice obrade bude promenjen od stranedrugih procesa.

∗ Proces može čitati podatke izmenjene od strane drugih korisnika, čak i prenego što su te izmene potvrđene (ne traži se deljeni katanac za čitanje).

– Za ostale operacije važe pravila nivoa izolovanosti CS.

Moguće je specifikovati koji se nivo izolovanosti koristi i on je u efektu tokom trajanjajedinice posla. Postoji nekoliko načina za podešavanje nivoa izolovanosti:

• Navođenje na nivou jedne naredbe je moguće izvršiti korišćenjem klauze WITH1, čijaje sintaksa data u nastavku:WITH (

RR [lock−request−clause] |RS [lock−request−clause] |CS |UR

)

gde je lock−request−clause klauza kojom se specifikuje tip katanca koji aplikacijazahteva od SUBP, a čija je sintaksa:USE AND KEEP (SHARE|UPDATE|EXCLUSIVE) LOCKS

Ova WITH klauza se može koristiti u narednim naredbama: DECLARE CURSOR, pretra-žujući UPDATE2, INSERT, SELECT, SELECT INTO i pretražujući DELETE3

• Podešavanjem specijalnog registra CURRENT ISOLATION, čiji je tip CHAR(2), a koji sa-drži informaciju o nivou izolacije za svaku dinamičku SQL naredbu koja se izvršava utekućoj sesiji. Moguće vrednosti su: prazna niska, 'RR', 'RS', 'CS' i 'UR'. Promenaove vrednosti se može izvršiti naredbom SET CURRENT ISOLATION, čija je sintaksa:SET [CURRENT] ISOLATION [=] (UR|CS|RR|RS|RESET)

Navođenjem vrednosti RESET će vrednost registra biti postavljena na praznu nisku,što znači da se neće koristiti ta vrednost za registar.

• Navođenjem vrednosti za nivo izolacije kao atribut paketa, čime se efektivno koristita vrednost za aplikacije koje koriste taj paket. Ovo se može uraditi navođenjemISOLATION opcije prilikom izvršavanja naredbi PRECOMPILE ili BIND. Ova opcija imanarednu sintaksu:ISOLATION (CS|RR|RS|UR)

Ukoliko se ne specifikuje nivo izolacije, DB2 će podrazumevano koristiti nivo CS.

Naredni primeri ilustruju različite efekte iste aplikacije pri različitim nivoima izolovano-sti. Primetimo da smo u narednim primerima koristili klauzu WITH za postavljanje nivoaizolovanosti.

1Obratiti pažnju da se ne radi o WITH klauzi za kreiranje privremenih tabela u SELECT naredbi, većda se ova WITH klauza nekad naziva i isolation−clause.

2Pretražujući UPDATE je varijanta naredbe UPDATE gde se u WHERE klauzi koristi restrikcija za prona-laženje redova u tabeli koji će biti izmenjeni — samim tim, može biti izmenjeno 0 ili više redova u tabeli.Nasuprot njoj, postoji i varijanta naredbe koja se naziva pozicionirani UPDATE koji će promeniti tačnoonaj red na koji pokazuje kursor koji se navodi u naredbi — samim tim, ova naredba menja tačno jedanred u tabeli.

3Videti fusnotu za pretražujući UPDATE.

Page 113: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.3 Nivoi izolovanosti 113

Primer 6.3 — Čas 05 — 10. Napisati program u programskom jeziku C sa ugnežđenimSQL-om (repeatableRead) koji dva puta ispisuje informacije o godini, oznaci, nazivu iperiodu prijavljivanja za svaki ispitni rok u 2016. godini. Omogućiti da se prilikom obaispisivanja dobijaju iste informacije.

Napisati program u programskom jeziku C sa ugnežđenim SQL-om (insertIspitniRok)koji unosi novi ispitni rok za mesec mart u 2016. godini. Postaviti istek vremena zazahtevanje katanaca na 5 sekundi.

Rešenje. Pre početka izvršavanja bilo kog programa, pokrenuti skript pripremaBaze.shkoji će uneti neke informacije o ispitnim rokovima u bazu podataka na osnovu skriptapripremaBaze.sql:

Kod 6.3: Primeri/cas05/NI-RR/pripremaBaze.sqlDELETE FROM ISPITNI_ROK

WHERE GODINA = 2016;

INSERT INTO ISPITNI_ROK VALUES(2016, 'Jan2016', 'Januar 2016', '01/01/2016', '01/12/2016', '1'),(2016, 'Feb2016', 'Februar 2016', '02/01/2016', '02/12/2016', '1');

Kod 6.4: Primeri/cas05/NI-RR/pripremaBaze.shdb2 connect to vstud

db2 −t −f pripremaBaze.sql

db2 connect reset

Pokrenuti program repeatableRead i započeti prvo ispisivanje. U toku ispisivanja ili nakonnjega, pokrenuti program insertIspitniRok, pa nastaviti sa daljim ispisivanjem ispitnihrokova.

Uveriti se da program insertIspitniRok ne može da izvrši unos sve dok program repeatableReadne završi sa svim ispisivanjima i takođe da oba ispisivanja imaju iste vrednosti.

Kod 6.5: Primeri/cas05/NI-RR/repeatableRead.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 godina;char oznaka[21],

naziv[51];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main()

Page 114: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

114 Glava 6. Rad u višekorisničkom okruženju

{EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DECLARE ispitniRok CURSOR FORselect godina, oznaka, nazivfrom ispitni_rokwhere godina = 2016WITH RR;

is_error("Declare cursor");

int i = 1;for(; i<3; ++i){

printf("\nCitanje rezultata %d. put. ""Pritisnite neki taster za pocetak.\n", i);

getchar();

EXEC SQL OPEN ispitniRok;is_error("Open");

for(;;){

EXEC SQL FETCH ispitniRokINTO :godina, :oznaka, :naziv;

is_error("Fetch");

if(SQLCODE == 100){

break;}

printf("Godina %d oznaka: %s i naziv %s \n", godina, oznaka, naziv);

printf("Pritisnite neki taster za dalje citanje.");getchar();

}

EXEC SQL CLOSE ispitniRok;is_error("Close");

}

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Kod 6.6: Primeri/cas05/NI-RR/insertIspitniRok.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);

Page 115: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.3 Nivoi izolovanosti 115

exit(EXIT_FAILURE);}

}

void obradi_cekanje(){

printf("Objekat je zakljucan od strane druge transakcije. ""Sacekati neko vreme...\n");

EXEC SQL ROLLBACK;is_error("Rollback");

}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL SET CURRENT LOCK TIMEOUT 5;is_error("Set timeout");

for(;;){

EXEC SQL INSERT INTO ispitni_rokvalues (2016, 'mar', 'Mart 2016', current_date − 1 month,

current_date − 1 month + 20 days, 1);

if (SQLCODE == 0){

break;}

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();}

is_error("Insert");}

EXEC SQL SET CURRENT LOCK TIMEOUT NULL;is_error("Set timeout");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 6.4 — Čas 05 — 11. Napisati program u programskom jeziku C sa ugnežđenimSQL-om (readStability) koji dva puta ispisuje informacije o godini, oznaci, nazivu iperiodu prijavljivanja za svaki ispitni rok u 2016. godini. Dozvoljeno je da se prilikomdrugog ispisivanja pojave novi redovi, ali ne i da budu vidljive izmene pročitanih redova.

Napisati program u programskom jeziku C sa ugnežđenim SQL-om (insertIspitniRok)koji unosi novi ispitni rok za mesec mart u 2016. godini. Postaviti istek vremena zazahtevanje katanaca na 5 sekundi.

Page 116: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

116 Glava 6. Rad u višekorisničkom okruženju

Napisati program u programskom jeziku C sa ugnežđenim SQL-om (updateIspitniRok) koji za svaki ispitni rok u 2016. godini produžava period prijavljivanja za 3 dana.Postaviti istek vremena za zahtevanje katanaca na 5 sekundi.

Rešenje. Pre početka izvršavanja bilo kog programa, pokrenuti skript pripremaBaze.shkoji će uneti neke informacije o ispitnim rokovima u bazu podataka na osnovu skriptapripremaBaze.sql:

Kod 6.7: Primeri/cas05/NI-RS/pripremaBaze.sqlDELETE FROM ISPITNI_ROK

WHERE GODINA = 2016;

INSERT INTO ISPITNI_ROK VALUES(2016, 'Jan2016', 'Januar 2016', '01/01/2016', '01/12/2016', '1'),(2016, 'Feb2016', 'Februar 2016', '02/01/2016', '02/12/2016', '1');

Kod 6.8: Primeri/cas05/NI-RS/pripremaBaze.shdb2 connect to vstud

db2 −t −f pripremaBaze.sql

db2 connect reset

Pokrenuti program readStability i započeti prvo ispisivanje. U toku ispisivanja ili nakonnjega, pokrenuti programe insertIspitniRok i updateIspitniRok, pa nastaviti sa daljimispisivanjem ispitnih rokova.

Uveriti se da program insertIspitniRok može da izvrši unos novog ispitnog roka tokomrada programa readStability i da se novi rok vidi prilikom drugog ispisivanja.

Takođe, uveriti se i da program updateIspitniRok ne može da promeni informacije oispitnim rokovima sve dok program readStability ne završi sa izvršavanjem.

Kod 6.9: Primeri/cas05/NI-RS/readStability.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 godina;char oznaka[21],

naziv[51];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

Page 117: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.3 Nivoi izolovanosti 117

EXEC SQL DECLARE ispitniRok CURSOR FORselect godina, oznaka, nazivfrom ispitni_rokwhere godina = 2016WITH RS;

is_error("Declare cursor");

int i = 1;for(; i<3; ++i){

printf("\nCitanje rezultata %d. put. ""Pritisnite neki taster za pocetak.\n", i);

getchar();

EXEC SQL OPEN ispitniRok;is_error("Open");

for(;;){

EXEC SQL FETCH ispitniRokINTO :godina, :oznaka, :naziv;

is_error("Fetch");

if(SQLCODE == 100){

break;}

printf("Godina %d oznaka: %s i naziv %s \n", godina, oznaka, naziv);

printf("Pritisnite neki taster za dalje citanje.");getchar();

}

EXEC SQL CLOSE ispitniRok;is_error("Close");

}

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Kod 6.10: Primeri/cas05/NI-RS/insertIspitniRok.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

Page 118: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

118 Glava 6. Rad u višekorisničkom okruženju

void obradi_cekanje(){

printf("Objekat je zakljucan od strane druge transakcije. ""Sacekati neko vreme...\n");

EXEC SQL ROLLBACK;is_error("Rollback");

}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL SET CURRENT LOCK TIMEOUT 5;is_error("Set timeout");

for(;;){

EXEC SQL INSERT INTO ispitni_rokvalues (2016, 'mar', 'Mart 2016', current_date − 1 month,

current_date − 1 month + 20 days, 1);

if (SQLCODE == 0){

break;}

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();}

is_error("Insert");}

EXEC SQL SET CURRENT LOCK TIMEOUT NULL;is_error("Set timeout");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Kod 6.11: Primeri/cas05/NI-RS/updateIspitniRok.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

Page 119: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.3 Nivoi izolovanosti 119

void obradi_cekanje(){

printf("Objekat je zakljucan od strane druge transakcije. ""Sacekati neko vreme...\n");

EXEC SQL ROLLBACK;is_error("Rollback");

}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL SET CURRENT LOCK TIMEOUT 5;is_error("Set timeout");

for(;;){

EXEC SQL UPDATE ispitni_rokSET kraj_prijavljivanja = kraj_prijavljivanja + 3 daysWHERE godina = 2016;

if (SQLCODE == 0){

break;}

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();}

is_error("UPDATE");}

EXEC SQL SET CURRENT LOCK TIMEOUT NULL;is_error("Set timeout");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 6.5 — Čas 05 — 12. Napisati program u programskom jeziku C sa ugnežđenimSQL-om (cursorStability) koji dva puta ispisuje informacije o godini, oznaci, nazivu iperiodu prijavljivanja za svaki ispitni rok u 2016. godini. Dozvoljeno je da se prilikomdrugog ispisivanja pojave novi redovi, kao i da budu vidljive izmene pročitanih redova.

Napisati program u programskom jeziku C sa ugnežđenim SQL-om (insertIspitniRok)koji unosi novi ispitni rok za mesec mart u 2016. godini. Postaviti istek vremena zazahtevanje katanaca na 5 sekundi.

Napisati program u programskom jeziku C sa ugnežđenim SQL-om (updateIspitniRok) koji za svaki ispitni rok u 2016. godini produžava period prijavljivanja za 3 dana.Postaviti istek vremena za zahtevanje katanaca na 5 sekundi.

Page 120: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

120 Glava 6. Rad u višekorisničkom okruženju

Rešenje. Pre početka izvršavanja bilo kog programa, pokrenuti skript pripremaBaze.shkoji će uneti neke informacije o ispitnim rokovima u bazu podataka na osnovu skriptapripremaBaze.sql:

Kod 6.12: Primeri/cas05/NI-CS/pripremaBaze.sqlDELETE FROM ISPITNI_ROK

WHERE GODINA = 2016;

INSERT INTO ISPITNI_ROK VALUES(2016, 'Jan2016', 'Januar 2016', '01/01/2016', '01/12/2016', '1'),(2016, 'Feb2016', 'Februar 2016', '02/01/2016', '02/12/2016', '1');

Kod 6.13: Primeri/cas05/NI-CS/pripremaBaze.shdb2 connect to vstud

db2 −t −f pripremaBaze.sql

db2 connect reset

Pokrenuti program cursorStability i započeti prvo ispisivanje. U toku ispisivanja ilinakon njega, pokrenuti programe insertIspitniRok i updateIspitniRok, pa nastaviti sadaljim ispisivanjem ispitnih rokova.

Uveriti se da program insertIspitniRok može da izvrši unos novog ispitnog roka tokomrada programa readStability i da se novi rok vidi prilikom drugog ispisivanja.

Takođe, uveriti se i da program updateIspitniRok može da promeni informacije o ispitnimrokovima i da se izmene vide u programu cursorStability tokom drugog ispisivanja.

Kod 6.14: Primeri/cas05/NI-CS/cursorStability.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 godina;char oznaka[21],

naziv[51];char pocetak[11],

kraj[11];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL DECLARE ispitniRok CURSOR FOR

Page 121: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.3 Nivoi izolovanosti 121

SELECT godina, oznaka, naziv, pocetak_prijavljivanja,kraj_prijavljivanja

FROM ispitni_rokWHERE godina = 2016WITH CS;

is_error("Declare cursor");

int i = 1;for(; i<3; ++i){

printf("\nCitanje rezultata %d. put. ""Pritisnite neki taster za pocetak.\n", i);

getchar();

EXEC SQL OPEN ispitniRok;is_error("Open");

for(;;){

EXEC SQL FETCH ispitniRokINTO :godina, :oznaka, :naziv, :pocetak, :kraj;

is_error("Fetch");

if(SQLCODE == 100){

break;}

printf("\nGodina %d oznaka: %s i naziv %s\n""Prijavljivanje: %s − %s\n", godina, oznaka, naziv, pocetak,

kraj);

printf("Pritisnite neki taster za dalje citanje.");getchar();

}

EXEC SQL CLOSE ispitniRok;is_error("Close");

}

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Kod 6.15: Primeri/cas05/NI-CS/insertIspitniRok.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

Page 122: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

122 Glava 6. Rad u višekorisničkom okruženju

void obradi_cekanje(){

printf("Objekat je zakljucan od strane druge transakcije. ""Sacekati neko vreme...\n");

EXEC SQL ROLLBACK;is_error("Rollback");

}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL SET CURRENT LOCK TIMEOUT 5;is_error("Set timeout");

for(;;){

EXEC SQL INSERT INTO ispitni_rokvalues (2016, 'mar', 'Mart 2016', current_date − 1 month,

current_date − 1 month + 20 days, 1);

if (SQLCODE == 0){

break;}

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();}

is_error("Insert");}

EXEC SQL SET CURRENT LOCK TIMEOUT NULL;is_error("Set timeout");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Kod 6.16: Primeri/cas05/NI-CS/updateIspitniRok.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

Page 123: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.4 Programersko zaključavanje tabela 123

void obradi_cekanje(){

printf("Objekat je zakljucan od strane druge transakcije. ""Sacekati neko vreme...\n");

EXEC SQL ROLLBACK;is_error("Rollback");

}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

EXEC SQL SET CURRENT LOCK TIMEOUT 5;is_error("Set timeout");

for(;;){

EXEC SQL UPDATE ispitni_rokSET kraj_prijavljivanja = kraj_prijavljivanja + 3 daysWHERE godina = 2016;

if (SQLCODE == 0){

break;}

if (SQLCODE == −911 || SQLCODE == −913){

obradi_cekanje();}

is_error("UPDATE");}

EXEC SQL SET CURRENT LOCK TIMEOUT NULL;is_error("Set timeout");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

6.4 Programersko zaključavanje tabela

Programeri mogu sami da zatraže katance od SUBP ukoliko smatraju da im je to ne-ophodno, ali sa ograničenjem da je na ovaj način jedino moguće zaključati tabelu, a neredove, blokove, i druge objekte. Naredba LOCK TABLE onemogućava konkurentnoj aplika-ciji da koristi ili menja tabelu, u zavinosti od režima u kojem se tabela zaključava. Ovakodobijeni katanac se oslobađa kada se završi jedinica posla u kojem je naredba LOCK TABLEizvršena, bilo operacijom pohranjivanjem izmena ili njenim završavanjem.

Korisnik koji izvršava naredbu LOCK TABLE mora da ima barem jednu od narednih privile-gija da bi je uspešno izvršio:

Page 124: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

124 Glava 6. Rad u višekorisničkom okruženju

• SELECT privilegiju nad tabelom koja se zaključava.• CONTROL privilegiju nad tabelom koja se zaključava.• DATAACCESS privilegiju.

Sintaksa ove naredbe je data u nastavku:LOCK TABLE table−name IN [SHARE|EXCLUSIVE] MODE

Ovom naredbom se traži odgovarajući katanac nad tabelom table−name. U zavisnosti ododabranih vrednosti narednih opcija prilikom deklaracije složene SQL naredbe, ta naredbamože imati različite varijante koji utiču na način izvršavanja:

• SHARE — Onemogućava konkurentnoj aplikaciji da izvrši bilo koju operaciju osimčitanja podataka iz tabele.

• EXCLUSIVE — Onemogućava konkurentnoj aplikaciji da izvrši bilo koju operacijunad tabelom. Napomenimo da ovaj režim ne onemogućava da aplikacioni procesiizvršavaju naredbe čitanja podataka iz tabele ukoliko oni rade na nivou izolacijenepohranjeno čitanje (UR).

Primer 6.6 — Čas 05 — 13. Napisati program u programskom jeziku C sa ugnežđenimSQL-om (shareMode) koji ispisuje idenfitikator, oznaku, naziv, broj semestara i bodoveza svaki smer u bazi podataka. Omogućiti da ostale aplikacije ne mogu da menjaju ovepodatke tokom ispisivanja podataka.

Napisati program u programskom jeziku C sa ugnežđenim SQL-om (exclusiveMode)koji ispisuje idenfitikator, oznaku, naziv, broj semestara i bodove za svaki smer u bazipodataka. Omogućiti da ostale aplikacije ne mogu da menjaju ove podatke tokomispisivanja podataka, kao ni da ih čitaju.

Rešenje. Isprobati sve kombinacije redosleda izvršavanja programa exclusiveMode ishareMode i uveriti se da jedino kombinacija (shareMode, shareMode) može raditi konku-rentno.

Kod 6.17: Primeri/cas05/zakljucavanje/shareMode.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_id;char d_oznaka[11];char d_naziv[201];short d_semestara;short d_bodovi;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main()

Page 125: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

6.4 Programersko zaključavanje tabela 125

{EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

// Zakljucavamo tabelu SMER u deljenom rezimuEXEC SQL LOCK TABLE smer IN SHARE MODE;is_error("Lock table");

EXEC SQL DECLARE c_smer CURSOR FORSELECT id_smera, oznaka, naziv, semestara, bodoviFROM smer;

is_error("Declare cursor");

EXEC SQL OPEN c_smer;is_error("Open cursor");

for(;;){

EXEC SQL FETCH c_smerINTO :d_id, :d_oznaka, :d_naziv, :d_semestara, :d_bodovi;

is_error("Fetch cursor");

if (SQLCODE == 100){

break;}

printf("ID:%d OZNAKA:%s NAZIV:%.70s SEMESTARA:%d bodovi:%d\n",d_id, d_oznaka, d_naziv, d_semestara, d_bodovi);

printf("Pritisnite neki taster za naredno citanje\n");getchar();

}

EXEC SQL CLOSE c_smer;is_error("Close cursor");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Kod 6.18: Primeri/cas05/zakljucavanje/exclusiveMode.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_id;char d_oznaka[11];char d_naziv[201];short d_semestara;short d_bodovi;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0)

Page 126: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

126 Glava 6. Rad u višekorisničkom okruženju

{printf("SQLCODE %d: %s\n\n", SQLCODE, err);exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;is_error("Connect");

// Zakljucavamo tabelu SMER u privatnom rezimuEXEC SQL LOCK TABLE smer IN EXCLUSIVE MODE;is_error("Lock table");

EXEC SQL DECLARE c_smer CURSOR FORSELECT id_smera, oznaka, naziv, semestara, bodoviFROM smer;

is_error("Declare cursor");

EXEC SQL OPEN c_smer;is_error("Open cursor");

for(;;){

EXEC SQL FETCH c_smerINTO :d_id, :d_oznaka, :d_naziv, :d_semestara, :d_bodovi;

is_error("Fetch cursor");

if (SQLCODE == 100){

break;}

printf("ID:%d OZNAKA:%s NAZIV:%.70s SEMESTARA:%d bodovi:%d\n",d_id, d_oznaka, d_naziv, d_semestara, d_bodovi);

printf("Pritisnite neki taster za naredno citanje\n");getchar();

}

EXEC SQL CLOSE c_smer;is_error("Close cursor");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Page 127: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7. Programiranje dinamičkih SQL naredbi

Do sada smo konstruisali aplikacije sa ugnežđenim SQL-om koje su koristile statičke SQLnaredbe. Da se podsetimo, u pitanju su bile naredbe čiji je plan izvršavanja mogućeizračunati u fazi pretprocesiranja. Ipak, kreiranje aplikacija koje koriste isključivo statičkeSQL naredbe (dakle, statičke SQL aplikacije) mogu nam tek donekle pomoći. Dizajniranjesloženijih SQL aplikacija zahteva nešto moćnije alate za rad koji se oslanjaju na rad sadinamičkim SQL naredbama, čime se kreiraju dinamičke SQL aplikacije. Samim tim što jeprogramiranje dinamičkih SQL aplikacija moćnije, to je i složenije jer, pored velikog brojanovih načina za pisanje aplikacija, otvara i nove teme, pre svega poređenje složenosti,performansi i upotrebljivosti u odnosu na statičke SQL aplikacije. Međutim, u ovompoglavlju, mi ćemo se baviti isključivo programiranjem dinamičkih SQL aplikacija, ne ipitanjima njihovog razvoja.

Pre nego što započnemo sa poglavljem, napomenimo da ukoliko se koriste struktuiranipodaci ili podaci koji su nekog od tipa LOB (BLOB, CLOB, DBLOB, itd.), onda je za neke odnaredbi potrebno izvršiti dodatna procesiranja. Zbog toga ćemo pretpostaviti da našeaplikacije neće baratati takvim podacima.

7.1 Naredbe za ugnežđavanje dinamičkih SQL naredbi

Da bismo mogli da izvršimo SQL naredbu dinamički, prvo je neophodno skladištiti je umatičnu promenljivu čiji je tip niska. Dinamička SQL naredba prihvata nisku-matičnupromenljivu i naziv SQL naredbe kao argumente. Ova naredba, koja je zadata kao tekst,biće procesirana dinamički.

Tekstualni oblik naredbe neće biti procesiran prilikom prekompilacije aplikacije. Zapravo,sam tekstualni sadrži ne mora ni da postoji u fazi pretprocesiranja. Umesto toga, odinamičkoj SQL naredbi možemo razmišljati kao matičnoj promenljivoj tokom faze pre-kompilacije na koju će se referisati prilikom faze izvršavanja.

Page 128: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

128 Glava 7. Programiranje dinamičkih SQL naredbi

Sadržaj dinamičkih SQL naredbi odgovara istoj sintaksi kao i za statičke SQL naredbe.Ipak, postoje neki izuzeci nametnuti od strane DB2 SUBP:

• Naredba ne sme počinjati ključnim rečima EXEC SQL.• Naredba se ne sme završavati karakterom za označavanje kraja naredbe. Jedini

izuzetak od ovog pravila jeste naredba CREATE TRIGGER koja može sadržati karaktertačka-zapeta (;).

Da bismo tekstualni oblik SQL naredbe transformisali u njegov izvršivi oblik, potrebnoje izvršiti odgovarajuće korake, odnosno, naredbe za podršku dinamičkom SQL-u. Ovenaredbe operišu nad matičnim promenljivama koristeći odgovarajući naziv naredbe kojise dodeljuje. Ovih naredbi ima više, a mi ćemo prikazati svaku od njih u nastavku.

7.2 Naredba EXECUTE IMMEDIATE

Naredba EXECUTE IMMEDIATE priprema izvršivi oblik dinamičke SQL naredbe od njegovogtekstualnog oblika i ujedno ga izvršava. Može biti korišćena za pripremu i izvršavanje SQLnaredbi koje ne sadrže ni matične promenljive ni parametarske oznake.

Sintaksa ove naredbe je data u nastavku:EXECUTE IMMEDIATE expression

Vrednost expression predstavlja izraz koji sadrži naredbu koja će se izvršiti. Izraz moraizračunavati nisku čija je najveća veličina 2 MB. Sama naredba mora biti jedna od narednihnaredbi1:

• ALTER• CALL• COMMIT• Složena SQL naredba (linijska)• Složena SQL naredba (kompilirana)• CREATE• DELETE• DROP• GRANT• INSERT• LOCK TABLE• MERGE• ROLLBACK• SAVEPOINT• SET CURRENT LOCK TIMEOUT• SET variable• UPDATE

Niska koja sadrži naredbu ne sme imati parametarske oznake ili reference na matičnepromenljive i ne sme počinjati ključnim rečima EXEC SQL. Ne sme sadržati operator zavr-šavanja naredbe sa izuzetkom složenih SQL naredbi koje mogu sadržati tačku-zapetu (;)za razdvajanje naredbi u bloku izvršavanja.

1Lista naredbi u tekstu nije potpuna, već prikazuje samo najosnovnije podržane naredbe.

Page 129: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.2 Naredba EXECUTE IMMEDIATE 129

Kada se naredba EXECUTE IMMEDIATE izvrši, specifikovana naredba se parsira i proveravajuse greške. Ako SQL naredba nije validna, ona se neće izvršiti i uslov koji je doveo dogreške se izveštava kroz SQLCA. Ako je SQL naredba validna, ali njeno izvršavanje dovodido greške, onda se ta greška takođe izveštava kroz SQLCA.

Primer 7.1 — Čas 06 — 01. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se korišćenjem dinamičkog SQL-a omogućava da korisnik sa standardnogulaza unosi SQL naredbu koja se potom izvršava. U slučaju da korisnik unese naredbuSELECT, dovoljno je prekinuti izvršavanje programa sa porukom o grešci. Pretpostavitida upit koji se unosi sa standardnog ulaza nije duži od 255 karaktera.

Rešenje.

Kod 7.1: Primeri/cas06/dinamicki1.sqc#include <stdio.h>#include <string.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char stmt[255];EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("Greska %d: %s\n\n", SQLCODE, err);EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud USER student USING abcdef;is_error("Connect");

printf("Unesite naredbu:\n");

// Ucitavamo naredbu sa standardnog ulaza.// Pretpostavljamo da je naredba u jednoj liniji.// fgets(stmt, 255, stdin);

// Alternativno:// Mozemo citati do pojave karaktera ';'// Ovako mozemo imati i karaktere za nov red unutar upitachar c;int broj_karaktera = 0;while(broj_karaktera < sizeof(stmt)){

c = getchar();

if (c == ';'){

break;}

Page 130: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

130 Glava 7. Programiranje dinamičkih SQL naredbi

stmt[broj_karaktera] = c;++broj_karaktera;

}

// Ispisujemo korisniku sta je uneoprintf("\nUneli ste naredbu:\n");printf("∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗\n");printf("%s\n", stmt);printf("∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗\n");

// Izvrsavamo unetu naredbuEXEC SQL EXECUTE IMMEDIATE :stmt;is_error("Execute immediate");

printf("Naredba je uspesno izvrsena.\n");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

7.3 Naredba PREPARE

Naredba PREPARE se koristi od strane aplikativnog programa da dinamički pripremi SQLnaredbu za izvršenje. Ova naredba kreira izvršivu SQL naredbu koja se naziva pripre-mljena naredba (engl. prepared statement) na osnovu tekstualnog oblika naredbe koji senaziva niska naredbe (engl. statement string).

Sintaksa ove naredbe data je u nastavku:PREPARE statement−name[[OUTPUT] INTO result−descriptor−name][INPUT INTO input−descriptor−name]FROM (host−variable|expression)

Specifikovanjem vrednosti za statement−name se imenuje pripremljena naredba. Ako ovoime identifikuje postojeću pripremljenu naredbu, ta prethodno pripremljena naredba seuništava. Ipak, ime statement−name ne sme idenfitikovati pripremljenu naredbu koja pred-stavlja SELECT naredbu u otvorenom kursoru.

Pripremljena naredba se izračunava na osnovu niske naredbe koja se nalazi u vrednosti uFROM klauzi. Može se navesti bilo matična promenljiva čiji je identifikator host−variablei tip niska ili izraz expression koji vraća nisku.

U zavisnosti od korišćenja narednih klauza, ova naredba ima sledeće efekte:

• OUTPUT INTO — Ako se ova klauza koristi i naredba PREPARE se izvrši uspešno, ondase informacije o izlaznim parametarskim oznakama u pripremljenoj naredbi upisujuu SQLDA promenljivu koja se specifikuje kao result−descriptor−name.

• INPUT INTO — Ako se ova klauza koristi i naredba PREPARE se izvrši uspešno, ondase informacije o ulaznim parametarskim oznakama u pripremljenoj naredbi upisujuu SQLDA promenljivu koja se specifikuje kao input−descriptor−name. Ulazne para-metarske oznake se uvek smatraju za potencijalno nedostajuće (engl. nullable), bezobzira od korišćenja.

Page 131: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.3 Naredba PREPARE 131

Umesto ovih klauza se može koristiti naredba DESCRIBE o kojoj će biti reči u kasnijemtekstu.

Naredbe koje se mogu pripremiti na ovaj način su iste one naredbe kao za naredbu EXECUTEIMMEDIATE, uz dodatak SELECT naredbe.

7.3.1 Parametarske oznake

Iako dinamička SQL naredba koja se priprema ne može da sadrži reference na matičnepromenljive, ona ipak može da koristi parametarske oznake (engl. parameter marker). Pa-rametarske oznake mogu biti zamenjene vrednostima iz matičnih promenljivih u trenutkuizvršavanja pripremljene naredbe.

Postoje dva načina za specifikovanje parametarskih oznaka:

• Neimenovana — Navodi se korišćenjem karaktera upitnika (?).• Imenovana — Navodi se dvotačkom (:) iza koje sledi identifikator markera parame-

tra, na primer, :name.

Oba opisana načina se koriste na istom mestu gde bi se koristile matične promenljiveu slučaju da je SQL naredba statička. Iako imenovane parametarske oznake imaju istusintaksu kao i matične promenljive, njihova upotrebna vrednost je svakako drugačija. Ma-tična promenljiva sadrži vrednost u memoriji i koristi se direktno u statičkoj SQL naredbi.Imenovana parametarska oznaka predstavlja tek zamenu (engl. placeholder) za vrednostu dinamičkoj SQL naredbi i njena vrednost se navodi prilikom izvršavanja pripremljenenaredbe.

Takođe, parametarske oznake imaju i dva tipa:

• Netipizirani — Parametarska oznaka se navodi bez tipa njenog cilja i ima formukaraktera upitnika. Sam tip vrednosti netipizirane parametarske oznake se izvodi izkonteksta u kojem se upotrebljava. Na primer, u naredbiUPDATE EMPLOYEESET SALARY = SALARY + 1000WHERE EMPNO = ?

koristi se netipizirana parametarska oznaka kao predikat restrikcije, čiji će tip bitionaj tip kojim je definisana kolona EMPNO.Netipizirane parametarske oznake se mogu koristiti u dinamičkim SQL naredbamasve dok se tip parametarske oznake može izvesti iz konteksta upotrebe. U suprotnom,SUBP prijavljuje SQLSTATE vrednost 42610 (SQLCODE −418).

• Tipizirani — Parametarska oznaka se navodi uz tip cilja. Sintaksa koja se koristi uovom slučaju jeCAST(? AS data−type)

gde je data−type odgovarajući tip. Ova notacija ne označava poziv funkcije, već”obećanje” da će tip vrednosti, koja će se koristiti umesto navedene tipizirane para-metarske oznake, odgovarati tipu koji je naveden ili da se makar može konvertovatiu njega. Na primer, u naredbiUPDATE EMPLOYEESET LASTNAME = TRANSLATE(CAST(? AS VARCHAR(12)))WHERE EMPNO = 123

Page 132: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

132 Glava 7. Programiranje dinamičkih SQL naredbi

vrednost argumenta funkcije TRANSLATE biće navedena tokom faze izvršavanja. Oče-kuje se da je tip te vrednosti bilo VARCHAR(12) ili tip koji se može konvertovati unjega.Tipizirane parametarske oznake se mogu koristiti u dinamičkim SQL naredbama gdegod je matična promenljiva podržana i tip podataka je kompatibilan sa ”obećanjem”navedenim u CAST funkciji.

Kada se naredba PREPARE izvrši, specifikovana naredba se parsira i proveravaju se greške.Ako SQL naredba nije validna, ona se neće izvršiti i uslov koji je doveo do greške seizveštava kroz SQLCA. Svako naredno izvršavanje naredbi EXECUTE ili OPEN koji referišu naovu naredbu će takođe dobiti istu grešku, osim ukoliko se prethodno ne ispravi.

Pripremljena naredba može biti referisana u narednim naredbama, sa odgovarajućim ogra-ničenjima navedenim u zagradama:

• DESCRIBE (može biti proizvoljna naredba)• DECLARE CURSOR (može biti isključivo SELECT naredba)• EXECUTE (ne sme biti SELECT naredba)

Prednost korišćenja pripremljenih naredbi je u činjenici da se one mogu izvršavati više puta.Ipak, ukoliko naredba ne sadrži parametarske oznake i izvršava se samo jednom, onda sepreporučuje korišćenje EXECUTE IMMEDIATE naredbe umesto korišćenja naredbi PREPARE iEXECUTE.

7.4 Naredba EXECUTE

Naredba EXECUTE izvršava prethodno pripremljenu SQL naredbu. Sintaksa ove naredbe jedata u nastavku:EXECUTE statement−name[INTO DESCRIPTOR result−descriptor−name][USING (lista−maticnih−promenljivih | DESCRIPTOR input−descriptor−name)]

Ova naredba izvršava prethodno pripremljenu naredbu koja se identifikuje pomoću statement−name. Ta vrednost mora odgovarati prethodno pripremljenoj naredbi i ta naredba ne smebiti SELECT. Pripremljena naredba se može izvršiti više puta.

U zavisnosti od korišćenja narednih klauza, ova naredba ima sledeće efekte:

• INTO DESCRIPTOR result−descriptor−name — Identifikuje izlaznu SQLDA strukturukoja mora sadržati validne opise matičnih promenljivih. Videti sekciju 7.5.1 za do-datne napomene.

• USING — Idenfitikuje listu promenljivih ili izraza koje će se koristiti prilikom zamenevrednosti za ulazne parametarske oznake u pripremljenoj naredbi. Ako se makarjedna ulazna parametarska oznaka nalazi u pripremljenoj naredbi, onda se moraspecifikovati klauza USING. U suprotnom, SUBP prijavljuje SQLSTATE vrednost 07004.Vrednosti se mogu specifikovati na dva načina:

– lista−maticnih−promenljivih — Identifikuje se lista matičnih promenljivihrazdvojena zapetom. Broj matičnih promenljivih u listi mora biti jednak brojuulaznih parametarskih oznaka u pripremljenoj naredbi. Dodatno, n-ta matičnapromenljiva u listi odgovara n-toj parametarskoj oznaci u pripremljenoj naredbi.

Page 133: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.4 Naredba EXECUTE 133

– DESCRIPTOR input−descriptor−name — Identifikuje se ulazna SQLDA strukturakoja mora sadržati validne opise matičnih promenljivih. Videti sekciju 7.5.1 zadodatne napomene.

Pre samog izvršavanja pripremljene naredbe, svaka ulazna parametarska oznaka se zame-njuje vrednošću odgovarajuće promenljive ili izraza. Za tipizirane parametarske oznake,atributi ciljne promenljive ili izraza su oni koji su navedeni u CAST specifikaciji. Za neti-pizirane parametarske oznake, atributi ciljne promenljive ili izraza se izvode iz kontekstaupotrebe parametarske oznake.

Primer 7.2 — Čas 06 — 02. Napisati program u programskom jeziku C sa ugnežđenimSQL-om kojim se omogućava da korisnik unese:

1. Prvo upit za unos novog ispitnog roka, a zatim i podatke o novom ispitnom roku.2. Samo podatke o novom ispitnom roku.

Koristeći dinamički SQL uneti novi ispitni rok u bazu podataka u oba slučaja, sa unetimpodacima. Pretpostaviti da upit koji se unosi sa standardnog ulaza nije duži od 255karaktera.

Rešenje.

Kod 7.2: Primeri/cas06/dinamicki2.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char stmt[255];sqlint32 godina;char sifra[11],

naziv[51],pocetak_prijave[11],kraj_prijave[11],tip[3];

EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("Greska %d: %s\n\n", SQLCODE, err);EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud USER student USING abcdef;is_error("Connect");

// Pitamo korisnika da li zeli da unese upit ili neprintf("Odaberite jednu od naredne dve opcije: [1/2]\n"

"\t1. Unos upita, a zatim i podataka za novi ispitni rok\n""\t2. Unos samo podataka za novi ispitni rok\n");

char unos_upita;

Page 134: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

134 Glava 7. Programiranje dinamičkih SQL naredbi

scanf("%c", &unos_upita);getchar();

if (unos_upita == '1'){

printf("Unesite upit za unos novog ispitnog roka (u jednoj liniji):\n");

fgets(stmt, sizeof(stmt), stdin);}else{

sprintf(stmt, "INSERT INTO ISPITNI_ROK VALUES(?, ?, ?, ?, ?, ?)");}

printf("\nNaredba: %s\n\n", stmt);

// Pripremamo naredbu za izvrsavanjeEXEC SQL PREPARE prep_stmt FROM :stmt;is_error("PREPARE");

// Ucitavamo podatke za unosenje u tabelu ispitni_rokprintf("Unesite godinu, sifru, naziv roka, pocetak i kraj prijave i tip

roka:\n");

scanf("%d", &godina);

scanf("%s", sifra);getchar();

fgets(naziv, sizeof(naziv), stdin);naziv[strcspn(naziv, "\n")] = '\0';

scanf("%s", pocetak_prijave);

scanf("%s", kraj_prijave);

scanf("%s", tip);

// Izvrsavamo prethodno pripremljenu naredbu// koriscenjem maticnih promenljivihEXEC SQL EXECUTE prep_stmt

USING :godina, :sifra, :naziv, :pocetak_prijave, :kraj_prijave, :tip;is_error("Execute");

printf("Naredba je uspesno izvrsena!\n");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 7.3 — Čas 06 — 03. Napisati program u programskom jeziku C sa ugnežđenimSQL-om. Koristeći dinamički SQL omogućiti izvršavanje upita kojim se izdvajaju podacio smerovima i to: identifikator, oznaka, naziv, broj semestara i bodovi, za svaki smerčiji se broj semestara unosi sa standardnog ulaza.

Page 135: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.4 Naredba EXECUTE 135

Rešenje.

Kod 7.3: Primeri/cas06/dinamicki3.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;sqlint32 d_id;char d_oznaka[11];char d_naziv[201];short d_semestara;short d_bodovi;

char naredba[255];short uneseno_semestara;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("Greska %d: %s\n\n", SQLCODE, err);EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud USER student USING abcdef;is_error("Connect");

// Kreiranje niske naredbe sa netipiziranom parametarskom oznakomsprintf(naredba,

"select id_smera, oznaka, rtrim(naziv), semestara, bodovi ""from smer ""where semestara = ?");

// Prevodjenje niske naredbe u pripremljenu naredbu// sa nazivom prep_naredbaEXEC SQL PREPARE prep_naredba FROM :naredba;is_error("Prepare");

// Deklaracija kursora na osnovu pripremljene naredbe.// Ne navodimo dvotacku ispred prep_naredba jer je to identifikator,// a ne maticna promenljiva.EXEC SQL DECLARE C1 CURSOR FOR

prep_naredba;is_error("Declare cursor");

printf("Unesite broj semestara: ");scanf("%hd", &uneseno_semestara);

// Otvaranje kursora i navodjenje vrednosti parametarske oznakeEXEC SQL OPEN C1

USING :uneseno_semestara;is_error("Open cursor");

for(;;)

Page 136: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

136 Glava 7. Programiranje dinamičkih SQL naredbi

{EXEC SQL FETCH C1

INTO :d_id, :d_oznaka, :d_naziv, :d_semestara, :d_bodovi;is_error("Fetch cursor");

if (SQLCODE == 100){

break;}

printf("ID: %d OZNAKA: %s NAZIV: %.70s SEMESTARA: %d BODOVI: %d\n",d_id, d_oznaka, d_naziv, d_semestara, d_bodovi);

}

EXEC SQL CLOSE C1;is_error("Close cursor");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

Primer 7.4 — Čas 06 — 04. Napisati program u programskom jeziku C sa ugnežđenimSQL-om. Koristeći dinamički SQL omogućiti izvršavanje upita kojim se izdvaja nazivpredmeta, prosečna ocena i procenat studenata iz tog predmeta u školskoj godini kojase unosi sa standardnog ulaza.

Rešenje.

Kod 7.4: Primeri/cas06/dinamicki4.sqc#include <stdio.h>#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char stmt[512];short godina;double prosek,

procenat;char naziv[51];short ind_prosek;EXEC SQL END DECLARE SECTION;

void is_error(char ∗err){

if (SQLCODE < 0){

printf("Greska %d: %s\n\n", SQLCODE, err);EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

int main(){

EXEC SQL CONNECT TO vstud USER student USING abcdef;

Page 137: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.4 Naredba EXECUTE 137

is_error("Connect");

sprintf(stmt,"SELECT RTRIM(P.NAZIV) AS NAZIV, "

"AVG(CASE ""WHEN OCENA > 5 AND STATUS_PRIJAVE = 'o' THEN OCENA + 0.0 ""ELSE NULL "

"END"") AS PROSEK, ""("

"SUM(CASE ""WHEN OCENA > 5 AND STATUS_PRIJAVE = 'o' THEN 1 ""ELSE 0 "

"END)"") ∗ 100.00 / (COUNT(∗)) AS PROCENAT "

"FROM ISPIT I ""JOIN PREDMET P "

"ON I.ID_PREDMETA = P.ID_PREDMETA ""WHERE GODINA_ROKA = ? ""GROUP BY P.NAZIV, P.ID_PREDMETA ""ORDER BY PROSEK DESC");

// Mozemo da referisemo na identifikator pripremljene naredbe// pre nego sto je pripremo// zato sto se identifikatori skladiste u fazi pretprocesiranja,// a ne u fazi izvrsavanja.EXEC SQL DECLARE C1 CURSOR FOR

prep_stmt;is_error("Declare");

EXEC SQL PREPARE prep_stmt FROM :stmt;is_error("Prepare");

printf("Unesite godinu roka:\n");scanf("%hd", &godina);

// Ono sto jeste bitno jeste da se// otvaranje kursora vrsi nakon pripremanje naredbeEXEC SQL OPEN C1

USING :godina;is_error("Open");

int broj_polaganih_predmeta = 0;for(;;){

EXEC SQL FETCH C1INTO :naziv, :prosek:ind_prosek, :procenat;

is_error("Fetch");

if (SQLCODE == 100){

break;}

++broj_polaganih_predmeta;

if(ind_prosek < 0){

printf("Predmet %s niko nije polozio u %hd. godini.\n\n", naziv,godina);

}

Page 138: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

138 Glava 7. Programiranje dinamičkih SQL naredbi

else{

printf("Na predmetu %s prosek studenata na rokovima u %d. godini je%.2lf.\n""Procenat studenta koji su polozili ovaj predmet te godine je

%.2lf.\n\n",naziv, godina, prosek, procenat);

}}

if(broj_polaganih_predmeta == 0){

printf("Nema polaganih predmeta u rokovima unete godine!\n");}

EXEC SQL CLOSE C1;is_error("Close");

EXEC SQL CONNECT RESET;is_error("Connect reset");

return 0;}

7.5 SQLDA

SQL prostor za opisivanje (engl. SQL Description Area, skr. SQLDA) predstavlja kolekcijupromenljivih koje su neophodne za izvršavanje SQL naredbe DESCRIBE. Da bismo moglida ga koristimo, zaglavlje je potrebno uključiti pomoću naredbe INCLUDE:EXEC SQL INCLUDE SQLDA;

Promenljive deklarisane u SQLDA zaglavlju predstavljaju podešavanja koja se mogu koristitiu naredbama poput PREPARE, OPEN, FETCH i EXECUTE. SQLDA komunicira sa dinamičkomSQL naredbom i ima nekoliko upotrebnih vrednosti. Značenje informacija u SQLDA zavisiod njenog korišćenja. U naredbama PREPARE i DESCRIBE, koristi se kao izvor informacijaka aplikaciji o pripremljenoj naredbi. U naredbama OPEN, EXECUTE i FETCH, SQLDA nosiinformacije o matičnim promenljivama.

Slika 7.1: Struktura SQLDA.

U nastavku sledi opis strukture SQLDA, a grafički prikaz se nalazi na slici 7.1.

Page 139: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.5 SQLDA 139

Zaglavlje strukture se sastoji od narednih informacija:

• sqldaid:– Tip: CHAR(8)– Značenje u DESCRIBE i PREPARE: Sedmi bajt ovog polja se naziva SQLDOUBLED i

postavlja se od strane SUBP na karakter 2 ukoliko se za svaku kolonu koristedve SQLVAR vrednosti.

– Značenje u FETCH, OPEN i EXECUTE: Ako je bilo koja od matičnih promenljivihopisuje kao struktuirani tip ili neka od LOB vrednosti, onda SQLDOUBLED morabiti postavljen na karakter 2.

• sqldabc:– Tip: INTEGER– Značenje u DESCRIBE i PREPARE: Veličina SQLDA strukture u bajtovima.– Značenje u FETCH, OPEN i EXECUTE: Isto.

• sqln:– Tip: SMALLINT– Značenje u DESCRIBE i PREPARE: Nepromenjena od strane SUBP. Mora biti

postavljena na vrednost veću ili jednaku nuli pre izvršavanja naredbe DESCRIBE.Indikuje ukupan broj pojavljivanja SQLVAR.

– Značenje u FETCH, OPEN i EXECUTE: Ukupan broj pojavljivanja SQLVAR u SQLDA.SQLN vrednost mora biti postavljena na vrednost veću ili jednaku nuli.

• sqld:– Tip: SMALLINT– Značenje u DESCRIBE i PREPARE: Broj kolona u rezultujućoj tabeli ili broj para-

metarskih oznaka, postavljen od strane SUBP.– Značenje u FETCH, OPEN i EXECUTE: Broj matičnih promenljivih opisanih poja-

vljivanjima SQLVAR.

Zaglavlje je praćeno proizvoljnim brojem pojavljivanja struktura koje se nazivaju SQLVAR.U naredbama OPEN, FETCH i EXECUTE svako pojavljivanje SQLVAR opisuje matičnu promen-ljivu. U DESCRIBE i PREPARE svako pojavljivanje SQLVAR opisuje kolonu rezultujuće tabeleili parametarsku oznaku. Svaka SQLVAR struktura ima naredna polja:

• sqltype:– Tip: SMALLINT– Značenje u DESCRIBE i PREPARE: Indikuje tip kolone ili parametarske oznake, kao

i informaciju o tome da li je potencijalno nedostajuća (pri čemu smo napomenulida se parametarske oznake uvek smatraju za potencijalno nedostajuće). Tabela7.1 prikazuje dozvoljene vrednosti i njihova značenja.

– Značenje u FETCH, OPEN i EXECUTE: Isto kao u prethodnom slučaju, samo prime-njeno na matične promenljive.

• sqllen:– Tip: SMALLINT– Značenje u DESCRIBE i PREPARE: Dužina atributa kolone ili parametarske oznake.– Značenje u FETCH, OPEN i EXECUTE: Dužina atributa matične promenljive.

• sqldata:– Tip: pokazivač– Značenje u DESCRIBE i PREPARE: Za različite varijante tipa niske sadrži informa-

ciju o preslikavanju karaktera u tačke kodova. Za ostale tipove je nedefinisan.– Značenje u FETCH, OPEN i EXECUTE: Adresa matične promenljive u kojoj će biti

smešteni dohvaćeni podaci.

Page 140: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

140 Glava 7. Programiranje dinamičkih SQL naredbi

• sqlind:– Tip: pokazivač– Značenje u DESCRIBE i PREPARE: Za različite varijante tipa niske sadrži informa-

ciju o preslikavanju karaktera u tačke kodova. Za ostale tipove je nedefinisan.– Značenje u FETCH, OPEN i EXECUTE: Adresa indikatorske promenljive za odgova-

rajuću matičnu promenljivu, ako postoji. Inače, ne koristi se. Ako je vrednostsqltype paran broj, ovo polje se ignoriše.

• sqlname:– Tip: VARCHAR (30)– Značenje u DESCRIBE i PREPARE: Sadrži naziv kolone ili parametarske oznake.– Značenje u FETCH, OPEN i EXECUTE: Različito značenje za različit tip baze poda-

taka (relacione ili XML).

Tabela 7.1: SQL tipovi kolona i njihovi odgovarajući SQLTYPE tipovi u SQLDA. Primetimoda svaki simbolički naziv počinje imenom SQL_TYP_ ukoliko vrednost nije potencijalnonedostajuća, a imenom SQL_TYP_N ukoliko jeste.

SQL tip koloneSQLTYPEnumeričkavrednost

SQLTYPE simboličko ime

DATE 384/385 SQL_TYP_DATE / SQL_TYP_NDATETIME 388/389 SQL_TYP_TIME / SQL_TYP_NTIMETIMESTAMP 392/393 SQL_TYP_STAMP / SQL_TYP_NSTAMPn/a 400/401 SQL_TYP_CGSTR / SQL_TYP_NCGSTRBLOB 404/405 SQL_TYP_BLOB / SQL_TYP_NBLOBCLOB 408/409 SQL_TYP_CLOB / SQL_TYP_NCLOBDBCLOB 412/413 SQL_TYP_DBCLOB / SQL_TYP_NDBCLOBVARCHAR 448/449 SQL_TYP_VARCHAR / SQL_TYP_NVARCHARCHAR 452/453 SQL_TYP_CHAR / SQL_TYP_NCHARLONG VARCHAR 456/457 SQL_TYP_LONG / SQL_TYP_NLONGn/a 460/461 SQL_TYP_CSTR / SQL_TYP_NCSTRVARGRAPHIC 464/465 SQL_TYP_VARGRAPH / SQL_TYP_NVARGRAPHGRAPHIC 468/469 SQL_TYP_GRAPHIC / SQL_TYP_NGRAPHICLONG VARGRAPHIC 472/473 SQL_TYP_LONGRAPH / SQL_TYP_NLONGRAPHFLOAT 480/481 SQL_TYP_FLOAT / SQL_TYP_NFLOATREAL 480/481 SQL_TYP_FLOAT / SQL_TYP_NFLOATDECIMAL 484/485 SQL_TYP_DECIMAL / SQL_TYP_DECIMALINTEGER 496/497 SQL_TYP_INTEGER / SQL_TYP_NINTEGERSMALLINT 500/501 SQL_TYP_SMALL / SQL_TYP_NSMALLn/a 804/805 SQL_TYP_BLOB_FILE / SQL_TYPE_NBLOB_FILEn/a 808/809 SQL_TYP_CLOB_FILE / SQL_TYPE_NCLOB_FILEn/a 812/813 SQL_TYP_DBCLOB_FILE / SQL_TYPE_NDBCLOB_FILEn/a 960/961 SQL_TYP_BLOB_LOCATOR / SQL_TYP_NBLOB_LOCATORn/a 964/965 SQL_TYP_CLOB_LOCATOR / SQL_TYP_NCLOB_LOCATORn/a 968/969 SQL_TYP_DBCLOB_LOCATOR / SQL_TYP_NDBCLOB_LOCATORXML 988/989 SQL_TYP_XML / SQL_TYP_XML

Page 141: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.6 Naredba DESCRIBE 141

7.5.1 Efekat naredbe EXECUTE na SQLDA

Pre nego što se naredba EXECUTE procesira, korisnik mora da postavi naredna polja uulaznoj SQLDA:

• SQLN za indikovanje broja pojavljivanja SQLVAR.• SQLDABC za indikovanje broja bajtova alociranih za SQLDA.• SQLD za indikovanje broja promenljivih koje se koriste u SQLDA prilikom procesiranja

naredbe.• SQLVAR pojavljivanja za indikovanje atributa promenljivih.

Pritom, SQLDA mora imati dovoljno alociranog prostora da sadrži sva pojavljivanja SQLVAR.Procedura za alociranje dovoljne veličine prostora glasi:

• Zaglavlje sadrži fiksnu veličinu od 16 bajtova.• Niz promenljive dužine SQLVAR struktura za svaki element sadrži 44 bajtova na 32-

bitnim, odnosno, 56 bajtova na 64-bitnim sistemima.

Drugim rečima, količina prostora koju treba alocirati je (SQLD je odgovarajući broj matičnihpromenljivih opisanih pojavljivanjima SQLVAR):16 + (SQLD ∗ sizeof(struct sqlvar))

Na raspolaganju nam je makro SQLDASIZE koji će izračunati ovu vrednost za nas, uzimajućiu obzir specifičnosti platforme. Njegov obavezni argument je upravo vrednost SQLD.

Dodatno, SQLDmora biti postavljen na vrednost veću ili jednaku nuli i manju od ili jednakuSQLN.

7.5.2 Efekat naredbe DESCRIBE na SQLDA

Za naredbe DESCRIBE OUTPUT ili PREPARE OUTPUT INTO, SUBP uvek postavlja SQLD na brojkolona u rezultujućoj tabeli ili na broj izlaznih parametarskih oznaka.

Za naredbe DESCRIBE INPUT ili PREPARE INPUT INTO, SUBP uvek postavlja SQLD na brojulaznih parametarskih oznaka u naredbi.

7.6 Naredba DESCRIBE

Naredba DESCRIBE dohvata informacije o pripremljenoj naredbi. Postoje dva tipa informa-cija koja se mogu dobiti ovom naredbom, i svaki od njih ćemo posebno opisati.

7.6.1 Naredba DESCRIBE INPUT

Dohvata informacije o ulaznim parametarskim oznakama u pripremljenoj naredbi. Ovainformacija se smešta u deskriptor.

Sintaksa ove naredbe je:DESCRIBE INPUT statement−name INTO descriptor−name

Ova naredba dohvata informacije iz perthodno pripremljene naredbe koja se identifikujeimenom statement−name.

Klauza INTO descriptor−name identifikuje SQLDA struktura za unos informacija.

Page 142: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

142 Glava 7. Programiranje dinamičkih SQL naredbi

Priprema SQLDA

Pre izvršavanja DESCRIBE INPUT naredbe, korisnik mora da alocira prostor za SQLDA struk-turu i da postavi vrednost promenljive SQLN na broj SQLVAR pojavljivanja u okviru SQLDAstrukture. Ova vrednost mora biti veća od nule ili jednaka nuli, pre nego što se naredbaizvrši.

Postoje tri tehnike za alociranje SQLDA strukture:

1. Alocirati prostor za SQLDA strukturu sa dovoljnim brojem SQLVAR promenljivih dasadrži bilo koju listu informacija koju aplikacija može da procesira. Najveći dozvoljenbroj informacija iznosi 255. Ova tehnika koristi veliku količinu prostora koja upraktičnim primenama neće biti korišćena.

2. Ponavljati naredna dva koraka:• Izvršiti naredbu EXECUTE INPUT sa SQLDA koja nema pojavljivanja SQLVAR, odno-

sno, u kojoj je SQLN vrednost postavljena na nulu. Vrednost koja je postavljenau SQLD nakon izvršavanja naredbe predstavlja broj kolona u rezultujućoj tabeli.SUBP u ovom slučaju postavlja SQLCODE na vrednost +236.

• Alocirati prostor za SQLDA strukturu sa dovoljnim brojem SQLVAR pojavljivanja.Zatim izvršiti naredbu DESCRIBE ponovo, korišćenjem nove alocirane SQLDA.

Ova tehnika ima bolji mehanizam rukovanja memorijom od prve tehnike, ali se brojizvršavanja naredbi DESCRIBE udvostručava.

3. Alocirati prostor za SQLDA strukturu koja je dovoljno velika da sadrži veliki broj, akone i sve liste informacija koju aplikacija može da procesira, ali je takođe i dovoljnomala. Ukoliko je ovo dovoljna količina prostora, nastaviti sa izvršavanjem. U su-protnom, alocirati novi prostor sa dovoljnim brojem SQLVAR pojavljivanja i izvršitinaredbu DESCRIBE ponovo. Ova tehnika predstavlja kompromis između prethodnedve tehnike i oslanja se na heuristiku izbora veličine prostora koja je dovoljno velika,a u isto vreme i dovoljno mala.

Efekat izvršenja naredbe

Nakon izvršavanja naredbe DESCRIBE INPUT, SUBP dodeljuje vrednosti promenljivamastrukture SQLDA na sledeći način:

• SQLDAID — Prvih 6 bajtova se postavlja na 'SQLDA ', a sedmi bajt (SQLDOUBLED)postavlja se na karakter '2' ili na razmak. Osmi bajt se postavlja na razmak.

• SQLDABC — Dužina SQLDA strukture u bajtovima.• SQLD — Broj ulaznih parametara procedure.• SQLVAR — Ako je vrednost SQLD jednaka nuli ili veća od SQLN, ne postavljaju se

vrednosti za pojavljivanja SQLVAR. Ako je vrednost SQLD jednaka n, gde je n > 0 in ≤ SQLN, onda se vrednosti dodeljuju prvih n pojavljivanja SQLVAR. Ove vrednostiopisuju parametarske oznake za ulazne parametre prodecure, redom.

7.6.2 Naredba DESCRIBE OUTPUT

Dohvata informacije o pripremljenoj naredbi ili informacije o listi kolona u pripremljenojSELECT naredbi. Ova informacija se smešta u deskriptor.

Sintaksa ove naredbe je:DESCRIBE [OUTPUT] statement−name INTO descriptor−name

Page 143: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.6 Naredba DESCRIBE 143

Ova naredba dohvata informacije iz perthodno pripremljene naredbe koja se identifikujeimenom statement−name. Ako je pripremljena naredba SELECT ili VALUES INTO, onda in-formacija koja se dohvata predstavlja informaciju o kolonama rezultujuće tabele.

Klauza INTO descriptor−name identifikuje SQLDA struktura za unos informacija.

Priprema SQLDA

Pre izvršavanja DESCRIBE OUTPUT naredbe, korisnik mora da alocira prostor za SQLDA struk-turu i da postavi vrednost promenljive SQLN na broj SQLVAR pojavljivanja u okviru SQLDAstrukture. Ova vrednost mora biti veća od nule ili jednaka nuli, pre nego što se naredbaizvrši.

Postoje tri tehnike za alociranje SQLDA strukture:

1. Alocirati prostor za SQLDA strukturu sa dovoljnim brojem SQLVAR promenljivih dasadrži bilo koju listu informacija koju aplikacija može da procesira. Najveći dozvoljenbroj informacija iznosi 255. Ova tehnika koristi veliku količinu prostora koja upraktičnim primenama neće biti korišćena.

2. Ponavljati naredna dva koraka:• Izvršiti naredbu EXECUTE INPUT sa SQLDA koja nema pojavljivanja SQLVAR, odno-

sno, u kojoj je SQLN vrednost postavljena na nulu. Vrednost koja je postavljenau SQLD nakon izvršavanja naredbe predstavlja broj kolona u rezultujućoj tabeli.SUBP u ovom slučaju postavlja SQLCODE na vrednost +236.

• Alocirati prostor za SQLDA strukturu sa dovoljnim brojem SQLVAR pojavljivanja.Zatim izvršiti naredbu DESCRIBE ponovo, korišćenjem nove alocirane SQLDA.

Ova tehnika ima bolji mehanizam rukovanja memorijom od prve tehnike, ali se brojizvršavanja naredbi DESCRIBE udvostručava.

3. Alocirati prostor za SQLDA strukturu koja je dovoljno velika da sadrži veliki broj, akone i sve liste informacija koju aplikacija može da procesira, ali je takođe i dovoljnomala. Ukoliko je ovo dovoljna količina prostora, nastaviti sa izvršavanjem. U su-protnom, alocirati novi prostor sa dovoljnim brojem SQLVAR pojavljivanja i izvršitinaredbu DESCRIBE ponovo. Ova tehnika predstavlja kompromis između prethodnedve tehnike i oslanja se na heuristiku izbora veličine prostora koja je dovoljno velika,a u isto vreme i dovoljno mala.

Efekat izvršenja naredbe

Nakon izvršavanja naredbe DESCRIBE INPUT, SUBP dodeljuje vrednosti promenljivamastrukture SQLDA na sledeći način:

• SQLDAID — Prvih 6 bajtova se postavlja na 'SQLDA ', a sedmi bajt (SQLDOUBLED)postavlja se na karakter '2' ili na razmak. Osmi bajt se postavlja na razmak.

• SQLDABC — Dužina SQLDA strukture u bajtovima.• SQLD — Ako je pripremljena naredba SELECT, polje SQLD se postavlja na broj kolona

u rezultujućoj tabeli. Inače, SQLD se postavlja na 0.• SQLVAR — Ako je vrednost SQLD jednaka nuli ili veća od SQLN, ne postavljaju se

vrednosti za pojavljivanja SQLVAR. Ako je vrednost SQLD jednaka n, gde je n > 0 in ≤ SQLN, onda se vrednosti dodeljuju prvih n pojavljivanja SQLVAR. Ove vrednostiopisuju parametarske oznake za ulazne parametre prodecure, redom.

Page 144: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

144 Glava 7. Programiranje dinamičkih SQL naredbi

Primer 7.5 — Čas 06 — 05. Napisati program u programskom jeziku C sa ugnežđenimSQL-om. Koristeći dinamički SQL omogućiti izvršavanje proizvoljne naredbe. Prepo-staviti da SELECT naredba nema parametarske oznake. Pretpostaviti da su jedini tipovipodataka koji se koriste numerički, tekstualni i datumi. Pretpostaviti da naredba kojase unosi sa standardnog ulaza nije duža od 512 karaktera.

Rešenje.

Kod 7.5: Primeri/cas06/dinamicki5.sqc#include <stdio.h>#include <string.h>#include <stdlib.h>

// Za SQLTYPE simbolicka imena#include <sqlenv.h>

EXEC SQL INCLUDE SQLCA;

EXEC SQL INCLUDE SQLDA;

EXEC SQL BEGIN DECLARE SECTION;char stmt[512];EXEC SQL END DECLARE SECTION;

// Deklarisemo SQLDA promenljivu za opisivanje dinamickih naredbistruct sqlda ∗ sqldaptr;

// Funkcije za obradu dinamickih naredbivoid unesi_i_pripremi_naredbu();void pripremi_sqlda(int bDebug);void izvrsi_naredbu_na_osnovu_tipa(int bDebug);void izvrsi_odmah_i_prekini(int bDebug);void obradi_select_naredbu(int bDebug);void oslobodi_prvih_i_SQLVAR_u_sqlda(int i);void ispisi_podatke(int bDebug);void oslobodi_sqlda();

// Funkcije za obradu gresakavoid is_error(char ∗err, int linenum);void izadji_bez_uspeha();

#define IS_ERROR_WITH_LINE(err) is_error(err, __LINE__)

int main(){

EXEC SQL CONNECT TO vstud user student using abcdef;IS_ERROR_WITH_LINE("Connect");

char detaljni_rezim;printf("Pokrenuti program u detaljnom rezimu? [d/n]: ");

scanf("%c", &detaljni_rezim);getchar(); // novi red

int bDebug = (detaljni_rezim == 'd') ? 1 : 0;

unesi_i_pripremi_naredbu();pripremi_sqlda(bDebug);izvrsi_naredbu_na_osnovu_tipa(bDebug);

Page 145: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.6 Naredba DESCRIBE 145

printf("\n##########################################################\n");printf("%s", stmt);printf("\n##########################################################\n");

oslobodi_sqlda();

EXEC SQL CONNECT RESET;IS_ERROR_WITH_LINE("Connect reset");

return 0;}

void unesi_i_pripremi_naredbu(){

printf("Unesite SQL naredbu do 512 karaktera:\n");

char c;int broj_karaktera = 0;while (broj_karaktera < sizeof(stmt)){

c = getchar();

if (c == ';'){

break;}

stmt[broj_karaktera] = c;++broj_karaktera;

}

EXEC SQL PREPARE prep_stmt FROM :stmt;IS_ERROR_WITH_LINE("Prepare");

}

void pripremi_sqlda(int bDebug){

// Ova funkcija koristi tehniku 2, koja sadrzi dva koraka,// za alokaciju najmanje potrebne memorije za SQLDA strukturu.

// Korak 1:// Alocirati prostor samo za zaglavlje strukturesqldaptr = (struct sqlda∗)malloc(SQLDASIZE(0));if(sqldaptr == NULL){

printf("Neuspesna alokacija SQLDA zaglavlja\n\n");izadji_bez_uspeha();

}

// Postaviti velicinu SQLN na 0sqldaptr−>sqln = 0;

// Izvrsiti prvi put naredbu DESCRIBE OUTPUTEXEC SQL DESCRIBE prep_stmt

INTO :∗sqldaptr;

// Dodajemo ovu proveru ispred provere greske// zato sto funkcija is_error ne oslobadja pokazivac na SQLDA.if (SQLCODE < 0){

free(sqldaptr);

Page 146: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

146 Glava 7. Programiranje dinamičkih SQL naredbi

}IS_ERROR_WITH_LINE("Describe − Korak 1");

if (bDebug){

printf("\nRezultat izvrsavanja DESCRIBE u koraku 1:\n""\tSQLCODE = %d\n""\tSQLN = %d\n""\tSQLD = %d\n",SQLCODE, sqldaptr−>sqln, sqldaptr−>sqld);

}

// Korak 2:int numcols;

// Ukoliko nismo alocirali dovoljno prostora za sve SQLVARif(SQLCODE == 236){

// Dohvatamo broj kolona u naredbinumcols = sqldaptr−>sqld;// Oslobadjamo prethodno alociranu strukturufree(sqldaptr);// Alociramo novu strukturu// sa ispravnim brojem SQLVAR promenljivihsqldaptr = (struct sqlda∗)malloc(SQLDASIZE(numcols));

if(sqldaptr == NULL){

printf("Neuspesna alokacija SQLDA strukture\n\n");izadji_bez_uspeha();

}}

// Postavljamo ispravnu vrednost za SQLNsqldaptr−>sqln = numcols;

// Izvrsavamo finalnu naredbu DESCRIBE OUTPUTEXEC SQL DESCRIBE prep_stmt

INTO :∗sqldaptr;

if (SQLCODE < 0){

free(sqldaptr);}IS_ERROR_WITH_LINE("Describe − Korak 2");

if (bDebug){

printf("\nRezultat izvrsavanja DESCRIBE u koraku 2:\n""\tSQLCODE = %d\n""\tSQLN = %d\n""\tSQLD = %d\n",SQLCODE, sqldaptr−>sqln, sqldaptr−>sqld);

}}

void izvrsi_naredbu_na_osnovu_tipa(int bDebug){

// Ukoliko naredba nije SELECT (SQLD == 0),// mozemo koristiti EXECUTE IMMEDIATE.// U suprotnom (SQLD != 0),

Page 147: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.6 Naredba DESCRIBE 147

// moramo obraditi naredbu SELECT pomocu kursora.if(sqldaptr−>sqld == 0){

izvrsi_odmah_i_prekini(bDebug);}

obradi_select_naredbu(bDebug);ispisi_podatke(bDebug);

}

void izvrsi_odmah_i_prekini(int bDebug){

if (bDebug){

printf("\nUnesena naredba nije SELECT.""Zbog toga ce biti odmah izvrsena.\n");

}

EXEC SQL EXECUTE IMMEDIATE :stmt;IS_ERROR_WITH_LINE("Execute immediate");

EXEC SQL COMMIT;IS_ERROR_WITH_LINE("Commit");

free(sqldaptr);

EXEC SQL CONNECT RESET;IS_ERROR_WITH_LINE("Connect reset");

exit(EXIT_SUCCESS);}

void obradi_select_naredbu(int bDebug){

// Pripremanje SQLDA strukture za SELECT upitint i = 0;short sqltype, sqllen;for( ; i < sqldaptr−>sqld; ++i){

sqltype = sqldaptr−>sqlvar[i].sqltype;sqllen = sqldaptr−>sqlvar[i].sqllen;

if (bDebug){

printf("\nInformacije o SQLVAR #%d:\n""\tSQLTYPE = %hd\n""\tSQLLEN = %hd\n",i, sqltype, sqllen);

}

// Alociramo prostor na osnovu informacije o tipu.// Za svaku kolonu alociramo maticnu promenljivu// kao i indikatorsku promenljivuswitch (sqltype){

case SQL_TYP_SMALL:case SQL_TYP_NSMALL:

sqldaptr−>sqlvar[i].sqldata = (char∗)calloc(1, sqllen);sqldaptr−>sqlvar[i].sqlind = (short∗)calloc(1, sizeof(short));break;

case SQL_TYP_INTEGER:

Page 148: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

148 Glava 7. Programiranje dinamičkih SQL naredbi

case SQL_TYP_NINTEGER:sqldaptr−>sqlvar[i].sqldata = (char∗)calloc(1, sqllen);sqldaptr−>sqlvar[i].sqlind = (short∗)calloc(1, sizeof(short));break;

case SQL_TYP_FLOAT:case SQL_TYP_NFLOAT:

sqldaptr−>sqlvar[i].sqldata = (char∗)calloc(1, sqllen);sqldaptr−>sqlvar[i].sqlind = (short∗)calloc(1, sizeof(short));break;

case SQL_TYP_DECIMAL:case SQL_TYP_NDECIMAL:

sqldaptr−>sqlvar[i].sqldata = (char∗)calloc(1, sqllen);sqldaptr−>sqlvar[i].sqlind = (short∗)calloc(1, sizeof(short));break;

case SQL_TYP_DATE:case SQL_TYP_TIME:case SQL_TYP_STAMP:case SQL_TYP_VARCHAR:case SQL_TYP_CHAR:

sqldaptr−>sqlvar[i].sqldata = (char∗)calloc(1, sqllen);sqldaptr−>sqlvar[i].sqlind = (short∗)calloc(1, sizeof(short));sqldaptr−>sqlvar[i].sqltype = SQL_TYP_CSTR;break;

case SQL_TYP_NDATE:case SQL_TYP_NTIME:case SQL_TYP_NSTAMP:case SQL_TYP_NVARCHAR:case SQL_TYP_NCHAR:

sqldaptr−>sqlvar[i].sqldata = (char∗)calloc(1, sqllen);sqldaptr−>sqlvar[i].sqlind = (short∗)calloc(1, sizeof(short));sqldaptr−>sqlvar[i].sqltype = SQL_TYP_NCSTR;break;

default:printf("Nepoznat tip: %hd\n", sqltype);break;

}

// Provera alokacije − moramo biti dobri C programeri :)// Provera alokacije za promenljivuif (sqldaptr−>sqlvar[i].sqldata == NULL){

printf("Neuspesna alokacija SQLVAR za kolonu %d\n", i);

// Oslobadjamo sve alocirane prostore do sadaoslobodi_prvih_i_SQLVAR_u_sqlda(i);izadji_bez_uspeha();

}// Provera alokacije za indikatorsku promenljivuif (sqldaptr−>sqlvar[i].sqlind == NULL){

printf("Neuspesna alokacija SQLVAR (indikator) za kolonu %d\n", i);

// Prvo oslobadjamo promenljivufree(sqldaptr−>sqlvar[i].sqldata);

// Pa onda i sve prethodneoslobodi_prvih_i_SQLVAR_u_sqlda(i);izadji_bez_uspeha();

Page 149: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.6 Naredba DESCRIBE 149

}}

}

void oslobodi_prvih_i_SQLVAR_u_sqlda(int i){

int j = 0;for (; j < i; ++j){

free(sqldaptr−>sqlvar[i].sqldata);free(sqldaptr−>sqlvar[i].sqlind);

}}

void ispisi_podatke(int bDebug){

EXEC SQL DECLARE c CURSOR FOR prep_stmt;IS_ERROR_WITH_LINE("Declare");

EXEC SQL OPEN c;IS_ERROR_WITH_LINE("Open");

int broj_reda = 1;

for(;;){

EXEC SQL FETCH cUSING DESCRIPTOR :∗sqldaptr;

IS_ERROR_WITH_LINE("Fetch");

if (SQLCODE == 100){

break;}

printf("\n# %3d >>\t", broj_reda);

int i = 0;for(; i < sqldaptr−>sqld; ++i){

short sqltype = sqldaptr−>sqlvar[i].sqltype;

switch (sqltype){

case SQL_TYP_SMALL:case SQL_TYP_NSMALL:

if (∗(short∗)(sqldaptr−>sqlvar[i].sqlind) < 0){

printf("%s \t", "NULL");}else{

printf("%hd \t", ∗((short∗)(sqldaptr−>sqlvar[i].sqldata)));

}break;

case SQL_TYP_INTEGER:case SQL_TYP_NINTEGER:

if (∗(short∗)(sqldaptr−>sqlvar[i].sqlind) < 0){

printf("%s \t", "NULL");

Page 150: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

150 Glava 7. Programiranje dinamičkih SQL naredbi

}else{

printf("%d \t", ∗((sqlint32∗)(sqldaptr−>sqlvar[i].sqldata)));

}break;

case SQL_TYP_FLOAT:case SQL_TYP_NFLOAT:

if (∗(short∗)(sqldaptr−>sqlvar[i].sqlind) < 0){

printf("%s \t", "NULL");}else{

printf("%f \t", ∗((float∗)(sqldaptr−>sqlvar[i].sqldata)));

}break;

case SQL_TYP_DECIMAL:case SQL_TYP_NDECIMAL:

if (∗(short∗)(sqldaptr−>sqlvar[i].sqlind) < 0){

printf("%s \t", "NULL");}else{

printf("%lf \t", ∗((double∗)(sqldaptr−>sqlvar[i].sqldata)));

}break;

case SQL_TYP_CSTR:case SQL_TYP_NCSTR:

if (∗(short∗)(sqldaptr−>sqlvar[i].sqlind) < 0){

printf("%s \t", "NULL");}else{

sqldaptr−>sqlvar[i].sqldata[sqldaptr−>sqlvar[i].sqllen]= 0;

printf("%s \t", (char∗)(sqldaptr−>sqlvar[i].sqldata));}break;

default:printf("Nepoznat tip: %hd", sqltype);break;

}}

++broj_reda;}

printf("\n");

EXEC SQL CLOSE c;IS_ERROR_WITH_LINE("Close");

EXEC SQL COMMIT;

Page 151: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

7.6 Naredba DESCRIBE 151

IS_ERROR_WITH_LINE("Commit");}

void oslobodi_sqlda(){

int i = 0;for(; i < sqldaptr−>sqld; ++i){

free(sqldaptr−>sqlvar[i].sqldata);free(sqldaptr−>sqlvar[i].sqlind);

}

free(sqldaptr);}

void is_error(char ∗err, int linenum){

if (SQLCODE < 0){

printf("Greska %d: %s (linija %d)\n\n",SQLCODE, err, linenum);

izadji_bez_uspeha();}

}

void izadji_bez_uspeha(){

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}

Page 152: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 153: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8. Povezivanje na više baza podataka

Do sada smo sve SQL naredbe izvršavali nad jednom bazom podataka. Nekada je potrebnopodatke skladištiti u više baza podataka, te je potrebno izvršavati različite operacije nadrazličitim bazama podataka. Ovo ponašanje podrazumeva postojanje odgovarajućih me-hanizama za rukovanje konekcijama kao i rešavanja pitanja transakcionog rada nad višebaza podataka. U ovom poglavlju ćemo se upoznati sa načinom ostvarivanja distribuira-nog transakcionog rada u DB2 sistemu za relacione baze podataka. Takođe, kroz primerećemo pokazati opisane načine za rukovanje višestrukim konekcijama nad već poznatombazom VSTUD i nad bazom MSTUD, čija je struktura data u dodatku B.

8.1 Osnovno o povezivanju na baze podataka

Distribuirane relacione baze podataka su zasnovane na principima serversko-klijentskihkomunikacionih protokola i funkcija. Aplikacioni zahtevač (engl. application requester)opslužuje aplikacioni deo konekcije. On transformiše zahtev za konekciju na bazu poda-taka od strane aplikacije u komunikacione protokole podesne za korišćenje u distribuiranojmreži baza podataka. Ovi zahtevi pristužu serveru baze podataka na drugom kraju konek-cije i bivaju procesirani od strane njih. Radeći zajedno, aplikacioni zahtevač i server bazepodataka upravljaju komunikacijom i uzimaju u obzir lokaciju, tako da aplikacija možeda operiše kao da radi sa lokalnom bazom podataka.

Aplikacioni proces se mora povezati na aplikacioni server upravljača baze podataka prenego što izvrši SQL naredbe kojima se referiše na tabele ili poglede. U tu svrhu, koristi senaredba CONNECT. Postoje dva tipa naredbe CONNECT:

1. CONNECT (Type 1) — Omogućava rad sa jednom bazom podataka u toku jedne jedi-nice posla, tzv. semantika udaljene jedinice posla (engl. Remote Unit of Work, skr.RUW).

2. CONNECT (Type 2) — Omogućava rad sa više baza podataka u toku jedne jedinice

Page 154: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

154 Glava 8. Povezivanje na više baza podataka

posla, tzv. semantika distribuirane jedinice posla pod upravljanjem aplikacije (engl.Application-Directed Distributed Unit of Work, skr. ADDUW).

Direktni pozivi DB2 funkcija i ugnežđeni SQL omogućavaju režim konekcije koji se nazivakonkurentne transakcije (engl. concurrent transactions) kojim se omogućavaju višestrukekonekcije, pri čemu svaka od njih je nezavisna transakcija. Aplikacija može da ima višekonkurentnih konekcija ka istoj bazi podataka.

Aplikacioni server može biti lokalan ili udaljen u odnosu na okruženje u kojem se procespokreće. Aplikacioni server je prisutan i u okruženju koje ne koristi distribuirane bazepodataka. Ovakvo okruženje sadrži lokalne podatke o aplikacionim serverima koji semogu identifikovati u CONNECT naredbi.

8.1.1 Semantika udaljene jedinice posla

Aplikacioni proces na računaru A može se povezati na aplikacioni server na računaru Bi, u okviru jedne ili više jedinica posla, izvršiti proizvoljan broj statičkih ili dinamičkihSQL naredbi koji referišu na objekte iz B. Nakon završetka jedinica posla u B, aplikacioniproces se može povezati na aplikacioni server na računaru C, pa da izvršava naredbe nadnjegovim objektima, itd.

Većina SQL naredbi može biti udaljeno pripremljena i izvršena, sa određenim restrikci-jama:

• Svi objekti na koje se referiše u okviru jedne SQL naredbe moraju biti upravljani odstrane istog aplikacionog servera.

• Sve SQL naredbe u jedinici posla moraju biti izvršene od strane istog aplikacionogservera.

U bilo kom trenutnu, aplikacioni proces se nalazi u jednom od narednih stanja:

• Poveziv i povezan (engl. Connectable and connected) — Aplikacioni proces je pove-zan na aplikacioni server i naredba CONNECT može da se izvrši.Aplikacioni proces ulazi u ovo stanje u narednim situacijama:

– Naredba CONNECT TO je uspešno izvršena iz stanja poveziv i nepovezan.– Naredba COMMIT ili ROLLBACK je uspešno izvršena ili je došlo do forsiranog poni-

štavanja iz nepoveziv i povezanog stanja.– (Ukoliko je implicitno povezivanje dostupno) Naredba CONNECT TO ili CONNECT

bez operanada je uspešno izvršena iz stanja poveziv i nepovezan.– (Ukoliko je implicitno povezivanje dostupno) Naredba koja nije jedna od CONNECT

RESET, DISCONNECT, SET CONNECTION ili RELEASE je izvršena iz stanja implicitnopovezan.

• Nepoveziv i povezan (engl. Unconnectable and connected) — Aplikacioni proces jepovezan na aplikacioni server, ali naredba CONNECT TO se ne može uspešno izvršiti radipromene aplikacionog servera. Aplikacioni proces ulazi u ovo stanje iz stanja povezivi povezan kada izvrši naredbu koja nije jedna od CONNECT TO, CONNECT bez operanada,CONNECT RESET, DISCONNECT, SET CONNECTION, RELEASE, COMMIT ili ROLLBACK.

Page 155: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.1 Osnovno o povezivanju na baze podataka 155

Slika 8.1: Dijagram prelaska stanja aplikacije u CONNECT (Type 1) ako je implicitnopovezivanje dostupno.

Slika 8.2: Dijagram prelaska stanja aplikacije u CONNECT (Type 1) ako implicitno povezi-vanje nije dostupno.

• Poveziv i nepovezan (engl. Connectable and unconnected) — Aplikacioni proces nijepovezan na aplikacioni server. CONNECT TO je jedina naredba koja se može izvršiti.U suprotnom, SUBP podiže grešku sa SQLSTATE vrednošću 08003.U ovo stanje se dolazi ukoliko dođe do greške prilikom izvršavanja CONNECT TO na-redbe ili ako dođe do greške u okviru jedinice posla, čime dolazi do gubitka konekcijei poništavanja izmena.Ukoliko implicitno povezivanje nije dostupno, aplikacija je inicijalno u ovom stanjui naredbe CONNECT RESET ili DISCONNECT dovode aplikaciju u ovo stanje.

Page 156: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

156 Glava 8. Povezivanje na više baza podataka

• Implicitno poveziv (engl. Implicitly connectable) — Dostupno ako je implicitno po-vezivanje dostupno. U tom slučaju, aplikacija je inicijalno u ovom stanju i naredbaCONNECT RESET dovodi aplikaciju u ovo stanje. Izvršavanje COMMIT ili ROLLBACK na-redbe, praćene naredbom DISCONNECT u stanju poveziv i povezan, takođe dovodiaplikaciju u ovo stanje.

Dostupnost implicitnog povezivanja je uslovljeno podešavanjima prilikom instalacije, pro-menljivama okruženja i podešavanjima autentikacije.

Nije greška izvršavati naredbu CONNECT uzastopno jer ta naredba sama po sebi ne uklanjaaplikaciju iz povezanog stanja. Međutim, jeste greška izvršavati naredbu CONNECT RESETuzastopno. Takođe je greška izvršavati naredbu koja nije jedna od CONNECT TO, CONNECTbez operanada, CONNECT RESET, SET CONNECTION, RELEASE, COMMIT ili ROLLBACK, a zatimizvršiti naredbu CONNECT TO. Da bi se izbegla ova greška, potrebno je izvršiti CONNECTRESET, DISCONNECT (kojem prethodi naredba COMMIT ili ROLLBACK), COMMIT ili ROLLBACKnaredbu pre izvršavanja CONNECT TO naredbe.

8.1.2 Semantika distribuirane jedinice posla pod upravljanjem aplikacije

Aplikacioni proces na računaru A može se povezati na aplikacioni server na računaruB izvršavanjem naredbi CONNECT ili SET CONNECTION. Aplikacioni proces može izvršavatiproizvoljan broj statičkih ili dinamičkih SQL naredbi koji referišu na objekte iz B, prezavršetka jedinice posla. Svi objekti na koje se referiše u okviru jedne SQL naredbemoraju biti upravljani od strane istog aplikacionog servera. Ipak, za razliku od RUW,proizvoljan broj aplikacionih servera može učestvovati u jednoj jedinici posla. Operacijapohranjivanja ili poništavanja izmena završava jedinicu posla.

ADDUW koristi konekciju tipa 2. Konekcija tipa 2 povezuje aplikacioni proces na identi-fikovani aplikacioni server i uspostavlja pravila za ADDUW. Za aplikacioni proces tipa 2važi sledeće:

• Uvek je poveziv.• Ili je u povezanom ili u nepovezanom stanju.• Ima nula ili više konekcija.

Svaka konekcija aplikacionog procesa se jedinstveno identifikuje alijasom baze podatakaaplikacionog servera za tu konekciju.

Individualna konekcija ima jedan od narednih stanja povezanosti:

• Važeći i držeći (engl. Current and held)• Važeći i do-daljnjeg-oslobođen (engl. Current and release-pending)• Uspavan i držeći (engl. Dormant and held)• Uspavan i do-daljnjeg-oslobođen (engl. Dormant and release-pending)

Aplikacioni proces tipa 2 je inicijalno u nepovezanom stanju i nema nijednu konekciju.Konekcija je inicijalno u stanju važeći i držeći.

Page 157: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.2 Opcije za definisanje semantike konekcije jedinice posla 157

Slika 8.3: Dijagram prelaska stanja aplikacionog procesa i konekcije u CONNECT (Type 2).

8.2 Opcije za definisanje semantike konekcije jedinice posla

Način na koji DB2 sistem odlučuje koji tip konekcije koristi, kao i podešavanja odabranogtipa konekcije, zavisi od određenog skupa pretprocesorskih podešavanja. Ova podešavanjasu:

• CONNECT (1 | 2) — Specifikuje da li se naredba CONNECT procesira kao tip 1 ili 2.Podrazumevana vrednost je 1.

• SQLRULES (DB2 | STD) — Specifikuje da li se naredba CONNECT (type 2) procesirapo pravilima DB2 sistema, koji dozvoljavaju naredbi CONNECT da prebaci konekcijuu stanje mirovanja, ili po standardu SQL92, koji ovo ne dozvoljava. Podrazumevanavrednost je DB2.

• DISCONNECT (EXPLICIT | CONDITIONAL | AUTOMATIC) — Specifikuje koje se konek-cije ka bazama podataka prekidaju prilikom izvršavanja operacije pohranjivanja iz-mena. Dozvoljene vrednosti su:

– EXPLICIT — Prekidaju se one koje su eksplicitno zadate u SQL naredbi RELEASE.– CONDITIONAL — Oslobađaju se one koje nemaju otvorene kursore deklarisane sa

klauzom WITH HOLD i one koje su označene za oslobađanje.– AUTOMATIC — Oslobađaju se sve konekcije.

Podrazumevana vrednost je EXPLICIT.• SYNCPOINT (ONEPHASE | TWOPHASE | NONE) — Specifikuje kako se izvršava koordina-

cija naredbi COMMIT i ROLLBACK između više konekcija ka bazama podataka. Dozvo-ljene vrednosti su:

Page 158: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

158 Glava 8. Povezivanje na više baza podataka

– ONEPHASE — Ažuriranja se mogu izvršiti samo nad jednom bazom podatakau jednoj jedinici posla. Sve ostale konekcije ka bazama podataka služe samoza čitanje podataka. Svaki pokušaj ažuriranja nad drugim bazama podatakaprijavljuje grešku sa SQLSTATE vrednošću 25000.

– TWOPHASE — Upravljač transakcijama se koristi u fazi izvršavanja da koordinišedvofazne operacije pohranjivanja izmena među onim bazama podataka kojepodržavaju ovaj protokol.

– NONE — Ne koristi se upravljač transakcijama da izvršava dvofazne operacijepohranjivanja i ne podstiče se pravilo ”jedno ažuriranje-više čitanja”. Kada seizvršava naredba COMMIT ili ROLLBACK, individualne naredbe COMMIT ili ROLLBACKse šalju svim bazama podataka. Ako se barem jedna naredba ROLLBACK izvršibez uspeha, podiže se greška (SQLSTATE 58005). Ako se barem jedna naredbaCOMMIT izvrši bez uspeha, podiže se druga greška (SQLSTATE 40003).

Podrazumevana vrednost je ONEPHASE.

Da bi se u fazi izvršavanja koristile drugačije vrednosti u odnosu na one postavljene ufazi pretprocesiranja, može se koristiti komanda SET CLIENT ili sqlesetc API. Da bi se do-hvatile informacije o trenutnim vrednostima ovih podešavanja, može se koristiti komandaQUERY CLIENT ili sqleqryc API. Primetimo da ovo nisu SQL naredbe, već API-ji definisaniu matičnim jezicima i DB2 procesoru komandne linije. U sekciji 8.4 biće opisani API-jisqlesetc i sqleqryc.

8.3 Naredbe za upravljanje konekcijama na baze podataka

Kako postoje različiti načini za ostvarivanje konekcije na baze podataka, to je potrebnorazumeti dejstva različitih naredbi DB2 SUBP koje nam stoje na raspolaganju. U ovomdelu teksta ćemo se osvrnuti na naredbe CONNECT, SET CONNECTION i DISCONNECT i pogledatikako one utiču na stanja konekcije u aplikacionim procesima.

8.3.1 Naredba CONNECT

Kao što smo napomenuli, naredba CONNECT ima dva tipa. Koji će tip biti korišćen jeodređeno pretprocesorskom opcijom CONNECT(1 | 2). Ipak, u osnovi oba tipa stoji istiefekat, a to je ostvarivanje konekcije između aplikacionog procesa i njegovog servera.

Sintaksa naredbe je data u nastavku:CONNECT (

TO (server−name|host−variable) [authorization] |RESET

)

a sintaksa poddela authorization je data u nastavku:USER (authorization−name|host−variable)USING (password|host−variable)

Efekat ove naredbe je određen klauzama koje se koriste:

• TO server−name ili host−variable — Idenfifikuje aplikacioni server na osnovu njego-vog alijasa zadatog kao server−name ili imena koje je smešteno u matičnu promenljivuhost−variable.Ako je naredba CONNECT uspešno izvršena:

Page 159: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.3 Naredbe za upravljanje konekcijama na baze podataka 159

– Postavlja se vrednost specijalnog registra CURRENT SERVER na server ka kome jeuspostavljena konekcija.

• RESET — Diskonektuje aplikacioni proces od tekućeg servera. Operacija pohranjiva-nja se izvršava.

• USER authorization−name/host−variable — Identifikuje korisničko ime kojim se us-postavlja konekcija na aplikacioni server.

• USING password/host−variable — Identifikuje lozinku za zadato korisničko ime.

U nastavku su date specifičnosti ove naredbe za svaki tip.

CONNECT (Type 1)

Efekat ove naredbe je određen klauzama koje se koriste:

• TO server−name ili host−variable:Prilikom izvršavanja CONNECT naredbe, aplikacija mora biti u povezivom stanju.Ako je naredba CONNECT uspešno izvršena:

– Svi otvoreni kursori se zatvaraju, sve pripremljene naredbe se uništavaju i svikatanci se oslobađaju od prethodnog aplikacionog servera.

– Aplikacioni proces raskida konekciju sa prethodnim aplikacionim serverom, akoje takva konekcija postojala, i konektuje se na identifikovan server.

Ako je naredba CONNECT neuspešno izvršena:– Ako aplikacioni proces nije bio u povezivom stanju, stanje konekcije ostaje

nepromenjeno.– Ako se alijas server−name ne nalazi u lokalnom direktorijumu, dolazi do greške

(SQLSTATE 08001) i pritom:∗ Ako aplikacioni zahtevač nije bio povezan na aplikacioni server, aplikacioniproces ostaje nepovezan.

∗ Ako je aplikacioni zahtevač već bio povezan na aplikacioni server, aplikaci-oni proces ostaje povezan na taj server. Sve naredne naredbe se izvršavajunad tim serverom.

– Ako je neuspeh bio iz bilo kog drugog razloga, aplikacioni proces se stavlja unepovezano stanje.

CONNECT (Type 2)

Efekat ove naredbe je određen klauzama koje se koriste:

• TO server−name ili host−variable:Ako je opcija SQLRULES(STD) aktivirana, onda server−name ne sme identifikovatipostojeću konekciju aplikacionog procesa. U suprotnom, podiže se greška (SQLSTATE08002).

Ako je opcija SQLRULES(DB2) aktivirana i server−name identifikuje postojeću konek-ciju aplikacionog procesa, ta konekcija se postavlja za važeću i prethodna konekcijase postavlja na stanje mirovanja. U ovom slučaju, efekat izvršavanja CONNECT na-redbe je ekvivalentan izvršavanju naredbe SET CONNECTION.Ako je naredba CONNECT uspešno izvršena:

– Konekcija ka aplikacionom serveru je bilo kreirana bilo prebačena iz stanjamirovanja, i postavljena u stanje važeći i držeći.

– Ako je CONNECT usmerena ka drugom serveru u odnosu na onaj koji je trenutnopostavljen, onda se trenutna konekcija postavlja u stanje mirovanja.

Ako je naredba CONNECT neuspešno izvršena:

Page 160: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

160 Glava 8. Povezivanje na više baza podataka

– Bez obzira na razlog neuspeha, povezivo stanje aplikacije i njenih stanja konek-cija ostaju nepromenjeni.

8.3.2 Naredba SET CONNECTION

Naredba SET CONNECTION menja stanje konekcije iz stanja mirovanja u važeći. Time jepostavlja aplikacioni server nad kojim se izvršavaju SQL naredbe.

Sintaksa ove naredbe je data u nastavku:SET CONNECTION (server−name|host−variable)

Slično kao i naredba CONNECT, ova naredba idenfifikuje aplikacioni server na osnovu nje-govog alijasa zadatog kao server−name ili imena koje je smešteno u matičnu promenljivuhost−variable. Dodatno, vrednost koja se koristi mora identifikovati postojeću konekcijuaplikacionog procesa. U suprotnom, podiže se greška (SQLSTATE 08003). Ukoliko se SETCONNECTION koristi da podesi konekciju koja je već važeća, onda sva stanja aplikacionogprocesa ostaju nepromenjena.

Ukoliko je naredba SET CONNECTION izvršena uspešno:

• Ne kreira se nova konekcija. Postavlja se vrednost specijalnog registra CURRENTSERVER na server ka kome je uspostavljena konekcija.

• Ukoliko postoji konekcija ka serveru i u naredbi SET CONNECTION je specifikovan alijasdrugog servera, onda se ta konekcija postavlja u stanje mirovanja.

Ako je naredba SET CONNECTION neuspešno izvršena:

• Bez obzira na razlog neuspeha, povezivo stanje aplikacije i njenih stanja konekcijaostaju nepromenjeni.

Treba imati u vidu naredba pravila i savete:

• Korišćenje CONNECT naredbe tipa 1 ne podrazumeva korišćenje SET CONNECTION na-redbe, te će u tom slučaju izvršavanje ove naredbe uvek podići grešku (SQLSTATE08003).

• U slučaju postavljanja opcije SQLRULES(DB2), nije neophodno koristiti ovu naredbuzato što se umesto nje može koristiti naredba CONNECT (Type 2), ali je, naravno,njeno korišćenje moguće.

• Kada se neka konekcija koristi, nakon toga se uspava, a zatim se ponovo postaviza važeću u okviru iste jedinice posla, status svih katanaca, kursora i pripremljenihnaredbi ostaje onakav kakav je bio pre uspavljivanja konekcije.

8.3.3 Naredba DISCONNECT

Naredba DISCONNECT služi za uništavanje jedne konekcije ili više njih kada nema aktivne je-dinice posla (odnosno, nakon izvršavanja operacije pohranjivanja ili poništavanja izmena).

Ako je samo jedna konekcija cilj naredbe DISCONNECT, onda se ta konekcija uništava samoukoliko je baza podataka učestvovala u jedinici posla koja prethodni naredbi, bez obzirada li postoji aktivna jedinica posla. Na primer, ako su izvršene operacije nad nekolikodrugih baza podataka, ali cilj naredbe nije, onda se i dalje može izvršiti diskonekcija odcilja bez uništavanja konekcije.

Sintaksa ove naredbe je data u nastavku:

Page 161: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.4 DB2 API za podešavanje konekcije 161

DISCONNECT (server−name |host−variable |CURRENT |ALL [SQL]

)

Ukoliko se specifikuje server−name ili host−variable, onda se tim vrednostima identifikujealijas aplikacionog servera kao cilj naredbe. Specifikovani alijas mora identifikovati posto-jeću konekciju u aplikacionom procesu. U suprotnom, podiže se greška (SQLSTATE 08003).

Navođenjem klauze CURRENT se identifikuje važeća konekcija aplikacionog procesa kao ciljnaredbe. Aplikacioni proces mora biti u povezanom stanju. U suprotnom, podiže se greška(SQLSTATE 08003).

Navođenjem klauze ALL se identifikuju sve postojeće konekcije aplikacionog procesa zauništavanje. Ne dolazi do greške ukoliko aplikacioni proces ne sadrži nijednu postojećukonekciju prilikom izvršenja naredbe.

Neke napomene i pravila koja treba imati u vidu prilikom korišćenja ove naredbe su:

• Uopšteno, naredbu DISCONNECT nije moguće uspešno izvršiti u okviru jedinice posla.Pokušaj ovakve akcije podiže grešku (SQLSTATE 25000). Izuzetak od ovog pravilajeste ako je specifikuje jedna konekcija kao cilj naredbe, pri čemu ta baza podatakanije učestvovala u postojećoj jedinici posla.

• Ako je ova naredba iskorišćenja za prekidanje važeće konekcije, onda bi naredna SQLnaredba koja se izvršava trebalo da bude CONNECT ili SET CONNECTION.

• S obzirom da održavanje konekcije ka serveru zahteva resurse, praktičan savet je dase oslobode sve konekcije čim nam nisu neophodne.

8.4 DB2 API za podešavanje konekcije

U sekciji 8.2 smo diskutovali o različitim opcijama pretprocesora za definisanje semantikekonekcije. Iako je ova podešavanja moguće definisati u fazi pretprocesiranja, nekada nammože biti korisno da izmenimo podešavanja programerski. DB2 API nam kroz zaglavljesqlenv.h nudi odgovarajuće strukture podataka i funkcije za ovu akciju, sa kojima ćemose upoznati u ovoj sekciji, a one su:

• Struktura sqle_conn_setting (engl. SQL environment connection setting)• Funkcija sqleqryc (engl. SQL environment query connection)• Funkcija sqlesetc (engl. SQL environment set connection)

Struktura sqle_conn_setting se koristi za specifikovanje podešavanja konekcije za APIfunkcija sqleqryc i sqlesetc. Sama struktura je veoma jednostavna — sastoji se od svegadva polja:

• type– Tip: SMALLINT (unsigned short)– Opis: Tip podešavanja koji se postavlja/dohvata.

• value– Tip: SMALLINT (unsigned short)– Opis: Vrednost podešavanja koji se postavlja/dohvata.

Page 162: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

162 Glava 8. Povezivanje na više baza podataka

Tabela 8.1 izlistava odgovarajuće vrednosti za polje TYPE, kao i moguće vrednosti za poljeVALUE, za svaki tip zasebno.

Tabela 8.1: Vrednosti koji se koriste za podešavanje konekcijeTip Vrednost Opis

SQL_CONNECT_TYPESQL_CONNECT_1SQL_CONNECT_2

Tip konekcije koji se koristi zaizvršavanje naredbe CONNECT.

SQL_RULESSQL_RULES_DB2SQL_RULES_STD

Omogućavanje da se naredba CONNECTkoristi za uspavljivanje konekcije ilida se zahteva izvršavanje naredbe SETCONNECTION.

SQL_DISCONNECTSQL_DISCONNECT_EXPLSQL_DISCONNECT_CONDSQL_DISCONNECT_AUTO

Definisanje skupa konekcija koje ćebiti uklonjene naredbom DISCONNECT.

SQL_SYNCPOINTSQL_SYNC_TWOPHASESQL_SYNC_ONEPHASESQL_SYNC_NONE

Način koordinisanja operacijapohranjivanja među više bazapodataka.

Funkcija sqleqryc služi za dohvatanje važećih informacija o konekciji aplikacionog procesa.Prilikom pozivanje funkcije, odgovarajuća struktura sqle_conn_setting biće popunjenavrednostima koje se dohvate. Parametri ove funkcije i njihovo značenje su dati u nastavku:

• struct sqle_conn_setting ∗ pConnectionSettings — Pokazivač na strukturusqle_conn_setting koja specifikuje parove tipova i vrednosti podešavanja konekcije.Korisnik definiše niz koji sadrži NumSettings struktura i funkcija popunjava važećevrednosti za svaku strukturu na osnovu vrednosti polja TYPE koji je specifikovan usvakoj strukturi.

• unsigned short NumSettings—Ceo broj u opsegu [0,7] koji označava broj strukturau prosleđenom nizu.

• struct sqlca ∗ pSqlca — Pokazivač na sqlca strukturu.

Funkcija sqlesetc služi za postavljanje novih podešavanja o konekciji aplikacionog pro-cesa. Prilikom pozivanje funkcije, koristi se odgovarajuća struktura sqle_conn_settingpopunjena vrednostima koje će biti postavljene. Parametri ove funkcije i njihovo značenjesu dati u nastavku:

• struct sqle_conn_setting ∗ pConnectionSettings — Pokazivač na strukturusqle_conn_setting koja specifikuje parove tipova i vrednosti podešavanja konekcije.Korisnik alocira prostor za niz koji sadrži NumSettings struktura. Za svaku strukturuse popunjavaju polja TYPE i VALUE. Funkcija koristi vrednosti iz svake strukture ipostavlja odgovarajuće podešavanje (TYPE) na odgovarajuću vrednost (VALUE).

• unsigned short NumSettings—Ceo broj u opsegu [0,7] koji označava broj strukturau prosleđenom nizu.

• struct sqlca ∗ pSqlca — Pokazivač na sqlca strukturu.

Page 163: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 163

8.5 Šabloni za rad, primeri i implementacione napomene

Prilikom instalacije DB2 SUBP, dostupni su nam šabloni koji, pored toga što nam mogukoristiti za učenje, tako nam mogu služiti i kao početne tačke za razvoj naših aplikacija.Ovi šabloni se mogu pronaći na lokaciji /opt/ibm/DB2/v10.5/samples/c.

Među ovim šablonima nalazi se i šablon za konekciju na više baza podataka — konkretnije,na dve baze podataka. Kod za povezivanje na dve baze je ogranizovan u nekoliko datotekakoje su, zajedno sa njihovom povezanošću, prikazani na slici 8.4.

Slika 8.4: Arhitektura koda za aplikaciju koja koristi dve baze podataka, kreirana naosnovu šablona dostupnih od strane DB2 SUBP.

Naravno, potrebno je izvršiti određena prilagođavanja ovog šablona. Mi ćemo izvršitinaredne promene, pre implementacije funkcija koje rade sa bazama podataka:

• Iz svih datoteka ćemo obrisati početne komentare.• Iz datoteka dbmcon.sqc, dbmcon1.sqc i dbmcon2.sqc ćemo obrisati pretprocesorsku

direktivu#include "utilemb.h"

• U datotekama dbmcon1.h/dbmcon1.sqc i dbmcon2.h/dbmcon2.sqc izmeniti deklaraci-je/definicije funkcija da odgovaraju našim potrebama.

• U datoteci dbmcon.sqc odabrati jednu od funkcija sa imenom TwoDBConnectType∗,u zavisnosti od tipa konekcije koju želimo da ostvarimo. Drugu funkciju možemoobrisati. Primetimo da ovaj šablon ne sadrži deklaraciju/definiciju za tip konekcije2 sa dvofaznim protokolom pohranjivanja izmena.

Page 164: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

164 Glava 8. Povezivanje na više baza podataka

• U datoteci dbmcon.sqc, u odabranoj funkciji TwoDBConnectType∗ ispraviti pozive kafunkcijama deklarisanim/definisanim u drugim datotekama.

• U datoteci dbmcon.sqc, u funkciji main obrisati poziv funkcije CmdLineArgsCheck4.U istoj funkciji postaviti korisničko ime i lozinku na osnovu argumenata komandnelinije (pogledati izmenu skripta za prevođenje u nastavku teksta za više informacija).

• U datoteci dbmcon.sqc, potrebno je definisati funkciju za proveru greške is_errorkoju smo koristili do sada. U ovom slučaju, može nam značiti informacija u kojojdatoteci i u kojoj liniji je došlo do greške, te ćemo promeniti definiciju ove funkcijeu narednu:extern void is_error(char ∗errString, char ∗fileName, int lineNum){

if (sqlca.sqlcode < 0){

printf("U fajlu %s u liniji %d\n""Greska %d: %d\n"fileName, lineNum,sqlca.sqlcode, errString);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

Primetimo da smo stavili ključnu reč extern ispred definicije funkcije. Ovo namomogućuje da funkcija bude vidljiva u drugim objektnim fajlovima prilikom faze lin-kovanja. Dodatno, u datotekama dbmcon1.sqc i dbmcon2.sqc dodajemo deklaracijuove funkcije:extern void is_error(char ∗errString, char ∗fileName, int lineNum);

• U datotekama dbmcon.sqc, dbmcon1.sqc i dbmcon2.sqc definisaćemo naredni makrokoji ćemo koristiti umesto poziva funkcije is_error:#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

Potrebno je ovaj makro definisati nakon deklaracije/definicije funkcije is_error uodgovarajućim datotekama.

Pošto sada rukujemo sa više od jedne datoteke, prirodno je zaključiti da se naš skript zaprevođenje razlikuje od onog kojeg smo koristiti do sada. Ipak, sam proces prevođenjakoji smo detaljno opisivali na početku ostaje isti, tako da ćemo samo prikazati novi skriptkoji koristimo, bez ulaženja u detalje. Ono što je vredno napomenuti jeste da smo krei-rali pomoćni skript embprep koji vrši kreiranje i ugrađivanje paketa na osnovu jedne sqcdatoteke.

Kod 8.1: Primeri/cas07/embprep.shdb2 connect to $2 user $3 using $4

db2 prep $1.sqc bindfile

db2 bind $1.bnddb2 connect reset

Page 165: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 165

Kod 8.2: Primeri/cas07/prevodjenje.sh#!/bin/sh

DB2PATH=/opt/ibm/db2/V10.5EXTRA_LFLAG="−Wl,−rpath,$DB2PATH/lib32"

./embprep.sh $1 $4 $6 $7

./embprep.sh $2 $4 $6 $7

./embprep.sh $3 $5 $6 $7

cc −I$DB2PATH/include −c $1.c $2.c $3.c

cc −o $1 $1.o $2.o $3.o $EXTRA_LFLAG −L$DB2PATH/lib32 −ldb2

Sam proces prevođenja se vrši pozivanjem skripta prevodjenje sa narednim argumentima(svi argumenti su obavezni):

1. Naziv glavne datoteke za povezivanje na više baza.2. Naziv datoteke sa definicijama funkcija za prvu bazu.3. Naziv datoteke sa definicijama funkcija za drugu bazu.4. Naziv prve baze podataka5. Naziv druge baze podataka6. Korisničko ime7. Lozinka

Na primer, za prevođenje primera koji slede u nastavku koristićemo narednu komandu:./prevodjenje dbmcon dbmcon1 dbmcon2 vstud mstud student abcdef

U ovom slučaju (među drugim datotekama) generiše se izvršna datoteka dbmcon. Napo-menimo da se u narednim primerima očekuje da datoteka bude pokrenuta sa narednimargumentima komandne linije:

1. Naziv prve baze podataka2. Naziv druge baze podataka3. Korisničko ime4. Lozinka

Na primer, za pokretanje primera koji slede u nastavku koristićemo narednu komandu:./dbmcon vstud mstud student abcdef

Primer 8.1 — Čas 07 — 01. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji omogućava konekciju na 2 baze (mstud i vstud).

Program redom:

• U bazi vstud pravi tabelu irok_stat koja sadrži naredne kolone: godinu roka,oznaku roka i prolaznost.

• U bazi mstud pravi tabelu pred_stat koja sadrži naredne kolone: identifikatorpredmeta i prosek.

• Iz baze vstud obrisati tabelu irok_stat.• Iz baze mstud obrisati tabelu pred_stat.• Iz baze mstud izlistati sadržaj tabele dosije.

Koristiti konekciju tipa 1 za ostvarivanje konekcije na dve baze.

Page 166: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

166 Glava 8. Povezivanje na više baza podataka

Rešenje.

Kod 8.3: Primeri/cas07/primer1/dbmcon.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon1.h"#include "dbmcon2.h"

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char dbAlias1[15];char dbAlias2[15];char user1[129];char pswd1[15];EXEC SQL END DECLARE SECTION;

void TwoDbConnectType1(void);

extern void is_error(char ∗errString, char ∗fileName, int lineNum){

if(sqlca.sqlcode < 0){

printf("U fajlu %s u liniji %d\n""Greska %d: %s\n",fileName, lineNum,sqlca.sqlcode, errString);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

int main(int argc, char ∗∗argv){

// Pokretanje programa:// ./dmbcon vstud mstud student abcdef

if(argc != 5){

printf(" Pokretanje programa: \n\t\t ./dmbcon vstud mstud studentabcdef\n\n");

exit(EXIT_FAILURE);}

strcpy(dbAlias1, argv[1]);strcpy(dbAlias2, argv[2]);strcpy(user1, argv[3]);strcpy(pswd1, argv[4]);

TwoDbConnectType1();

return 0;}

void TwoDbConnectType1(void)

Page 167: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 167

{// Inicijalizujemo strukturu koja se koristi za// podesavanje opcija konekcijestruct sqle_conn_setting clientAppInfo[2];

clientAppInfo[0].type = SQL_CONNECT_TYPE;clientAppInfo[0].value = SQL_CONNECT_1;

clientAppInfo[1].type = SQL_DISCONNECT;clientAppInfo[1].value = SQL_DISCONNECT_EXPL;

// Pozivom naredne funkcije izvrsavamo podesavanje opcija konekcijesqlesetc(&clientAppInfo[0], 2, &sqlca);IS_ERROR_WITH_POSITION("Set client information");

printf("\n−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n");printf("USE TYPE1 CONNECT TO TWO DATABASES.\n");

// Rad sa bazamaprintf("\nConnect to %s\n", dbAlias1);

EXEC SQL CONNECT TO :dbAlias1 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − prva baza");

// Kreiranje tabele u prvoj baziFirstDbCreateTable();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − prva baza");

// Raskid konekcije sa prvom bazomprintf("CONNECT RESET\n");

EXEC SQL CONNECT RESET;IS_ERROR_WITH_POSITION("Connect reset − prva baza");

// Povezivanje sa drugom bazomprintf("\nConnect to %s\n", dbAlias2);

EXEC SQL CONNECT TO :dbAlias2 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − druga baza");

// Kreiranje tabele u drugoj baziSecondDbCreateTable();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − druga baza");

// Raskid konekcije sa drugom bazomprintf("CONNECT RESET\n");

EXEC SQL CONNECT RESET;IS_ERROR_WITH_POSITION("Connect reset − druga baza");

printf("\nConnect to %s\n", dbAlias1);

Page 168: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

168 Glava 8. Povezivanje na više baza podataka

EXEC SQL CONNECT TO :dbAlias1 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − prva baza");

// Uklanjanje prethodno kreirane tabele iz prve bazeFirstDbDropTable();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − prva baza");

printf("CONNECT RESET\n");

EXEC SQL CONNECT RESET;IS_ERROR_WITH_POSITION("Connection reset − prva baza");

printf("\nConnect to %s\n", dbAlias2);EXEC SQL CONNECT TO :dbAlias2 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − druga baza");

// Uklanjanje prethodno kreirane tabele iz druge bazeSecondDbDropTable();// Citanje podataka iz druge bazeSecondDbSelect();

printf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − druga baza");

printf("CONNECT RESET\n");

EXEC SQL CONNECT RESET;IS_ERROR_WITH_POSITION("Connect reset − druga baza");

}

Kod 8.4: Primeri/cas07/primer1/dbmcon1.h#ifndef DBMCON1_H#define DBMCON1_H

void FirstDbCreateTable(void);void FirstDbDropTable(void);

#endif /∗ DBMCON1_H ∗/

Kod 8.5: Primeri/cas07/primer1/dbmcon1.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon1.h"

EXEC SQL INCLUDE SQLCA;

extern void is_error(char ∗errString, char ∗fileName, int lineNum);

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

Page 169: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 169

void FirstDbCreateTable(void){

printf("CREATE TABLE irok_stat(\n"

"godina SMALLINT NOT NULL,\n""oznaka VARCHAR(20),\n""prolaznost float\n"

")\n");

EXEC SQL CREATE TABLE irok_stat(godina SMALLINT NOT NULL,oznaka VARCHAR(20),prolaznost float);

IS_ERROR_WITH_POSITION("Create table");}

void FirstDbDropTable(void){

printf("DROP TABLE irok_stat\n");

EXEC SQL DROP TABLE irok_stat;IS_ERROR_WITH_POSITION("Drop table");

}

Kod 8.6: Primeri/cas07/primer1/dbmcon2.h#ifndef DBMCON2_H#define DBMCON2_H

void SecondDbCreateTable(void);void SecondDbDropTable(void);void SecondDbSelect(void);

#endif /∗ DBMCON2_H ∗/

Kod 8.7: Primeri/cas07/primer1/dbmcon2.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon1.h"

EXEC SQL INCLUDE SQLCA;

extern void is_error(char ∗errString, char ∗fileName, int lineNum);

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

EXEC SQL BEGIN DECLARE SECTION;sqlint32 indeks;char ime[21];char prezime[26];char datum_rodjenja[11];short ind_datum_rodjenja;char mesto_rodjenja[101];short ind_mesto_rodj;EXEC SQL END DECLARE SECTION;

void SecondDbCreateTable(void)

Page 170: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

170 Glava 8. Povezivanje na više baza podataka

{printf(

"CREATE TABLE pred_stat(\n""id_predmeta INTEGER NOT NULL,\n""prosek FLOAT\n"

")\n");

EXEC SQL CREATE TABLE pred_stat(id_predmeta INTEGER NOT NULL,prosek FLOAT);

IS_ERROR_WITH_POSITION("Create table pred_stat");}

void SecondDbDropTable(void){

printf("DROP TABLE pred_stat\n");

EXEC SQL DROP TABLE pred_stat;IS_ERROR_WITH_POSITION("Drop table");

}

void SecondDbSelect(void){

printf("SELECT FROM dosije\n");

EXEC SQL DECLARE dcur CURSOR FORselect indeks, ime, prezime, datum_rodjenja, mesto_rodjenjafrom dosije;

IS_ERROR_WITH_POSITION("Declare cursor dcur");

EXEC SQL OPEN dcur;IS_ERROR_WITH_POSITION("Open dcur");

printf("INDEKS IME PREZIME DATUM_RODJENJAMEST0_RODJENJA\n");

printf("====================================================================\n");

for(;;){

EXEC SQL FETCH dcurINTO :indeks, :ime, :prezime,

:datum_rodjenja:ind_datum_rodjenja,:mesto_rodjenja:ind_mesto_rodj;

IS_ERROR_WITH_POSITION("Fetch dcur");

if(SQLCODE == 100){

break;}

printf("%−10d %−10s %−15s %−15s %−15s\n", indeks, ime, prezime,(ind_datum_rodjenja < 0 ? "NULL" : datum_rodjenja),(ind_mesto_rodj < 0 ? "NULL" : mesto_rodjenja));

}

EXEC SQL CLOSE dcur;IS_ERROR_WITH_POSITION("Close dcur");

}

Page 171: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 171

Primer 8.2 — Čas 07 — 02. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji omogućava konekciju na 2 baze (mstud i vstud).

Program redom:

• U bazi vstud pravi tabelu irok_stat koja sadrži naredne kolone: godinu roka,oznaku roka i prolaznost.

• Iz baze mstud izlistati sadržaj tabele dosije.• U bazi mstud pravi tabelu pred_stat koja sadrži naredne kolone: identifikator

predmeta i prosek.• Iz baze vstud obrisati tabelu irok_stat.• Iz baze mstud obrisati tabelu pred_stat.• Iz baze mstud izlistati sadržaj tabele dosije.

Koristiti konekciju tipa 2 sa jednofaznim pohranjivanjem za ostvarivanje konekcije nadve baze.

Rešenje.

Kod 8.8: Primeri/cas07/primer2/dbmcon.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon1.h"#include "dbmcon2.h"

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char dbAlias1[15];char dbAlias2[15];char user1[129];char pswd1[15];EXEC SQL END DECLARE SECTION;

void TwoDbConnectType2OnePhaseCommit(void);

extern void is_error(char ∗errString, char ∗fileName, int lineNum){

if(sqlca.sqlcode < 0){

printf("U fajlu %s u liniji %d\n""Greska %d: %s\n",fileName, lineNum,sqlca.sqlcode, errString);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

int main(int argc, char ∗∗argv){

// Pokretanje programa:// ./dmbcon vstud mstud student abcdef

Page 172: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

172 Glava 8. Povezivanje na više baza podataka

if(argc != 5){

printf(" Pokretanje programa: \n\t\t ./dmbcon vstud mstud studentabcdef\n\n");

exit(EXIT_FAILURE);}

strcpy(dbAlias1, argv[1]);strcpy(dbAlias2, argv[2]);strcpy(user1, argv[3]);strcpy(pswd1, argv[4]);

TwoDbConnectType2OnePhaseCommit();

return 0;}

void TwoDbConnectType2OnePhaseCommit(void){

struct sqle_conn_setting clientAppInfo[3];

clientAppInfo[0].type = SQL_CONNECT_TYPE;clientAppInfo[0].value = SQL_CONNECT_2;

clientAppInfo[1].type = SQL_DISCONNECT;clientAppInfo[1].value = SQL_DISCONNECT_EXPL;

clientAppInfo[2].type = SQL_SYNCPOINT;clientAppInfo[2].value = SQL_SYNC_ONEPHASE;

sqlesetc(&clientAppInfo[0], 3, &sqlca);IS_ERROR_WITH_POSITION("Client Connection Attributes −− set");

printf("\n−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n");printf("USE TYPE2 CONNECT TO TWO DATABASES − ONE PHASE COMMIT.\n");

// Na pocetku se konektujemo na obe baze// i drzimo obe konekcije.printf("\nConnect to %s\n", dbAlias1);

EXEC SQL CONNECT TO :dbAlias1 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − prva baza");

printf("\nConnect to %s\n", dbAlias2);

EXEC SQL CONNECT TO :dbAlias2 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − druga baza");

// U zavisnosti od toga nad kojom bazom zelimo da vrsimo operacije// postavljamo konekciju naredbom SET CONNECTION// Ovde imamo ogranicenje da ne mozemo imati dve operacije menjanja// nad dve baze podataka u istoj transakciji.// Ali mozemo imati menjanje i citanje podataka.printf("\nSET CONNECTION %s\n", dbAlias1);

EXEC SQL SET CONNECTION :dbAlias1;IS_ERROR_WITH_POSITION("Set connection − prva baza");

FirstDbCreateTable();

printf("\nSET CONNECTION %s\n", dbAlias2);

Page 173: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 173

EXEC SQL SET CONNECTION :dbAlias2;IS_ERROR_WITH_POSITION("Set connection − druga baza");

SecondDbSelect();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − obe baze");

printf("\nSET CONNECTION %s\n", dbAlias2);

EXEC SQL SET CONNECTION :dbAlias2;IS_ERROR_WITH_POSITION("Set connection − druga baza");

SecondDbCreateTable();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − druga baza");

printf("\nSET CONNECTION %s\n", dbAlias1);

EXEC SQL SET CONNECTION :dbAlias1;IS_ERROR_WITH_POSITION("Set connection − prva baza");

FirstDbDropTable();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − prva baza");

printf("\nSET CONNECTION %s\n", dbAlias2);

EXEC SQL SET CONNECTION :dbAlias2;IS_ERROR_WITH_POSITION("Set connection − druga baza");

SecondDbDropTable();SecondDbSelect();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit − druga baza");

printf("\nDISCONNECT ALL\n");

EXEC SQL DISCONNECT ALL;IS_ERROR_WITH_POSITION("All connections −− disconnect");

}

Datoteke dbmcon1.h, dbmcon1.sqc, dbmcon2.h i dbmcon2.sqc su identične kao i one u pri-meru 8.1.

Page 174: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

174 Glava 8. Povezivanje na više baza podataka

Primer 8.3 — Čas 07 — 03. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji omogućava konekciju na 2 baze (mstud i vstud).

Program redom:

• U bazi vstud pravi tabelu irok_stat koja sadrži naredne kolone: godinu roka,oznaku roka i prolaznost.

• U bazi mstud pravi tabelu pred_stat koja sadrži naredne kolone: identifikatorpredmeta i prosek.

• Iz baze vstud obrisati tabelu irok_stat.• Iz baze mstud obrisati tabelu pred_stat.• Iz baze mstud izlistati sadržaj tabele dosije.

Koristiti konekciju tipa 2 sa dvofaznim pohranjivanjem za ostvarivanje konekcije na dvebaze.

Rešenje.

Kod 8.9: Primeri/cas07/primer3/dbmcon.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon1.h"#include "dbmcon2.h"

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char dbAlias1[15];char dbAlias2[15];char user1[129];char pswd1[15];EXEC SQL END DECLARE SECTION;

void TwoDbConnectType2TwoPhaseCommit(void);

extern void is_error(char ∗errString, char ∗fileName, int lineNum){

if(sqlca.sqlcode < 0){

printf("U fajlu %s u liniji %d\n""Greska %d: %s\n",fileName, lineNum,sqlca.sqlcode, errString);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

int main(int argc, char ∗∗argv){

// Pokretanje programa:// ./dmbcon vstud mstud student abcdefif(argc != 5)

Page 175: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 175

{printf(" Pokretanje programa: \n\t\t ./dmbcon vstud mstud student

abcdef\n\n");exit(EXIT_FAILURE);

}

strcpy(dbAlias1, argv[1]);strcpy(dbAlias2, argv[2]);strcpy(user1, argv[3]);strcpy(pswd1, argv[4]);

TwoDbConnectType2TwoPhaseCommit();

return 0;}

void TwoDbConnectType2TwoPhaseCommit(void){

struct sqle_conn_setting clientAppInfo[3];

clientAppInfo[0].type = SQL_CONNECT_TYPE;clientAppInfo[0].value = SQL_CONNECT_2;

clientAppInfo[1].type = SQL_DISCONNECT;clientAppInfo[1].value = SQL_DISCONNECT_EXPL;

clientAppInfo[2].type = SQL_SYNCPOINT;clientAppInfo[2].value = SQL_SYNC_TWOPHASE;

sqlesetc(&clientAppInfo[0], 3, &sqlca);IS_ERROR_WITH_POSITION("Set client information");

printf("\n−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n");printf("USE TYPE2 CONNECT TO TWO DATABASES − TWO PHASE COMMIT.\n");

// Rad sa bazama// Ovde mozemo imati u istom kontekstu bilo koje operacije// nad bilo kojim brojem baza podataka.printf("\nConnect to %s\n", dbAlias1);

EXEC SQL CONNECT TO :dbAlias1 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Coneect − prva baza");

FirstDbCreateTable();

printf("\nConnect to %s\n", dbAlias2);

EXEC SQL CONNECT TO :dbAlias2 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − druga baza");

SecondDbCreateTable();

printf("\nSET CONNECTION %s\n", dbAlias1);

EXEC SQL SET CONNECTION :dbAlias1;IS_ERROR_WITH_POSITION("Set connection − prva baza");

FirstDbDropTable();

printf("\nSET CONNECTION %s\n", dbAlias2);

Page 176: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

176 Glava 8. Povezivanje na više baza podataka

EXEC SQL SET CONNECTION :dbAlias2;IS_ERROR_WITH_POSITION("Set connection − druga baza");

SecondDbDropTable();SecondDbSelect();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit transakcije");

printf("\nDISCONNECT ALL\n");

EXEC SQL DISCONNECT ALL;IS_ERROR_WITH_POSITION("all connections −− disconnect");

}

Datoteke dbmcon1.h, dbmcon1.sqc, dbmcon2.h i dbmcon2.sqc su identične kao i one u pri-meru 8.1.

Primer 8.4 — Čas 07 — 04. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji omogućava konekciju na 2 baze (mstud i vstud).

Program redom:

• U bazi vstud broj bodova se uvećava za 1 predmetima koji su obavezni na smeru”Informatika” (koristiti podatak da je za ovaj smer identifikator 201).

• U bazi mstud se unose podaci u tabelu dosije o studentu Stefanu Laziću, čiji jedatum upisa 01.09.2012. i dodeliti mu broj indeksa 20120001.

• Iz baze vstud islistati predmete koji su obavezni na smeru ”Informatika”.• Iz baze mstud izlistati sve studente.• Iz baze mstud obrisati unetog studenta.

Rešenje.

Kod 8.10: Primeri/cas07/primer4/dbmcon.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon1.h"#include "dbmcon2.h"

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;char dbAlias1[15];char dbAlias2[15];char user1[129];char pswd1[15];EXEC SQL END DECLARE SECTION;

void TwoDbConnectType2TwoPhaseCommit(void);

extern void is_error(char ∗errString, char ∗fileName, int lineNum){

if(sqlca.sqlcode < 0)

Page 177: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 177

{printf("U fajlu %s u liniji %d\n"

"Greska %d: %s\n",fileName, lineNum,sqlca.sqlcode, errString);

EXEC SQL ROLLBACK;exit(EXIT_FAILURE);

}}

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

int main(int argc, char ∗∗argv){

// Pokretanje programa:// ./dmbcon vstud mstud student abcdefstrcpy(dbAlias1, argv[1]);strcpy(dbAlias2, argv[2]);strcpy(user1, argv[3]);strcpy(pswd1, argv[4]);

TwoDbConnectType2TwoPhaseCommit();

return 0;}

void TwoDbConnectType2TwoPhaseCommit(void){

struct sqle_conn_setting clientAppInfo[3];

clientAppInfo[0].type = SQL_CONNECT_TYPE;clientAppInfo[0].value = SQL_CONNECT_2;

clientAppInfo[1].type = SQL_DISCONNECT;clientAppInfo[1].value = SQL_DISCONNECT_EXPL;

clientAppInfo[2].type = SQL_SYNCPOINT;clientAppInfo[2].value = SQL_SYNC_TWOPHASE;

sqlesetc(&clientAppInfo[0], 3, &sqlca);IS_ERROR_WITH_POSITION("Set client information");

printf("\n−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n");printf("USE TYPE2 CONNECT TO TWO DATABASES − TWO PHASE COMMIT.\n");

// Rad sa bazamaprintf("\nConnect to %s\n", dbAlias1);

EXEC SQL CONNECT TO :dbAlias1 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Coneect − prva baza");

FirstDbUpdate();

printf("\nConnect to %s\n", dbAlias2);

EXEC SQL CONNECT TO :dbAlias2 USER :user1 USING :pswd1;IS_ERROR_WITH_POSITION("Connect − druga baza");

SecondDbInsert();

Page 178: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

178 Glava 8. Povezivanje na više baza podataka

printf("\nSET CONNECTION %s\n", dbAlias1);

EXEC SQL SET CONNECTION :dbAlias1;IS_ERROR_WITH_POSITION("Set connection − prva baza");

FirstDbSelect();

printf("\nSET CONNECTION %s\n", dbAlias2);

EXEC SQL SET CONNECTION :dbAlias2;IS_ERROR_WITH_POSITION("Set connection − druga baza");

SecondDbSelect();SecondDbDelete();

// Potvrdjivanje izmenaprintf("COMMIT\n");

EXEC SQL COMMIT;IS_ERROR_WITH_POSITION("Commit transakcije");

printf("\nDISCONNECT ALL\n");

EXEC SQL DISCONNECT ALL;IS_ERROR_WITH_POSITION("All connections −− disconnect");

}

Kod 8.11: Primeri/cas07/primer4/dbmcon1.h#ifndef DBMCON1_H#define DBMCON1_H

void FirstDbUpdate(void);void FirstDbSelect(void);

#endif /∗ DBMCON1_H ∗/

Kod 8.12: Primeri/cas07/primer4/dbmcon1.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon1.h"

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;EXEC SQL INCLUDE predmet;EXEC SQL END DECLARE SECTION;

extern void is_error(char ∗errString, char ∗fileName, int lineNum);

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

void FirstDbUpdate(void){

printf("UPDATE predmet\n""SET bodovi = 6\n""WHERE id_predmeta in (\n"

Page 179: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 179

"\tselect id_predmeta\n""\tfrom obavezan_predmet\n""\twhere id_smera = 201\n"

")\n");

EXEC SQL UPDATE predmetSET bodovi = 6WHERE id_predmeta in (

select id_predmetafrom obavezan_predmetwhere id_smera = 201

);IS_ERROR_WITH_POSITION("Update table predmet");

}

void FirstDbSelect(void){

printf("SELECT FROM predmet...\n");

EXEC SQL DECLARE pcur CURSOR FORSELECT ∗FROM predmetWHERE id_predmeta in (

SELECT id_predmetaFROM obavezan_predmetWHERE id_smera = 201

);IS_ERROR_WITH_POSITION("Declare cursor pcur");

EXEC SQL OPEN pcur;IS_ERROR_WITH_POSITION("Open pcur");

printf("%−11s %−5s %−40s %−10s %−6s\n", "ID_PREDMETA","SIFRA","NAZIV","SEMESLUS","BODOVI");

int i = 0;for(; i < 80; ++i){

putchar('=');}putchar('\n');

for(;;){

EXEC SQL FETCH pcurINTO :predmet;

IS_ERROR_WITH_POSITION("Fetch pcur");

if(SQLCODE == 100){

break;}

printf("%−11d %−.5s %−.40s %−10d %−6d\n",predmet.id_predmeta,predmet.sifra.data,predmet.naziv.data,predmet.broj_semestara,predmet.bodovi);

}

Page 180: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

180 Glava 8. Povezivanje na više baza podataka

EXEC SQL CLOSE pcur;IS_ERROR_WITH_POSITION("Close pcur");

}

Kod 8.13: Primeri/cas07/primer4/dbmcon2.h#ifndef DBMCON2_H#define DBMCON2_H

void SecondDbInsert(void);void SecondDbSelect(void);void SecondDbDelete(void);

#endif /∗ DBMCON2_H ∗/

Kod 8.14: Primeri/cas07/primer4/dbmcon2.sqc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sqlenv.h>#include <sqlutil.h>#include "dbmcon2.h"

EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;EXEC SQL INCLUDE dosije;EXEC SQL END DECLARE SECTION;

extern void is_error(char ∗errString, char ∗fileName, int lineNum);

#define IS_ERROR_WITH_POSITION(str) is_error(str, __FILE__, __LINE__);

void SecondDbInsert(void){

printf("INSERT INTO dosije\n""\tVALUES (20120001, 'Stefan', 'Lazic', '01/09/2012', NULL, NULL)\n");

EXEC SQL INSERT INTO dosijeVALUES (20120001, 'Stefan', 'Lazic', '01/09/2012', NULL, NULL);

IS_ERROR_WITH_POSITION("Insert dosije");}

void SecondDbSelect(void){

printf("SELECT FROM dosije\n");

EXEC SQL DECLARE dcur CURSOR FORSELECT ∗FROM dosije;

IS_ERROR_WITH_POSITION("Declare dcur");

EXEC SQL OPEN dcur;IS_ERROR_WITH_POSITION("Open dcur");

printf("INDEKS IME PREZIME ""DATUM_UPISA DATUM_RODJENJA MESTO_RODJENJA \n""======================================""===============================================\n");

for(;;)

Page 181: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

8.5 Šabloni za rad, primeri i implementacione napomene 181

{EXEC SQL FETCH dcur

INTO :dosije:ind_dosije;IS_ERROR_WITH_POSITION("Fetch dcur");

if(SQLCODE == 100){

break;}

dosije.ime.data[dosije.ime.length] = '\0';dosije.prezime.data[dosije.prezime.length] = '\0';

if (ind_dosije[5] >= 0){

dosije.mesto_rodjenja.data[dosije.mesto_rodjenja.length] = '\0';}

printf("%−10d %−10s %−15s %−15s %−15s %−15s\n",dosije.indeks,dosije.ime.data,dosije.prezime.data,(ind_dosije[3] < 0 ? "NULL" : dosije.datum_upisa),(ind_dosije[4] < 0 ? "NULL" : dosije.datum_rodjenja),(ind_dosije[5] < 0 ? "NULL" : dosije.mesto_rodjenja.data));

}

EXEC SQL CLOSE dcur;IS_ERROR_WITH_POSITION("Close dcur");

}

void SecondDbDelete(void){

printf("DELETE FROM dosije\n""WHERE indeks = 20120001\n");

EXEC SQL DELETE FROM dosije WHERE indeks = 20120001;IS_ERROR_WITH_POSITION("Delete");

}

Page 182: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 183: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

III9 Programiranje SQLJ aplikacija . . . . . . . . 1859.1 Baze podataka i programski jezik Java9.2 Programiranje SQLJ aplikacija9.3 Iteratori u SQLJ

10 SQLJ, transakcije i višekorisničko okruženje217

10.1 Ostvarivanje transakcija u SQLJ aplikacijama10.2 Rad u višekorisničkom okruženju

11 Programiranje JDBC aplikacija . . . . . . . 23511.1 Kreiranje konekcije11.2 Obrada SQL grešaka11.3 Upravljanje podacima

12 Napredni koncepti u JDBC aplikacijama 27112.1 Transakcioni rad12.2 Rad u višekorisničkom okruženju12.3 Povezivanje na više baza podataka

13 Okruženje za razvoj Hibernate . . . . . . . . 30313.1 Podešavanje Hibernate projekta13.2 Podešavanje konekcije na bazu podataka13.3 Skladištenje objekata13.4 Omogućavanje skladištenja objekata i OR preslikavanje13.5 Dohvatanje jednog sloga13.6 Brisanje jednog sloga13.7 Složeni ključ13.8 Rad sa skupovima slogova13.9 Asocijativne veze i strani ključevi13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-

ja

Programiranje baza podatakau programskom jeziku Java

Page 184: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 185: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9. Programiranje SQLJ aplikacija

9.1 Baze podataka i programski jezik Java

Java Database Connectivity (JDBC) is a Java programming API that standardizes themeans to work and access databases. In JDBC the code is easily portable between severalRDBMS vendors. The only changes required to the code are normally which JDBC driverto load and the connection string. JDBC uses only dynamic SQL and it is very popular.

SQLJ is the standard for embedding SQL in Java programs. It is mainly used withstatic SQL, though it can inter-operate with JDBC as shown in Figure 9.1. Though itis normally more compact than JDBC programs and provides better performance, it hasnot been widely accepted. SQLJ programs must be run through a preprocessor (the SQLJtranslator) before they can be compiled.

Slika 9.1: Relationship between SQLJ and JDBC applications.

Page 186: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

186 Glava 9. Programiranje SQLJ aplikacija

In Figure 9.1, a DB2 client may or may not be required depending on the type of JDBCdriver used.

Though there are several types of JDBC drivers such as type 1, 2, 3 and 4; type 1 and 3are not commonly used, and DB2’s support of these types has been deprecated. For type2, there are two drivers as we will describe shortly, but one of them is also deprecated.

Type 2 and type 4 are supported with DB2 software, as shown in Table 9.1. Type 2 driversneed to have a DB2 client installed, as the driver uses it to establish communication tothe database. Type 4 is a pure Java client, so there is no need for a DB2 client, but thedriver must be installed on the machine where the JDBC application is running.

Tabela 9.1: DB2 JDBC and SQLJ drivers.

Driver Type Driver Name Packaged as SupportsMinimum levelof SDK forJava required

Type 2

DB2 JDBC Type 2Driver for Linux,UNIX® and Windows(Deprecated)

db2java.zip JDBC 1.2and JDBC 2.0 1.4.2

Type 2 andType 4

IBM Data ServerDriver for JDBCand SQLJ

db2jcc.jarand sqlj.zip

JDBC 3.0compliant 1.4.2

db2jcc4.jarand sqlj4.zip

JDBC 4.0and earlier 6

As mentioned earlier and shown also in Table 9.1, Type 2 is provided with two differentdrivers; however the DB2 JDBC Type 2 Driver for Linux, UNIX and Windows, withfilename db2java.zip is deprecated.

When you install a DB2 server, a DB2 client or the IBM Data Server Driver for JDBC andSQLJ, the db2jcc.jar and sqlj.zip files compliant with JDBC 3.0 are automatically addedto your classpath.

9.2 Programiranje SQLJ aplikacija

SQLJ programming is a standard for embedding SQL statements into Java programs. AllSQL statements are run statically using contexts. A context gives you information thathelps interpret where the SQL statement is executed. There are different types of contexts:

• Connection context. This is equivalent to the Connection object in JDBC. A defaultconnection context is used when no connection context is specified.

• Execution context. This is required to get the information regarding the SQL state-ment before and after executing the statement.

When working with SQLJ, there is different syntax that can be used that can help aprecompiler identify the statements to translate from other statements in the embeddedSQL Java program. There are different types of syntax, but they all start with ”#sql”and use curly brackets as delimiters as shown below:

• #sql [connection−context] { sql statement }

Page 187: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 187

• #sql [connection−context, execution context] { sql statement }• #sql { sql statement }• #sql [execution context] { sql statement }

Tabela 9.2: Mappings of database server data types to Java data types for retrieving datafrom database server tables.

SQL data typeRecommended Javadata type orJava object type

Other supportedJava data types

SMALLINT shortbyte, int, long, float,double, java.math.BigDecimal,boolean, java.lang.String

INTEGER intshort, byte, long, float,double, java.math.BigDecimal,boolean, java.lang.String

BIGINT longint, short, byte, float,double, java.math.BigDecimal,boolean, java.lang.String

DECIMAL(p,s)or NUMERIC(p,s) java.math.BigDecimal

long, int, short, byte,float, double, boolean,java.lang.String

DECFLOAT(n) java.math.BigDecimallong, int, short, byte,float, double, java.math.BigDecimal,boolean, java.lang.String

REAL floatlong, int, short, byte,double, java.math.BigDecimal,boolean, java.lang.String

DOUBLE doublelong, int, short, byte,float, java.math.BigDecimal,boolean, java.lang.String

CHAR(n) java.lang.String

long, int, short, byte,float, double, java.math.BigDecimal,boolean, java.sql.Date,java.sql.Time, java.sql.Timestamp,java.io.InputStream, java.io.Reader

VARCHAR(n) java.lang.String

long, int, short, byte,float, double, java.math.BigDecimal,boolean, java.sql.Date,java.sql.Time, java.sql.Timestamp,java.io.InputStream, java.io.Reader

DATE java.sql.Date java.sql.String, java.sql.TimestampTIME java.sql.Time java.sql.String, java.sql.TimestampTIMESTAMP,TIMESTAMP(p),TIMESTAMP WITHTIME ZONE,TIMESTAMP(p) WITHTIME ZONE

java.sql.Timestamp java.sql.String, java.sql.Date,java.sql.Time, java.sql.Timestamp

Page 188: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

188 Glava 9. Programiranje SQLJ aplikacija

9.2.1 Matične promenljive

Host variables can be identified by a colon as in the example below:#sql {

SELECT EMPNOFROM EMPWHERE WORKDEPT = :dept

};

To write efficient JDBC and SQLJ programs, you need to use the best mappings betweenJava™ data types and table column data types.

Table 9.2 summarizes the mappings of Db2 or IBM Informix data types to Java data typesfor ResultSet.getXXX methods in JDBC programs, and for iterators in SQLJ programs.This table does not list Java numeric wrapper object types, which are retrieved usingResultSet.getObject.

Table 9.3 summarizes the mappings of Java data types to database data types for Pre-paredStatement.setXXX or ResultSet.updateXXX methods in JDBC programs, and forinput host expressions in SQLJ programs. When more than one Java data type is listed,the first data type is the recommended data type.

Tabela 9.3: Mappings of Java data types to database server data types for updatingdatabase tables.

Java data type Database data typeshort, java.lang.Short SMALLINTboolean, byte,java.lang.Boolean, java.lang.Byte SMALLINT

int, java.lang.Integer INTEGERlong, java.lang.Long BIGINTjava.math.BigInteger BIGINTjava.math.BigInteger CHAR(n)float, java.lang.Float REALdouble, java.lang.Double DOUBLEjava.math.BigDecimal DECIMAL(p,s)java.math.BigDecimal DECFLOAT(n)java.lang.String CHAR(n)java.lang.String VARCHAR(n)java.sql.Date DATEjava.sql.Time TIME

java.sql.TimestampTIMESTAMP, TIMESTAMP(p),TIMESTAMP WITH TIME ZONE,TIMESTAMP(p) WITH TIME ZONE

java.util.Date CHAR(n)java.util.Date VARCHAR(n)java.util.Date DATEjava.util.Date TIME

java.util.DateTIMESTAMP, TIMESTAMP(p),TIMESTAMP WITH TIME ZONE,TIMESTAMP(p) WITH TIME ZONE

Page 189: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 189

9.2.2 Kreiranje konteksta konekcije

To work with SQL in an SQLJ program, you need to first establish a database connection.A connection context is used for that purpose. There are different ways to work withconnection contexts as shown in the two code examples below:import java.sql.∗; // (1)import sqlj.runtime.∗; // (2)import sqlj.runtime.ref.∗; // (3)

#sql context ctx; // (4)

class myprg {public static void main (String argv[]){

Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance(); // (5)ctx ctx1 = new ctx("jdbc:db2:sample",false); // (6)

#sql [ctx1] { // (7)DELETE FROM dept

};

// ...

In this code:

(1) This statement imports the java.sql package, which contains the JDBC core API.(2), (3) These packages need to be imported to provide for SQLJ runtime support.

(4) Declare a class for the connection context using the syntax:#sql context <context−class−name>

(5) This statement loads the driver classes from the IBM Data Server Driver for JDBCand SQLJ (db2jcc.jar/db2jcc4.jar/sqlj.zip/sqlj4.zip). The forName method takes astring argument whose value is the name of the class which implements the inter-faces defined in java.sql package. In this case the class name is "com.ibm.db2.jcc.DB2Driver".

(6) Invoke the constructor of the context class.(7) An SQL statement (DELETE) is executed under the connection context ”ctx1”.

import java.sql.∗;

#sql context ctx;

class myprg {public static void main (String argv[]){

Connection con = null;

Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();String url = "jdbc:db2://168.100.10.1:50000/SAMPLE"; // (1)

if (argv.length != 2){

throw new Exception("\n Usage: java myprg userID password\n");}

String userID = argv[0];String passwd = argv[1];

Page 190: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

190 Glava 9. Programiranje SQLJ aplikacija

con = DriverManager.getConnection(url,userID,passwd); // (2)ctx ctx1 = new ctx(con); // (3)

#sql [ctx1] {DELETE FROM dept

};

// ...

This code shows the exact same code snippet as in the previous one, but the URL hasbeen changed to use the Type 4 syntax:"jdbc:db2://<IP address or hostname>:<DB2 Instance port number>/<dbname>"

(1) The fictitious IP address 168.100.10.1 was used. The DB2 instance port number is50000, and the database name to connect to is SAMPLE. To test a connection whenyou are not connected to a network you can always use localhost or the loopback IPaddress 127.0.0.1 to point to yourself.

(2) Using the Connection object: two arguments are passed to the program (userID andpassword), these will be used to get the connection; otherwise the program throwsan exception. DriverManager.getConnection(url,userID,passwd) can also be calledwithout a userID and passwd as follows: DriverManager.getConnection(url). In thiscase the user ID logged on to the system would be used. For Type 4, this will notwork, as this connection is taken as a remote TCPIP connection and DB2 needs auser ID and password for all remote connections.

(3) Invoke the constructor of the context class, using the Connection object.

9.2.3 Kreiranje podrazumevanog konteksta konekcije

In addition, you can also create a default context for the connection. This means thatlater on there will not be a need to specify a context when performing SQL operations,as the context to use will be the one specified as the default one. The syntax would be ofthis form:#sql { sql statement }

The following code snippet shows a part of the program which creates the default contextconnection:Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();String url = "jdbc:db2://168.100.10.1:50000/SAMPLE";

Connection con = DriverManager.getConnection(url, "username", "password");DefaultContext ctx1 = new DefaultContext(con); // (1)DefaultContext.setDefaultContext(ctx1); // (2)

#sql { // (3)DELETE FROM dept

};

In the above code:

(1) A DefaultContext is created.(2) Set the default context to be ctx1.

Page 191: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 191

(3) Specify the SQL to execute, in this case it is a DELETE statement. Note that thereis no need to put the context name in the syntax. The default context ctx1 will beused.

9.2.4 Kreiranje konteksta izvršavanja

An execution context monitors and controls a SQL statement while executing. It is createdwithin a connection context object. To create an ExecutionContext object use the getExe-cutionContext method of the connection context. Some ExecutionContext methods workbefore an SQL statement is executed while others apply only after execution. Considerthe next example:#sql context ctx; // this should be outside the class

// ...

String url = "jdbc:db2:sample";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con=DriverManager.getConnection(url);ctx ctx1=new ctx(con);

ExecutionContext exectx1 = ctx1.getExecutionContext(); // (1)#sql [ctx1, exectx1] = { // (2)

DELETE FROM purchaseorderWHERE status='UnShipped'

};

int i = exectx1.getUpdateCount(); // (3)

// ...

In the above code:

(1) An execution context is created with the getExecutionContext method of the con-nection context object.

(2) Specifying the SQL to run associated to connection context ctx1, and executioncontext exectx1.

(3) Invoking the getUpdateCount method of the execution context object to obtain thenumber of records deleted or updated.

Once we have created a connection object, we can set a number of connection propertiesthat control the application behavior. For example, one commonly used connection pro-perty is Auto commit mode: This indicates whether all SQL statements executed undera given connection should be committed automatically. We can set it to true or false byusing the setAutoCommit() method:con.setAutoCommit(false);

This way, we will need to explicitly execute the commit statements in our code.

9.2.5 Zatvaranje konteksta i konekcije

In order to properly finish out program execution, we have to close the connection contextas well as the connection to a database itself. To achieve this, before our program finished,we can call methods close, defined on both context object and Connection object:

Page 192: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

192 Glava 9. Programiranje SQLJ aplikacija

ctx.close();con.close();

9.2.6 Obrada SQL grešaka

Just like any Java program, in JDBC, exception handling is done using the try-catchblock. A DB2 application throws a SQLException whenever it encounters a SQL error ora SQLWarning whenever it encounters a SQL warning when executing SQL statements.

An object of SQLException is created and thrown whenever an error occurs while accessingthe database. The SQLException object provides the information listed in Table 9.4.

Tabela 9.4: SQLException information.SQLExceptioninformation Description Method to retrieve

this information

Message Textual representationof the error code. getMessage

SQLState The SQLState string. getSQLState

ErrorCode

An integer valuethat indicates the errorwhich caused the exceptionto be thrown.

getErrorCode

Apart from the above information, the DB2 JCC driver provides an extra interfacecom.ibm.db2.jcc.DB2Diagnosable. This interface gives more information regarding theerror that occurred while accessing the DB2 database.

If multiple SQLExceptions are thrown, they are chained. The next exception informationcan be retrieved by calling the getNextException method of the current SQLExceptionobject. This method will return null if the current SQLException object is last in thechain. A while loop in the catch block of the program can be used to retrieve all theSQLException objects one by one.try{

// code which can throw SQLException go here}catch (SQLException sqle){

System.out.println("Rollback the transaction and quit the program");System.out.println();

try{

#sql {rollback;

};}catch (Exception e) {}

System.exit(1);}

Page 193: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 193

9.2.7 Prevođenje SQLJ aplikacija

You can use the bldsqlj build file to build SQLJ applications. The build file takes up tothree parameters. The first parameter specifies the name of your program. The secondparameter specifies the user ID for the database instance, the third parameter specifiesthe password. For all but the first parameter, program name, default values can be used,which need to be hardcoded in the bldsqlj build file.

Procedure for building and running the SQLJ application:

1. Build the application with this command:$ ./bldsqlj ime_fajla_bez_sqlj_ekstenzije username password

2. Run the Java interpreter on the application with this command:$ ./pokreni ime_fajla_bez_sqlj_ekstenzije

The scripts bldsqlj and pokreni are defined as follows (note that the script bldsqlj usesanother script db2sqljcustomize2, which is also defined below):

Kod 9.1: Primeri/cas09/bldsqlj.sh#!/bin/sh

# Hardcoded user ID (USER) and password (PSWD) valuesUSER="student"PSWD="abcdef"# You can replace the defaults for each of the following# with a new value. Note that the PORTNUM number cannot# be one already used by another process.SERVER=bpPORTNUM=50001DB="vstud"

# Translate and compile the SQLJ source file# and bind the package to the database.if ( [ $# −eq 1 ] && [ $USER != "NULL" ] && [ $PSWD != "NULL" ] ) || ( [ $# −

ge 3 ] && [ $# −le 6 ] )then

# Remove .sqlj extensionprogname=${1%.sqlj}

sqlj "${progname}.sqlj"

if [ $# −eq 1 ]then

./db2sqljcustomize2 −url jdbc:db2://$SERVER:$PORTNUM/$DB \−user $USER −password $PSWD "${progname}_SJProfile0"

elif [ $# −eq 3 ]then

./db2sqljcustomize2 −url jdbc:db2://$SERVER:$PORTNUM/$DB −user $2 −password $3 \

"${progname}_SJProfile0"elif [ $# −eq 4 ]then

./db2sqljcustomize2 −url jdbc:db2://$4:$PORTNUM/$DB −user $2 −password$3 \

"${progname}_SJProfile0"elif [ $# −eq 5 ]then

./db2sqljcustomize2 −url jdbc:db2://$4:$5/$DB −user $2 −password $3 \

Page 194: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

194 Glava 9. Programiranje SQLJ aplikacija

"${progname}_SJProfile0"else

./db2sqljcustomize2 −url jdbc:db2://$4:$5/$6 −user $2 −password $3 \"${progname}_SJProfile0"

fielse

echo 'Usage: bldsqlj prog_name (requires hardcoding user ID and password)'echo ' bldsqlj prog_name userid password'echo ' bldsqlj prog_name userid password server_name'echo ' bldsqlj prog_name userid password server_name port_number'echo ' bldsqlj prog_name userid password server_name port_number

db_name'echo ''echo ' Defaults:'echo ' userid = '$USERecho ' password = '$PSWDecho ' server_name = '$SERVERecho ' port_number = '$PORTNUMecho ' db_name = '$DB

fi

Kod 9.2: Primeri/cas09/db2sqljcustomize2.sh#!/bin/sh

java com.ibm.db2.jcc.sqlj.Customizer "$@"

Kod 9.3: Primeri/cas09/pokreni.sh#!/bin/sh

java −Djava.library.path="/opt/ibm/db2/V10.5/lib32" $1

9.2.8 Primeri

Naredni primeri ilustruju osnovne elemente programiranja SQLJ aplikacija.

Primer 9.1 — Čas 09 — 01. Napisati SQLJ aplikaciju koja izdvaja maksimalni brojindeksa studenta iz tabele DOSIJE.

Rešenje.

Kod 9.4: Primeri/cas09/Primer1.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

public class Primer1{

public static void main(String argv[]){

try{

// Host promenljiveint d_indeks = 0;

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";

Page 195: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 195

Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("−−−Connected−−−");

#sql {select max(d.indeks) into :d_indeks

from dosije d};

System.out.printf("%d\n", d_indeks);

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("−−−Disconnect−−−");

}// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}}

}

Primer 9.2 — Čas 09 — 02. Napisati SQLJ aplikaciju koja izdvaja identifikator i opissmera čiji je identifikator 210.

Rešenje.

Kod 9.5: Primeri/cas09/Primer2.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

public class Primer2{

public static void main(String argv[]){

try{

// Host promenljiveint d_id_smera = 0;String d_opis = null;

Page 196: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

196 Glava 9. Programiranje SQLJ aplikacija

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("−−−Connected−−−");

#sql {select id_smera, opisinto :d_id_smera, :d_opisfrom smerwhere id_smera = 210

};

System.out.printf("%d %−50s\n", d_id_smera, d_opis);

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("−−−Disconnect−−−");

}

// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}

}}

Primer 9.3 — Čas 09 — 03. Napisati SQLJ aplikaciju koja izdvaja identifikator i opissmera čiji je identifikator 210. U slučaju da je opis nedostajuća vrednost u bazi podataka,ispisati "Nema opisa".

Rešenje.

Kod 9.6: Primeri/cas09/Primer3.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

public class Primer3

Page 197: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 197

{public static void main(String argv[]){

try{

// Host promenljiveint d_id_smera = 0;String d_opis = null;short ind_opis = 0;

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("−−−Connected−−−");

#sql {select id_smera, opisinto :d_id_smera, :d_opis:ind_opisfrom smerwhere id_smera = 210

};

System.out.printf("%d %−50s\n", d_id_smera, (ind_opis < 0) ? "Nemaopisa" : d_opis);

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("−−−Disconnect−−−");

}

// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}

}}

Primer 9.4 — Čas 09 — 04. Napisati SQLJ aplikaciju koja izdvaja identifikator predmeta,šifru, naziv, kao i broj ESPB bodova za jedan predmet koji nije položio nijedan student,

Page 198: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

198 Glava 9. Programiranje SQLJ aplikacija

a koji ima najviše ESPB bodova od svih takvih predmeta.

Rešenje.

Kod 9.7: Primeri/cas09/Primer4.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

public class Primer4{

public static void main(String argv[]){

try{

int id_predmeta = 0;String sifra = null;String naziv = null;short bodovi = 0;

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("−−−Connected−−−");

#sql {select id_predmeta, trim(sifra), trim(naziv), bodoviinto :id_predmeta, :sifra, :naziv, :bodovifrom predmet pwhere not exists (

select ∗from ispitwhere ocena > 5

and status_prijave='o'and id_predmeta=p.id_predmeta

)order by bodovi descfetch first 1 rows only

};

System.out.printf("ID: %d Sifra: %s Naziv: %s Bodovi: %d\n",id_predmeta, sifra, naziv, bodovi);

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("−−−Disconnect−−−");

}

Page 199: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 199

// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}

}}

Primer 9.5 — Čas 09 — 05. Napisati za svaki od narednih zahteva po jednu SQLJaplikaciju koja:

1. Kreira tabelu student_uspeh (sa kolonama indeks, esbp i prosek).2. Kreira okidač espb koji pre unošenja podataka u tabelu student_uspeh računa i

unosi broj ESPB bodova.

Rešenje.

Kod 9.8: Primeri/cas09/Primer5a.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

public class Primer5a{

public static void main(String argv[]){

try{

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("−−−Connected−−−");

try {#sql {

drop table student_uspeh};

System.out.println("Tabela je obrisana!");}catch(Exception e) {}

#sql {create table student_uspeh (

indeks integer not null,

Page 200: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

200 Glava 9. Programiranje SQLJ aplikacija

espb smallint,prosek float,primary key (indeks),foreign key (indeks) references dosije

)};

System.out.println("Kreirana je tabela!");

#sql {commit};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("−−−Disconnect−−−");

}

// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}

}}

Kod 9.9: Primeri/cas09/Primer5b.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

public class Primer5b{

public static void main(String argv[]){

try{

int indeks = 0;short espb = 0;double prosek = 0.0;PosIter iter1;

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("−−−Connected−−−");

Page 201: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.2 Programiranje SQLJ aplikacija 201

try{

#sql {drop trigger espb

};

System.out.println("Obrisan je okidac!");}catch (Exception e){}

#sql {create trigger espbbefore insert on student_uspehreferencing new as unosfor each rowbegin atomic

set unos.espb = (select sum(p.bodovi)from ispit i

join predmet pon i.id_predmeta = p.id_predmeta

where i.indeks = unos.indeksand ocena > 5and status_prijave = 'o');

end};

System.out.println("Kreiran je okidac!");

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("−−−Disconnect−−−");

}

// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}

}}

Page 202: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

202 Glava 9. Programiranje SQLJ aplikacija

9.3 Iteratori u SQLJ

SQLj defines iterators for selecting multiple rows using the SELECT statement. Iteratorsare the SQLj equivalent of cursors in programming language C.

To iterators, the application needs to create an iterator class by defining the iterator andan object of that class. The result of the SELECT statement can be assigned to this object.

SQLj provides two types of iterators:

• Positioned iterators• Named iterators

9.3.1 Pozicioni iteratori

A positioned iterator identifies a row by its position in the result set. So while definingthe position iterator, you need to give only the data types of the columns.

For example:#sql iterator positionedIterator (int, String); // (1)

String status = null; // (2)int poid = 0; // (3)

positionedIterator iterator1; // (4)#sql iterator1 = { // (5)

select poid, statusfrom purchaseorder

};

#sql { // (6)fetch :iterator1into :poid, :status

};

while(!iterator1.endFetch()) { // (7)System.out.println("poid: " + poid + // (8)

"Status: "+ status);

#sql { // (9)fetch :iterator1into :poid, :status

};}

iterator1.close(); // (10)

In the above code snippet:

(1) A position iterator is declared with two columns. Note that the column does nothave names, just the data type. This is why this is a position iterator.

(2) A variable status is declared. This is a host variable that are used to receive thevalues from the iterator.

(3) Similar to (2) for variable poid.(4) A positioned iterator iterator1 is created.(5) In the default connection context, the iterator1 is defined with a ”select poid,

status from purchaseorder”.

Page 203: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.3 Iteratori u SQLJ 203

(6) Before starting the loop, we fetch the first record into the host variables poid andstatus.

(7) Looping through the iterator using the condition endFetch(), which will return falsewhen there are no more rows in the result to be fetched.

(8) Printing the poid and status of each row retrieved.(9) Fetching the next record in the iterator.

(10) Closing iterator1.

Primer 9.6 — Čas 09 — 06. Napisati SQLJ aplikaciju koja unosi podatke u tabelustudent_uspeh, kreiranu u primeru 9.5 i ispisuje ih koristeći pozicioni iterator.

Rešenje.

Kod 9.10: Primeri/cas09/Primer6.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

// Deklaracija pozicionog iteratora#sql iterator PosIter (int, short, double);

public class Primer6{

public static void main(String argv[]){

try{

int indeks = 0;short espb = 0;double prosek = 0.0;PosIter iter1;

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("−−−Connected−−−");

#sql {delete from student_uspeh

};

#sql {insert into student_uspeh (indeks, prosek)select i.indeks, avg(ocena + 0.0)from ispit i

join dosije don i.indeks = d.indeks

left outer join obavezan_predmet opon op.id_smera = d.id_smera

and op.id_predmeta = i.id_predmetawhere ocena > 5

Page 204: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

204 Glava 9. Programiranje SQLJ aplikacija

and status_prijave = 'o'group by i.indekshaving count(op.id_predmeta) = 20

};

// Deklaracija pozicionog iteratora za prolazak tabelomstudent_uspeh

#sql iter1 = {select ∗from student_uspeh−− where prosek < 0

};

#sql {fetch :iter1into :indeks, :espb, :prosek

};

if (!iter1.endFetch()){

System.out.printf("%−10s %−5s %−6s\n\n", "INDEKS", "ESPB", "PROSEK");

}

while(!iter1.endFetch()){

System.out.printf("%−10d %−5d %−6.2f\n", indeks, espb, prosek);

#sql {fetch :iter1into :indeks, :espb, :prosek

};}

iter1.close();

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("−−−Disconnect−−−");

}

// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}

}}

Page 205: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.3 Iteratori u SQLJ 205

9.3.2 Imenovani iteratori

Named iterators identify a row by the name of the column in the result set. So whiledefining the named iterator, you need to specify the name of the columns and their datatypes selected by the SELECT statement.

For example:#sql iterator namediterator (int poid, String status) // (1)

namediterator iterator1; // (2)#sql iterator1 = { // (3)

select poid, statusfrom purchaseorder

};

while (iterator1.next()) { // (4)System.out.println(

"poid: " + iterator1.poid() + // (5)"Status: " + iterator1.status());

}

iterator1.close(); // (6)

In the above code snippet:

(1) A named iterator is declared with two columns. Note that the column names poidand status are explicitly mentioned. This is why this is a named iterator.

(2) A named iterator iterator1 is declared.(3) In a default connection context, the iterator1 is defined with a ”select poid, status

from purchaseorder”.(4) Looping through the iterator using the method next(). This method returns false if

there are no more rows to be processed in the result. Otherwise, it returns true, andthe developer can use appropriate methods for fetching the data (see (5)).

(5) Printing the poid and status of each row retrieved. Note the syntax: “iterator1.poid()”,and “iterator1.status()”.

(6) Closing iterator1.

Primer 9.7 — Čas 09 — 07. Napisati SQLJ aplikaciju koja unosi podatke u tabelustudent_uspeh, kreiranu u primeru 9.5 i ispisuje ih koristeći imenovani iterator.

Rešenje.

Kod 9.11: Primeri/cas09/Primer7.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;

// Deklaracija imenovanog iteratora#sql iterator NameIter (int indeks, double prosek, short espb);

public class Primer7{

public static void main(String argv[]){

try{

Page 206: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

206 Glava 9. Programiranje SQLJ aplikacija

int indeks = 0;short espb = 0;double prosek = 0.0;NameIter iter1;

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/VSTUD";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("\n−−−Connected−−−");

// Deklaracija imenovanog iteratora za prolazak tabelomstudent_uspeh

#sql iter1 = {select ∗from student_uspeh

};

boolean prva_iteracija = true;

while(iter1.next()){

if (prva_iteracija){

System.out.printf("%−10s %−5s %−6s\n\n", "INDEKS", "ESPB","PROSEK");

prva_iteracija = false;}

indeks = iter1.indeks();espb = iter1.espb();prosek = iter1.prosek();

System.out.printf("%−10d %−5d %−6.2f\n", indeks, espb, prosek);}

iter1.close();

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}

// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2)

Page 207: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.3 Iteratori u SQLJ 207

{System.out.println("−−−Exception−−−");e2.printStackTrace();

}

}}

Primer 9.8 — Čas 09 — 08. Napisati SQLJ aplikaciju koja omogućava izdvajanje polo-ženih obaveznih predmeta za studenta čiji se indeks unosi sa standardnog ulaza.

Rešenje.

Kod 9.12: Primeri/cas09/primer8/Primer.sqljimport java.sql.∗;import sqlj.runtime.ref.∗;import java.util.∗;

#sql iterator ObavezniPredmeti (String, short, java.sql.Date);

//Izdvajanje polozenih obaveznih predmeta za studenta ciji se indeks unosi sastandardnog ulaza

public class Primer {public static void main(String argv[]) {

try {// Host promenljive

String naziv = null;short ocena = 0;java.sql.Date datum = null;int indeks = 0;

// Parser standardnog ulazaScanner skener = new Scanner(System.in);

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/vstud";

Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student","abcdef");

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("\n−−−Connected−−−");

System.out.print("Unesite indeks:");indeks = skener.nextInt();

ObavezniPredmeti iter;

#sql iter = { select rtrim(naziv), ocena, max(coalesce(datum_usmenog,datum_pismenog)) from ispit i join dosije d on d.indeks=i.

indeksjoin predmet p on p.id_predmeta=i.id_predmeta joinobavezan_predmet op on op.id_predmeta=p.id_predmeta andop.id_smera=d.id_smera where ocena>5 and status_prijave='o' andd.indeks=:indeks group by naziv, ocena };

Page 208: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

208 Glava 9. Programiranje SQLJ aplikacija

#sql { fetch :iter into :naziv, :ocena, :datum };

while (!iter.endFetch()) {System.out.println(naziv + " " + ocena + " " + datum);

#sql { fetch :iter into :naziv, :ocena, :datum };};

// Zatvaranje iteratoraiter.close();

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}// Obrada izuzetakacatch (SQLException e1) {

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

} catch (Exception e2) {System.out.println("−−−Exception−−−");e2.printStackTrace();// try blok je neophodan zbog sql naredbe ROLLBACK

}

}}

9.3.3 Iteratori za ažuriranje i brisanje podataka

As in database applications in other languages, performing positioned UPDATEs andDELETEs with SQLJ is an extension of retrieving rows from a result table.

The basic steps are:

1. Declare the iterator.The iterator can be positioned or named. For positioned UPDATE or DELETEoperations, declare the iterator as updatable, using one or both of the followingclauses:implements sqlj.runtime.ForUpdate

This clause causes the generated iterator class to include methods for using updatableiterators. This clause is required for programs with positioned UPDATE or DELETEoperations.with (updateColumns="column−list")

This clause specifies a comma-separated list of the columns of the result table thatthe iterator will update. This clause is optional if the iterator is used for a DELETEoperation.You need to declare the iterator as public, so you need to follow the rules for declaringand using public iterators in the same file or different files.

Page 209: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.3 Iteratori u SQLJ 209

If you declare the iterator in a file by itself, any SQLJ source file that has addressa-bility to the iterator and imports the generated class can retrieve data and executepositioned UPDATE or DELETE statements using the iterator.

2. Disable autocommit mode for the connection.If autocommit mode is enabled, a COMMIT operation occurs every time the positi-oned UPDATE statement executes, which causes the iterator to be destroyed unlessthe iterator has the with (holdability=true) attribute. Therefore, you need to turnautocommit off to prevent COMMIT operations until you have finished using theiterator. If you want a COMMIT to occur after every update operation, an alterna-tive way to keep the iterator from being destroyed after each COMMIT operation isto declare the iterator with (holdability=true).

3. Create an instance of the iterator class.This is the same step as for a non-updatable iterator.

4. Assign the result table of a SELECT to an instance of the iterator.This is the same step as for a non-updatable iterator. The SELECT statement mustnot include a FOR UPDATE clause.

5. Retrieve and update rows.For a positioned iterator, do this by performing the following actions in a loop:(a) Execute a FETCH statement in an executable clause to obtain the current row.(b) Test whether the iterator is pointing to a row of the result table by invoking

the PositionedIterator.endFetch method.(c) If the iterator is pointing to a row of the result table, execute an SQL UP-

DATE… WHERE CURRENT OF :iterator-object statement in an executableclause to update the columns in the current row. Execute an SQL DELETE…WHERE CURRENT OF :iterator-object statement in an executable clause todelete the current row.

For a named iterator, do this by performing the following actions in a loop:(a) Invoke the next method to move the iterator forward.(b) Test whether the iterator is pointing to a row of the result table by checking

whether next returns true.(c) Execute an SQL UPDATE…WHERE CURRENT OF iterator-object statement

in an executable clause to update the columns in the current row. Execute anSQL DELETE… WHERE CURRENT OF iterator-object statement in an exe-cutable clause to delete the current row.

6. Close the iterator.Use the close method to do this.

The following code shows how to declare a positioned iterator and use it for positionedUPDATEs. The numbers to the right of selected statements correspond to the previouslydescribed steps.

First, in one file, declare positioned iterator UpdByPos, specifying that you want to usethe iterator to update column SALARY:import java.math.∗; // Import this class for BigDecimal data type

Page 210: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

210 Glava 9. Programiranje SQLJ aplikacija

#sql public iterator UpdByPos implements sqlj.runtime.ForUpdate // (1)with(updateColumns="SALARY") (String, BigDecimal);

Then, in another file, use UpdByPos for a positioned UPDATE, as shown in the followingcode fragment:import sqlj.runtime.∗; // Import files for SQLJ and JDBC APIsimport java.sql.∗;import java.math.∗; // Import this class for BigDecimal data typeimport UpdByPos; // Import the generated iterator class that

// was created by the iterator declaration clause// for UpdByName in another file

#sql context HSCtx; // Create a connection context class HSCtx

public static void main (String args[]){

try {Class.forName("com.ibm.db2.jcc.DB2Driver");

}catch (ClassNotFoundException e) {

e.printStackTrace();}

Connection HSjdbccon =DriverManager.getConnection("jdbc:db2:SANJOSE");

// Create a JDBC connection objectHSjdbccon.setAutoCommit(false);

// Set autocommit off so automatic commits // (2)// do not destroy the cursor between updates

HSCtx myConnCtx = new HSCtx(HSjdbccon);// Create a connection context object

UpdByPos upditer; // Declare iterator object of UpdByPos class // (3)String empnum; // Declares host variable to receive EMPNOBigDecimal sal; // and SALARY column values

#sql [myConnCtx] upditer = { // (4)SELECT EMPNO, SALARYFROM EMPLOYEEWHERE WORKDEPT = 'D11'

}; // Assign result table to iterator object

#sql { // (5)FETCH :upditerINTO :empnum, :sal

}; // Move cursor to next row

while (!upditer.endFetch()) // (5b)// Check if on a row

{#sql [myConnCtx] {

UPDATE EMPLOYEESET SALARY = SALARY∗1.05WHERE CURRENT OF :upditer // (5c)

}; // Perform positioned update

System.out.println("Updating row for " + empnum);

#sql {FETCH :upditerINTO :empnum,:sal

Page 211: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.3 Iteratori u SQLJ 211

}; // Move cursor to next row}

upditer.close(); // (6)// Close the iterator

#sql [myConnCtx] {COMMIT};// Commit the changes

myConnCtx.close();// Close the connection context

}

Primer 9.9 — Čas 09 — 09. Napisati SQLJ aplikaciju koja za svaki predmet koji jeobavezan na smeru čiji je identifikator 201, pita korisnika da li želi da poveća broj bodovaza 1. Ukoliko je odgovor korisnika ”d” ili ”D”, izvršava se odgovarajuća naredba.

Rešenje.

Kod 9.13: Primeri/cas09/primer9/UpdatePredmet.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;

#sql public iterator UpdatePredmet implements sqlj.runtime.ForUpdatewith(updateColumns = "bodovi")(String, short);

Kod 9.14: Primeri/cas09/primer9/Primer.sqljimport java.sql.∗;import sqlj.runtime.ref.∗;import java.util.∗;

//Primer sa iteratorom za azuriranje

public class Primer{

public static void main(String argv[]){

try{

// Host promenljiveString naziv = null;short bodovi=0;

// Parser standardnog ulazaScanner skener = new Scanner(System.in);

// Odgovor korisnikachar c;

// Povezivanje na bazuString url = "jdbc:db2://localhost:50001/vstud";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);

Page 212: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

212 Glava 9. Programiranje SQLJ aplikacija

DefaultContext.setDefaultContext(ctx);System.out.println("\n−−−Connected−−−");

// Deklaracija promenljive koja referise na objekat iteratoraUpdatePredmet iter = null;

#sql iter = {select rtrim(naziv), bodovifrom predmetwhere id_predmeta in (

select id_predmetafrom obavezan_predmetwhere id_smera = 201

)};

#sql {fetch :iterinto :naziv, :bodovi

};

while (!iter.endFetch()){

System.out.println("Da li korisnik zeli da poveca za 1 brojbodova za predmet " + naziv +" koji trenutno ima " + bodovi + " bodova? (d ili n)");

c = skener.next().charAt(0);

if(c == 'd' || c == 'D'){

// Pozicionirana UPDATE naredba

#sql {update predmetset bodovi = bodovi+1where current of :iter

};}

#sql {fetch :iterinto :naziv, :bodovi

};}

iter.close();

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}// Obrada izuzetakacatch (SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

Page 213: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.3 Iteratori u SQLJ 213

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}}

}

9.3.4 Ugnežđeni iteratori

Kao što smo u programskom jeziku C mogli da ugnežđavamo kursore jedan u drugi, takomožemo isti efekat postići ugnežđavanjem iteratora u SQLJ aplikacijama. Kao i kodkursora, potrebno je celokupnu proceduru za upravljanje unutrašnjeg iteratora smestitiu delu za obradu spoljašnjeg iteratora. Naredni primer ilustruje korišćenje ugnežđenihiteratora.

Primer 9.10 — Čas 09 — 10. Za svaki ispitni rok izdvojiti naziv, početak prijave ispita utom roku i kraj prijave ispita u tom roku, a zatim izdvojiti ispite na kojima su dobijenenajveće ocene u tom ispitnom roku. Za svaki ispit izdvojiti: indeks, ime i prezimestudenta, smer koji student studira, naziv položenog predmeta i ocenu. Ispite ureditiprema indeksu studenta.

Rešenje.

Kod 9.15: Primeri/cas09/primer10/Primer.sqljimport java.sql.∗;import sqlj.runtime.ref.∗;import java.util.∗;

#sql iterator Rokovi (short, String, String, java.sql.Date, java.sql.Date,short);

#sql iterator Ispiti(int indeks, String ime, String prezime, String smer,String predmet);

public class Primer{

public static void main(String argv[]){

try{

// Host promenljiveshort godina=0;String oznaka=null;String naziv_roka = null;java.sql.Date pocetak_prijave = null;java.sql.Date kraj_prijave = null;short max_ocena=0;

int indeks=0;String ime=null;String prezime=null;String naziv_smera=null;String naziv_predmeta=null;short ocena = 0;

// Povezivanje sa bazom

Page 214: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

214 Glava 9. Programiranje SQLJ aplikacija

String url = "jdbc:db2://localhost:50001/vstud";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student","abcdef");

con.setAutoCommit(false);DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);

System.out.println("\n−−−Connected−−−");

Rokovi rok=null;Ispiti ispit=null;

#sql rok = {select ir.godina, oznaka, naziv, pocetak_prijave, kraj_prijave,

max(ocena)from ispitni_rok ir

join ispit ion ir.godina = i.godina_rokaand ir.oznaka=i.oznaka_roka

where ocena > 5and status_prijave = 'o'

group by ir.godina, oznaka, naziv, pocetak_prijave,kraj_prijave

};

#sql {fetch :rokinto :godina, :oznaka, :naziv_roka, :pocetak_prijave, :

kraj_prijave, :max_ocena};

while (!rok.endFetch()){

System.out.printf("\n\n%−15s %−15s %−15s\n\n",naziv_roka, pocetak_prijave, kraj_prijave);

#sql ispit = {select d.indeks, ime, prezime, rtrim(s.naziv) smer, rtrim(p

.naziv) predmetfrom ispit i

join dosije don d.indeks = i.indeks

join predmet pon p.id_predmeta = i.id_predmeta

join smer son s.id_smera = d.id_smera

where i.godina_roka = :godinaand i.oznaka_roka = :oznakaand ocena = :max_ocenaand status_prijave='o'

order by indeks};

while(ispit.next()){

indeks = ispit.indeks();ime = ispit.ime();prezime = ispit.prezime();naziv_smera = ispit.smer();

Page 215: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

9.3 Iteratori u SQLJ 215

naziv_predmeta = ispit.predmet();

System.out.printf("%10d %−15s %−15s %−15s %−15s\n",indeks, ime, prezime, naziv_smera, naziv_predmeta);

}

ispit.close();

#sql {fetch :rokinto :godina, :oznaka, :naziv_roka, :pocetak_prijave, :

kraj_prijave, :max_ocena};

}

// Zatvaranje iteratorarok.close();

#sql {commit

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}// Obrada izuzetakacatch (SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

}}

}

Page 216: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 217: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10. SQLJ, transakcije i višekorisničko okruženje

Ovo poglavlje predstavlja proširenje poglavlja 5 i 6, sa razlikom da ćemo sada primereimplementirati kao SQLJ aplikacije. Samim tim, pretpostavka je da je čitalac uspešnousvojio pojmove iz pomenutih poglavlja, te je tekst u nastavku pisan u skladu sa tompretpostavkom.

10.1 Ostvarivanje transakcija u SQLJ aplikacijama

To maintain the consistency and integrity in a transaction, SQLJ includes the followingconcepts:

• Auto commit mode• Transaction isolation level• Savepoints

10.1.1 Auto commit mode

A transaction is started whenever an SQL statement requires one and there is no transac-tion in place. There is no explicit API defined to start a transaction.

Auto commit mode is set to indicate when to end a transaction. Auto commit modecan be set by setting the auto-commit attribute of the Connection object. This attributeis set to either enable or disable. Enabling this attribute makes each SQL statement aseparate transaction. So whenever an SQL statement is issued by the application, a newtransaction is started and once the statement is executed successfully, the transaction iscompleted by committing any updates done to the database. Disabling this attribute givesthe application flexibility to end the transaction any time by calling the commit methodof the Connection object. if any of the SQL statements in the transaction failed, theapplication needs to restore the state of the database by calling the rollback method of

Page 218: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

218 Glava 10. SQLJ, transakcije i višekorisničko okruženje

the Connection object. Disabling this attribute gives the flexibility to the application toinclude multiple SQL statements in a transaction and commit and roll back the transactionwhenever needed.

The value of the auto-commit attribute of the Connection object can be set by callingthe Connection object method setAutoCommit. The default value for this attribute istrue (enable). If the value of the auto-commit attribute is changed in the middle of thetransaction, the current transaction is committed and a new transaction with the changedvalue is started.

If you disable autocommit for an SQLJ connection, you need to perform explicit commit orrollback operations. You do this using execution clauses that contain the SQL COMMITor ROLLBACK statements.

To commit a transaction in an SQLJ program, use a statement like this:#sql [myConnCtx] {COMMIT};

To roll back a transaction in an SQLJ program, use a statement like this:#sql [myConnCtx] {ROLLBACK};

Ponašanje iteratora u transakcijama

S obzirom da se iteratori većinski ponašaju kao i kursori, za očekivati je da se prilikomizvršavanja naredbe COMMIT svi iteratori zatvaraju. Da bismo sprečili ovo ponašanje,potrebno je u deklaraciji iteratora postaviti parametar holdability na vrednost true, kaou narednom primeru:#sql public iterator testUpdateIter implements sqlj.runtime.ForUpdate

with(updateColumns = "EMPNO", holdability=true)(int, String);

10.1.2 Transaction isolation level

To set the isolation level for a unit of work within an SQLJ program, use the SET TRANS-ACTION ISOLATION LEVEL clause.

Table 10.1 shows the values that you can specify in the SET TRANSACTION ISOLATIONLEVEL clause and their data server equivalents.

Tabela 10.1: Equivalent SQLJ and data server isolation levels.SET TRANSACTION value Data server isolation levelSERIALIZABLE Repeatable readREPEATABLE READ Read stabilityREAD COMMITTED Cursor stabilityREAD UNCOMMITTED Uncommitted read

For example:#sql [myConnCtx] {

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE};

Page 219: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.1 Ostvarivanje transakcija u SQLJ aplikacijama 219

10.1.3 Savepoints

A savepoint defines a particular state of the database during a unit of work or transaction.A savepoint is required if we want to roll back the transaction to a particular state insteadof rolling back to the start of the transaction. DB2 Universal driver provides the methodset Savepoint of the Connection object to set a savepoint during the transaction.

A savepoint can be release by calling the method releaseSavePoint method of the Connec-tion object. Releasing a savepoint will release all the savepoints created after the releasedsavepoint. After releasing the savepoint, the transaction cannot be rolled back to thereleased savepoint or any of the savepoints created subsequently.

A transaction can be rolled back to a savepoint by calling the rollback method and givingthe savepoint variable as an argument to this method.

Any cursor opened inside a savepoint will remain open even after rollback to the savepointbut can go to an invalid state if they depend on some DDL statements which were rolledback.

In this example, we will create a transaction having multiple savepoints and we will seehow to use them:

1. Creating a connection object and a connection context: Before we can execute anySQL statement against the database, we first need to set up the database connection.To do that, we need to load the database driver and then create a connection object.Also, we will create a default context:Class.forName("com.ibm.db2.jcc.DB2Driver ").newInstance();String url = "jdbc:db2:sample";Connection con = DriverManager.getConnection(url);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);

2. AutoCommit: Disable the AutoCommit option by using the setAutoCommit() met-hod:con.setAutoCommit(false);

3. In SQLJ, we can directly embed the SQL statements, so we can also embed theSAVEPOINT statement. Let’s insert a few records in a test table and create a fewsavepoints:#sql {INSERT INTO TEST_SVPT VALUES (1, 'Bob', 101)};#sql {SAVEPOINT SAVEPOINT1 ON ROLLBACK RETAIN CURSORS};

#sql {INSERT INTO TEST_SVPT VALUES (2, 'Mat', 102)};#sql {SAVEPOINT SAVEPOINT2 ON ROLLBACK RETAIN CURSORS};

#sql {INSERT INTO TEST_SVPT VALUES (3, 'Joe', 103)};#sql {SAVEPOINT SAVEPOINT3 ON ROLLBACK RETAIN CURSORS};

#sql {INSERT INTO TEST_SVPT VALUES (4, 'Pat', 104)};

4. By now, we have inserted four records in the table and we have three savepoints.We can use a ROLLBACK TO command to roll back to any savepoint:#sql {ROLLBACK TO SAVEPOINT SAVEPOINT3};#sql {ROLLBACK TO SAVEPOINT SAVEPOINT1};

Page 220: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

220 Glava 10. SQLJ, transakcije i višekorisničko okruženje

10.2 Rad u višekorisničkom okruženju

U poglavlju 6 smo govorili detaljno o problemima konkurentnog rada sa bazom podataka.Aplikacije pisane u programskom jeziku Java, bilo one SQLJ ili JDBC, takođe ”boluju” odistih problema kao i aplikacije koje smo pisali u programskom jeziku C. Zbog toga ćemoimati na umu sve napomene koje smo tada uveli, sa određenim napomenama koje slede udaljem tekstu.

S obzirom da se u programskom jeziku Java greške prijavljuju kroz objekte klase SQLE-xception, proveru da li je došlo do nekog problema konkurentnog okruženja možemo izvršitiproverom koda greške, pozivom metoda getErrorCode() nad datim objektom klase. Zaštonam je ova informacija važna? Prisetimo se da, ukoliko dođe do nekog problema konku-rentnog okruženja, DB2 SUBP šalje grešku −911 ili −913. U tom slučaju, potrebno jeizvršiti obradu isteka vremena ili pojave mrtve petlje, i poništiti eventualne izmene.

Na primer:// U main funkciji:

try{

NekiIterator iter;

// Kod koji moze da dovede do problema// u visekorisnickom okruzenju

}catch(SQLException e){

if(e.getErrorCode() == −911 || e.getErrorCode() == −913){

obradiCekanje();iter = otvoriIterator();

}}

// ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗// Izvan main funkcije:

public static void obradiCekanje(){

System.out.println("Objekat je zakljucan od strane druge transakcije\n.Sacekati neko vreme.");

try{

#sql {ROLLBACK};System.out.println("−−−Rollback−−−");

}catch(Exception e) {}

}

public static NekiIterator otvoriIterator() throws Exception{

NekiIterator iter = null;

// #sql iter = { SELECT upit };

return iter;}

Page 221: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.2 Rad u višekorisničkom okruženju 221

Naredni primeri ilustruju konstrukciju SQLJ aplikacija koje koriste transakcioni rad uvišekorisničkom okruženju.

Primer 10.1 — Čas 09 — 11. Napisati SQLJ aplikaciju koja za svaki predmet koji jeobavezan na smeru čiji je identifikator 201, pita korisnika da li želi da poveća brojbodova za 1. Ukoliko je odgovor korisnika ”d” ili ”D”, izvršava se odgovarajuća naredba.Zadatak uraditi tako da aplikacija radi u višekorisničkom okruženju. Obrada jednogpredmeta treba da predstavlja jednu transakciju.

Rešenje.

Kod 10.1: Primeri/cas09/primer11/UpdatePredmet.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;

#sql public iterator UpdatePredmet implements sqlj.runtime.ForUpdatewith(updateColumns = "bodovi", holdability=true)(int, String, short

);

Kod 10.2: Primeri/cas09/primer11/Primer.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;import java.lang.Integer;

public class Primer{

public static void main(String argv[]){

try{

// Host promenljiveint id_predmeta = 0;String naziv = null;short bodovi = 0;

// Niz u kojem cemo smestiti obradjene predmete (tj. njihoveidentifikatore)

ArrayList<Integer> obradjeni = new ArrayList<Integer>();

// Parser standardnog ulazaScanner skener = new Scanner(System.in);

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/vstud";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("\n−−−Connected−−−");

// Podesavanje isteka vremena za katance#sql {

Page 222: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

222 Glava 10. SQLJ, transakcije i višekorisničko okruženje

SET CURRENT LOCK TIMEOUT 5};

// Deklaracija promenljive koja referise na objekat iteratoraUpdatePredmet iter = otvoriIterator();

while(!iter.endFetch()){

// Proverava se da li trazeni katanac ne dovodi do nekog// od problema konkurentog izvrsavanjatry{

#sql {fetch :iterinto :id_predmeta, :naziv, :bodovi

};}catch(SQLException e){

if(e.getErrorCode() == −911 || e.getErrorCode() == −913){

System.out.println("Objekat je zakljucan od stranedruge transakcije.\nSacekati neko vreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

iter = otvoriIterator();continue;

}}

// Ako predmet nije ranije obradjenif(!obradjeni.contains(id_predmeta)){

// Ispisuju se procitane vrednosti za predmetSystem.out.printf("%5d %−20s %5d\n", id_predmeta, naziv,

bodovi);

// Odgovor korisnikachar c;

System.out.println("Da li korisnik zeli da promeni brojkredita za dati predmet? (d ili n)");

c = skener.next().charAt(0);

if(c == 'd' || c == 'D'){

// Azuriranje pozicioniranom UPDATE naredbom:// Proverava se da li trazeni katanac ne dovodi do

nekog// od problema konkurentog izvrsavanjatry{

#sql {update predmetset bodovi = bodovi + 1where current of :iter

};}catch(SQLException e)

Page 223: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.2 Rad u višekorisničkom okruženju 223

{if(e.getErrorCode() == −911 || e.getErrorCode() ==

−913){

System.out.println("Objekat je zakljucan odstrane druge transakcije.\nSacekati nekovreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

iter = otvoriIterator();continue;

}}

// Potvrda obrade.// Iterator se ne zatvara, vec se pozicionira ispred

narednog reda rezultujuce tabele,// jer je specifikovana opcija holdability = true

prilikom njegove definicijeSystem.out.println("−−−Commit−−−");#sql { COMMIT };

}

// Evidentiranje obradeobradjeni.add(id_predmeta);

}} // kraj while petlje

iter.close();

// Ukidanje isteka vremena za katance#sql {

SET CURRENT LOCK TIMEOUT NULL};

#sql { COMMIT };

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

// try blok je neophodan zbog SQL naredbe ROLLBACKtry{

#sql { ROLLBACK };System.out.println("\n−−−Rollback−−−");

}catch(Exception e) {}

}catch (Exception e2){

System.out.println("−−−Exception−−−");

Page 224: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

224 Glava 10. SQLJ, transakcije i višekorisničko okruženje

e2.printStackTrace();

// try blok je neophodan zbog sql naredbe ROLLBACKtry{

#sql { ROLLBACK };System.out.println("\n−−−Rollback−−−");

}catch(Exception e) {}

}}

public static UpdatePredmet otvoriIterator() throws Exception{

UpdatePredmet iter = null;

#sql iter = {select id_predmeta, rtrim(naziv), bodovifrom predmetwhere id_predmeta in (

select id_predmetafrom obavezan_predmetwhere id_smera = 201

)fetch first 5 rows only

};

return iter;}

}

Primer 10.2 — Čas 09 — 12. Za svaki od narednih zahteva napisati po jednu SQLJaplikaciju koja:

1. Kreira tabelu stipendije sa sledećim kolonama:• naziv varchar(100) not null,• godina smallint not null,• broj_stipendista smallint not null,• visina_stipendije smallint,• min prosek float,• napomena varchar(50).

Aplikacija treba radi u višekorisničkom okruženju.

2. Unosi podatke o nekoliko stipendija u tabelu stipendije. Izračunati i broj unetihredova. U slučaju da je broj unetih redova jednak nuli, ispisati poruku ”Nijedanred nije dodat”, a inače ispisati poruku u unetom broju redova. Aplikacija trebaradi u višekorisničkom okruženju.

3. Za svaku stipendiju, pita korisnika da li želi da promeni broj studenata za tu stipen-diju i ukoliko je odgovor korinika potvrdan, od korisnika traži da unese novi brojstudenata i izvršava odgovarajuću naredbu. Aplikacija treba radi u višekorisnič-kom okruženju. Obrada jedne stipendije treba da predstavlja jednu transakciju.

Page 225: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.2 Rad u višekorisničkom okruženju 225

4. Za svaku stipendiju, pita korisnika da li želi da obriše tu stipendiju i ukoliko jeodgovor korinika potvrdan, izvršava odgovarajuću naredbu. Aplikacija treba radiu višekorisničkom okruženju. Obrada jedne stipendije treba da predstavlja jednutransakciju.

Rešenje.

Kod 10.3: Primeri/cas09/primer12/tabela.sqlcreate table stipendije (

naziv varchar(100) not null,godina smallint not null,broj_stipendista smallint not null,visina_stipendije smallint,min_prosek float,napomena varchar(50)

);

Kod 10.4: Primeri/cas09/primer12/Primer2.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;import java.lang.Integer;

public class Primer2{

public static void main(String argv[]){

try{

// Host promenljiveint id_predmeta = 0;String naziv = null;int updateCount;

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/vstud";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("\n−−−Connected−−−");

// Podesavanje isteka vremena za katance#sql {

SET CURRENT LOCK TIMEOUT 5};

ExecutionContext execCtx = new ExecutionContext();

boolean stipendije_su_uspesno_unete = false;

while(!stipendije_su_uspesno_unete){

try

Page 226: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

226 Glava 10. SQLJ, transakcije i višekorisničko okruženje

{#sql [execCtx] {

INSERT INTO stipendijeVALUES ('Stipendija Ministarstva prosvete', 2010, 40,

1000, 8.0, null),('Stipendija Fonda za mlade talente', 2010, 20,

5000, 9.0, null),('Stipendija kompanije Coca Cola', 2010, 2,

8000, 8.5, null)};

updateCount = execCtx.getUpdateCount();if (updateCount == 0){

System.out.println("Nijedan red nije dodat");}else{

System.out.println(updateCount + " red(a) je dodat(o)");

}

stipendije_su_uspesno_unete = true;}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() == −913){

System.out.println("Objekat je zakljucan od stranedruge transakcije\n. Sacekati neko vreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

}}

}

// Ukidanje isteka vremena za katance#sql {

SET CURRENT LOCK TIMEOUT NULL};

#sql {COMMIT

};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

// try blok je neophodan zbog SQL naredbe ROLLBACKtry{

#sql { ROLLBACK };

Page 227: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.2 Rad u višekorisničkom okruženju 227

System.out.println("\n−−−Rollback−−−");}catch(Exception e) {}

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

// try blok je neophodan zbog sql naredbe ROLLBACKtry{

#sql { ROLLBACK };System.out.println("\n−−−Rollback−−−");

}catch(Exception e) {}

}}

}

Kod 10.5: Primeri/cas09/primer12/UpdateStipendije.sqljimport sqlj.runtime.∗;

#sql public iterator UpdateStipendije implements ForUpdatewith(updateColumns = "broj_stipendista, visina_stipendije",

holdability=true)(String, int, int, int, float);

Kod 10.6: Primeri/cas09/primer12/Primer2update.sqljimport java.sql.∗;import sqlj.runtime.ref.∗;import java.util.∗;import java.lang.Integer;

public class Primer2update{

public static void main(String argv[]){

try{

// Host promenljiveint godina = 0, broj_stipendista = 0, visina_stipendije = 0, brojSt

= 0, visinaSt, c, c1;float min_prosek = 0;String naziv = null;

// Parser standardnog ulazaScanner skener = new Scanner(System.in);

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/vstud";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(false);

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("\n−−−Connected−−−");

Page 228: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

228 Glava 10. SQLJ, transakcije i višekorisničko okruženje

// Podesavanje isteka vremena za katance#sql {

SET CURRENT LOCK TIMEOUT 5};

UpdateStipendije iter = otvoriIterator();

while (!iter.endFetch()){

try{

#sql {fetch :iterinto :naziv, :godina, :broj_stipendista, :

visina_stipendije, :min_prosek};

}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() == −913){

System.out.println("FETCH: Objekat je zakljucan odstrane druge transakcije.\nSacekati neko vreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

iter = otvoriIterator();continue;

}}

System.out.println(naziv + " god:" + godina +" broj stipendista: " + broj_stipendista +" visina stipendije: " + visina_stipendije +" min prosek: " + min_prosek);

System.out.println("Da li korisnik zeli da promeni brojstudenata za navedenu stipendiju? (d ili n)");

c = skener.next().charAt(0);

if (c == 'd' || c == 'D'){

System.out.println("Unesite broj studenata");brojSt = skener.nextInt();

// Azuriranje pozicionirajucom UPDATE naredbom:try{

#sql {UPDATE stipendijeSET broj_stipendista = :brojStWHERE CURRENT OF :iter

};}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() ==−913)

{

Page 229: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.2 Rad u višekorisničkom okruženju 229

System.out.println("UPDATE 1: Objekat je zakljucanod strane druge transakcije.\nSacekati nekovreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

iter = otvoriIterator();continue;

}}

}

System.out.println("Da li korisnik zeli da promeni visinustipendije za navedenu stipendiju? (d ili n)");

c1 = skener.next().charAt(0);

if (c1 == 'd' || c1 == 'D'){

System.out.println("Unesite novu visinu stipendije");visinaSt = skener.nextInt();

// Azuriranje pozicionirajucom UPDATE naredbom:try{

#sql {UPDATE stipendijeSET visina_stipendije = :visinaStWHERE CURRENT OF :iter

};}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() ==−913)

{System.out.println("UPDATE 2: Objekat je zakljucan

od strane druge transakcije.\nSacekati nekovreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

iter = otvoriIterator();continue;

}}

}

if (c == 'd' || c == 'D' || c1 == 'd' || c1 == 'D'){

System.out.println("−−−Commit−−−");#sql { COMMIT };

}} // kraj while petlje

iter.close();

// Ukidanje isteka vremena za katance#sql {

SET CURRENT LOCK TIMEOUT NULL

Page 230: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

230 Glava 10. SQLJ, transakcije i višekorisničko okruženje

};

#sql { COMMIT };

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

// try blok je neophodan zbog SQL naredbe ROLLBACKtry{

#sql { ROLLBACK };System.out.println("\n−−−Rollback−−−");

}catch(Exception e) {}

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

// try blok je neophodan zbog sql naredbe ROLLBACKtry{

#sql { ROLLBACK };System.out.println("\n−−−Rollback−−−");

}catch(Exception e) {}

}

}

public static UpdateStipendije otvoriIterator() throws Exception{

UpdateStipendije iter = null;

#sql iter = {select naziv, godina, broj_stipendista, visina_stipendije,

min_prosekfrom stipendije

};

return iter;}

}

Kod 10.7: Primeri/cas09/primer12/DeleteStipendije.sqljimport sqlj.runtime.∗;

#sql public iterator DeleteStipendije implements ForUpdatewith(holdability=true)(String, int, int, int, float);

Page 231: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.2 Rad u višekorisničkom okruženju 231

Kod 10.8: Primeri/cas09/primer12/Primer2delete.sqljimport java.sql.∗;import sqlj.runtime.∗;import sqlj.runtime.ref.∗;import java.util.∗;import java.lang.Integer;

public class Primer2delete{

public static void main(String argv[]){

try{

// Host promenljiveint godina = 0, broj_stipendista = 0, visina_stipendije = 0, brojSt

= 0, visinaSt, c;float min_prosek = 0;String naziv = null;

// Parser standardnog ulazaScanner skener = new Scanner(System.in);

// Povezivanje sa bazomString url = "jdbc:db2://localhost:50001/vstud";Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

Connection con = DriverManager.getConnection(url, "student", "abcdef");

con.setAutoCommit(true); // AUTO COMMIT! :)

DefaultContext ctx = new DefaultContext(con);DefaultContext.setDefaultContext(ctx);System.out.println("\n−−−Connected−−−");

// Podesavanje isteka vremena za katance#sql {

SET CURRENT LOCK TIMEOUT 5};

DeleteStipendije iter = otvoriIterator();

while (!iter.endFetch()){

try{

#sql {fetch :iterinto :naziv, :godina, :broj_stipendista, :

visina_stipendije, :min_prosek};

}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() == −913){

System.out.println("FETCH: Objekat je zakljucan odstrane druge transakcije.\nSacekati neko vreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

Page 232: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

232 Glava 10. SQLJ, transakcije i višekorisničko okruženje

iter = otvoriIterator();continue;

}}

System.out.println(naziv + " god:" + godina +" broj stipendista: " + broj_stipendista +" visina stipendije: " + visina_stipendije +" min prosek: " + min_prosek);

System.out.println("Da li korisnik zeli da obrise podatke zanavedenu stipendiju? (d ili n)");

c = skener.next().charAt(0);

if (c == 'd' || c == 'D'){

// Brisanje pozicionirajucom DELETE naredbom:try{

#sql {DELETE FROM stipendijeWHERE CURRENT OF :iter

};}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() ==−913)

{System.out.println("DELETE: Objekat je zakljucan od

strane druge transakcije.\nSacekati neko vreme.");

#sql { ROLLBACK };System.out.println("−−−Rollback−−−");

iter = otvoriIterator();continue;

}}

}} // kraj while petlje

// Ukidanje isteka vremena za katance#sql {

SET CURRENT LOCK TIMEOUT NULL};

// Raskid konekcije sa bazomctx.close();con.close();System.out.println("\n−−−Disconnect−−−");

}// Obrada izuzetakacatch(SQLException e1){

System.out.println("−−−SQL Exception−−−");System.out.println(e1.getMessage());

// try blok je neophodan zbog SQL naredbe ROLLBACK

Page 233: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

10.2 Rad u višekorisničkom okruženju 233

try{

#sql { ROLLBACK };System.out.println("\n−−−Rollback−−−");

}catch(Exception e) {}

}catch (Exception e2){

System.out.println("−−−Exception−−−");e2.printStackTrace();

// try blok je neophodan zbog sql naredbe ROLLBACKtry{

#sql { ROLLBACK };System.out.println("\n−−−Rollback−−−");

}catch(Exception e) {}

}

}

public static DeleteStipendije otvoriIterator() throws Exception{

DeleteStipendije iter = null;

#sql iter = {select naziv, godina, broj_stipendista, visina_stipendije,

min_prosekfrom stipendije

};

return iter;}

}

Zadatak 10.1 Uraditi prethodne primere korišćenjem imenovanih iteratora umesto po-zicionih. ■

Page 234: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 235: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11. Programiranje JDBC aplikacija

In this chapter, we discuss the fundamentals of application development using DB2 JDBCand guide you through the Java application development process.

11.1 Kreiranje konekcije

A connection to a database can be obtained using the DriverManager class of the java.sqlpackage.

Java.sql package defines the classes and interfaces required for the JDBC program to accessthe relation data stored in a database. These APIs can be used to connect to the relationaldatabase and manipulate the data (insert, update, delete, and so on) stored in tabularform using the SQL standard. The interfaces defined in this package are implemented bythe driver specific classes and the definition can differ from vendor to vendor.

Before getting connection, the driver specific classes must be loaded and registered to theDriverManager. Any number of drivers can be loaded and registered with the DriverMa-nager using the forName method:class ProgramName{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

Page 236: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

236 Glava 11. Programiranje JDBC aplikacija

// ...}

Java supports a special block, called static block (also called static clause) which can beused for static initializations of a class. This code inside static block is executed onlyonce: the first time you make an object of that class or the first time you access a staticmember of that class (even if you never make an object of that class). We will be usingstatic blocks in our programs to load and register DB2 JDBC driver, as shown in the codeexample above.

The forName method take a string argument whose value is the name of the package whichimplements the interfaces defined in java.sql package.

The connection to a database can be obtained by calling the getConnection method ofDriverManager class. This method takes a string value (URL) as an input, which givesthe information required to connect to the database. A typical URL format for Type 4driver is:jdbc:db2://<servername>:<port number>/<database name>

The code in the following example returns the connection as Connection class object:public static void main(String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

if (argv.length == 0){

con = DriverManager.getConnection(url, "student", "abcdef");}else if (argv.length == 2){

String userid = argv[0];String passwd = argv[1];con = DriverManager.getConnection(url,userid,passwd);

}else{

throw new Exception("\n Usage: java ProgramName[,username,password]\n");

}

// ...}

11.2 Obrada SQL grešaka

Just like any Java program, in JDBC, exception handling is done using the try-catchblock. A DB2 application throws a SQLException whenever it encounters a SQL error ora SQLWarning whenever it encounters a SQL warning when executing SQL statements.

An object of SQLException is created and thrown whenever an error occurs while accessingthe database. The SQLException object provides the information listed in Table 11.1.

Page 237: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.2 Obrada SQL grešaka 237

Tabela 11.1: SQLException information.

SQLExceptioninformation Description

Method toretrieve thisinformation

Message Textual representation of the error code. getMessageSQLState The SQLState string. getSQLState

ErrorCode An integer value that indicates the errorwhich caused the exception to be thrown. getErrorCode

Apart from the above information, the DB2 JCC driver provides an extra interfacecom.ibm.db2.jcc.DB2Diagnosable. This interface gives more information regarding theerror that occurred while accessing the DB2 database.

If multiple SQLExceptions are thrown, they are chained. The next exception informationcan be retrieved by calling the getNextException method of the current SQLExceptionobject. This method will return null if the current SQLException object is last in thechain. A while loop in the catch block of the program can be used to retrieve all theSQLException objects one by one.

Connection con = null;

try{

con = DriverManager.getConnection(url, username, password);

// code which can throw SQLException goes here}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

Page 238: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

238 Glava 11. Programiranje JDBC aplikacija

11.3 Upravljanje podacima

After getting the connection, data can be selected, inserted, updated, or deleted from therelational tables using SQL statements. JDBC driver implements two interfaces Statementand PreparedStatement for this purpose. An object of any of these classes is required forrunning an SQL statement.

11.3.1 Interfejs Statement

An object of Statement (or class implementing the Statement interface) can be used toexecute the SQL statement which does not contain parameter markers. An object can becreated from the Connection object using createStatement method.

Any number of statements can be created for a particular connection object.

Statement interface defines executeQuery and executeUpdate methods to execute a querystatement. The executeQuery method is used when the result set is expected (for exam-ple, for the SELECT statement) as output of the query. Alternatively, executeUpdatemethod is used for updating the database contents (for example, INSERT, UPDATE, andDELETE statements). The executeQuery method returns the ResultSet object, which re-presents a set of rows returned by the SELECT query. This ResultSet object can be usedto fetch the result row by row. Method executeUpdate returns an integer value, whichindicates the number of rows updated, inserted, or deleted from the database based onthe type of SQL statement.

The following example illustrates the retrieval of data using the Statement.executeQuerymethod. This method returns a result table in a ResultSet object. After you obtain theresult table, you need to use ResultSet methods to move through the result table andobtain the individual column values from each row.

To retrieve rows from a table using a SELECT statement with no parameter markers, youneed to perform these steps:

1. Invoke the Connection.createStatement method to create a Statement object.2. Invoke the Statement.executeQuery method to obtain the result table from the SE-

LECT statement in a ResultSet object.3. In a loop, position the cursor using the next method, and retrieve data from each

column of the current row of the ResultSet object using getXXX methods. XXXrepresents a data type.

4. Invoke the ResultSet.close method to close the ResultSet object.5. Invoke the Statement.close method to close the Statement object when you have

finished using that object.

Primer 11.1 — Čas 10 — 01. Napisati JDBC aplikaciju koja izlistava šifre i nazive svihpredmeta koji imaju više od 20 ESPB bodova.

Rešenje.

Kod 11.1: Primeri/cas10/src/primer01/Primer.javapackage primer01;

import java.sql.∗;

public class Primer

Page 239: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 239

{

// Staticki blok koji sluzi za ucitavanje JDBC DB2 drajvera.// Izvrsava se kada se prvi put instancira objekat ove klase,// ili kada se prvi put pozove staticki metod.static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main(String argv[]){

// Objekat koji ce sadrzati konekcijuConnection con = null;// URL za JDBC konekciju tipa 4String url = "jdbc:db2://localhost:50001/vstud";

try{

// U zavisnosti od broja argumenata programa,// kreiramo konekciju na bazi podataka zadatoj u promenljivoj url,// koriscenjem DriverManager.getConnection metoda.// Argumenti za korisnicko ime i lozinku su obavezni!if (argv.length == 0){

con = DriverManager.getConnection(url, "student", "abcdef");}else if (argv.length == 2){

String userid = argv[0];String passwd = argv[1];con = DriverManager.getConnection(url, userid, passwd);

}else{

throw new Exception("\n Usage: java Primer [username password]\n");

}

// Iskljucujemo automatsko pohranjivanje izmenacon.setAutoCommit(false);

// Kreiramo objekat naredbe (Statement)Statement stmt = con.createStatement();

// SQL upit ili naredbu koju zelimo da izvrsimo// zapisujemo kao niskuString queryStr =

"SELECT sifra, naziv " +"FROM predmet " +"WHERE bodovi > 20";

// Za izvrsavanje upita koristimo Statement.executeQuery metod.// Ovaj metod vraca objekat klase ResultSet,// koji sadrzi rezultate upita (kursor).

Page 240: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

240 Glava 11. Programiranje JDBC aplikacija

ResultSet rs = stmt.executeQuery(queryStr);

// Ispisujemo zaglavljeSystem.out.printf("%−15s %−50S\n\n", "SIFRA", "NAZIV");

// Metodom ResultSet.next pozicioniramo kursor na naredni red.// Ako vise nema redova, metod ce vratiti vrednost false.// Inace, vratice true, pa mozemo da ga koristimo kao uslov u

petljiwhile (rs.next()){

// Izdvajamo podatke koriscenjem familije metoda ResultSet.getXXX,

// gde je XXX neki tip podataka,// a argument je broj kolone koja se dohvata iz projekcije

upita.String sifra = rs.getString(1);String naziv = rs.getString(2);

System.out.printf("%−15s %−50S\n", sifra.trim(), naziv.trim());}

// Zatvaramo kursorrs.close();// Zatvaramo naredbustmt.close();

// S obzirom da je sve proslo kako treba ako se doslo do ove tacke,// pohranjujemo izmene pre raskidanje konekcijecon.commit();

// Raskidamo konekciju ka bazi podatakacon.close();

}// Obrada SQL gresakacatch (SQLException e){

// Ispisujemo sve informacije na standardni izlazSystem.out.println(

"SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

// U slucaju neuspeha, ponistavamo eventualne izmenetry{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}// Obrada drugih gresakacatch (Exception e){

e.printStackTrace();

System.exit(1);}

Page 241: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 241

}

}

The Statement.executeUpdate is one of the JDBC methods that you can use to updatetables. You can use the Statement.executeUpdate method to do the following things:

• Execute data definition statements, such as CREATE, ALTER, DROP, GRANT,REVOKE.

• Execute INSERT, UPDATE, DELETE, and MERGE statements that do not containparameter markers.

To execute these SQL statements, you need to perform these steps:

1. Invoke the Connection.createStatement method to create a Statement object.2. Invoke the Statement.executeUpdate method to perform the SQL operation.3. Invoke the Statement.close method to close the Statement object.

Method Statement.executeUpdate returns an integer which represents the number of up-dated rows.

Primer 11.2 — Čas 10 — 02. Napisati JDBC aplikaciju koja svim predmetima koji imaju5 ESPB bodova, postavlja broj bodova na 6. Nakon toga ispisati broj ažuriranih redova.

Rešenje.

Kod 11.2: Primeri/cas10/src/primer02/Primer.javapackage primer02;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

if (argv.length == 0){

con = DriverManager.getConnection(url, "student", "abcdef");}else if (argv.length == 2){

Page 242: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

242 Glava 11. Programiranje JDBC aplikacija

String userid = argv[0];String passwd = argv[1];con = DriverManager.getConnection(url, userid, passwd);

}else{

throw new Exception("\n Usage: java Primer2[,username,password]\n");

}

con.setAutoCommit(false);

Statement updStmt = con.createStatement();String updStr =

"UPDATE predmet " +"SET bodovi = 6 " +"WHERE bodovi = 5";

System.out.println("Azuriram bodove u tabeli PREDMET...");

// Ovoga puta koristimo metod Statement.executeUpdate// za izvrsavanje SQL naredbe UPDATE.// Metod vraca broj azuriranih redova.int numRows = updStmt.executeUpdate(updStr);

System.out.println("Broj azuriranih redova: " + numRows);

updStmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

Page 243: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 243

Primer 11.3 — Čas 10 — 03. Napisati JDBC aplikaciju koja u tabelu PREDMET unosipodatak o predmetu čiji je identifikator 2001, šifra Pred1, naziv Predmet 1, koji se slušau prvom semestru i nosi 5 ESPB bodova.

Rešenje.

Kod 11.3: Primeri/cas10/src/primer03/Primer.javapackage primer03;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

String url = "jdbc:db2://localhost:50001/vstud";Connection con = null;

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

String sql ="INSERT INTO predmet " +"VALUES (20001, 'Pred1', 'Predmet 1', 1, 6)";

Statement stmt = con.createStatement();

System.out.println("Unosim podatke u tabelu PREDMET...");

// Metod executeUpdate se koristi ne samo za azuriranje,// vec i za unos, brisanje, i slicne naredbe.int insertCount = stmt.executeUpdate(sql);

System.out.println("Broj unetih redova: " + insertCount);

stmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +

Page 244: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

244 Glava 11. Programiranje JDBC aplikacija

"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

11.3.2 Interfejs PreparedStatement

An object of PreparedStatement (or a class implementing the PreparedStatement inter-face) can be used to run the queries, which can contain parameter markers. A Prepared-Statement object can be created using the prepareStatement method of Connection object.PreparedStatement extends the Statement interface.

If the SQL statement contains parameter markers, the values for these parameter markersneed to be set before executing the statement. Value can be set using setXXX methodsof PreparedStatement object where XXX denoted the data type of the parameter marker.setXXX methods are also called setter methods.

The following are the examples of setXXX methods:

• setInt,• setString,• setDouble,• setBytes,• setClob,• setBlob

After setting the parameter values, the SQL statement can be executed using any of theexecuteQuery, executeUpdate, or execute method based on the SQL type.

Primer 11.4 — Čas 10 — 04. Napisati JDBC aplikaciju koja svim predmetima koji imajuX ESPB bodova, postavlja broj bodova na Y. Nakon toga ispisati broj ažuriranih redova.Brojevi X i Y se prosleđuju kao argumenti aplikacije.

Rešenje.

Kod 11.4: Primeri/cas10/src/primer04/Primer.javapackage primer04;

import java.sql.∗;

Page 245: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 245

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

// JDBC koristi iskljucivo dinamicke SQL naredbe,// tako da se u JDBC ne koriste maticne promenljive,// kao sto je to bio slucaj u SQLJ.// S obzirom da su nam vrednosti za bodove u klauzama SET i WHERE

nepoznate do faze izvrsavanja,// potrebno je da koristimo parametarske oznake na tim mestima.String updateStr =

"UPDATE predmet " +"SET bodovi = ? " +"WHERE bodovi = ?";

PreparedStatement pUpd = con.prepareStatement(updateStr);

// Postavljamo odgovarajuce vrednosti za parametarske oznake// na osnovu argumenata komandne linijeif(argv.length > 1){

// Prvu parametarsku oznaku menjamo celim brojem// koji je prvi argument komandne linijepUpd.setInt(1, Integer.parseInt(argv[0]));

// Drugu parametarsku oznaku menjamo celim brojem// koji je drugi argument komandne linijepUpd.setInt(2, Integer.parseInt(argv[1]));

}else{

throw new Exception("\n Usage: java Primer4 stariBodovinoviBodovi\n");

}

// Izvrsavamo naredbu i ispisujemo broj azuriranih redovaint numRows = pUpd.executeUpdate();System.out.println("Broj azuriranih redova: " + numRows);

pUpd.close();

Page 246: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

246 Glava 11. Programiranje JDBC aplikacija

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

Primer 11.5 — Čas 10 — 05. Napisati JDBC aplikaciju koja iz tabele predmet brišepodatak o predmetu čija se šifra zadaje kao argument komandne linije. Ukoliko se nenavede šifra, iz tabele PREDMET obrisati podatke o predmetu čija je šifra Pred1.

Rešenje.

Kod 11.5: Primeri/cas10/src/primer05/Primer.javapackage primer05;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

Connection con = null;

Page 247: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 247

String url = "jdbc:db2://localhost:50001/vstud";

try{

// Ukoliko nema argumenata komandne linije,// neka ovo bude sifra predmeta cije podatke brisemoString sifra = "Pred1";

if (argv.length > 0){

sifra = argv[0];}

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

String sql ="DELETE FROM predmet " +"WHERE sifra = ?";

PreparedStatement pstmt = con.prepareStatement(sql);

// Umesto parametarske oznake u DELETE naredbi koju cemo izvrsiti,// potrebno je da figurise niska koja se nalazi u promenljivoj

sifrapstmt.setString(1, sifra);int deleteCount = pstmt.executeUpdate();

System.out.println("Broj obrisanih redova: " + deleteCount);

pstmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

Page 248: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

248 Glava 11. Programiranje JDBC aplikacija

Primer 11.6 — Čas 10 — 06. Napisati JDBC aplikaciju kojom se izdvajaju indeks, ime,prezime i naziv smera svih studenata koji su položili tačno N predmeta, kao i spisak tihpredmeta (naziv i ocena). Broj N se zadaje kao argument komandne linije, a ukoliko sene navede, podrazumeva se da je 10.

Rešenje.

Kod 11.6: Primeri/cas10/src/primer06/upit.sqlwith ispitBr as (

select indeksfrom ispitwhere ocena > 5

and status_prijave = 'o'group by indekshaving count(∗) = ?

)select d.indeks, ime, prezime, s.naziv, p.naziv, i.ocenafrom dosije d

join ispitBr ibron d.indeks = ibr.indeks

join smer son d.id_smera = s.id_smera

join ispit ion d.indeks = i.indeks

join predmet pon i.id_predmeta = p.id_predmeta

where i.ocena > 5and i.status_prijave = 'o'

order by d.indeks, ime, prezime, s.naziv, p.naziv

Kod 11.7: Primeri/cas10/src/primer06/Primer.javapackage primer06;

import java.sql.∗;import java.util.∗;import java.io.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

Page 249: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 249

int brojPredmeta = 10;int indeks = 0;

if (argv.length > 0){

brojPredmeta = Integer.parseInt(argv[0]);}

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

// String sql = "" +// "with ispitBr as ( " +// "select indeks " +// "from ispit " +// "where ocena > 5 " +// "and status_prijave = 'o' " +// "group by indeks "+// "having count(∗) = ? " +// ") " +// "select d.indeks, ime, prezime, s.naziv, p.naziv, i.ocena " +// "from dosije d " +// "join ispitBr ibr " +// "on d.indeks = ibr.indeks " +// "join smer s " +// "on d.id_smera = s.id_smera " +// "join ispit i " +// "on d.indeks = i.indeks " +// "join predmet p " +// "on i.id_predmeta = p.id_predmeta " +// "where i.ocena > 5 " +// "and i.status_prijave = 'o' " +// "order by d.indeks, ime, prezime, s.naziv, p.naziv";

// Eclipse aplikacije se pokrecu iz direktorijuma projekta,// dakle, u podrazumevanom slucaju, ˜/IBM/rationalsdp/workspace/

cas10/.// Mozemo koristiti sistemsko svojstvo System.getProperty("user.dir

")// da dohvatimo putanju u kojoj se pokrece aplikacija.Scanner skenerFajla = new Scanner(new File("./bin/primer6/upit.sql

"), "utf−8");StringBuilder sql = new StringBuilder("");String linija = null;

while (skenerFajla.hasNextLine()){

linija = skenerFajla.nextLine();sql.append(linija);sql.append("\n");

}

skenerFajla.close();

// System.out.println(sql.toString());

PreparedStatement pstmt = con.prepareStatement(sql.toString());pstmt.setInt(1, brojPredmeta);

ResultSet result = pstmt.executeQuery();int brojRedova = 0;

Page 250: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

250 Glava 11. Programiranje JDBC aplikacija

while(result.next()){

// Ispisujemo informacije o studentu// samo kad naidjemo na novog studentaif(indeks != result.getInt(1)){

if(indeks != 0){

System.out.print("\n\n\n");}

System.out.println("Indeks: " + result.getInt(1) + "\n" +"Ime: " + result.getString(2).trim() + "\n" +"Prezime: " + result.getString(3).trim() + "\n" +"Smer: " + result.getString(4).trim() + "\n");

brojRedova = 1;}

// Ispisujemo informacije o i−tom predmetuSystem.out.println(

brojRedova + ". predmet: " + result.getString(5).trim() +"\n\t"

+ "ocena: " + result.getInt(6));

// Uvecavamo broj reda++brojRedova;// Pamtimo tekuci indeks za narednu iteracijuindeks = result.getInt(1);

}

pstmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

Page 251: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 251

}

}

11.3.3 Rukovanje nedostajućim vrednostima

Što se tiče rada sa podacima koji su potencijalno nedostajući, na raspolaganju namje metod ResultSet.wasNull, koji je potrebno pozvati odmah nakon pozivanja metoda-dohvatača za neku kolonu. Ukoliko je vrednost za tu kolonu bila NULL, onda će metodwasNull vratiti vrednost true, a inače će vratiti false. Napomenimo da se poziv wasNullmetoda vezuje samo za poslednji poziv metoda getXXX, te samim tim i na poslednju do-hvaćenu kolonu. Zbog toga je potrebno više puta pozivati ovaj metod ukoliko ima višepotencijalno nedostajućih kolona:// ResultSet res = ...

while (res.next()){

int kolona1_notnull = res.getInt(1);

int kolona2_nullable = res.getInt(2);boolean kol2IsNull = res.wasNull();

Date kolona3_nullable = res.getDate(3);boolean kol3IsNull = res.wasNull();

// ...}

Primer 11.7 — Čas 10 — 07. Napisati JDBC aplikaciju kojom se izdvajaju ime, prezimei datum rođenja za sve studentkinje (pol = ’z’) iz tabele DOSIJE. Ukoliko datum rođenjanije poznat, ispisati Nepoznat.

Rešenje.

Kod 11.8: Primeri/cas10/src/primer07/Primer.javapackage primer07;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

Page 252: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

252 Glava 11. Programiranje JDBC aplikacija

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

Statement stmt = con.createStatement();String queryStr =

"SELECT ime, prezime, datum_rodjenja " +"FROM dosije " +"WHERE pol = 'z'";

ResultSet rs = stmt.executeQuery(queryStr);

System.out.printf("%−25s %−25s %−15s \n\n", "IME", "PREZIME", "DATUM");

while (rs.next()){

String ime = rs.getString(1).trim();String prezime = rs.getString(2).trim();String datum = rs.getString(3);// Ukoliko je u tekucem redu kursora datum bio NULL,// onda ce rs.wasNull() biti trueboolean datumIsNull = rs.wasNull();

System.out.printf("%−25s %−25s %−15s \n",ime, prezime, (datumIsNull) ? "NEPOZNAT" : datum.trim());

}

rs.close();stmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

Page 253: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 253

}

Primer 11.8 — Čas 10 — 08. Napisati JDBC aplikaciju kojom se za studenta sa rednimbrojem indeksa 20080250 korisniku nudi da unese datum rođenja ili n/N ukoliko želi daspecifikuje da je datum rođenja nepoznat (u tom slučaju se unosi podatak NULL).

Rešenje.

Kod 11.9: Primeri/cas10/src/primer08/Primer.javapackage primer08;

import java.sql.∗;import java.util.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main(String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

Scanner scanner = new Scanner(System.in);

System.out.println("Uneti datum rodjenja studenta sa brojem indeksa20080250 " +"ili neki od karaktera n/N za nepoznat datum:");

String datum = scanner.next();

scanner.close();

String sql ="UPDATE DOSIJE " +"SET datum_rodjenja = ? " +"WHERE indeks = 20080250";

PreparedStatement stmt = con.prepareStatement(sql);

boolean unosiSeNULL = datum.equalsIgnoreCase("n");

if (unosiSeNULL){

// Postavljanje NULL vrednosti za vrednost parametarske oznake

Page 254: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

254 Glava 11. Programiranje JDBC aplikacija

stmt.setString(1, null);}else{

stmt.setString(1, datum);}

stmt.executeUpdate();

System.out.println("Uspesno je promenjena vrednost na " + (unosiSeNULL ? "NULL" : datum));

stmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

11.3.4 Podešavanje kursora

A ResultSet maintains a cursor, which points to a row in the result set. It works like acursor in database programs. You can scroll the cursor to a specific row in the result setto access or manipulate the column values for that row. The cursor can point to only onerow at a time. The row to which it points at a point in time is called the current row.There are different ways to move the cursor of a ResultSet to a row in the result set.

The following three properties of a ResultSet need to be discussed before you can look atan example:

• Scrollability• Concurrency• Holdability

Page 255: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 255

Scrollability determines the ability of the ResultSet to scroll through the rows. By default,a ResultSet is scrollable only in the forward direction. When you have a forward-onlyscrollable ResultSet, you can move the cursor starting from the first row to the last row.Once you move to the last row, you cannot reuse the ResultSet because you cannot scrollback in a forward-only scrollable ResultSet. You can also create a ResultSet that can scrollin the forward as well as the backward direction. We call this ResultSet a bidirectionalscrollable ResultSet.

A bidirectional scrollable ResultSet has another property called update sensitivity. Itdetermines whether the changes in the underlying database will be reflected in the resultset while you are scrolling through its rows. A scroll sensitive ResultSet shows you changesmade in the database, whereas a scroll insensitive one would not show you the changesmade in the database after you have opened the ResultSet. The following three constantsin the ResultSet interface are used to specify the scrollability of a ResultSet:

• TYPE_FORWARD_ONLY: Allows a ResultSet to scroll only in the forward direction.• TYPE_SCROLL_SENSITIVE: Allows a ResultSet to scroll in the forward and backward

directions. It makes the changes in the underlying database made by other transac-tions or statements in the same transaction visible to the ResultSet. This type ofResultSet is aware of the changes made to its data by other means.

• TYPE_SCROLL_INSENSITIVE: Allows a ResultSet to scroll in the forward and backwarddirections. It does not make the changes in the underlying database made by othertransactions or statements in the same transaction visible to the ResultSet whilescrolling. This type of ResultSet determines its data set when it is open and thedata set does not change if it is updated through any other means except throughthis ResultSet itself. If you want to get up-to-date data, you must re-execute thequery.

Concurrency refers to the ability of a ResultSet to update data. By default, a ResultSet isread-only and it does not let you update its data. If you want to update data in a databasethrough a ResultSet, you need to request an updatable result set from the JDBC driver.The following two constants in the ResultSet interface are used to specify the concurrencyof a ResultSet:

• CONCUR_READ_ONLY: Makes a result set read-only.• CONCUR_UPDATABLE: Makes a result set updatable.

Holdability refers to the state of a ResultSet after a transaction that it is associated withhas been committed. A ResultSet may be closed or kept open when the transaction iscommitted. The default value of the holdability of a ResultSet is dependent on the JDBCdriver. For DB2 driver, the holdability is set to false. It is specified using one of thefollowing two constants defined in the ResultSet interface:

• HOLD_CURSORS_OVER_COMMIT: Keeps the ResultSet open after the transaction is com-mitted.

• CLOSE_CURSORS_AT_COMMIT: Closes the ResultSet after the transaction is committed.

Da bismo definisali ponašanje ResultSet objekta, potrebno je da prosledimo odgovarajućeopcije metodima createStatement, odnosno, prepareStatement, koji su definisani nadobjektom klase Connection, u zavisnosti od toga da li želimo da naredbu izvršimo krozinterfejse Statement ili PreparedStatement, redom.

U slučaju kreiranja objekta Statement, na raspolaganju su nam naredna dva preoptereće-

Page 256: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

256 Glava 11. Programiranje JDBC aplikacija

nja metoda createStatement:

• Metod sa dva argumenta:– int resultSetType — Tip skupa rezultata.– int resultSetConcurrency — Tip konkurentnosti.

• Metod sa tri argumenta:– int resultSetType– int resultSetConcurrency– int resultSetHoldability — Tip zadrživosti kursora prilikom izvršavanja ope-

racije pohranjivanja.

U slučaju kreiranja objekta PreparedStatement, na raspolaganju su nam naredna dvapreopterećenja metoda prepareStatement, sa istim značenjima parametara kao i u slučajumetoda createStatement:

• Metod sa tri argumenta:– String sql — Niska koja sadrži tekstualni oblik SQL naredbe. Može sadržati

nula ili više parametarskih oznaka.– int resultSetType– int resultSetConcurrency

• Metod sa četiri argumenta:– String sql– int resultSetType– int resultSetConcurrency– int resultSetHoldability

Primer 11.9 — Čas 10 — 09. Napisati JDBC aplikaciju koja ispisuje podatke o ispitnimrokovima koristeći kursor kome je omogućeno kretanje i unazad kroz podatke. Podatkeurediti po nazivu rastuće, ali ih ispisivati opadajuće.

Rešenje.

Kod 11.10: Primeri/cas10/src/primer09/Primer.javapackage primer09;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main(String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

Page 257: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 257

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

String sql ="SELECT ∗ " +"FROM ispitni_rok " +"ORDER BY naziv";

Statement stmt = con.createStatement(// Podesavamo da je kursor bidirekcioni i nesenzitivni,// sto znaci da moze da se krece kroz njega u oba smera,// i da izmene u bazi podataka nece biti vidljive tokom

prolazenja kroz kursoraResultSet.TYPE_SCROLL_INSENSITIVE,// Podesavamo da se kursor koristi samo za citanjeResultSet.CONCUR_READ_ONLY);

ResultSet res = stmt.executeQuery(sql);

System.out.printf("%−10s %−10s %−20s %−20s %−20s %−5s\n\n","GODINA", "OZNAKA", "NAZIV", "POCETAK PRIJAVE", "KRAJ PRIJAVE",

"TIP");

// Pozicioniranje na kraj kursorares.afterLast();

// Citanje unazadwhile (res.previous()){

int godina = res.getInt(1);String oznaka = res.getString(2).trim();String naziv = res.getString(3).trim();Date datum_pocetka = res.getDate(4);Date datum_kraja = res.getDate(5);String tip = res.getString(6).trim();

System.out.printf("%−10d %−10s %−20s %−20s %−20s %−5s\n",godina, oznaka, naziv, datum_pocetka.toString(),

datum_kraja.toString(), tip);}

res.close();stmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

Page 258: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

258 Glava 11. Programiranje JDBC aplikacija

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

11.3.5 Ažuriranje redova korišćenjem ResultSet kursora

Postoje dve procedure za ažuriranje informacija u bazi podataka na osnovu ResultSetkursora:

• Korišćenjem pozicionirajuće UPDATE naredbe.• Korišćenjem metoda updateXXX i updateRow.

Kao što znamo, možemo koristiti pozicionirajuću UPDATE naredbu za menjanje podatakau bazi podataka, na osnovu tekućeg reda kursora, tako što se na kursor referiše u WHERECURRENT OF klauzi naredbe. Da bismo dohvatili naziv ResultSet kursora, možemo iskori-stiti metod ResultSet.getCursorName, koji vraća nisku sa nazivom kursora koji je vezanza taj ResultSet. Naredni primer ilustruje kombinaciju korišćenja ovog metoda i pripre-mljene naredbe za ažuriranje.

Primer 11.10 — Čas 10 — 10. Napisati JDBC aplikaciju kojom se korisniku nudi da liželi da promeni broj bodova svakom predmetu čija šifra počinje slovom M. Ukoliko jeodgovor potvrdan, korisniku se nudi da unese broj bodova, a potom se vrši odgovara-juće ažuriranje. Nakon svake iteracije, pitati korisnika da li želi da završi sa obradom.Koristiti pozicionirajuću UPDATE naredbu.

Rešenje.

Kod 11.11: Primeri/cas10/src/primer10/Primer.javapackage primer10;

import java.sql.∗;import java.util.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

Page 259: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 259

public static void main(String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

// Kreiramo SELECT upit za azurirajuci kursor.// Primetimo da smo stavili klauzu FOR UPDATE OF,// koja sluzi da oznaci kolone koje mogu da se menjaju.String selectSql =

"SELECT sifra, naziv, bodovi " +"FROM predmet " +"FOR UPDATE OF bodovi";

// Kreiramo pozicionirajucu UPDATE naredbu,// koju cemo koristiti za azuriranje tekuceg reda kursora.// Primetimo da smo stavili klauzu WHERE CURRENT OF,// ali ne i ime kursora.// To cemo dodati na ovaj tekst naknadno ispod.String updateSql =

"UPDATE predmet " +"SET bodovi = ? " +"WHERE CURRENT OF ";

Statement stmt = con.createStatement();ResultSet rs = stmt.executeQuery(selectSql);

// Dohvatamo naziv kursora iz ResultSet objekta metodomgetCursorName,

// i dodajemo naziv na tekstualni oblik UPDATE naredbe,// od koje pravimo pripremljenu naredbu.String cursorName = rs.getCursorName();PreparedStatement ps = con.prepareStatement(updateSql + cursorName)

;

Scanner scanner = new Scanner(System.in);

while(rs.next()){

String sifra = rs.getString(1);String naziv = rs.getString(2);int trenutniBodovi = rs.getInt(3);

if (sifra.startsWith("M")){

System.out.println("Da li zelite da promenite broj bodovaza predmet " +naziv.trim() +" koji trenutno ima " +trenutniBodovi +" bodova? [da/ne]");

String odgovor = scanner.next();if(odgovor.equalsIgnoreCase("da")){

System.out.println("Unesite novi broj poena:");int noviBodovi = scanner.nextInt();

Page 260: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

260 Glava 11. Programiranje JDBC aplikacija

// Postavljamo parametarsku oznaku u pripremljenojUPDATE naredbi

// na ucitanu vrednost od korisnikaps.setInt(1, noviBodovi);// Izvrsavamo pozicioniraju UPDATE naredbups.executeUpdate();

}

System.out.println("Zavrsiti obradu? [da/ne]");odgovor = scanner.next();

if (odgovor.equalsIgnoreCase("da")){

break;}

}}

scanner.close();

rs.close();ps.close();stmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

Another approach is to use specific methods in order to update the data in the cursor,effectively updating the data in the database. Here are the steps involved in updating anexisting row in a ResultSet:

• Move the cursor to a valid row in the result set. Note that you can update data only

Page 261: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 261

for an existing row. It is obvious that the cursor should not be positioned before thefirst row or after the last row if you want to update the data in a row.

• Call the updateXXX() method for a column to update the column’s value.• If you do not want to go ahead with the changes made using updateXxx() method

calls, you need to call the cancelRowUpdates() method of the ResultSet to cancelthe changes.

• When you are done updating all the column’s values for the current row, call theupdateRow() method to send the changes to the database. If the auto-commit modeis enabled for the Connection, changes will be committed. Otherwise, you need tocommit the changes to the database.

• If you move the cursor to a different row before calling the updateRow(), all yourchanges made using the updateXXX() method calls will be discarded.

• There is another way to lose your updates to columns in a row. If you call therefreshRow() method after calling updateXxx(), but before calling updateRow(),your changes will be lost because the JDBC driver will refresh the row’s data fromthe database.

Primer 11.11 — Čas 10 — 11. Napisati JDBC aplikaciju koja ispisuje sadržaj tabelePREDMET i, u istoj iteraciji, ukoliko je broj bodova jednak 6, postavlja se broj bodova na12 i ispisuje se poruka da je promena izvršena, zajedno sa ispisom novih podataka otom predmetu. Ne koristiti pozicionirajuću UPDATE naredbu.

Rešenje.

Kod 11.12: Primeri/cas10/src/primer11/Primer.javapackage primer11;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main(String argv[]){

String url = "jdbc:db2://localhost:50001/vstud";Connection con = null;

try{

int stariBrBodova, noviBrBodova;

if (argv.length == 2){

stariBrBodova = Integer.parseInt(argv[0]);noviBrBodova = Integer.parseInt(argv[1]);

Page 262: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

262 Glava 11. Programiranje JDBC aplikacija

}else if (argv.length == 0){

stariBrBodova = 5;noviBrBodova = 10;

}else{

throw new Exception("Usage: java Primer12 [stariBodovinoviBodovi]");

}

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

String sql ="SELECT ∗ " +"FROM predmet";

Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,// Definisemo da je kursor azurirajuci,// pa su nam dostupni metodi// ResultSet.updateXXX i ResultSet.updateRowResultSet.CONCUR_UPDATABLE);

ResultSet rs = stmt.executeQuery(sql);

while(rs.next()){

System.out.println("Sifra: " + rs.getString(2).trim() + ", " +"Naziv:" + rs.getString(3).trim() + ", " +"Bodovi: " + rs.getInt(5));

if(rs.getInt(5) == stariBrBodova){

// Azuriramo vrednost u koloni broj 5rs.updateInt(5, noviBrBodova);// Kada zavrsimo sa azuriranjem svih kolona,// pozivamo metod updateRow// da bi se sve promene odmah oslikalers.updateRow();

// Sada kada zahtevamo vrednosti u kolonama,// dobicemo azurirane vrednosti:System.out.println("−−−−−−> Izvrsena je naredna promena:");System.out.println(

"\tSifra: " + rs.getString(2).trim() + ", " +"Naziv:" + rs.getString(3).trim() + ", " +"Bodovi: " + rs.getInt(5) /∗ azurirana vrednost ∗/ + "\

n");}

}

rs.close();stmt.close();

con.commit();con.close();

}catch (SQLException e){

Page 263: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 263

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

11.3.6 Brisanje redova korišćenjem ResultSet kursora

Poput ažuriranja podataka, i za brisanje podataka postoje dve procedure:

• Korišćenjem pozicionirajuće DELETE naredbe.• Korišćenjem metoda deleteRow.

Kao što znamo, možemo koristiti pozicionirajuću DELETE naredbu za brisanje podataka izbaze podataka, na osnovu tekućeg reda kursora, tako što se na kursor referiše u WHERECURRENT OF klauzi naredbe.

Primer 11.12 — Čas 10 — 12. Napisati JDBC aplikaciju koja briše sve nepoložene ispiteu godini koja se zadaje sa standarnog ulaza. Nakon svakog brisanja ispita, ispisatinaredne informacije o njemu na standardni izlaz: indeks, oznaku roka, godinu roka iidentifikator predmeta. Koristiti pozicionirajuću DELETE naredbu.

Rešenje.

Kod 11.13: Primeri/cas10/src/primer12/Primer.javapackage primer12;

import java.sql.∗;import java.util.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}

Page 264: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

264 Glava 11. Programiranje JDBC aplikacija

catch (Exception e){

e.printStackTrace();}

}

public static void main(String argv[]){

String url = "jdbc:db2://localhost:50001/vstud";Connection con = null;

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

System.out.println("Unesite godinu za koju zelite da obrisetenepolozene ispite:");

Scanner skener = new Scanner(System.in);int godina_roka = skener.nextInt();

skener.close();

String selectSql ="SELECT i.indeks, i.oznaka_roka, i.id_predmeta " +"FROM ispit i " +"WHERE godina_roka = ? " +

"AND ocena = 5 " +"AND status_prijave='o' ";

PreparedStatement prepSelectStmt = con.prepareStatement(selectSql,ResultSet.TYPE_FORWARD_ONLY,// Podesavamo kursor da bude za menjanje,// da bi smo mogli da brisemo redove pozicionirajucom DELETE

naredbomResultSet.CONCUR_UPDATABLE);

prepSelectStmt.setInt(1, godina_roka);ResultSet ispiti = prepSelectStmt.executeQuery();

String deleteSql ="DELETE FROM ispit " +"WHERE CURRENT OF " + ispiti.getCursorName();

Statement deleteStmt = con.createStatement();

while(ispiti.next()){

int indeks = ispiti.getInt(1);String oznaka_roka = ispiti.getString(2).trim();int id_predmeta = ispiti.getInt(3);

deleteStmt.executeUpdate(deleteSql);

System.out.printf("Obrisan je ispit %−10d %−10s %−5d %−10d\n",indeks, oznaka_roka, godina_roka, id_predmeta);

}

ispiti.close();

deleteStmt.close();prepSelectStmt.close();

Page 265: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 265

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

Deleting a row from a ResultSet is easier than updating a row. Here are the steps to deletea row:

• Position the cursor at a valid row.• Call the deleteRow() method of the ResultSet to delete the current row.

The deleteRow() method deletes the row from the ResultSet and, at the same time, itdeletes the row from the database. There is no way to cancel the delete operation exceptby rolling back the transaction. If the auto-commit mode is enabled on the Connection,deleteRow() will permanently delete the row from the database.

Primer 11.13 — Čas 10 — 13. Napisati JDBC aplikaciju koja briše sve nepoložene ispiteu godini koja se zadaje sa standarnog ulaza. Nakon svakog brisanja ispita, ispisatinaredne informacije o njemu na standardni izlaz: indeks, oznaku roka, godinu roka iidentifikator predmeta. Ne koristiti pozicionirajuću DELETE naredbu.

Rešenje.

Kod 11.14: Primeri/cas10/src/primer13/Primer.javapackage primer13;

import java.sql.∗;import java.util.∗;

public class Primer{

static{

Page 266: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

266 Glava 11. Programiranje JDBC aplikacija

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main(String argv[]){

String url = "jdbc:db2://localhost:50001/vstud";Connection con = null;

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

System.out.println("Unesite godinu za koju zelite da obrisetenepolozene ispite:");

Scanner skener = new Scanner(System.in);int godina_roka = skener.nextInt();

skener.close();

String selectSql ="SELECT i.indeks, i.oznaka_roka, i.id_predmeta " +"FROM ispit i " +"WHERE godina_roka = ? " +

"AND ocena = 5 " +"AND status_prijave='o' ";

PreparedStatement prepSelectStmt = con.prepareStatement(selectSql,ResultSet.TYPE_FORWARD_ONLY,// Podesavamo kursor da bude za menjanje,// da bi smo mogli da brisemo redove metodom deleteRow()ResultSet.CONCUR_UPDATABLE);

prepSelectStmt.setInt(1, godina_roka);ResultSet ispiti = prepSelectStmt.executeQuery();

while(ispiti.next()){

int indeks = ispiti.getInt(1);String oznaka_roka = ispiti.getString(2).trim();int id_predmeta = ispiti.getInt(3);

ispiti.deleteRow();

System.out.printf("Obrisan je ispit %−10d %−10s %−5d %−10d\n",indeks, oznaka_roka, godina_roka, id_predmeta);

}

ispiti.close();

prepSelectStmt.close();

con.commit();con.close();

}

Page 267: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 267

catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

11.3.7 Ugnežđeni kursori

U JDBC aplikacijama se kursori jednostavno ugnežđuju: potrebno je celokupnu obraduunutrašnjeg kursora smestiti u okviru obrade jednog reda iz spoljašnjeg kursora. Naredniprimer ilustruje upotrebu ugnežđenih kursora.

Primer 11.14 — Čas 10 — 14. Napisati JDBC aplikaciju kojom se izdvajaju indeks, ime,prezime i naziv smera svih studenata koji su položili tačno N predmeta, kao i spisak tihpredmeta (naziv i ocena). Broj N se zadaje kao argument komandne linije, a ukolikose ne navede, podrazumeva se da je 10. Za svakog studenta napraviti posebnu sekcijuizveštaja.

Rešenje.

Kod 11.15: Primeri/cas10/src/primer14/Primer.javapackage primer14;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

Page 268: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

268 Glava 11. Programiranje JDBC aplikacija

e.printStackTrace();}

}

public static void main (String argv[]){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

int ukupnoPredmeta = 10;

if (argv.length > 0){

ukupnoPredmeta = Integer.parseInt(argv[0]);}

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

PreparedStatement pstmt1;PreparedStatement pstmt2;

String sql1 ="SELECT d.indeks, trim(ime), trim(prezime), trim(naziv) " +"FROM dosije d " +

"JOIN smer s " +"ON d.id_smera = s.id_smera " +

"JOIN ispit i " +"ON d.indeks = i.indeks " +

"WHERE ocena > 5 " +"AND status_prijave = 'o' " +

"GROUP BY d.indeks, ime, prezime, naziv " +"HAVING count(∗) = ?";

String sql2 ="SELECT trim(naziv), ocena " +"FROM ispit i " +

"JOIN predmet p " +"ON i.id_predmeta = p.id_predmeta " +

"WHERE i.indeks = ? " +"AND ocena > 5 " +"AND status_prijave = 'o' " +

"ORDER BY naziv";

pstmt1 = con.prepareStatement(sql1);pstmt2 = con.prepareStatement(sql2);

pstmt1.setInt(1, ukupnoPredmeta);ResultSet ispiti = pstmt1.executeQuery();

while(ispiti.next()){

System.out.printf("\n\nIndeks: %−10d\nIme: %−10s\nPrezime: %−20s\nNaziv smera: %−30s\n\n",ispiti.getInt(1), ispiti.getString(2), ispiti.getString(3),

ispiti.getString(4));

pstmt2.setInt(1, ispiti.getInt(1));ResultSet predmeti = pstmt2.executeQuery();

Page 269: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

11.3 Upravljanje podacima 269

int redniBr = 1;

while(predmeti.next()){

System.out.printf("\t%d. predmet: %s\n\t\tOcena: %d\n",redniBr, predmeti.getString(1), predmeti.getShort(2));

++redniBr;}

predmeti.close();}

ispiti.close();

pstmt1.close();pstmt2.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

Page 270: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 271: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12. Napredni koncepti u JDBC aplikacijama

U ovom poglavlju ćemo demonstrirati rad sa transakcijama, rad u konkurentnom okruže-nju, kao i povezivanje na više baza podataka u JDBC aplikacijama.

12.1 Transakcioni rad

JDBC supports the following concepts:

• Setting the Auto-Commit Mode• Transaction isolation level• Savepoints

12.1.1 Auto-Commit Mode

When you connect to a database, the auto-commit property for the Connection objectis set to true by default. If a connection is in the auto-commit mode, a SQL statementis committed automatically after its successful execution. If a connection is not in theauto-commit mode, you must call the commit() or rollback() method of the Connectionobject to commit or roll back a transaction. Typically, you disable the auto-commit modefor a connection in a JDBC application, so the logic in your application controls thefinal outcome of the transaction. To disable the auto-commit mode, you need to call thesetAutoCommit(false) on the Connection object after a connection has been established.If a connection URL allows you to set the auto-commit mode, you can also specify it aspart of the connection URL. You set the auto-commit mode of your connection in theJDBCUtil.getConnection() method to false after you get a Connection object.// Get a connectionConnection con = DriverManager.getConnection(dbURL, userId, password);

// Set the auto−commit off

Page 272: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

272 Glava 12. Napredni koncepti u JDBC aplikacijama

con.setAutoCommit(false);

If you have enabled the auto-commit mode for your connection, you cannot use its com-mit() and rollback() methods. Calling the commit() and rollback() methods on a Connec-tion object, which has enabled the auto-commit mode, throws a SQLException.

If the setAutoCommit() method is called to change the auto-commit mode of a connectionin the middle of a transaction, the transaction is committed at that time. Typically, youwould set the auto-commit mode of a connection just after connecting to the database.

Committing and Rolling Back Transactions

If the auto-commit mode is disabled for a connection, you can use the commit() or roll-back() method to commit or roll back a transaction. Typical code in a JDBC applicationthat performs a database transaction is as shown:// Get a connectionConnection con = DriverManager.getConnection(dbURL, userId, password);

// Set the auto−commit offcon.setAutoCommit(false);

try{

// Perform database transaction activities here

// Successful scenario:con.commit();

}catch (SQLException e){

System.out.println("An error occured: " + e.getMessage());System.out.println("Rolling back the transaction");

try{

con.rollback();}catch (SQLException e) {}

System.exit(1);}

// Close the connectionconn.close();

12.1.2 Transaction Isolation Level

The ANSI SQL-92 standard defines four transaction isolation levels in terms of the dataconsistency. Each isolation level defines what kinds of data inconsistencies are allowed, ornot allowed. The four transaction isolation levels are as follows:

• Read uncommitted• Read committed• Repeatable read• Serializable

Page 273: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.1 Transakcioni rad 273

Java defines the following four constants in the Connection interface that correspond tothe four isolation levels defined by the ANSI SQL-92 standard:

• TRANSACTION_READ_UNCOMMITTED• TRANSACTION_READ_COMMITTED• TRANSACTION_REPEATABLE_READ• TRANSACTION_SERIALIZABLE

You can set the isolation level of a transaction for a database connection using the set-TransactionIsolation(int level) method of the Connection interface.// Get a Connection objectConnection con = DriverManager.getConnection(dbURL, userId, password);

// Set the transaction isolation level to read committedcon.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

12.1.3 Savepoints in a Transaction

A database transaction consists of one or more changes as a unit of work. A savepoint ina transaction is like a marker that marks a point in a transaction so that, if needed, thetransaction can be rolled back (or undone) up to that point.

An object of the Savepoint interface represents a savepoint in a transaction. To mark asavepoint in a transaction, you simply call the setSavepoint() method of the Connection.The setSavepoint() method is overloaded. One version accepts no argument and anotheraccepts a string, which is the name of the savepoint. The setSavepoint() method returnsa Savepoint object, which is your marker and you must keep it for future use. Here’s anexample:Connection con = DriverManager.getConnection(dbURL, userId, password);Statement stmt = con.createStatement();

stmt.execute("insert into person values ('John', 'Doe')");Savepoint sp1 = con.setSavepoint(); // 1

stmt.execute("insert into person values ('Jane', 'Doe')");Savepoint sp2 = con.setSavepoint(); // 2

stmt.execute("insert into person values ('Another', 'Unknown')");Savepoint sp3 = con.setSavepoint(); // 3

At this point, you have finer control on the transaction if you want to undo any of thesethree inserts into the person table. Now you can use another version of the rollback()method of the Connection, which accepts a Savepoint object. If you want to undo allchanges that were made after savepoint 1, you can do so as follows:// Rolls back inserts 2 and 3con.rollback(sp1);

Once you roll back up to a savepoint (say, spx), all savepoints that were created after thesavepoint spx are released and you cannot refer to them again. If you refer to a releasedsavepoint, the JDBC driver will throw a SQLException. The following snippet of codewill throw a SQLException:con.rollback(sp2); // Will release sp3con.rollback(sp3); // Will throw an exception: sp3 is already released.

Page 274: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

274 Glava 12. Napredni koncepti u JDBC aplikacijama

Note that when you roll back a transaction to a savepoint, that savepoint itself is notreleased. When you call, for example, con.rollback(sp2), savepoint sp2 remains valid. Youcan add more savepoints afterward and roll back up to savepoint sp2 again.

12.2 Rad u višekorisničkom okruženju

U poglavlju 6 smo govorili detaljno o problemima konkurentnog rada sa bazom podataka.Aplikacije pisane u programskom jeziku Java, bilo one SQLJ ili JDBC, takođe ”boluju” odistih problema kao i aplikacije koje smo pisali u programskom jeziku C. Zbog toga ćemoimati na umu sve napomene koje smo tada uveli, sa određenim napomenama koje slede udaljem tekstu.

S obzirom da se u programskom jeziku Java greške prijavljuju kroz objekte klase SQLException, proveru da li je došlo do nekog problema konkurentnog okruženja možemo izvršiti prove-rom koda greške, pozivom metoda getErrorCode() nad objektom klase SQLException kojismo uhvatili. Zašto nam je ova informacija važna? Prisetimo se da, ukoliko dođe do nekogproblema konkurentnog okruženja, DB2 SUBP šalje grešku −911 ili −913. U tom slučaju,potrebno je izvršiti obradu isteka vremena ili pojave mrtve petlje, i poništiti eventualneizmene.

Na primer:// U main funkciji:

Connection con = null;String sql = "SELECT ...";Statement stmt = con.createStatement(

ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_UPDATABLE,ResultSet.HOLD_CURSORS_OVER_COMMIT

);ResultSet kursor = otvoriKursor(stmt, sql);

try{

// Kod koji moze da dovede do problema// u visekorisnickom okruzenju

}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() == −913){

kursor.close();kursor = obradiCekanje("FETCH, UPDATE, ...", con, stmt, sql);continue;

}}

// ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗// Izvan main funkcije:

private static ResultSet otvoriKursor(Statement stmt,String sql) throws SQLException

{ResultSet kursor = stmt.executeQuery(sql);return kursor;

Page 275: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.2 Rad u višekorisničkom okruženju 275

}

private static ResultSet obradiCekanje(String codeHint,Connection con,Statement stmt,String sql) throws SQLException

{System.out.printf("[%s] Objekat je zakljucan od strane druge transakcije!\n

" +"Molimo sacekajte!\n", codeHint);

try{

con.rollback();} catch (SQLException e) {}

return otvoriKursor(stmt, sql);}

Naredni primeri ilustruju konstrukciju JDBC aplikacija koje koriste transakcioni rad uvišekorisničkom okruženju.

Primer 12.1 — Čas 11 — 01. Napisati JDBC aplikaciju koja za svaki predmet koji jeobavezan na smeru čiji je identifikator 201, pita korisnika da li želi da poveća broj bodovaza 1. Ukoliko je odgovor korisnika ”da”, izvršava se odgovarajuća naredba. Zadatakuraditi tako da aplikacija radi u višekorisničkom okruženju. Obrada jednog predmetatreba da predstavlja jednu transakciju. Postaviti istek vremena na 5 sekundi.

Rešenje.

Kod 12.1: Primeri/cas11/src/primer1/Primer.javapackage primer1;

import java.sql.∗;import java.util.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main(String[] args){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

Page 276: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

276 Glava 12. Napredni koncepti u JDBC aplikacijama

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

// Niz identifikatora predmeta koji su obradjeniArrayList<Integer> obradjeni = new ArrayList<Integer>();

Scanner ulaz = new Scanner(System.in);

// Postavljanje isteka vremena za katanceStatement lockStmt = con.createStatement();lockStmt.execute("SET CURRENT LOCK TIMEOUT 5");

String sql ="SELECT id_predmeta, naziv, bodovi " +"FROM predmet " +"WHERE id_predmeta IN ( " +

"SELECT id_predmeta " +"FROM obavezan_predmet " +"WHERE id_smera = 201 " +

")";

Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_UPDATABLE,// Kursor deklarisemo sa opcijom HOLD_CURSORS_OVER_COMMIT// da bi ostao otvoren prilikom izvrsavanja COMMIT naredbeResultSet.HOLD_CURSORS_OVER_COMMIT);

ResultSet kursor = otvoriKursor(stmt, sql);

// Citanje reda moze dovesti do problema zbog S ili U katanaca,// te moramo poziv metoda next() obraditi zasebno,// pa zato ide unutar petlje za obraduboolean ima_redova = true;for(;;){

// S ili U katanactry{

ima_redova = kursor.next();}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() == −913){

kursor.close();kursor = obradiCekanje("FETCH", con, stmt, sql);continue;

}}

if (!ima_redova){

break;}

int id_predmeta = kursor.getInt(1);String naziv = kursor.getString(2);short bodovi = kursor.getShort(3);

if (!obradjeni.contains(id_predmeta))

Page 277: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.2 Rad u višekorisničkom okruženju 277

{System.out.printf("\nPredmet %s ima %d bodova\n", naziv.

trim(), bodovi);System.out.println("Da li zelite da uvecate broj bodova za

1? [da/ne]");

String odgovor = ulaz.next();if (odgovor.equalsIgnoreCase("da")){

// X katanactry{

// Ovde koristimo metode updateXXX i updateRow zaazuriranje podataka.

// Za vezbu uraditi zadatak pozicionirajucom UPDATEnaredbom.

kursor.updateShort(3, (short) (bodovi + 1));kursor.updateRow();

}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() ==−913)

{kursor.close();kursor = obradiCekanje("UPDATE", con, stmt, sql

);continue;

}}

System.out.println("Uspesno su azurirani bodovi zatekuci predmet!");

}

// Evidentiranje obradeobradjeni.add(id_predmeta);

// Zavrsavamo jednu transakcijucon.commit();

System.out.println("Da li zelite da zavrsite sa obradom? [da/ne]");

odgovor = ulaz.next();

if (odgovor.equalsIgnoreCase("da")){

break;}

}}

ulaz.close();kursor.close();stmt.close();

// Vracanje podrazumevane vrednosti za istek vremenalockStmt.execute("SET CURRENT LOCK TIMEOUT NULL");lockStmt.close();

con.commit();

Page 278: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

278 Glava 12. Napredni koncepti u JDBC aplikacijama

con.close();}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

private static ResultSet otvoriKursor(Statement stmt,String sql) throws SQLException

{ResultSet kursor = stmt.executeQuery(sql);return kursor;

}

private static ResultSet obradiCekanje(String codeHint,Connection con,Statement stmt,String sql) throws SQLException

{System.out.printf("[%s] Objekat je zakljucan od strane druge

transakcije!\n" +"Molimo sacekajte!\n", codeHint);

try{

con.rollback();} catch (SQLException e) {}

return otvoriKursor(stmt, sql);}

}

Primer 12.2 — Čas 11 — 02. Napisati JDBC aplikaciju koji za sve ispitne rokove pro-nalazi informacije o polaganjima za svaki položeni predmet u tom ispitnom roku i tepodatke unosi u tabelu ispitni_rokovi_polaganja. Tabela ispitni_rokovi_polaganja

Page 279: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.2 Rad u višekorisničkom okruženju 279

sadrži kolone sa podacima o:

• godini roka• oznaci roka• identifikatoru predmeta• oceni• broju položenih ispita na tom predmetu sa tom ocenom• nazivu roka• nazivu predmeta

Definisati primarni ključ na osnovu prvih 5 kolona. Pre jednog unosa podataka ispisatipodatke koji ce biti uneti. Takođe, omogućiti da se podaci unose tako što korisnik morada odobri unos podataka na svakih 20 redova (tzv. batch unos). Napisati program takoda može da radi u višekorisničkom okruženju. Unos podataka za jedan ispitni rok ijedno polaganje predstavlja jednu transakciju. Postaviti istek vremena za zahtevanjekatanaca na 5 sekundi. Obraditi sve moguće greške.

SQL naredbe za kreiranje i brisanje tabele sačuvati u datotekama 2a.sql i 2b.sql,redom, a SELECT upit kojim se izdvajaju potrebni podaci sačuvati u datoteci 2c.sql.

Rešenje.

Kod 12.2: Primeri/cas11/src/primer2/2a.sqlcreate table ispitni_rokovi_polaganja (

godina smallint not null,oznaka varchar(20) not null,id_predmeta integer not null,ocena smallint not null,broj integer not null,naziv_roka varchar(50),naziv_predmeta varchar(200),primary key(godina, oznaka, id_predmeta, ocena, broj)

)

Kod 12.3: Primeri/cas11/src/primer2/2b.sqldrop table ispitni_rokovi_polaganja

Kod 12.4: Primeri/cas11/src/primer2/2c.sqlselect ir.godina,

ir.oznaka,p.id_predmeta,i.ocena,count(∗) as broj,ir.naziv,p.naziv

from ispit ijoin ispitni_rok ir

on i.godina_roka = ir.godinaand i.oznaka_roka = ir.oznaka

join predmet pon i.id_predmeta = p.id_predmeta

where ocena is not nullgroup by ir.godina, ir.oznaka, p.id_predmeta, i.ocena, ir.naziv, p.nazivorder by godina, oznaka, id_predmeta, ocena desc

Page 280: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

280 Glava 12. Napredni koncepti u JDBC aplikacijama

Kod 12.5: Primeri/cas11/src/primer2/Primer.javapackage primer2;

import java.sql.∗;import java.util.∗;import java.io.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

private static class IspitniRokoviPolaganja{

// Stavljamo public modifikatore da bismo im lakse pristupali,// mada ovo nije u skladu sa objektno−orijentisanih pristupom

programiranjapublic short godina;public String oznaka;public int id_predmeta;public short ocena;public int broj;

public IspitniRokoviPolaganja(short godina, String oznaka,int id_predmeta, short ocena, int broj)

{this.godina = godina;this.oznaka = oznaka;this.id_predmeta = id_predmeta;this.ocena = ocena;this.broj = broj;

}

// Metod equals nam je neophodan zbog metoda contains sablonske klaseArrayList

@Overridepublic boolean equals(Object o){

if (o == this) {return true;

}

if (!(o instanceof IspitniRokoviPolaganja)) {return false;

}

IspitniRokoviPolaganja other = (IspitniRokoviPolaganja) o;

return this.godina == other.godina &&this.oznaka.equals(other.oznaka) &&this.id_predmeta == other.id_predmeta &&

Page 281: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.2 Rad u višekorisničkom okruženju 281

this.ocena == other.ocena &&this.broj == other.broj;

}}

public static void main(String[] args){

Connection con = null;String url = "jdbc:db2://localhost:50001/vstud";

try{

con = DriverManager.getConnection(url, "student", "abcdef");con.setAutoCommit(false);

Scanner ulaz = new Scanner(System.in);

// Naredbe za kreiranje i brisanje tabeleString kreirajTabeluSQL = ucitajSqlIzDatoteke("2a.sql");String obrisiTabeluSQL = ucitajSqlIzDatoteke("2b.sql");Statement tabelaStmt = con.createStatement();

System.out.println("Da li zelite da obrisete tabelu? [da/ne]");String odgovor = ulaz.next();

if (odgovor.equalsIgnoreCase("da")){

// Brisemo tabelu samo ako postojitry{

tabelaStmt.execute(obrisiTabeluSQL);System.out.println("Tabela je obrisana!");

} catch (SQLException e) {}}

// Zatim, kreiramo tabelu, ponovo, samo ako ne postojitry{

tabelaStmt.execute(kreirajTabeluSQL);System.out.println("Tabela je kreirana!");

} catch (SQLException e) {}

// Pohranjujemo izmenecon.commit();

// Niz primarnih kljuceva tabele koji su obradjeniArrayList<IspitniRokoviPolaganja> obradjeni = new ArrayList<

IspitniRokoviPolaganja>();

// Postavljanje isteka vremena za katanceStatement lockStmt = con.createStatement();lockStmt.execute("SET CURRENT LOCK TIMEOUT 5");

// Ucitavanje SQL upita za kursorString sql = ucitajSqlIzDatoteke("2c.sql");

Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_UPDATABLE,// Kursor deklarisemo sa opcijom HOLD_CURSORS_OVER_COMMIT// da bi ostao otvoren prilikom izvrsavanja COMMIT naredbe

Page 282: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

282 Glava 12. Napredni koncepti u JDBC aplikacijama

ResultSet.HOLD_CURSORS_OVER_COMMIT);

ResultSet kursor = otvoriKursor(stmt, sql);

// Ovoliko podataka cemo uneti odjednom,// pa cemo od korisnika zahtevati nastavak unosafinal int batch_size = 20;// Trenutni broj unetih redovaint uneto_redova = 0;

// Kreiramo pripljemljenu naredbu za unos podatakaString unosSQL =

"INSERT INTO ispitni_rokovi_polaganja " +"VALUES (?, ?, ?, ?, ?, ?, ?)";

PreparedStatement pUnosStmt = con.prepareStatement(unosSQL);

// Citanje reda moze dovesti do problema zbog S ili U katanaca,// te moramo poziv metoda next() obraditi zasebno,// pa zato ide unutar petlje za obraduboolean ima_redova = true;for(;;){

// S ili U katanactry{

ima_redova = kursor.next();}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() == −913){

kursor.close();kursor = obradiCekanje("FETCH", con, stmt, sql);continue;

}}

if (!ima_redova){

break;}

// Podaci za primarni kljucshort godina = kursor.getShort(1);String oznaka = kursor.getString(2);int id_predmeta = kursor.getInt(3);short ocena = kursor.getShort(4);int broj = kursor.getInt(5);// Ostale koloneString naziv_roka = kursor.getString(6);boolean naziv_roka_null = kursor.wasNull();String naziv_predmeta = kursor.getString(7);boolean naziv_predmeta_null = kursor.wasNull();

IspitniRokoviPolaganja primKljuc =new IspitniRokoviPolaganja(godina, oznaka, id_predmeta,

ocena, broj);

if (!obradjeni.contains(primKljuc)){

System.out.println("\nUnosim naredno polaganje: ");

Page 283: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.2 Rad u višekorisničkom okruženju 283

System.out.printf("%d,%s,%d,%d,%d,%s,%s\n",godina, oznaka.trim(), id_predmeta, ocena, broj,naziv_roka_null ? "NEMA NAZIVA ROKA" : naziv_roka.

trim(),naziv_predmeta_null ? "NEMA NAZIVA PREDMETA" :

naziv_predmeta.trim());

// X katanactry{

pUnosStmt.setShort(1, godina);pUnosStmt.setString(2, oznaka);pUnosStmt.setInt(3, id_predmeta);pUnosStmt.setShort(4, ocena);pUnosStmt.setInt(5, broj);pUnosStmt.setString(6, naziv_roka_null ? null:

naziv_roka);pUnosStmt.setString(7, naziv_predmeta_null ? null :

naziv_predmeta);

pUnosStmt.executeUpdate();}catch (SQLException e){

if (e.getErrorCode() == −911 || e.getErrorCode() ==−913)

{kursor.close();kursor = obradiCekanje("INSERT", con, stmt, sql);continue;

}}

// Evidentiranje obradeobradjeni.add(primKljuc);

// Zavrsavamo jednu transakcijucon.commit();

// Uvecavamo broj redova za trenutnu batch obradu++uneto_redova;

if (batch_size == uneto_redova){

System.out.println("\nDa li zelite da izvrsite narednibatch unos? [da/ne]");

odgovor = ulaz.next();if (odgovor.equalsIgnoreCase("ne")){

break;}

uneto_redova = 0;}

}}

ulaz.close();

pUnosStmt.close();

Page 284: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

284 Glava 12. Napredni koncepti u JDBC aplikacijama

kursor.close();stmt.close();

// Vracanje podrazumevane vrednosti za istek vremenalockStmt.execute("SET CURRENT LOCK TIMEOUT NULL");lockStmt.close();

con.commit();con.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != con){

con.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

private static ResultSet otvoriKursor(Statement stmt,String sql) throws SQLException

{ResultSet kursor = stmt.executeQuery(sql);return kursor;

}

private static ResultSet obradiCekanje(String codeHint,Connection con,Statement stmt,String sql) throws SQLException

{System.out.printf("[%s] Objekat je zakljucan od strane druge

transakcije!\n" +"Molimo sacekajte!\n", codeHint);

try{

con.rollback();} catch (SQLException e) {}

return otvoriKursor(stmt, sql);}

Page 285: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 285

private static String ucitajSqlIzDatoteke(String nazivDatoteke) throwsFileNotFoundException

{StringBuffer sql = new StringBuffer();String putanja = System.getProperty("user.dir") + "/bin/primer2/" +

nazivDatoteke;

Scanner datoteka = new Scanner(new File(putanja));

while(datoteka.hasNext()){

String linija = datoteka.nextLine();sql.append(linija);sql.append("\n");

}

datoteka.close();

return sql.toString();}

}

Zadatak 12.1 Napisati JDBC aplikaciju koja redom:

1. Kreira tabelu stipendije sa sledećim kolonama:• naziv varchar(100) not null,• godina smallint not null,• broj_stipendista smallint not null,• visina_stipendije smallint,• min prosek float,• napomena varchar(50).

2. Unosi podatke o nekoliko stipendija u tabelu stipendije. Izračunati i broj unetihredova. U slučaju da je broj unetih redova jednak nuli, ispisati poruku ”Nijedanred nije dodat”, a inače ispisati poruku u unetom broju redova.

3. Za svaku stipendiju, pita korisnika da li želi da promeni broj studenata za tustipendiju i ukoliko je odgovor korinika potvrdan, od korisnika traži da unesenovi broj studenata i izvršava odgovarajuću naredbu.

4. Za svaku stipendiju, pita korisnika da li želi da obriše tu stipendiju i ukoliko jeodgovor korinika potvrdan, izvršava odgovarajuću naredbu.

Aplikacija treba da radi u višekorisničkom okruženju. Obrada jedne stipendije trebada predstavlja jednu transakciju. Postaviti istek vremena na 5 sekundi. ■

12.3 Povezivanje na više baza podataka

Upravljanje podacima nad više baza podataka u JDBC aplikacijama je značajno jedno-stavnije nego u C aplikacijama sa ugnežđenim SQL-om.

U JDBC aplikacijama možemo imati proizvoljan broj objekata klase Connection i svakiod njih predstavlja i ostvaruje konekciju ka jednoj bazi podataka. Pretpostavimo daimamo dve konekcije ka bazama podataka X i Y ostvarene kroz objekte conX i conY klaseConnection.

Page 286: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

286 Glava 12. Napredni koncepti u JDBC aplikacijama

Ukoliko je potrebno da izvršimo naredbu nad bazom podataka X, onda je potrebno da krei-ramo objekat naredbe (bilo kroz klasu Statement ili PreparedStatement) koristeći objekatconX. Za izvršavanje naredbe nad drugom bazom podataka Y, koristićemo objekat conYza kreiranje objekta naredbe.

Naredni primeri ilustruju korišćenje dve baze podataka: VSTUD i MSTUD.

Primer 12.3 — Čas 11 — 03. Napisati JDBC aplikaciju koja omogućava konekciju na 2baze (vstud i mstud).

Program redom:

• Iz baze mstud ispisuje naziv predmeta, za svaki predmet koji postoji u toj bazi.• Iz baze vstud, za svaki predmet iz prethodnog koraka, ispisuje ime i prezime

studenta koji su položili taj predmet, kao i ocenu koju su dobili.

Napraviti izveštaj tako što se za svaki predmet prvo ispiše njegov naziv, a zatim se ispi-suju informacije o studentima koji su ga položili. Predmete iz različitih baza podatakaspajati po nazivu predmeta.

Rešenje.

Kod 12.6: Primeri/cas11/src/primer3/Primer.javapackage primer3;

import java.sql.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

// Prva baza: VSTUDString urlVstud = "jdbc:db2://localhost:50001/vstud";Connection conVstud = null;

// Druga baza: MSTUDString urlMstud = "jdbc:db2://localhost:50001/mstud";Connection conMstud = null;

try{

// Kreiramo konekcije ka obema bazama podatakaconVstud = DriverManager.getConnection(urlVstud, "student", "abcdef

");conVstud.setAutoCommit(false);conMstud = DriverManager.getConnection(urlMstud, "student", "abcdef

Page 287: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 287

");conMstud.setAutoCommit(false);

// Kreiramo/Pripremamo naredbeStatement stmtMstud = conMstud.createStatement();ResultSet predmetiMstud = stmtMstud.executeQuery(

"SELECT naziv " +"FROM predmet");

PreparedStatement stmtVstud = conVstud.prepareStatement("SELECT ime, prezime, ocena " +"FROM dosije d " +

"JOIN ispit i " +"ON d.indeks = i.indeks " +

"JOIN predmet p " +"ON i.id_predmeta = p.id_predmeta " +

"WHERE ocena > 5 " +"AND status_prijave = 'o' " +"AND p.naziv = ? " +

"FETCH FIRST 7 ROWS ONLY");

// Za svaki predmet iz baze MSTUDwhile (predmetiMstud.next()){

String naziv = predmetiMstud.getString(1);

// Dohvatamo podatke iz baze VSTUDstmtVstud.setString(1, naziv);ResultSet studentiVstud = stmtVstud.executeQuery();

System.out.println("Predmet: " + naziv + "\n");int br_studenata = 0;

while(studentiVstud.next()){

System.out.println("Ime: " + studentiVstud.getString(1).trim() + ", "

+"Prezime: " + studentiVstud.getString(2).trim() +

", " +"Ocena: " + studentiVstud.getShort(3));

++br_studenata;}

studentiVstud.close();

if (0 == br_studenata){

System.out.println("Nema studenata koji su polozili ovajpredmet!");

}

System.out.println("\n\n");}

predmetiMstud.close();

stmtVstud.close();stmtMstud.close();

Page 288: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

288 Glava 12. Napredni koncepti u JDBC aplikacijama

conVstud.commit();conMstud.commit();

conVstud.close();conVstud.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != conVstud){

conVstud.rollback();}if (null != conMstud){

conMstud.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

}

Primer 12.4 — Čas 08 — 04. Napisati program u programskom jeziku C sa ugnežđenimSQL-om koji omogućava konekciju na 2 baze (vstud i mstud).

Program redom:

• Zahteva od korisnika da unese broj bodova B.• Iz baze mstud izdvaja indeks, ime i prezime studenata koji su položili sve predmete

koji nose više od B bodova.• Zatim, zahteva od korisnika da unese ocenu O (ceo broj od 6 do 10).• Iz baze vstud izlistava indeks, naziv, ocenu, godinu i oznaku ispitnog roka za sve

studente koji nikada nisu dobili ocenu manju nego što je ocena O.• Nakon ispisivanja tih podataka, u bazi mstud, iz tabele ispit briše sva polaganja

za studenta sa maksimalnim brojem indeksa I iz dosije, i vraća I.• Na kraju, u bazi vstud, u tabeli predmet za sve predmete koje je položio student

sa brojem indeksa I, uvećava broj bodova za jedan (osim ako je broj bodova većiod 10, tada ostavlja nepromenjeno stanje).

Rešenje.

Kod 12.7: Primeri/cas11/src/primer4/Primer.javapackage primer4;

Page 289: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 289

import java.sql.∗;import java.util.∗;

public class Primer{

static{

try{

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

public static void main (String argv[]){

String urlVstud = "jdbc:db2://localhost:50001/vstud";Connection conVstud = null;

String urlMstud = "jdbc:db2://localhost:50001/mstud";Connection conMstud = null;

try{

System.out.println("Povezivanje na VSTUD...");conVstud = DriverManager.getConnection(urlVstud, "student", "abcdef

");conVstud.setAutoCommit(false);System.out.println("Uspesno je ostvarena konekcija!");

System.out.println("Povezivanje na MSTUD...");conMstud = DriverManager.getConnection(urlMstud, "student", "abcdef

");conMstud.setAutoCommit(false);System.out.println("Uspesno je ostvarena konekcija!");

Scanner ulaz = new Scanner(System.in);

// Program redom:// Zahteva od korisnika da unese broj bodova B.

System.out.println("Unesite broj bodova B:");short brojBodova = ulaz.nextShort();

// Iz baze MSTUD izdvaja indeks, ime i prezime studenata// koji su polozili sve predmete koji nose vise od B bodova.

izlistajStudenteMstud(conMstud, brojBodova);

// Zatim, zahteva od korisnika da unese ocenu O (ceo broj od 6 do10).

System.out.println("Unesite ocenu O:");short ocena = ulaz.nextShort();

// Iz baze VSTUD izlistava indeks, naziv, ocenu, godinu i oznaku

Page 290: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

290 Glava 12. Napredni koncepti u JDBC aplikacijama

ispitnog roka// za sve studente koji nikada nisu dobili ocenu manju nego sto je

ocena O.

izlistajPolaganjaVstud(conVstud, ocena);

// Nakon ispisivanja tih podataka, u bazi MSTUD, iz tabele ISPIT// brise sva polaganja za studenta sa maksimalnim brojem indeksa I// iz DOSIJE, i vraca I.

int indeks = obrisiPolaganjaIVratiIndeksMstud(conMstud);

// Na kraju, u bazi VSTUD, u tabeli PREDMET// za sve predmete koje je polozio student sa brojem indeksa I,// uvecava broj bodova za jedan (osim ako je broj bodova veci od

10,// tada ostavlja nepromenjeno stanje).

uvecajBodoveZaPredmeteVstud(conVstud, indeks);

ulaz.close();

conVstud.commit();conMstud.commit();

conVstud.close();conVstud.close();

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

if (null != conVstud){

conVstud.rollback();}if (null != conMstud){

conMstud.rollback();}

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

System.exit(1);}

}

private static void izlistajStudenteMstud(Connection con, short brojBodova)throws SQLException

{PreparedStatement stmt = con.prepareStatement(

Page 291: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 291

"SELECT indeks, ime, prezime " +"FROM dosije d " +"WHERE NOT EXISTS ( " +

"SELECT ∗ " +"FROM predmet p " +"WHERE bodovi = ? " +

"AND NOT EXISTS ( " +"SELECT ∗ " +"FROM ispit i " +"WHERE i.indeks = d.indeks " +

"AND i.id_predmeta = p.id_predmeta " +"AND i.ocena > 5 " +

") " +")");

stmt.setShort(1, brojBodova);ResultSet rez = stmt.executeQuery();

System.out.println("\n\nStudenti koji su polozili sve predmete od " +brojBodova + " bodova\n");

while(rez.next()){

System.out.println("Indeks: " + rez.getInt(1) + ", " +"Ime: " + rez.getString(2).trim() + ", " +"Prezime: " + rez.getString(3).trim() + ", ");

}

rez.close();stmt.close();

}

private static void izlistajPolaganjaVstud(Connection con, short ocena)throws SQLException

{PreparedStatement stmt = con.prepareStatement(

"SELECT indeks, p.naziv, ocena, godina_roka, oznaka_roka " +"FROM ispit i " +

"JOIN predmet p " +"ON i.id_predmeta = p.id_predmeta " +

"WHERE ocena > 5 " +"AND status_prijave = 'o' " +"AND NOT EXISTS ( " +

"SELECT ∗ " +"FROM ispit i2 " +"WHERE i.indeks = i2.indeks " +

"AND ocena < ? " +")");

stmt.setShort(1, ocena);ResultSet rez = stmt.executeQuery();

System.out.println("Polozeni ispiti studenata koji nemaju ocenumanju od " + ocena);

while(rez.next()){

System.out.println("Indeks: " + rez.getInt(1) + ", " +"Naziv: " + rez.getString(2).trim() + ", " +"Ocena: " + rez.getInt(3) + ", " +"Godina roka: " + rez.getInt(4) + ", " +

Page 292: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

292 Glava 12. Napredni koncepti u JDBC aplikacijama

"Oznaka roka: " + rez.getString(5).trim());}

rez.close();stmt.close();

}

private static int obrisiPolaganjaIVratiIndeksMstud(Connection con) throwsException

{int indeks = 0;

Statement stmt = con.createStatement();

ResultSet rez = stmt.executeQuery("SELECT max(indeks) " +"FROM dosije ");

boolean dohvacenIndeks = rez.next();if (!dohvacenIndeks){

throw new Exception("Ne postoji nijedan indeks u bazi podataka");}

indeks = rez.getInt(1);

rez.close();

int brojObrisanih = stmt.executeUpdate("DELETE FROM ispit " +"WHERE indeks = ( " +

"SELECT max(indeks) " +"FROM dosije " +

")");

System.out.println("Broj obrisanih redova: " + brojObrisanih);

stmt.close();

return indeks;}

private static void uvecajBodoveZaPredmeteVstud(Connection con, int indeks)throws SQLException

{PreparedStatement stmt = con.prepareStatement(

"UPDATE predmet p " +"SET bodovi = bodovi + 1 " +"WHERE bodovi < 10 " +

"AND EXISTS ( " +"SELECT ∗ " +"FROM ispit i " +"WHERE i.id_predmeta = p.id_predmeta " +

"AND ocena > 5 " +"AND indeks = ? " +

")");stmt.setInt(1, indeks);

int brojAzuriranih = stmt.executeUpdate();

System.out.println("Broj azuriranih redova: " + brojAzuriranih);

Page 293: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 293

stmt.close();}

}

Zadatak 12.2 Napisati JDBC aplikaciju koja omogućava konekciju na 2 baze (vstud imstud).

Program redom:

• U bazi vstud pravi tabelu irok_stat koja sadrži naredne kolone: godinu roka,oznaku roka i prolaznost.

• U bazi mstud pravi tabelu pred_stat koja sadrži naredne kolone: identifikatorpredmeta i prosek.

• Iz baze vstud obrisati tabelu irok_stat.• Iz baze mstud obrisati tabelu pred_stat.• Iz baze mstud izlistati sadržaj tabele dosije.

Zadatak 12.3 Napisati JDBC aplikaciju koja omogućava konekciju na 2 baze (vstud imstud).

Program redom:

• U bazi vstud broj bodova se uvećava za 1 predmetima koji su obavezni na smeru”Informatika” (koristiti podatak da je za ovaj smer identifikator 201).

• U bazi mstud se unose podaci u tabelu dosije o studentu Stefanu Laziću, čiji jedatum upisa 01.09.2012. i dodeliti mu broj indeksa 20120001.

• Iz baze vstud islistati predmete koji su obavezni na smeru ”Informatika”.• Iz baze mstud izlistati sve studente.• Iz baze mstud obrisati unetog studenta.

12.3.1 Objektno-orijentisani pristup kreiranju JDBC aplikacija

Do sada smo naše JDBC aplikacije pisali u proceduralnom stilu — metod main() namje služio kao alat koji je izvršavao sve potrebne aktivnosti, kao što su: povezivanje nabazu podataka, kreiranje objekata naredbi, izvršavanje naredbi, procesiranje podataka,oslobađanje resursa i diskonekcija sa baze podataka.

Ovaj pristup nije problematičan prilikom kreiranja jednostavnih aplikacija kao što su tobile aplikacije koje smo videli do sada. Međutim, što se složenost aplikacije povećava,ovakav pristup postaje izuzetno naporan za održavanje — što je i jedna od najvećih manaproceduralne paradigme programiranja.

Primer 12.5 Uraditi primer 12.4 primenjujući neke tehnike objektno-orijentisanog pro-gramiranja.

Rešenje. Jedan od problema koji smo imali prilike da vidimo jeste umnožavanje ”istog”koda — u primeru 12.4, za obe baze podataka, metod main()1 mora da čuva po jedan obje-

1Zapravo, ovo važi za klasu koja sadrži metod main(), ali da nismo implementirali pomoćne funkcije,

Page 294: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

294 Glava 12. Napredni koncepti u JDBC aplikacijama

kat konekcije, URL ka bazi podataka, da izvršava povezivanje, oslobađanje resursa i drugo.Jedina svetla tačka tog koda jeste izdvajanje logičkih celina nad jednom bazom podataka uodgovarajuću funkciju, umesto da se i te obrade izvršavaju u metodi main(). Ova odlukazapravo predstavlja prvi korak ka jednom od osnovnih koncepata objektno-orijentisaneparadigme — jedna klasa treba da implementira jednu jezgrovitu funkcionalnost. U tusvrhu, u nastavku teksta, pokušaćemo da rešimo neke probleme koje se javljaju u rešenjuprimera 12.4.

Za početak, pogledajmo koji su to elementi koji se ponavljaju za obe baze podataka(naravno, sa različitim vrednostima): objekat konekcije, naziv baze podataka, URL, ko-risničko ime i lozinka. Svi ovi elementi su idealni kandidati za članice klase za svaku odbaza podataka. Od ponašanja koje ove baze podataka imaju zajedničko jesu: povezivanje,diskonekcija, pohranjivanje i poništavanje izmena. Ovo će se direktno oslikati u metodeklasa koje kreiramo. Takođe, primetimo da postoje i funkcionalnosti koje se razlikuju. Upitanju su operacije procesiranja podataka — za svaku bazu podataka imamo različitezahteve.

Kako imamo elemente koji su zajednički za obe baze podataka, ali i oni koji su razli-čiti, to nas dovodi do zaključka da bi trebalo da kreiramo jednu baznu klasu, na primer,Database, koja će implementirati zajedničko ponašanje, ali i skladištiti zajedničke podatke(i implementirati pomoćne funkcije za njihovo lakše upravljanje), kao i po jednu klasu zasvaku bazu podataka, na primer, Vstud i Mstud, koje će dodeliti odgovarajuće vrednostipodacima i implementirati zahteve nad tim bazama podataka. Time dobijamo naredneklase:

Kod 12.8: Primeri/cas11/src/primer5/Database.javapackage primer5;

import java.sql.∗;

/∗∗∗ Database is the abstract base class for all database contexts∗ which allow an application to perform basic operations on a∗ database, using the JDBC API.∗∗ In order to use this class, for each database, there needs to∗ exists an inherited class from this class. The inherited class∗ needs to set the following protected members in its constructor∗ method:∗ <code>dbName</code>,∗ <code>url</code>,∗ <code>username</code>,∗ <code>password</code>.∗∗ @author Nikola Ajzenhamer∗ @version %I%, %G%∗ @since 1.0∗/public abstract class Database{

static{

try{

onda bi se sva odgovornost zaista smestila u metod main(), tako da u ovom tekstu izjednačujemo metodmain() sa klasom koja je sadrži.

Page 295: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 295

Class.forName("com.ibm.db2.jcc.DB2Driver");}catch (Exception e){

e.printStackTrace();}

}

/∗∗∗ The object which is used for keeping the resources∗ used in a connection to a database.∗/protected Connection con;

/∗∗∗ The name of the database used for printing purposes.∗/protected String dbName = null;/∗∗∗ The Type 4 JDBC URL used for connecting to a database.∗/protected String url = null;/∗∗∗ The user which is being used for connecting to a database∗ and executing the statements.∗/protected String username = null;/∗∗∗ The password for the specified user.∗/protected String password = null;

/∗∗∗ The helper function for getting the name of a database.∗ @return the name of a database∗/protected String getName() { return dbName; }/∗∗∗ The helper function for getting the URL of a database.∗ @return the URL of a database∗/protected String getUrl() { return url; }/∗∗∗ The helper function for getting the username of a database.∗ @return the username of a database∗/protected String getUsername() { return username; }/∗∗∗ The helper function for getting the password of a database user.∗ @return the password of a database user∗/protected String getPassword() { return password; }

/∗∗∗ Connects to a database using the information stored in the∗ following protected members:∗ <code>url</code>,∗ <code>username</code>,∗ <code>password</code>.∗ These members must be set in the constructor method∗ of inherited classes.

Page 296: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

296 Glava 12. Napredni koncepti u JDBC aplikacijama

∗∗ @throws SQLException If an SQL error occured∗ while connecting to a database∗/public void connect() throws SQLException{

if (null == con){

System.out.println("Povezivanje na " + getName() + "...");con = DriverManager.getConnection(getUrl(), getUsername(),

getPassword());con.setAutoCommit(false);System.out.println("Uspesno je ostvarena konekcija!");

}}

/∗∗∗ Disconnects from a previously connected database.∗ Does nothing if the connection does not exists.∗∗ @param successful whether to commit or rollback potential changes∗ made to the database∗ @throws SQLException If an SQL error occured∗ while disconnecting from a database∗/public void disconnect(boolean successful) throws SQLException{

if (null != con){

if (successful){

commit();}else{

rollback();}

con.close();con = null;

System.out.println("Diskonektovano sa " + getName() + "!");}

}

/∗∗∗ Commits the potential changes made to the database.∗ Ignores any SQL errors that might occur.∗/public void commit(){

try{

if (null != con){

con.commit();}

System.out.println("Sve izmene su pohranjene u bazi podataka " +getName());

} catch (SQLException e) {}

Page 297: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 297

}

/∗∗∗ Rolls back the potential changes made to the database.∗ Ignores any SQL errors that might occur.∗/public void rollback(){

try{

if (null != con){

con.rollback();}System.out.println("Sve izmene su ponistene u bazi podataka " +

getName());} catch (SQLException e) {}

}

}

Kod 12.9: Primeri/cas11/src/primer5/Vstud.javapackage primer5;

import java.sql.∗;

public class Vstud extends Database{

public Vstud(){

dbName = "VSTUD";url = "jdbc:db2://localhost:50001/vstud";username = "student";password = "abcdef";

}

public void izlistajPolaganja(short ocena) throws SQLException{

PreparedStatement stmt = con.prepareStatement("SELECT indeks, p.naziv, ocena, godina_roka, oznaka_roka " +"FROM ispit i " +

"JOIN predmet p " +"ON i.id_predmeta = p.id_predmeta " +

"WHERE ocena > 5 " +"AND status_prijave = 'o' " +"AND NOT EXISTS ( " +

"SELECT ∗ " +"FROM ispit i2 " +"WHERE i.indeks = i2.indeks " +

"AND ocena < ? " +")");

stmt.setShort(1, ocena);ResultSet rez = stmt.executeQuery();

System.out.println("Polozeni ispiti studenata koji nemaju ocenumanju od " + ocena);

while(rez.next()){

System.out.println(

Page 298: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

298 Glava 12. Napredni koncepti u JDBC aplikacijama

"Indeks: " + rez.getInt(1) + ", " +"Naziv: " + rez.getString(2).trim() + ", " +"Ocena: " + rez.getInt(3) + ", " +"Godina roka: " + rez.getInt(4) + ", " +"Oznaka roka: " + rez.getString(5).trim());

}

rez.close();stmt.close();

}

public void uvecajBodoveZaPredmete(int indeks) throws SQLException{

PreparedStatement stmt = con.prepareStatement("UPDATE predmet p " +"SET bodovi = bodovi + 1 " +"WHERE bodovi < 10 " +

"AND EXISTS ( " +"SELECT ∗ " +"FROM ispit i " +"WHERE i.id_predmeta = p.id_predmeta " +

"AND ocena > 5 " +"AND indeks = ? " +

")");stmt.setInt(1, indeks);

int brojAzuriranih = stmt.executeUpdate();

System.out.println("Broj azuriranih redova: " + brojAzuriranih);

stmt.close();}

}

Kod 12.10: Primeri/cas11/src/primer5/Mstud.javapackage primer5;

import java.sql.∗;

public class Mstud extends Database{

public Mstud(){

dbName = "MSTUD";url = "jdbc:db2://localhost:50001/mstud";username = "student";password = "abcdef";

}

public void izlistajStudente(short brojBodova) throws SQLException{

PreparedStatement stmt = con.prepareStatement("SELECT indeks, ime, prezime " +"FROM dosije d " +"WHERE NOT EXISTS ( " +

"SELECT ∗ " +"FROM predmet p " +"WHERE bodovi = ? " +

"AND NOT EXISTS ( " +

Page 299: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 299

"SELECT ∗ " +"FROM ispit i " +"WHERE i.indeks = d.indeks " +

"AND i.id_predmeta = p.id_predmeta " +"AND i.ocena > 5 " +

") " +")");

stmt.setShort(1, brojBodova);ResultSet rez = stmt.executeQuery();

System.out.println("\n\nStudenti koji su polozili sve predmete od " +brojBodova + " bodova\n");

while(rez.next()){

System.out.println("Indeks: " + rez.getInt(1) + ", " +"Ime: " + rez.getString(2).trim() + ", " +"Prezime: " + rez.getString(3).trim() + ", ");

}

rez.close();stmt.close();

}

public int obrisiPolaganjaIVratiIndeks() throws Exception{

int indeks = 0;

Statement stmt = con.createStatement();

ResultSet rez = stmt.executeQuery("SELECT max(indeks) " +"FROM dosije ");

boolean dohvacenIndeks = rez.next();if (!dohvacenIndeks){

throw new Exception("Ne postoji nijedan indeks u bazi podataka");}

indeks = rez.getInt(1);

rez.close();

int brojObrisanih = stmt.executeUpdate("DELETE FROM ispit " +"WHERE indeks = ( " +

"SELECT max(indeks) " +"FROM dosije " +

")");

System.out.println("Broj obrisanih redova: " + brojObrisanih);

stmt.close();

return indeks;}

}

Page 300: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

300 Glava 12. Napredni koncepti u JDBC aplikacijama

Metod main() je sada značajno uprošćen jer je sva odgovornost za rukovanje bazamapodataka premeštena u odgovarajuće klase:

Kod 12.11: Primeri/cas11/src/primer5/Primer.javapackage primer5;

import java.sql.∗;import java.util.∗;

public class Primer{

public static void main(String[] args){

Vstud vstud = new Vstud();Mstud mstud = new Mstud();

try{

vstud.connect();mstud.connect();

Scanner ulaz = new Scanner(System.in);

// Program redom:// Zahteva od korisnika da unese broj bodova B.

System.out.println("Unesite broj bodova B:");short brojBodova = ulaz.nextShort();

// Iz baze MSTUD izdvaja indeks, ime i prezime studenata// koji su polozili sve predmete koji nose vise od B bodova.

mstud.izlistajStudente(brojBodova);

// Zatim, zahteva od korisnika da unese ocenu O (ceo broj od 6 do10).

System.out.println("Unesite ocenu O:");short ocena = ulaz.nextShort();

// Iz baze VSTUD izlistava indeks, naziv, ocenu, godinu i oznakuispitnog roka

// za sve studente koji nikada nisu dobili ocenu manju nego sto jeocena O.

vstud.izlistajPolaganja(ocena);

// Nakon ispisivanja tih podataka, u bazi MSTUD, iz tabele ISPIT// brise sva polaganja za studenta sa maksimalnim brojem indeksa I// iz DOSIJE, i vraca I.

int indeks = mstud.obrisiPolaganjaIVratiIndeks();

// Na kraju, u bazi VSTUD, u tabeli PREDMET// za sve predmete koje je polozio student sa brojem indeksa I,// uvecava broj bodova za jedan (osim ako je broj bodova veci od

10,// tada ostavlja nepromenjeno stanje).

vstud.uvecajBodoveZaPredmete(indeks);

Page 301: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

12.3 Povezivanje na više baza podataka 301

ulaz.close();

vstud.disconnect(true);mstud.disconnect(true);

}catch (SQLException e){

System.out.println("SQLCODE: " + e.getErrorCode() + "\n" +"SQLSTATE: " + e.getSQLState() + "\n" +"PORUKA: " + e.getMessage());

try{

vstud.disconnect(false);mstud.disconnect(false);

} catch (SQLException e2) {}

System.exit(1);}catch (Exception e){

e.printStackTrace();

try{

vstud.disconnect(false);mstud.disconnect(false);

} catch (SQLException e2) {}

System.exit(1);

}}

}

Zadatak 12.4 Refaktorisati sve primere i zadatke sa povezivanjem na više baza podatakakoji su implementirani u proceduralnom stilu, tako da koriste klase implementirane uprethodnom primeru. ■

Page 302: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 303: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13. Okruženje za razvoj Hibernate

Prilikom izrade aplikacija, Java programeri se oslanjaju na objektno-orijentisane konceptekoji, kako im i samo ime kaže, počivaju na upotrebi objekata (i naravno, ostalih koncepatakoji se dalje zasnivaju na njima, poput klase, učauravanja, interfejsi i drugi). Ovi objektimodeliraju poslovnu logiku iz realnog sveta, definisanu od strane naručilaca proizvoda.Podaci u memoriji, sa kojima aplikacija upravlja, nisu korisni ukoliko se ne mogu negdetrajno skladištiti. Dodatno, veliki broj podataka počiva upravo iz nekih skladišta poda-taka, te je potrebno da aplikacije pristupaju takvim izvorima informacija. Tradicionalno,ali i dalje u ogromnoj meri, ovi podaci se zapisuju u relacionim bazama podataka zbograzličitih prednosti koje su nam poznate iz dobro razrađene teorije relacionog računa nakojima ove baze podataka počivaju.

Ovim se otvara naredno pitanje — ako Java aplikacije rade sa podacima u memoriji koji suzapisani kao objekti, a naši podaci od interesa se skladište u relacionim bazama podatakakoji su zapisani u tabelama, da li je moguće dizajnirati sistem koji će automatski izvršitiprevođenje podataka iz jednog oblika u drugi i obrnuto? Ovaj problem se naziva problemobjektno-relacionog preslikavanja (engl. Object-Relation Mapping problem) i odgovor napitanje je da može. U ovom poglavlju biće predstavljeno okruženje za razvoj Hibernate,koje omogućava Java programerima da u svojim aplikacijama implementiraju poslovnulogiku, dok se operacije niskog nivoa, kao što su čitanje, skladištenje, brisanje i menjanjepodataka, izvršavaju u pozadini, čime se veliki deo posla olakšava.

Upotreba Hibernate okruženja za razvoj će biti prikazana kroz jedan veći primer, koji ćebiti izrađen deo-po-deo. Ovo znači da, pored toga što će se u projektu povećavati brojklasa sa (gotovo) svakim zahtevom, i same klase će biti proširivane kako bi zadovoljile svezahteve. Takođe, radićemo u alatu IBM Data Studio 4.1.1.

Cilj ovog poglavlja jeste razvoj aplikacije koja ispunjava naredne zahteve (svi zahtevi seimplementiraju nad poznatom bazom podataka VSTUD):

1. Unos podataka o novom smeru u tabelu SMER sa narednim podacima:

Page 304: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

304 Glava 13. Okruženje za razvoj Hibernate

Identifikator 300Oznaka MATF_2019Naziv Novi MATF smer u 2019. godiniBroj semestara 8Broj bodova 240Zvanje Diplomirani informaticarOpis Novi smer na Matematickom fakultetu

2. Brisanje podataka o prethodno unetom smeru iz tabele SMER.3. Unos podataka o novom ispitnom roku (jun 2019. godine) u tabelu ISPITNI_ROK.4. Brisanje podataka o prethodno unetom ispitnom roku iz tabele ISPITNI_ROK.5. Ispisivanje podataka o svim ispitnim rokovima.6. Ispisivanje podataka o ispitnom roku čija se oznaka roka i godina roka unose sa

standarnog ulaza.7. Ispisivanje naziva svih smerova. Nakon svakog naziva smera, ispisuju se indeks, ime

i prezime svih studenata na tom smeru. Dopuniti ispis o studentu tako da se zasvakog studenta ispisuje i prosek.

8. Za zadati indeks studenta ispisati nazive svih položenih predmeta i dobijene ocene.Implementirati dva metoda — jedan koji ne koristi Hibernate Criteria API i drugikoji ga koristi.

Takođe, omogućiti da obrada svakog zahteva predstavlja zasebnu transakciju.

13.1 Podešavanje Hibernate projekta

Nakon pokretanja IBM Data Studio alata, potrebno je da napravimo novi Java projekat.S obzirom da ćemo nakon implementacije svakog zahteva izvesti po jedan projekat, onda jepotrebno kreirati novi (ili duplicirati prethodni) projekat pre svakog novog zahteva. Nakonkreiranja projekta, potrebno je otvoriti njegova podešavanja: desni klik na projekat, paklikom na Properties. Nakon toga je potrebno odabrati meni Java Build Path i u okvirunjega karticu Libraries:

Slika 13.1:

Page 305: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.1 Podešavanje Hibernate projekta 305

Odatle je potrebno odabrati Add Library... dugme, nakon čega se otvara prozor kao nanarednoj slici, u kojem se bira User Library, pa Next:

Slika 13.2:

Ukoliko niste ranije dodavali korisničke biblioteke, ova lista će biti prazna, kao u prozoruna narednoj slici. Odatle je potrebno odabrati User Libraries... dugme:

Slika 13.3:

Page 306: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

306 Glava 13. Okruženje za razvoj Hibernate

Tada će se otvoriti prozor za prikazivanje korisničkih biblioteka. Potrebno je da u tomprozoru izaberemo New... dugme:

Slika 13.4:

Otvoriće nam se mali dijalog u kojem je potrebno uneti naziv biblioteke. U našem slučaju,biblioteku će nazvati HibernateLib, kao na narednoj slici, a zatim pritisnuti OK:

Slika 13.5:

Page 307: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.1 Podešavanje Hibernate projekta 307

Nakon toga se kreira nova biblioteka, u kojoj je potrebno dodati jar datoteke klikom naAdd External JARs... dugme:

Slika 13.6:

U biraču datoteka potrebno je pozicionirati se na lokaciju na kojoj je Hibernate otpako-van nakon preuzimanja, a zatim ući u poddirektorijum lib. Iz tog direktorijuma je po-trebno uključiti sve jar pakete iz narednih poddirektorijuma: envers, jpa, jpa−metamodel−generator, osgi i required.

Slika 13.7:

Page 308: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

308 Glava 13. Okruženje za razvoj Hibernate

Takođe, potrebno je na isti način dodati i db2jcc.jar i db2jcc_licence_cu.jar datotekeiz poddirektorijuma java direktorijuma u kojem je instaliran IBM DB2:

Slika 13.8:

Nakon dodavanja svih paketa, prozor sa korisničkim bibliotekama bi trebalo da izgledakao na narednoj slici. Potrebno je odabrati novokreiranu biblioteku klikom na njen nazivi pritisnuti OK:

Slika 13.9:

Page 309: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.2 Podešavanje konekcije na bazu podataka 309

Finalni korak je biranje Finish dugmeta:

Slika 13.10:

Nakon toga bi naš projekat trebalo da izgleda kao na narednoj slici:

Slika 13.11:

13.2 Podešavanje konekcije na bazu podataka

To create a connection to the database, Hibernate must know the details of our database,tables, classes, and other mechanics. This information is ideally provided as an XML file(usually named hibernate.cfg.xml) or as a simple text file with name/value pairs (usuallynamed hibernate.properties).

For this exercise, we use XML style. We name this file hibernate.cfg.xml so the frameworkcan load this file automatically.

The following snippet describes such a configuration file. Because we are using IBM DB2as the database, the connection details for the IBM DB2 database are declared in thishibernate.cfg.xml file.

Da bismo napravili ovu datoteku, potrebno je da desnim klikom na naziv projekta otvorimopadajući meni iz kojeg biramo New, zatim Other... i onda pronađemo XML File iz filteraXML. Klikom na Next, potrebno je da unesemo naziv datoteke — u ovom slučaju, to je

Page 310: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

310 Glava 13. Okruženje za razvoj Hibernate

hibernate.cfg.xml, odaberemo da se datoteka smesti u direktorijum src i odaberemoFinish.

Ova datoteka će se automatski otvoriti u XML pregledaču, ali je nama neophodno dabude otvorena kao tekstualna datoteka. Ovo se može uraditi desnim klikom na nazivdatoteke hibernate.cfg.xml, a zatim biranjem Open with i Text Editor. U ovu datotekuje potrebno smestiti sledeće:

Kod 13.1: Primeri/cas12/cas12_1/src/hibernate.cfg.xml<?xml version="1.0" encoding="UTF−8"?><hibernate−configuration>

<session−factory><property name="connection.url">

jdbc:db2://localhost:50001/VSTUD</property><property name="connection.driver_class">

com.ibm.db2.jcc.DB2Driver</property><property name="hibernate.connection.username">

student</property><property name="hibernate.connection.password">

abcdef</property><property name="hibernate.dialect">

org.hibernate.dialect.DB2Dialect</property>

</session−factory></hibernate−configuration>

This file has enough information to get a live connection to an IBM DB2 database.

The preceding properties can also be expressed as name/value pairs. For example, here’sthe same information represented as name/value pairs in a text file titled hibernate.properties:

hibernate.connection.driver_class = com.ibm.db2.jcc.DB2Driverhibernate.dialect = org.hibernate.dialect.DB2Dialecthibernate.connection.url = jdbc:db2://localhost:50001/VSTUDhibernate.connection.username = studenthibernate.connection.password = abcdef

Property connection.url indicates the URL to which we should be connected; driver_classrepresents the relevant Driver class to make a connection, and the dialect indicates whichdatabase dialect we are using (IBM DB2, in this case). Similarly, connection.usernameand connection.password specifies the username and password for connecting to a data-base.

If you are following the hibernate.properties file approach, note that all the proper-ties are prefixed with ”hibernate” and follow a pattern — hibernate.∗ properties, forinstance.

Pre nego što pređemo na implementiranje klasa i definisanje preslikavanja između tabelau bazi podataka i klasa u programskom jeziku Java, pogledajmo kako se može kreiratijednostavan klijent za skladištenje objekata.

Page 311: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.3 Skladištenje objekata 311

13.3 Skladištenje objekata

Ovu sekciju započinjemo primerom koji nas stavlja na put ka cilju za našu aplikaciju.

Primer 13.1 — Čas 12 — 01. Omogućiti da prethodno kreirani projekat implementiranaredni zahtev:

• Unos podataka o novom smeru u tabelu SMER sa narednim podacima:

Identifikator 300Oznaka MATF_2019Naziv Novi MATF smer u 2019. godiniBroj semestara 8Broj bodova 240Zvanje Diplomirani informaticarOpis Novi smer na Matematickom fakultetu

Sada kada smo podesili konekciju na bazu podataka, kreirajmo klijenta koji će skladištitiobjekte uz pomoć Hibernate okruženja za razvoj. Pre nego što započnemo implementaciju,kreirajmo paket koji će sadržati sve naše klase i nazovimo ga, na primer, hibernateVstud.

Potrebna nam je instanca klase SessionFactory iz koje možemo da kreiramo objekat klaseSession. U tu svrhu, kreiramo klasu HibernateUtil, koja će predstavljati taj klijent:

Kod 13.2: Primeri/cas12/cas12_1/src/hibernateVstud/HibernateUtil.javapackage hibernateVstud;

import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;

public class HibernateUtil {private static SessionFactory sessionFactory = null;

static {try {

Configuration con = new Configuration();con.configure("hibernate.cfg.xml")

.addAnnotatedClass(Smer.class);

sessionFactory = con.buildSessionFactory();} catch (Throwable e) {

System.err.println("Session factory error");e.printStackTrace();

System.exit(1);}

}

public static SessionFactory getSessionFactory() {return sessionFactory;

}

}

Note that we don’t have to explicitly mention the mapping or configuration or propertiesfiles, because the Hibernate runtime looks for default filenames, such as hibernate.cfg.

Page 312: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

312 Glava 13. Okruženje za razvoj Hibernate

xml or hibernate.properties, in the classpath and loads them. If we have a nondefaultname, make sure you pass that as an argument — like configure("my−hibcfg.xml"), forexample.

Sada se verovatno pitate — zašto se poziva metod addAnotatedClass nad objektom tipaConfiguration u prethodnom koda i to nad klasom Smer koju još nismo ni napisali? Vremeje da to dopunimo.

13.4 Omogućavanje skladištenja objekata i OR preslikavanje

Da bismo rešili prethodni primer, potrebno je da kreiramo klasu Smer i da joj dodamosvojstva koja odgovaraju kolonama u tabeli SMER:package hibernateVstud;

public class Smer {private int id_smera;private String Oznaka;private String Naziv;private int Semestara;private int Bodovi;private Integer Nivo;private String Zvanje;private String Opis;

}

Sada je potrebno da definišemo preslikavanje između klase Smer i tabele SMER u bazi po-dataka. U Hibernate-u je moguće korišćenje dva pristupa za definisanje preslikavanja:

1. Korišćenjem XML datoteka — Za svaku tabelu se definiše XML datoteka koja jestruktuirana na odgovarajući način i koristi etikete i njihova svojstva za definisanjepreslikavanja.

2. Korišćenjem Java anotacija — Koriste se Java konstrukti oblika @NazivAnotacije injihova svojstva za definisanje preslikavanja.

Mi ćemo u daljem tekstu koristiti pristup zasnovan na Java anotacijama.

Hibernate uses the Java Persistence API (JPA) annotations. JPA is the standard specifica-tion dictating the persistence of Java objects. So the preceding annotations are importedfrom the javax.persistence package.

Each persistent object is tagged (at a class level) with an @Entity annotation. The @Tableannotation declares our database table where these entities will be stored. Ideally, weshould not have to provide the @Table annotation if the name of the class and the tablename are the same (in our example, the class is Smer, whereas the table name is SMER).Kod se menja u naredni:...

@Entity@Table (name = "SMER")public class Smer {

...

Page 313: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.4 Omogućavanje skladištenja objekata i OR preslikavanje 313

Sada je potrebno da definišemo preslikavanje kolona. All persistent entities must havetheir identifiers defined. The @Id annotation indicates that the variable is the uniqueidentifier of the object instance (in other words, a primary key). When we annotate theid_smera variable with the @Id annotation, as in the preceding example, Hibernate mapsa field called id_smera from our table Smer to the id_smera variable on the Smer class....

@Entity@Table (name = "SMER")public class Smer {

@Idprivate int id_smera;

...

If your variable doesn’t match the column name, you must specify the column name usingthe @Column annotation. Dodatno, ukoliko kolona ne može imati NULL vrednosti u bazipodataka, potrebno je postaviti još i svojstvo nullable na vrednost false u anotaciji@Column:...

@Entity@Table (name = "SMER")public class Smer {

@Idprivate int id_smera;

@Column (name = "oznaka", nullable = false)private String Oznaka;

@Column (name = "naziv", nullable = false)private String Naziv;

@Column (name = "semestara", nullable = false)private Integer Semestara;

@Column (name = "bodovi", nullable = false)private Integer Bodovi;

@Column (name = "id_nivoa", nullable = false)private Integer Nivo;

@Column (name = "zvanje", nullable = false)private String Zvanje;

@Column (name = "opis", nullable = true)private String Opis;

...

Takođe, s obzirom da su ova svojstva deklarisana modifikatorom private, potrebno jeimplementirati metode za postavljanje i dohvatanje njihovih vrednosti. U ovu svrhu, moženam pomoći IBM Data Studio alat. Desnim klikom na prazan deo koda, možemo odabratiSource, pa zatim Generate Getters and Setters... opciju. Klikom na Select All, azatim OK, biće nam generisane odgovarajuće metode. Možete istražiti sve mogućnostiove opcije, kao što su generisanje samo postavljačkih ili dohvatačkih metoda, generisanjemetoda samo za neka svojstva i drugo.

Page 314: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

314 Glava 13. Okruženje za razvoj Hibernate

Cela implementacija klase Smer data je u nastavku:

Kod 13.3: Primeri/cas12/cas12_1/src/hibernateVstud/Smer.javapackage hibernateVstud;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;

// Svaki trajni objekat mora biti dekorisan anotacijom @Entity.// Anotacija @Table je neophodna jer se ime klase i ime tabele razlikuju.@Entity@Table (name = "SMER")public class Smer {

// Anotacija @Id znaci da svojstvo koje ono dekorise// predstavlja jedinstveni identifikator instance objekta (tj. primarni

kljuc).// Ime polja i ime kolone u bazi je isto u ovom slucaju.@Idprivate int id_smera;

// Za svojstvo Oznaka, ime kolone u bazi podataka je "oznaka",// pa je dodatno ime kolone naglaseno kroz svojstvo name anotacije @Column.// Dodatno, u bazi oznaka ova kolona ne moze biti null,// pa dodajemo svojstvo nullable = false anotaciji @Column.@Column (name = "oznaka", nullable = false)private String Oznaka;

@Column (name = "naziv", nullable = false)private String Naziv;

@Column (name = "semestara", nullable = false)private Integer Semestara;

@Column (name = "bodovi", nullable = false)private Integer Bodovi;

@Column (name = "id_nivoa", nullable = false)private Integer Nivo;

@Column (name = "zvanje", nullable = false)private String Zvanje;

@Column (name = "opis", nullable = true)private String Opis;

// Automatski generisani dohvatacki i postavljacki metodi:// 1. Desni klik na prazan deo koda// 2. Source > Generate Getters and Setters...// 3. Select All// 4. OK

public int getId_smera() {return id_smera;

}

public void setId_smera(int id_smera) {this.id_smera = id_smera;

}

Page 315: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.4 Omogućavanje skladištenja objekata i OR preslikavanje 315

public String getOznaka() {return Oznaka;

}

public void setOznaka(String oznaka) {Oznaka = oznaka;

}

public String getNaziv() {return Naziv;

}

public void setNaziv(String naziv) {Naziv = naziv;

}

public Integer getSemestara() {return Semestara;

}

public void setSemestara(Integer semestara) {Semestara = semestara;

}

public Integer getBodovi() {return Bodovi;

}

public void setBodovi(Integer bodovi) {Bodovi = bodovi;

}

public Integer getNivo() {return Nivo;

}

public void setNivo(Integer nivo) {Nivo = nivo;

}

public String getZvanje() {return Zvanje;

}

public void setZvanje(String zvanje) {Zvanje = zvanje;

}

public String getOpis() {return Opis;

}

public void setOpis(String opis) {Opis = opis;

}

}

Napišimo sada i klasu Main koja će sadržati statički metod main u kojem ćemo testiratirad naše aplikacije. Trenutno, metod main će uraditi dve stvari: prva je pozivanje statičke

Page 316: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

316 Glava 13. Okruženje za razvoj Hibernate

funkcije za unos novog smera, a druga je zatvaranje fabrike sesija:package hibernateVstud;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();

System.out.println("Zavrsetak rada\n");

// Zatvaranje fabrike sesijaHibernateUtil.getSessionFactory().close();

}

...

Sada prelazimo na implementaciju metoda insertSmer koji treba da unese novi red utabelu Smer. Sve akcije se izvršavaju u okviru tzv. sesija. Da bismo mogli da radimo sabazom podataka, potrebno je da otvorimo novu sesiju, što nam je omogućemo metodomopenSession iz klase SessionFactory.

Sledeći korak jeste kreiranje objekta klase Smer i postavljanje odgovarajućih vrednosti. Naovaj način smo podatke smestili u memoriju računara. Ono što je potrebno uraditi da bise oni trajno sačuvali u bazu podataka jeste pozivanjem metoda save() nad objektomsesije (tj. klase Session). Na kraju, potrebno je da zatvorimo sesiju. Kod bi mogao daizgleda kao u nastavku:public static void insertSmer() {

Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

// Postavljanje odgovarajucih vrednosti za smer ide ovde...

session.save(smer);System.out.println("Smer je sacuvan");

session.close();}

Iz ovog dela koda vidimo koliko je jednostavno trajno skladištiti podatke u bazu podataka,koji su se nalazili u memoriji računara. Ipak, postoji još jedna stvar kojom treba dopunitiprethodni kod.

Napomenuli smo na početku poglavlja da aplikacija koju budemo kreirali mora da raditako da svaki zahtev predstavlja jednu transakciju. Ono što je dobra vest jeste da jedefinisanje transakcija u Hibernate-u veoma jednostavno. Pogledajmo naredni kod:Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

// Postavljanje odgovarajucih vrednosti za smer ide ovde...

Transaction TR = session.beginTransaction();try {

Page 317: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.4 Omogućavanje skladištenja objekata i OR preslikavanje 317

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

TR.rollback();System.out.println("Cuvanje smera nije uspelo! Transakcija se ponistava!");

} finally {session.close();

}

Transakcije se u Hibernate-u predstavljaju klasom Transaction. We initiate a transactionby invoking the session.beginTrasaction() method, which creates a new Transactionobject and returns the reference to us. It gets associated with the session and is open untilthat transaction is committed or rolled back.

We perform the required work in a transaction, then issue a commit on this transaction. Atthis stage, the entities are persisted to the database. While persisting, if for whatever rea-son there are any errors, the Hibernate runtime will catch and throw a HibernateException(which is an unchecked RuntimeException). We then have to catch the exception and rollback the transaction.

Cela implementacija klase Main data je u nastavku:

Kod 13.4: Primeri/cas12/cas12_1/src/hibernateVstud/Main.javapackage hibernateVstud;

import org.hibernate.Session;import org.hibernate.Transaction;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();

System.out.println("Zavrsetak rada\n");

// Zatvaranje fabrike sesijaHibernateUtil.getSessionFactory().close();

}

public static void insertSmer() {// Otvaranje sesijeSession session = HibernateUtil.getSessionFactory().openSession();// Kreiranje objekta klase Smer.// U ovom objektu ce biti zapisane sve informacije o novom smeru,// koje ce zatim biti skladistene u bazi podataka.Smer smer = new Smer();

// Postavljanje odgovarajucih vrednosti za smersmer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");

Page 318: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

318 Glava 13. Okruženje za razvoj Hibernate

smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

// Zapocinjemo novu transakcijuTR = session.beginTransaction();

// Skladistimo kreirani smer u tabelu SMER u bazi podatakasession.save(smer);// Pohranjivanje izmena i zavrsavanje transakcijeTR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

// Doslo je do greske: ponistavamo izmene u transakcijiSystem.out.println("Cuvanje smera nije uspelo! Transakcija se

ponistava!");

if (TR != null) {TR.rollback();

}} finally {

// Bilo da je doslo do uspeha ili do neuspeha,// duzni smo da zatvorimo sesijusession.close();

}}

}

13.5 Dohvatanje jednog sloga

S obzirom da smo u prethodnom primeru postavili sva preslikavanja i pripremne korake,ispostaviće se da se dohvatanje jednog sloga iz baze podataka sastoji u jednostavnompozivanju odgovarajućih metoda. Nakon što dohvatimo jedan slog, možemo ga menjati iliobrisati, o čemu će biti reči u narednoj sekciji.

Ukoliko je potrebno da pronađemo (dohvatimo) red iz tabele sa odgovarajućim primarnimključem, na raspolaganju nam je metod load() definisan nad objektima klase Session.Postoji više preopterećenja ovog metoda, a ono koje ćemo mi koristiti jeste potpisa:public void load(Object object, Serializable id)

Prvi argument ovog metoda bi trebalo da bude prazna instanca klase reda koji želimo daučitamo, a drugi argument je instanca primarnog ključa. Nakon izvršavanja ovog metoda,objekat object će biti popunjen vrednostima iz kolona reda čiji je primarni ključ zadat said.

Ukoliko nismo sigurni da slog sa zadatim primarnim ključem postoji u tabeli, nije dobrokoristiti metod load(). U tom slučaju, bolje je koristiti metod get(). Razlika je u tomešto, ukoliko primarni ključ nije pronađen u bazi podataka, metod load() će izbaciti izu-zetak, dok će metod get() vratiti null referencu, što je lakše za korišćenje. Ipak, njegovaupotreba je nešto drugačija jer su nam na raspolaganju naredna dva preopterećenja:public <T> T get(Class<T> clazz, Serializable id)public Object get(String entityName, Serializable id)

Page 319: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.6 Brisanje jednog sloga 319

Prvi od njih je šablonskog tipa i koristi klasu da odredi iz koje tabele dohvata slog, a drugikoristi naziv entiteta, koji je moguće dobiti poziv metoda getEntityName() nad objektomklase Session:public String getEntityName(Object object)

Slede primeri kodova koji koriste metod get():// get an id from some other Java class,// for instance, through a web applicationSupplier supplier = session.get(Supplier.class, id);if (supplier == null) {

System.out.println("Supplier not found for id " + id);return;

}

// ili...

String entityName = session.getEntityName(supplier);Supplier secondarySupplier =

(Supplier) session.load(entityName, id);

13.6 Brisanje jednog sloga

Brisanje slogova iz baze podataka se jednostavno vrši pozivanjem metoda delete() nadobjektom klase Session:public void delete(Object object)

Argument ovog metoda je trajni objekat. Naravno, postoje i složeniji metodi brisanjapodataka.

Primer 13.2 — Čas 12 — 02. Dopuniti prethodni primer tako da implementira narednizahtev:

• Brisanje podataka o prethodno unetom smeru iz tabele SMER.

Rešenje prethodnog primera je dato kroz metod deleteSmer() proširene klase Main.javaiz prethodnog primera:

Kod 13.5: Primeri/cas12/cas12_2/src/hibernateVstud/Main.javapackage hibernateVstud;

import org.hibernate.Session;import org.hibernate.Transaction;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();deleteSmer();

System.out.println("Zavrsetak rada\n");HibernateUtil.getSessionFactory().close();

}

Page 320: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

320 Glava 13. Okruženje za razvoj Hibernate

public static void insertSmer() {Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

smer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

System.out.println("Cuvanje smera nije uspelo! Transakcija seponistava!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteSmer(){Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

Transaction TR = null;try {

TR = session.beginTransaction();

// Ucitavanje (dohvatanje) smera na osnovu primarnog kljucasession.load(smer, 300);// Brisanje ucitanog smera iz bazesession.delete(smer);

System.out.println("Smer obrisan");

// Potvrdjivanje i zavrsavanje transakcijeTR.commit();

} catch (Exception e) {System.err.println("Brisanje smera nije uspelo! Ponistavanje

transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

Page 321: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.7 Složeni ključ 321

}

}

13.7 Složeni ključ

Upravljanje tabelama koje imaju jednostavne primarne ključeve, kao što je to tabela SMER,vrlo je jednostavno. Nešto složenije je rukovati tabelom čiji se primarni ključ sastoji odnekoliko kolona. Takvi primarni ključevi se nazivaju složeni ključevi (engl. compoundparimery key).

You must create a class to represent this primary key. It will not require a primary keyof its own, of course, but it must be a public class, must have a default constructor,must be serializable, and must implement hashCode() and equals() methods to allow theHibernate code to test for primary key collisions (i.e., they must be implemented with theappropriate database semantics for the primary key values).

Your three strategies for using this primary key class once it has been created are asfollows:

1. Mark it as @Embeddable and add to your entity class a normal property for it, markedwith @Id.

2. Add to your entity class a normal property for it, marked with @EmbeddableId.3. Add properties to your entity class for all of its fields, mark them with @Id, and

mark your entity class with @IdClass, supplying the class of your primary key class.

The use of @Id with a class marked as @Embeddable, as shown in the following example, isthe most natural approach The @Embeddable annotation allows you to treat the compoundprimary key as a single property, and it permits the reuse of the @Embeddable class in othertables.// U CPKBook.java datoteci

// Ovo je klasa koja ima slozeni kljuc ISBN@Entitypublic class CPKBook {

@IdISBN id;

...

}

// U ISBN.java datoteci

// Ovo je klasa koja predstavlja slozeni kljuc@Embeddablepublic class ISBN implements Serializable {

// Naziv "group" je nevalidan naziv kolone u SQL−u@Column(name="group_number")int group;int publisher;int title;int checkdigit;

// Podrazumevani konstruktor

Page 322: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

322 Glava 13. Okruženje za razvoj Hibernate

public ISBN() {}

// Get i set metodi...

@Overridepublic boolean equals(Object o) {

if (this == o) return true;if (!(o instanceof ISBN)) return false;

ISBN isbn = (ISBN) o;

if (checkdigit != isbn.checkdigit) return false;if (group != isbn.group) return false;if (publisher != isbn.publisher) return false;if (title != isbn.title) return false;

return true;}

@Overridepublic int hashCode() {

int result = group;result = 31 ∗ result + publisher;result = 31 ∗ result + title;result = 31 ∗ result + checkdigit;return result;

}

}

The next most natural approach is the use of the @EmbeddedId tag. Here, the primary keyclass cannot be used in other tables since it is not an @Embeddable entity, but it does allowus to treat the key as a single attribute of the Account class.@Entitypublic class EmbeddedPKBook {

@EmbeddedIdEmbeddedISBN id;

@ColumnString name;

// Get/set metodi

static class EmbeddedISBN implements Serializable {@Column(name="group_number")int group;int publisher;int title;int checkdigit;

public ISBN() {}

// Get/set metodi, equals, hashCode...}

}

Finally, the use of the @IdClass and @Id annotations allows us to map the compound

Page 323: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.7 Složeni ključ 323

primary key class using properties of the entity itself corresponding to the names of theproperties in the primary key class. The names must correspond (there is no mechanismfor overriding this), and the primary key class must honor the same obligations as withthe other two techniques. The only advantage to this approach is its ability to ”hide” theuse of the primary key class from the interface of the enclosing entity.

The @IdClass annotation takes a value parameter of Class type, which must be the classto be used as the compound primary key. The fields that correspond to the properties ofthe primary key class to be used must all be annotated with @Id — note in the followingcode example that the getCode() and getNumber() methods of the Account class are soannotated, and the AccountPk class is not mapped as @Embeddable, but it is supplied asthe value of the @IdClass annotation.@Entity@IdClass(IdClassBook.EmbeddedISBN.class)public class IdClassBook {

@Idint group;@Idint publisher;@Idint title;@Idint checkdigit;String name;

public IdClassBook() {}

// Get/set metodi

static class EmbeddedISBN implements Serializable {@Column(name="group_number")int group;int publisher;int title;int checkdigit;

public ISBN() {}

// Get/set metodi, equals, hashCode...}

}

Primer 13.3 — Čas 12 — 03. Dopuniti prethodni primer tako da implementira narednizahtev:

• Unos podataka o novom ispitnom roku (jun 2019. godine) u tabelu ISPITNI_ROK.

Rešenje ovog primera je sada vrlo jednostavno. Potrebno je da prvo napravimo klasukoja će predstavljati složeni ključ. Nazovimo je IspitniRokId. U nastavku je data njenaimplementacija. Obratiti pažnju na metode equals() i hashCode(). Definicije ovih metodaće biti gotovo identične za sve klase koje ih prevazilaze iz klase Object:

• Metod equals() prvo ispituje da li je reference objekata this i o (koji se prosleđujekao argument metoda) poklapaju. Zatim proverava da li drugi objekat (o) predsta-

Page 324: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

324 Glava 13. Okruženje za razvoj Hibernate

vlja referencu iste klase kao objekat sa kojim se poredi (this). Zatim proverava dali se svi atributi objekata poklapaju pozivajući metod Objects.equals za svaki paratributa.

• Metod hashCode() jednostavno poziva metod Objects.hash koja prima proizvoljnibroj argumenata i vraća heš vrednost na osnovu njihovih vrednosti. Obično je boljekoristiti ovaj metod nego implementirati svoju heš funkciju.

Cela implementacija je data u nastavku:

Kod 13.6: Primeri/cas12/cas12_3/src/hibernateVstud/IspitniRokId.javapackage hibernateVstud;

import java.io.Serializable;import java.util.Objects;

import javax.persistence.Embeddable;

// Tabela ISPITNI_ROK ima primarni kljuc koji se sastoji od dve kolone.// Ovakav primarni kljuc se naziva slozeni kljuc.// Za slozeni kljuc je potrebno da se kreira posebna klasa// koja mora da implementira interfejs java.io.Serializable.// Stoga moraju biti definisana i naredna dva metoda: equals() i hashCode().// Takodje, neophodno je da ima definisan i podrazumevani konstruktor.

// S obzirom da se ova klasa koristi kao primarni kljuc za drugu klasu,// onda je ne anotiramo pomocu @Entity,// vec koristimo anotaciju @Embeddable@Embeddablepublic class IspitniRokId implements Serializable {

// Podrazumevani serijski ID verzijeprivate static final long serialVersionUID = 1L;

// Kolone koje ulaze u primarni kljucprivate Integer godina;private String oznaka;

// Podrazumevani konstruktorpublic IspitniRokId() {}

public IspitniRokId(Integer godina, String oznaka) {this.godina = godina;this.oznaka = oznaka;

}

// Autogenerisani get/set metodipublic Integer getGodina() {

return godina;}

public void setGodina(Integer godina) {this.godina = godina;

}

public String getOznaka() {return oznaka;

}

public void setOznaka(String oznaka) {this.oznaka = oznaka;

Page 325: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.7 Složeni ključ 325

}

// Prevazilazenje metoda radi testiranja kolizije primarnih kljuceva

@Overridepublic boolean equals(Object o) {

if (this == o) {return true;

}

if (!(o instanceof IspitniRokId)) {return false;

}

IspitniRokId irOther = (IspitniRokId)o;

return Objects.equals(this.godina, irOther.getGodina()) &&Objects.equals(this.oznaka, irOther.getOznaka());

}

@Overridepublic int hashCode() {

return Objects.hash(this.godina, this.oznaka);}

}

Zatim je potrebno specifikovati instancu ove klase kao primarni ključ klase IspitniRok.java, koju takođe kreiramo:

Kod 13.7: Primeri/cas12/cas12_3/src/hibernateVstud/IspitniRok.javapackage hibernateVstud;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;

@Entity@Table(name = "ispitni_rok")public class IspitniRok {

// Za primarni kljuc koristimo instancu klase IspitniRokId,// s obzirom da ova tabela ima slozeni kljuc.// Pogledati klasu IspitniRokId za jos informacija.

@Idprivate IspitniRokId id = null;

// Ostale kolone

@Column(name = "naziv", nullable = false)private String Naziv;

@Column(name = "pocetak_prijavljivanja", nullable = false)private String Pocetak;

@Column(name = "kraj_prijavljivanja", nullable = false)private String Kraj;

@Column(name = "tip", nullable = false)private String Tip = "B";

Page 326: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

326 Glava 13. Okruženje za razvoj Hibernate

// Autogenerisani Get/Set metodi

public IspitniRokId getId() {return id;

}

public void setId(IspitniRokId id) {this.id = id;

}

public String getNaziv() {return Naziv;

}

public void setNaziv(String naziv) {Naziv = naziv;

}

public String getPocetak() {return Pocetak;

}

public void setPocetak(String pocetak) {Pocetak = pocetak;

}

public String getKraj() {return Kraj;

}

public void setKraj(String kraj) {Kraj = kraj;

}

public String getTip() {return Tip;

}

// Zelimo da podrzimo automatsko biranje tipa// ukoliko korisnik prosledi null.public void setTip(String tip) {

if (tip == null) {Tip = "B";return;

}Tip = tip;

}

}

Definisane klase se sada jednostavno koriste u metodu insertIspitniRok() proširene klaseMain.java iz prethodnog primera:

Kod 13.8: Primeri/cas12/cas12_3/src/hibernateVstud/Main.javapackage hibernateVstud;

import org.hibernate.Session;import org.hibernate.Transaction;

Page 327: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.7 Složeni ključ 327

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();deleteSmer();insertIspitniRok();

System.out.println("Zavrsetak rada\n");HibernateUtil.getSessionFactory().close();

}

public static void insertSmer() {Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

smer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

System.out.println("Cuvanje smera nije uspelo! Transakcija seponistava!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteSmer(){Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(smer, 300);session.delete(smer);

System.out.println("Smer obrisan");

TR.commit();} catch (Exception e) {

Page 328: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

328 Glava 13. Okruženje za razvoj Hibernate

System.err.println("Brisanje smera nije uspelo! Ponistavanjetransakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

private static void insertIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

// Kreiramo praznu instancu objekta ispitnog roka// koju cemo popuniti vrednostima koje treba sacuvatiIspitniRok ir = new IspitniRok();

// Kreiramo prvo identifikator, tj. slozeni kljuc,// a zatim i ostale podatkeIspitniRokId id = new IspitniRokId(2019, "jun");ir.setId(id);ir.setNaziv("Jun 2019");ir.setPocetak("6/1/2019");ir.setKraj("6/22/2018");// Ne moramo da podesimo jer ce biti izabrana podrazumevana vrednost// ir.setTip("B");

// Procedura za cuvanje je ista kao i do sadaTransaction TR = null;try {

TR = session.beginTransaction();

session.save(ir);

System.out.println("Ispitni rok je sacuvan");TR.commit();

} catch (Exception e) {System.err.println("Cuvanje ispitnog roka nije uspelo! Ponistavanje

transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

}

Ne zaboravimo da dodamo IspitniRok kao anotiranu klasu u konfiguraciju:

Kod 13.9: Primeri/cas12/cas12_3/src/hibernateVstud/HibernateUtil.javapackage hibernateVstud;

import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;

public class HibernateUtil {private static SessionFactory sessionFactory = null;

Page 329: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.7 Složeni ključ 329

static {try {

Configuration con = new Configuration();con.configure("hibernate.cfg.xml")

.addAnnotatedClass(Smer.class)

.addAnnotatedClass(IspitniRok.class);

sessionFactory = con.buildSessionFactory();} catch (Throwable e) {

System.err.println("Session factory error");e.printStackTrace();

System.exit(1);}

}

public static SessionFactory getSessionFactory() {return sessionFactory;

}

}

Primer 13.4 — Čas 12 — 04. Dopuniti prethodni primer tako da implementira narednizahtev:

• Brisanje podataka o prethodno unetom ispitnom roku iz tabele ISPITNI_ROK.

Sa svim znanjem do sada, ovaj zahtev se trivijalno implementira. Prikazujemo samoažuriranu klasu Main.java i skrećemo pažnju na njen metod deleteIspitniRok() kojiilustruje rešenje ovog zahteva.

Kod 13.10: Primeri/cas12/cas12_4/src/hibernateVstud/Main.javapackage hibernateVstud;

import org.hibernate.Session;import org.hibernate.Transaction;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();deleteSmer();insertIspitniRok();deleteIspitniRok();

System.out.println("Zavrsetak rada\n");HibernateUtil.getSessionFactory().close();

}

public static void insertSmer() {Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

smer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");

Page 330: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

330 Glava 13. Okruženje za razvoj Hibernate

smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

System.out.println("Cuvanje smera nije uspelo! Transakcija seponistava!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteSmer(){Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(smer, 300);session.delete(smer);

System.out.println("Smer obrisan");

TR.commit();} catch (Exception e) {

System.err.println("Brisanje smera nije uspelo! Ponistavanjetransakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

private static void insertIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();

IspitniRokId id = new IspitniRokId(2019, "jun");ir.setId(id);ir.setNaziv("Jun 2019");ir.setPocetak("6/1/2019");

Page 331: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.7 Složeni ključ 331

ir.setKraj("6/22/2018");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(ir);

System.out.println("Ispitni rok je sacuvan");TR.commit();

} catch (Exception e) {System.err.println("Cuvanje ispitnog roka nije uspelo! Ponistavanje

transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();IspitniRokId id = new IspitniRokId(2019, "jun");

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(ir, id);session.delete(ir);

System.out.println("Ispitni rok je obrisan");TR.commit();

} catch (Exception e) {System.err.println("Brisanje ispitnog roka nije uspelo!

Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

}

Page 332: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

332 Glava 13. Okruženje za razvoj Hibernate

13.8 Rad sa skupovima slogova

Za rad sa potencijalno većim brojem slogova u tabeli, na raspolaganju su nam dva pristupa:

1. Korišćenje HQL-a (Hibernate Query Language).2. Korišćenje nativnog SQL-a.

13.8.1 HQL (Hibernate Query Language)

While most ORM tools and object databases offer an object query language, Hibernate’sHQL stands out as complete and easy to use. HQL was inspired by SQL and is a majorinspiration for the Java Persistence Query Language (JPQL).

Menjanje

UPDATE alters the details of existing objects in the database. In-memory entities, managedor not, will not be updated to reflect changes resulting from issuing UPDATE statements.Here’s the syntax of the UPDATE statement:UPDATE [VERSIONED]

[FROM] path [[AS] alias] [, ...]SET property = value [, ...][WHERE logicalExpression]

The fully qualified name of the entity or entities is path. The alias names may be usedto abbreviate references to specific entities or their properties, and must be used whenproperty names in the query would otherwise be ambiguous. VERSIONED means that theupdate will update timestamps, if any, that are part of the entity being updated. Theproperty names are the names of properties of entities listed in the FROM path.

An example of the update in action might look like this:Query query = session.createQuery(

"update Person set creditscore=:creditscore where name=:name");query.setInteger("creditscore", 612);query.setString("name", "John Q. Public");int modifications = query.executeUpdate();

Brisanje

DELETE removes the details of existing objects from the database. In-memory entities willnot be updated to reflect changes resulting from DELETE statements. This also meansthat Hibernate’s cascade rules will not be followed for deletions carried out using HQL.However, if you have specified cascading deletes at the database level (either directly orthrough Hibernate, using the @OnDelete annotation), the database will still remove thechild rows. This approach to deletion is commonly referred to as ”bulk deletion”, since itis the most efficient way to remove large numbers of entities from the database. Here’sthe syntax of the DELETE statement:DELETE

[FROM] path [[AS] alias][WHERE logicalExpression]

The fully qualified name of the entity or entities is path. The alias names may be usedto abbreviate references to specific entities or their properties, and must be used whenproperty names in the query would otherwise be ambiguous.

Page 333: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.8 Rad sa skupovima slogova 333

In practice, deletes might look like this:Query query = session.createQuery(

"delete from Person where accountstatus=:status");query.setString("status", "purged");int rowsDeleted = query.executeUpdate();

Unošenje

A HQL INSERT cannot be used to directly insert arbitrary entities — it can only be used toinsert entities constructed from information obtained from SELECT queries (unlike ordinarySQL, in which an INSERT command can be used to insert arbitrary data into a table, aswell as insert values selected from other tables). Here’s the syntax of the INSERT statement:INSERT

INTO path ( property [, ...])select

The name of an entity is path. The property names are the names of properties of entitieslisted in the FROM path of the incorporated SELECT query. The select query is a HQLSELECT query (as described in the next section). As this HQL statement can only use dataprovided by a HQL select, its application can be limited. An example of copying users toa purged table before actually purging them might look like this:Query query = session.createQuery(

"insert into purged_users(id, name, status) " +"select id, name, status from users where status = :status");

query.setString("status", "purged");int rowsCopied = query.executeUpdate();

Dohvatanje

A HQL SELECT is used to query the database for classes and their properties. As notedpreviously, this is very much a summary of the full expressive power of HQL SELECT queries;however, for more complex joins and the like, you may find that using the Criteria API ismore appropriate. Here’s the syntax of the SELECT statement:[SELECT [DISTINCT] property [, ...]]

FROM path [[AS] alias] [, ...] [FETCH ALL PROPERTIES]WHERE logicalExpressionGROUP BY property [, ...]HAVING logicalExpressionORDER BY property [ASC | DESC] [, ...]

The fully qualified name of the entity or entities is path. The alias names may be usedto abbreviate references to specific entities or their properties, and must be used whenproperty names in the query would otherwise be ambiguous. The property names are thenames of properties of entities listed in the FROM path.

If FETCH ALL PROPERTIES is used, then lazy loading semantics will be ignored, and all theimmediate properties of the retrieved object(s) will be actively loaded (this does not applyrecursively).

When the properties listed consist only of the names of aliases in the FROM clause, theSELECT clause can be omitted in HQL.

Page 334: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

334 Glava 13. Okruženje za razvoj Hibernate

The FROM Clause and Aliases

We have already discussed the basics of the from clause in HQL. The most importantfeature to note is the alias. Hibernate allows you to assign aliases to the classes in yourquery with the as clause. Use the aliases to refer back to the class inside the query. Forinstance, instead of a simple HQL queryfrom Supplier

the example could be the following:from Product as p

The as keyword is optional — you can also specify the alias directly after the class name,as follows:from Product p

If you need to fully qualify a class name in HQL, just specify the package and class name.Hibernate will take care of most of this behind the scenes, so you really need this onlyif you have classes with duplicate names in your application. If you have to do this inHibernate, use syntax such as the following:from businessapp.model.Product

The SELECT Clause and Projection

The select clause provides more control over the result set than the from clause. If youwant to obtain the properties of objects in the result set, use the select clause. For instance,we could run a projection query on the products in the database that only returned thenames, instead of loading the full object into memory, as follows:select product.name from Product product

The result set for this query will contain a List of Java String objects. Additionally, wecan retrieve the prices and the names for each product in the database, like so:select product.name, product.price from Product product

This result set contains a List of Object arrays (therefore, List<Object[]>) — each arrayrepresents one tuple of properties (in this case, a pair that represents name and price).

If you’re only interested in a few properties, this approach can allow you to reduce networktraffic to the database server and save memory on the application’s machine.

Using Named Parameters

Hibernate supports named parameters in its HQL queries. The simplest example of namedparameters uses regular SQL types for the parameters:String hql = "from Product where price > :price";Query query = session.createQuery(hql);query.setDouble("price", 25.0);List results = query.list();

Normally, you do not know the values that are to be substituted for the named parameters;if you did, you would probably encode them directly into the query string. When the value

Page 335: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.8 Rad sa skupovima slogova 335

to be provided will be known only at run time, you can use some of HQL’s object-orientedfeatures to provide objects as values for named parameters. The Query interface has asetEntity() method that takes the name of a parameter and an object.

Using this functionality, we could retrieve all the products that have a supplier whoseobject we already have:String supplierHQL = "from Supplier where name='MegaInc'";Query supplierQuery = session.createQuery(supplierHQL);Supplier supplier = (Supplier) supplierQuery.list().get(0);

String hql = "from Product as product where product.supplier=:supplier";Query query = session.createQuery(hql);query.setEntity("supplier",supplier);List results = query.list();

Moguće je koristiti i metod setParameter() za postavljanje vrednosti imenovane parame-tarske oznake koji ima dva korisna preopterećenja:Query setParameter(String name, Object val)Query setParameter(String name, Object val, org.hibernate.type.Type type)

Oba preopterećenja uzimaju naziv parametarske oznake kao prvi argument i vrednostkojom ona treba biti zamenjena kao drugi argument. Hibernate će pokušati da dedukujetip na osnovu pozicije imenovane parametarske oznake u upitu, a ako to nije dovoljno,onda će koristiti tip objekta koji se prosleđuje, tj. treći argument, ukoliko je zadat.

Associations

Associations allow you to use more than one class in n HQL query, just as SQL allows youto use joins between tables in a relational database. You add an association to a HQLquery with the join clause.

Hibernate supports five different types of joins: inner join, cross join, left outer join,right outer join, and full outer join. If you use cross join, just specify both classesin the from clause (from Product p, Supplier s). For the other joins, use a join clauseafter the from clause. Specify the type of join, the object property to join on, and an aliasfor the other class.

You can use inner join to obtain the supplier for each product, and then retrieve thesupplier name, product name, and product price, as so:select s.name, p.name, p.price from Product p inner join p.supplier as s

You can retrieve the objects using similar syntax:from Product p inner join p.supplier as s

Notice that Hibernate does not return Object objects in the result set; instead, Hibernatereturns Object arrays in the results. This join results in a projection, thus the use ofthe Object arrays. You will have to access the contents of the Object arrays to get theSupplier and the Product objects.

13.8.2 Using Native SQL

Although you should probably use HQL whenever possible, Hibernate does provide a wayto use native SQL statements directly through Hibernate.

Page 336: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

336 Glava 13. Okruženje za razvoj Hibernate

Underlying Hibernate’s native SQL support is the org.hibernate.query.NativeQuery in-terface, which extends the org.hibernate.query.Query interface already discussed. Yourapplication will create a native SQL query from the session with the createSQLQuery()method on the Session interface:public NativeQuery createSQLQuery(String queryString)

After you pass a string containing the SQL query to the createSQLQuery() method, youshould associate the SQL result with an existing Hibernate entity, a join, or a scalar result.The NativeQuery interface has addEntity() , addJoin() , and addScalar() methods. TheaddEntity() methods take an alias argument and either a class name or an entity name.The addJoin() methods take an alias argument and a path to join.

Using native SQL with scalar results is the simplest way to get started with native SQL.Our Java code looks like this:String sql = "select avg(product.price) as avgPrice from Product product";SQLQuery query = session.createSQLQuery(sql);query.addScalar("avgPrice", Hibernate.DOUBLE);List results = query.list();

Because we did not specify any entity aliases, Hibernate executes exactly the same SQLthat we passed through:select avg(product.price) as avgPrice from Product product

The SQL is regular SQL (we did not have to do any aliasing here). We created anSQLQuery object, and then added a scalar mapping with the built-in double type (fromthe org.hibernate._Hibernate class). We needed to map the avgPrice SQL alias to theobject type. The results are a List with one object — a Double.

A bit more complicated than the previous example is the native SQL that returns a resultset of objects. In this case, we will need to map an entity to the SQL query. The entityconsists of the alias we used for the object in the SQL query and its class. For this example,we used our Supplier class:String sql = "select {supplier.∗} from Supplier supplier";SQLQuery query = session.createSQLQuery(sql);query.addEntity("supplier", Supplier.class);List results = query.list();

Hibernate modifies the SQL and executes the following command against the database:select Supplier.id as id0_, Supplier.name as name2_0_ from Supplier supplier

The special aliases allow Hibernate to map the database columns back to the objectproperties.

Primer 13.5 — Čas 12 — 05. Dopuniti prethodni primer tako da implementira narednizahtev:

• Ispisivanje podataka o svim ispitnim rokovima.

U nastavku dajemo dva rešenja: korišćenjem nativnog SQL-a i korišćenjem HQL-a. Obaova pristupa su implementirana u metodu readispitniRok() klase Main.java:

Page 337: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.8 Rad sa skupovima slogova 337

Kod 13.11: Primeri/cas12/cas12_5/src/hibernateVstud/Main.javapackage hibernateVstud;

import java.util.Collections;//import java.util.Iterator;import java.util.List;

import org.hibernate.Query;import org.hibernate.SQLQuery;import org.hibernate.Session;import org.hibernate.Transaction;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();deleteSmer();insertIspitniRok();deleteIspitniRok();readIspitniRok();

System.out.println("Zavrsetak rada\n");HibernateUtil.getSessionFactory().close();

}

public static void insertSmer() {Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

smer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

System.out.println("Cuvanje smera nije uspelo! Transakcija seponistava!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteSmer(){

Page 338: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

338 Glava 13. Okruženje za razvoj Hibernate

Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(smer, 300);session.delete(smer);

System.out.println("Smer obrisan");

TR.commit();} catch (Exception e) {

System.err.println("Brisanje smera nije uspelo! Ponistavanjetransakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

private static void insertIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();

IspitniRokId id = new IspitniRokId(2019, "jun");ir.setId(id);ir.setNaziv("Jun 2019");ir.setPocetak("6/1/2019");ir.setKraj("6/22/2018");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(ir);

System.out.println("Ispitni rok je sacuvan");TR.commit();

} catch (Exception e) {System.err.println("Cuvanje ispitnog roka nije uspelo! Ponistavanje

transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();IspitniRokId id = new IspitniRokId(2019, "jun");

Page 339: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.8 Rad sa skupovima slogova 339

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(ir, id);session.delete(ir);

System.out.println("Ispitni rok je obrisan");TR.commit();

} catch (Exception e) {System.err.println("Brisanje ispitnog roka nije uspelo!

Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readIspitniRok(){

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

// Dohvatanje vise redova − I nacin:// Koriscenjem nativnog SQL−a

// Metod createSQLQuery() od SQL koda zadatog kao nisku// konstruise objekat klase SQLQuerySQLQuery query = session.createSQLQuery(

"SELECT ∗ " +"FROM ispitni_rok");

// S obzirom da je rezultat niz objekata,// potrebno je da specifikujemo koje klase su ti objekti,// i to radimo metodom addEntity().query.addEntity(IspitniRok.class);// Upit se izvrsava pozivanjem nekog od metoda// list(), scroll() ili iterate().List<IspitniRok> ispitniRokovi =

Collections.checkedList(query.list(), IspitniRok.class);

// Dohvatanje vise redova − II nacin:// Koriscenjem HQL−a

// Metod createQuery() od HQL koda zadatog kao nisku// konstruise objekat klase Query.// Primetimo da u FROM klauzi nismo stavili ime tabele (ispitni_rok

)// vec naziv klase (IspitniRok).// Hibernate ovo razume i znace koju tabelu da iskoristi.Query upit2 = session.createQuery("from IspitniRok");ispitniRokovi =

Collections.checkedList(upit2.list(), IspitniRok.class);

// Ispisivanje podataka

Page 340: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

340 Glava 13. Okruženje za razvoj Hibernate

for(IspitniRok ir : ispitniRokovi){System.out.println(ir.getNaziv());

}

// Ukoliko zelimo da ispisemo podatke iteratorom:

// Iterator<IspitniRok> iterator = ispitniRokovi.iterator();// while(iterator.hasNext()){// IspitniRok ir = iterator.next();// System.out.println(ir.getNaziv());// }

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem ispitnihrokova! Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

}

Primer 13.6 — Čas 12 — 06. Dopuniti prethodni primer tako da implementira narednizahtev:

• Ispisivanje podataka o ispitnom roku čija se oznaka roka i godina roka unose sastandarnog ulaza.

Prethodni kod za dohvatanje podataka se menja tako što dodajemo restrikciju na HQLupit, kao što je to implementirano u metodu readIspitniRok(Integer, String) klaseMain.java:

Kod 13.12: Primeri/cas12/cas12_6/src/hibernateVstud/Main.javapackage hibernateVstud;

import java.util.Collections;import java.util.Iterator;import java.util.Scanner;//import java.util.Iterator;import java.util.List;

import org.hibernate.Query;import org.hibernate.SQLQuery;import org.hibernate.Session;import org.hibernate.Transaction;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();deleteSmer();insertIspitniRok();

Page 341: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.8 Rad sa skupovima slogova 341

deleteIspitniRok();readIspitniRok();

Scanner ulaz = new Scanner(System.in);System.out.println("Unesite prvo godinu, pa oznaku za ispitni rok: ");int godina = ulaz.nextInt();String oznaka = ulaz.next();

readIspitniRok(godina, oznaka);

ulaz.close();

System.out.println("Zavrsetak rada\n");HibernateUtil.getSessionFactory().close();

}

public static void insertSmer() {Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

smer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

System.out.println("Cuvanje smera nije uspelo! Transakcija seponistava!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteSmer(){Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(smer, 300);session.delete(smer);

System.out.println("Smer obrisan");

Page 342: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

342 Glava 13. Okruženje za razvoj Hibernate

TR.commit();} catch (Exception e) {

System.err.println("Brisanje smera nije uspelo! Ponistavanjetransakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

private static void insertIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();

IspitniRokId id = new IspitniRokId(2019, "jun");ir.setId(id);ir.setNaziv("Jun 2019");ir.setPocetak("6/1/2019");ir.setKraj("6/22/2018");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(ir);

System.out.println("Ispitni rok je sacuvan");TR.commit();

} catch (Exception e) {System.err.println("Cuvanje ispitnog roka nije uspelo! Ponistavanje

transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();IspitniRokId id = new IspitniRokId(2019, "jun");

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(ir, id);session.delete(ir);

System.out.println("Ispitni rok je obrisan");TR.commit();

} catch (Exception e) {

Page 343: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.8 Rad sa skupovima slogova 343

System.err.println("Brisanje ispitnog roka nije uspelo!Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readIspitniRok() {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

SQLQuery query = session.createSQLQuery("SELECT ∗ " +"FROM ispitni_rok");

query.addEntity(IspitniRok.class);List<IspitniRok> ispitniRokovi =

Collections.checkedList(query.list(), IspitniRok.class);

Query upit2 = session.createQuery("from IspitniRok");ispitniRokovi =

Collections.checkedList(upit2.list(), IspitniRok.class);

for(IspitniRok ir : ispitniRokovi){System.out.println(ir.getNaziv());

}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem rokova!Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readIspitniRok(Integer godina, String oznaka) {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

// U ovom slucaju koristimo imenovane parametarske oznake// da bismo postavili restrikciju// koristeci parametre metodaQuery query = session.createQuery(

// Podsetimo se da se u from klauzi nalazi ime Klase"from IspitniRok ir " +

Page 344: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

344 Glava 13. Okruženje za razvoj Hibernate

// Tako da se restrikcije postavljaju// nad poljima objekata te klase,// a ne nad kolonama tabele.// Ukoliko bismo ispod stavili uslov "where ir.godina = :

god:,// ispaljen bi bio naredni izuzetak:// Exception in thread "main" org.hibernate.QueryException:// could not resolve property: godina of:

hibernateVstud.IspitniRok"where ir.id.godina = :god " +"and ir.id.oznaka = :ozn");

// Postavljanje parametra se vrsi metodom setParameter// koji prima naziv parametra i vrednostquery.setParameter("god", godina);query.setParameter("ozn", oznaka);

List<IspitniRok> ispitniRokovi = query.list();Iterator<IspitniRok> iterator = ispitniRokovi.iterator();while(iterator.hasNext()){

IspitniRok ir = iterator.next();System.out.println("Ispitni rok: " + ir.getNaziv());

}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem rokova!Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

}

13.9 Asocijativne veze i strani ključevi

Jedan od najznačajnijih elemenata relacionih baza podataka jesu tzv. asocijativne vezekoje se ostvaruju između tabela. Na šta mislimo pod tim pojmom? Neka su nam date dvetabele Student i Knjiga:create table Student (

id_studenta integer not null,ime_prezime varchar(50) not null,naziv_smera varchar(50) not null,

primary key (id_studenta))

create table Knjiga (id_knjige integer not null,naziv_knjige varchar(50) not null,autor varchar(50) not null,

primary key (id_knjige)

Page 345: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 345

)

Ove dve tabele trenutno nisu povezane, odnosno, slogovi iz tabele Student i slogovi iztabele Knjiga ”žive” potpuno odvojeno i bilo kakva izmena jedne tabele nikako ne utičena drugu tabelu.

Međutim, šta ukoliko je potrebno da čuvamo informaciju o tome koji student je pozajmiokoju knjigu iz biblioteke? Implementiranje ovog zahteva će kreirati asocijativnu vezuizmeđu ovih tabela jer sada postoji zavisnost među podacima iz ovih tabela.

U zavisnosti od toga koja je semantika veze koja se ostvaruje podacima, razlikujemonekoliko tipova veza, o kojima ćemo detaljnije diskutovati u nastavku. Za sada, potrebnoje da sebi postavimo naredna pitanja:

• P1: Može li jedna knjiga pripadati više studenata?• P2: Može li student imati više od jedne knjige?

Odgovori na ova pitanja, koja su postavljena u poslovnom domenu, direktno utiču na tipasocijativne veze koja se formira. Tipovi veza, zajedno sa odgovorima, dati su u tabeli13.1.

Tabela 13.1: Određivanje tipa asocijativne veze između klasa Student i Knjiga.Odgovor na P1 Odgovor na P2 Veza između Student i KnjigaNe Ne Jedan-ka-jedanDa Ne Više-ka-jedanNe Da Jedan-ka-višeDa Da Više-ka-više

13.9.1 Veza jedan-ka-jedan

Veza jedan-ka-jedan se može ostvariti na nekoliko načina. U najjednostavnijoj varijanti,svojstva obe klase se čuvaju u istoj tabeli:create table StudentKnjiga (

skid integer not null,ime_prezime ...,naziv_smera ...,naziv_knjige ...,autor ...,

primary key (skid))

// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

@EntityClass StudentKnjiga {

@Idprivate Integer skid;

// Ostala polja i get/set metodi}

Alternativno, trajni objekti se mogu čuvati u različitim tabelama, od kojih svaka ima svojprimarni ključ, ali za svakog studenta i svaku knjigu mora da važi naredno pravilo: student

Page 346: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

346 Glava 13. Okruženje za razvoj Hibernate

koji je vlasnik neke knjige i ta knjiga moraju imati isti primarni ključ.

Moguće je održavati strani ključ od jednog entiteta ka drugom, ali ne bismo smeli imalidvosmerni strani ključ u ovakvom odnosu jer bismo kreirali kružnu zavisnost. Naravno,možemo da ne kreiramo strani ključ i da ostavimo Hibernate-u da se stara o tome. U tomslučaju bi tabele i klase izgledale:create table Student (

id_studenta integer not null,ime_prezime ...,naziv_smera ...,

primary key (id_studenta))

create table Knjiga (id_knjige integer not null,naziv_knjige ...,autor ...,

primary key (id_knjige))

// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

@Entityclass Student {

@Idprivate Integer id_studenta;

// ...}

@Entityclass Knjiga {

@Idprivate Integer id_knjige;

// ...}

Poslednja opcija je da se održava odnos stranim ključem između dve tabele, pri čemuse postavlja opcija unique nad kolonom koja predstavlja strani ključ. Ovaj pristup imaprednost u tome što jednostavnim uklanjanjem opcije unique, od veze jedan-ka-jedan možese ostvariti veza više-ka-jedan. U nastavku dajemo kako bi izgledale tabele i klase u ovompristupu:create table Student (

id_studenta integer not null,ime_prezime ...,naziv_smera ...,

primary key (id_studenta))

create table Knjiga (id_knjige integer not null,naziv_knjige ...,autor ...,id_studenta integer not null,

Page 347: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 347

primary key (id_knjige),

foreign key (id_studenta)references Student,

unique (id_studenta))

// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

@Entityclass Student {

@Idprivate Integer id_studenta;

@OneToOne(mappedBy="student")private Knjiga knjiga;

// Get/set metodi}

@Entityclass Knjiga {

@Idprivate Integer id_knjige;

// Ostala polja

@OneToOneprivate Student student;

// Get/set metodi}

Ono što prvo primećujemo u kodu jeste da smo uveli novu anotaciju @OneToOne. Ovaanotacija se koristi ukoliko jedna klasa sadrži referencu na objekat druge klase (na primer,Knjiga sadrži polje student koje čuva referencu na klasu Student) i ukoliko želimo dakažemo Hibernate-u da je veza koja se ostvaruje jedan-ka-jedan.

Da klasa Student ne čuva referencu ka klasi Knjiga, time bi ovaj odnos bio rešen. Međutim,ukoliko nam je potrebno da obe klase čuvaju referencu jedna ka drugoj, onda dobijamosituaciju kao u prethodnom kodu. Ovakav pristup dovodi do toga da je veza koja seostvaruje bidirekciona, odnosno, za datog studenta možemo dobiti referencu na knjigu čijije on vlasnik, ali takođe, za datu knjigu, možemo dobiti referencu na studenta koji je njenvlasnik. U tom slučaju, potrebno je da obe reference (polja knjiga i student) u obe klase(Student i Knjiga, redom) budu dekorisana anotacijom @OneToOne.

Međutim, sad se javlja novi problem — kako Hibernate da zna da li se ova bidirekcionaveza održava u tabeli STUDENT ili u tabeli KNJIGA? I drugi tipovi veze mogu dovesti doovakve situacije i rešenje se sastoji u postavljanju opcije mappedBy kojom se navodi kojepolje u drugoj klasi ostvaruje vezu stranog ključa. U ovom slučaju, želimo da postoji straniključ nad kolonom id_studenta u tabeli KNJIGA, pa zato u klasi Student navodimo da jeveza ostvarena kroz polje student u klasi Knjiga.

Page 348: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

348 Glava 13. Okruženje za razvoj Hibernate

13.9.2 Veza jedan-ka-više/više-ka-jedan

Veza jedan-ka-više (ili iz perspektive druge klase, više-ka-jedan) može biti jednostavnoreprezentovana stranim ključem ka primarnom ključu tabele koja se nalazi na ”jedan”kraju ove veze u tabeli koja se nalazi na ”više” kraju ove veze, bez dodatnih ograničenja.

U nastavku dajemo kako bi izgledala shema tabela i implementacija klasa u slučaju da seostvaruje veza jedan-ka-više u smeru od klase Student do klase Knjiga (odnosno, jedanstudent može da ima više knjiga):create table Student (

id_studenta integer not null,ime_prezime ...,naziv_smera ...,

primary key (id_studenta))

create table Knjiga (id_knjige integer not null,naziv_knjige ...,autor ...,

primary key (id_knjige))

// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

@Entityclass Student {

@Idprivate Integer id_studenta;

@OneToMany(mappedBy="student")private List<Knjiga> knjige;

// Get/set metodi}

@Entityclass Knjiga {

@Idprivate Integer id_knjige;

// Ostala polja

@ManyToOne@JoinColumn(name="id_studenta")private Student student;

// Get/set metodi}

Ono što bi trebalo da primetimo iz prethodnog koda je sledeće:

1. Koristimo anotacije @OneToMany i @ManyToOne da definišemo odgovarajući tip vezeizmeđu ovih klasa. U klasi koja predstavlja ”jedan” stranu veze koristimo @OneToMany,a u drugoj koristimo @ManyToOne.

2. U klasi Student, umesto da čuvamo referencu na jednu knjigu, potrebno nam je daimamo referencu na kolekciju knjiga, s obzirom da ih jedan student može imati više.

Page 349: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 349

U ovom konkretnom primeru, za kolekciju smo odabrali List<T>, ali mogli smo imatii, na primer, Set<T>, Map<K, V>, i druge (iz paketa java.util).

3. Možemo koristiti anotaciju @JoinColumn da specifikujemo naziv kolone koja učestvujeu stranom ključu koji se kreira u ovoj vezi.

Dodatno, veza jedan-ka-više/više-ka-jedan može se održavati postojanjem treće tabele kojase naziva spojna tabela (engl. link table). U našem primeru, ovakva tabela bi održavalastrane ključeve ka tabelama STUDENT i KNJIGA, a te kolone bi učestvovale u primarnomključu vezivne tabele. Dodatno, mora biti postavljeno ograničenje jedinstvenosti nadjednom stranom odnosa — inače, spojna tabela može predstavljati sve moguće kombinacije,čime bi se ostvarila veza više-ka-više. Dajmo primer sheme spojne tabele:create table StudentKnjigaLink (

id_studenta integer not null,id_knjige integer not null,

primary key (id_studenta, id_knjige),

foreign key (id_studenta)references Student,

foreign key (id_knjige)references Knjiga,

unique (id_knjige))

Korišćenje spojne tabele se ostvaruje korišćenjem anotacije @JoinTable, koju ćemo samopomenuti bez daljeg diskutovanja o njoj.

13.9.3 Veza više-ka-više

Kao što smo napomenuli na kraju prethodne podsekcije, ako se ograničenje jedinstveno-sti ne primeni na ”jedan” kraju bidirekcione asocijativne veze prilikom korišćenja spojnetabele, ta veza postaje više-ka-više veza. Sve moguće varijante parova (Student, Knjiga)mogu biti reprezentovane, ali nije moguće da jedan student ima više puta istu knjigu, sobzirom da bi u takvoj situaciji došlo do dupliciranja složenog primarnog ključa te spojnetabele.

Ukoliko umesto tog pristupa dodelimo spojnoj tabeli svoj primarni ključ, koji ne sadržikolone koje ulaze kao deo stranih ključeva ka drugim tabelama, onda time možemo repre-zentovati punu više-ka-više vezu, naravno, ukoliko to odgovara domenskom problemu. Utom slučaju, shema spojne tabele bi mogla izgledati kao u narednom kodu:create table StudentKnjigaLink (

surogat_id integer not null,id_studenta integer not null,id_knjige integer not null,

primary key (surogat_id),

foreign key (id_studenta)references Student,

foreign key (id_knjige)references Knjiga

)

Page 350: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

350 Glava 13. Okruženje za razvoj Hibernate

U svakom slučaju, anotacija koja se koristi je @ManyToMany i ona se navodi u obe klase. Kaoi do sada, ukoliko je veza bidirekciona, potrebno je navesti mappedBy opciju anotacije. Akojedna klasa navede ovu opciju, onda je druga strana vlasnik asocijacije i vrednost opcijemora biti polje te druge klase. Dajemo primer korišćenja kroz klase Student i Knjiga:@Entityclass Student {

@Idprivate Integer id_studenta;

@ManyToManyprivate List<Knjiga> knjige;

// Get/set metodi}

@Entityclass Knjiga {

@Idprivate Integer id_knjige;

@ManyToMany(mappedBy="student")private List<Student> student;

// Get/set metodi}

13.9.4 Strani ključevi u složenim primarnim ključevima

Pretpostavimo da imamo tabelu KORISNIK čiji se složeni primarni kljušastoji od kolonakorisnicko_ime i id_odeljenja, kao i da imamo tabelu ODELJENJE koja sadrži primarniključ id. Takođe, postoji strani ključ fk_korisnik_odeljenje koji postavlja ograničenjena kolonu id_odeljenja iz tabele KORISNIK u odnosu na kolonu id iz tabele ODELJENJE ikoji predstavlja odnos više-ka-jedan (jedno odeljenje može imati više korisnika, a jedankorisnik može pripadati samo jednom odeljenju). Kako bismo ovo anotirali u Hibernaterazvojnom okruženju?

Na raspolaganju nam je anotacija @MapsId koja je dizajnirana upravo iz ovog razloga.public class KorisnikId implements Serializable {

protected String korisnicko_ime;protected Long id_odeljenja;// ...

}

@Entitypublic class Korisnik {

@EmbeddedIdprotected KorisnikId id;

@ManyToOne@MapsId("id_odeljenja")protected Odeljenje odeljenje;

public Korisnik(KorisnikId id) {this.id = id;

}

Page 351: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 351

// ...}

Anotacija @MapsId kaže Hibernate razvojnom okruženju da ignoriše vrednost polja KorisnikId−> id_odeljenja prilikom čuvanja instance klase Korisnik. Hibernate će umesto togakoristiti identifikator iz klase Odeljenje dodeljen polju Korisnik −> odeljenje prilikomčuvanja sloga u tabeli KORISNIK.

13.9.5 Strani ključevi ka složenim ključevima

Slična situacija se javlja kada je potrebno mapirati asocijativnu vezu složenog stranogključa. Pogledajmo DDL za naredne dve tabele:CREATE TABLE Korisnik (

korisnicko_ime integer NOT NULL,id_odeljenja integer NOT NULL,

PRIMARY KEY (korisnicko_ime, id_odeljenja))

CREATE TABLE Artikal (id integer NOT NULL,korisnicko_ime_prodavca integer NOT NULL,id_odeljenja_prodavca integer NOT NULL,

PRIMARY KEY (id),

FOREIGN KEY (korisnicko_ime_prodavca,id_odeljenja_prodavca)REFERENCES Korisnik

)

U ovoj shemi, prodavac artikla je predstavljen složenim stranim ključem u tabeli Artikal.Ova veza predstavlja odnos jedan-ka-više (jedan korisnik je vlasnik više artikala, a jedanartikal pripada samo jednom korisniku). U domenskom modelu, ovo mapiranje se možerešiti na sledeći način:@Entitypublic class Korisnik {

@IdKorisnikId id;

// ...}

@Embeddablepublic class KorisnikId implements Serializable {

Integer korisnicko_ime;Integer id_odeljenja;

// ...}

// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

@Entitypublic class Artikal {

Page 352: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

352 Glava 13. Okruženje za razvoj Hibernate

@IdInteger id_artikla;

@ManyToOne@JoinColumns({

@JoinColumn(name = "korisnicko_ime_prodavca",referencedColumnName = "korisnicko_ime"),

@JoinColumn(name = "id_odeljenja_prodavca",referencedColumnName = "id_odeljenja")

})Korisnik prodavac;

// ...}

Anotacija @JoinColumns predstavlja listu kolona u složenom stranom ključu koje učestvujuu ovoj asocijativnoj vezi. Napomenimo da bi trebalo zaboraviti postavljanje vrednostireferencedColumnName, čime se ostvaruje veza između izvora i cilja stranog ključa. Hiber-nate nas, nažalost, neće upozoriti ukoliko ovo zaboravimo, a može dovesti do problemausled pogrešnog redosleda kolona u generisanoj shemi.

13.9.6 Složeni strani ključevi kao delovi složenih primarnih ključeva

Najkomplikovaniji slučaj se može pojaviti ukoliko se izmeni shema Artikal tako da kolonestranog ključa učestvuju u složenom primarnom ključu, kao u narednoj shemi:CREATE TABLE Artikal (

id integer NOT NULL,korisnicko_ime_prodavca integer NOT NULL,id_odeljenja_prodavca integer NOT NULL,

PRIMARY KEY (id,korisnicko_ime_prodavca,id_odeljenja_prodavca),

FOREIGN KEY (korisnicko_ime_prodavca,id_odeljenja_prodavca)REFERENCES Korisnik

)

Rešenje ovog problema leži u kombinaciji prethodna dva rešenja — korišćenje @MapsId i@JoinColumns, zajedno sa odgovarajućom anotacijom za tip veze, kao u narednom kodu:public class ArtikalId implements Serializable {

Integer id;KorisnikId id_korisnika;

// ...}

@Entitypublic class Artikal {

@EmbeddedIdArtikalId id_artikla;

// Naredne anotacije se vezuju za polje "Korisnik prodavac;" ispod.// Odvojene su radi lakseg analiziranja i komentarisanja.

Page 353: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 353

// 1. Vezujemo ArtikalId−>id_korisnika za identifikator klase Korisnik@MapsId("id_korisnika")

// 2. Definisemo po cemu se vrsi spajanje za slozeni strani kljuc// koji postoji izmedju klasa Artikal i Korisnik@JoinColumns({

@JoinColumn(name = "korisnicko_ime_prodavca",referencedColumnName = "korisnicko_ime"),

@JoinColumn(name = "id_odeljenja_prodavca",referencedColumnName = "id_odeljenja")

})

// 3. Definisemo tip veze izmedju Artikal i Korisnik@ManyToOne

Korisnik prodavac;

// ...}

Primer 13.7 — Čas 12 — 07. Dopuniti prethodni primer tako da implementira narednizahtev:

• Ispisivanje naziva svih smerova. Nakon svakog naziva smera, ispisuju se indeks,ime i prezime svih studenata na tom smeru. Dopuniti ispis o studentu tako da seza svakog studenta ispisuje i prosek.

Ovaj zahtev je do sada najsloženiji jer uvodi dosta novih klasa i preslikavanja. Za početak,s obzirom da su nam potrebni podaci iz tabela DOSIJE i SMER koje do sada nismo koristili,potrebno je da kreiramo klase Student i Ispit, i definišemo preslikavanja između njih iodgovarajućih tabela, kao i između samih klasa.

Krenimo od klase Student:

Kod 13.13: Primeri/cas12/cas12_7/src/hibernateVstud/Student.javapackage hibernateVstud;

import java.util.ArrayList;import java.util.List;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.OneToMany;import javax.persistence.Table;

@Entity@Table (name = "dosije")public class Student {

// Primarni kljuc

@Id@Columnprivate Integer indeks;

// Kolone od znacaja

@Column(name = "id_smera", nullable = false)

Page 354: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

354 Glava 13. Okruženje za razvoj Hibernate

private Integer idSmera;

@Column(name = "ime", nullable = false)private String ime;

@Column(name = "prezime", nullable = false)private String prezime;

// Da bismo izracunali prosek polozenih predmeta za studenta,// potrebno nam je da dohvatimo informacije o njegovim ispitima.// Zbog toga definisemo listu ispita,// i dekorisemo je anotacijom veze izmedju tabela "dosije" i "ispit".// S obzirom da tabela "ispit" treba da odrzava strani kljuc,// onda koristimo mappedBy da bismo specifikovali// da je ta tabela odgovorna za bidirekcionu vezu.@OneToMany(mappedBy = "student")private List<Ispit> ispiti = new ArrayList<>();

// Get/set metodi

public Integer getIndeks() {return indeks;

}

public void setIndeks(Integer indeks) {this.indeks = indeks;

}

public Integer getId_smera() {return idSmera;

}

public void setId_smera(Integer id_smera) {this.idSmera = id_smera;

}

public String getIme() {return ime;

}

public void setIme(String ime) {this.ime = ime;

}

public String getPrezime() {return prezime;

}

public void setPrezime(String prezime) {this.prezime = prezime;

}

public List<Ispit> getIspiti() {return ispiti;

}

public void setIspiti(List<Ispit> ispiti) {this.ispiti = ispiti;

}

// Metod koji racuna prosek studenta

Page 355: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 355

public double prosek() {double ukupno = 0;int broj_polozenih = 0;List<Ispit> ispiti = this.getIspiti();for (Ispit ispit : ispiti) {

// Izdvajamo informacije samo o polozenim ispitimaif(ispit.getStatus().equalsIgnoreCase("o") && ispit.getOcena() > 5)

{ukupno += ispit.getOcena();broj_polozenih++;

}}if(broj_polozenih == 0)

return 0;return ukupno/broj_polozenih;

}

}

S obzirom da je potrebno da izračunamo prosek položenih predmeta za datog studenta,definišemo metod prosek() koji koristi listu svih ispita studenta. Za listu ispita smomorali da napravimo odgovarajuće preslikavanje. S obzirom da jedan student može imativiše ispita, koristimo vezu jedan-ka-više. Dodatno, moramo da navedemo po čemu se vrši”spajanje” između klasa, i to je u ovom slučaju, po koloni indeks.

Ono što je još bilo potrebno uraditi jeste kreiranje veze između klasa Smer i Student. Ovaveza je definisana u klasi Smer kao jedan-ka-više, s obzirom da jedan smer može sadržativiše studenata:

Kod 13.14: Primeri/cas12/cas12_7/src/hibernateVstud/Smer.javapackage hibernateVstud;

import java.util.ArrayList;import java.util.List;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.OneToMany;import javax.persistence.Table;

@Entity@Table (name = "SMER")public class Smer {

@Idprivate int id_smera;

@Column (name = "oznaka", nullable = false)private String Oznaka;

@Column (name = "naziv", nullable = false)private String Naziv;

@Column (name = "semestara", nullable = false)private Integer Semestara;

@Column (name = "bodovi", nullable = false)private Integer Bodovi;

Page 356: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

356 Glava 13. Okruženje za razvoj Hibernate

@Column (name = "id_nivoa", nullable = false)private Integer Nivo;

@Column (name = "zvanje", nullable = false)private String Zvanje;

@Column (name = "opis", nullable = true)private String Opis;

// Kreiramo asocijativnu vezu izmedju klasa Smer i Student.// Primetimo da u klasi Student nemamo referencu na klasu Smer,// sto ovu vezu cini jednosmernom.@OneToMany@JoinColumn(name = "id_smera")private List<Student> studentiNaSmeru = new ArrayList<>();

public int getId_smera() {return id_smera;

}

public void setId_smera(int id_smera) {this.id_smera = id_smera;

}

public String getOznaka() {return Oznaka;

}

public void setOznaka(String oznaka) {Oznaka = oznaka;

}

public String getNaziv() {return Naziv;

}

public void setNaziv(String naziv) {Naziv = naziv;

}

public Integer getSemestara() {return Semestara;

}

public void setSemestara(Integer semestara) {Semestara = semestara;

}

public Integer getBodovi() {return Bodovi;

}

public void setBodovi(Integer bodovi) {Bodovi = bodovi;

}

public Integer getNivo() {return Nivo;

}

Page 357: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 357

public void setNivo(Integer nivo) {Nivo = nivo;

}

public String getZvanje() {return Zvanje;

}

public void setZvanje(String zvanje) {Zvanje = zvanje;

}

public String getOpis() {return Opis;

}

public void setOpis(String opis) {Opis = opis;

}

public List<Student> getStudentiNaSmeru() {return studentiNaSmeru;

}

public void setStudentiNaSmeru(List<Student> studentiNaSmeru) {this.studentiNaSmeru = studentiNaSmeru;

}

}

Ovo je bilo relativno jednostavno uraditi. Problematika se javlja u implementaciji klaseIspit. Za početak, dajmo njenu celu definiciju, pa ćemo obratiti pažnju na neke detalje:

Kod 13.15: Primeri/cas12/cas12_7/src/hibernateVstud/Ispit.javapackage hibernateVstud;

import javax.persistence.Column;import javax.persistence.EmbeddedId;import javax.persistence.Entity;import javax.persistence.JoinColumn;import javax.persistence.JoinColumns;import javax.persistence.ManyToOne;import javax.persistence.MapsId;import javax.persistence.Table;

@Entity@Table(name = "ispit")public class Ispit {

// Primarni kljuc// U ovom slucaju cemo koristiti drugi pristup kreiranju primarnog kljuca,// tj. koriscenjem @EmbeddedId anotacije.// Pogledati skriptu za vise detalja.@EmbeddedIdprivate IspitId id_ispita;

// Ostale kolone

@Columnprivate Integer ocena;

Page 358: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

358 Glava 13. Okruženje za razvoj Hibernate

@Column(name="status_prijave")private String status;

// Resavanje asocijativnih veza izmedju klasa

// Kreiranje veze izmedju Ispit i Student@ManyToOne@JoinColumn(name = "indeks",

referencedColumnName = "indeks",insertable = false,updatable = false)

private Student student;

// Problem je sto se u primarnom kljucu javlja "potkljuc" IspitniRokId,// koji ima kolone "godina" i "oznaka".// A u primarnom kljucu tabele "ispit",// te kolone se nazivaju "godina_roka" i "oznaka_roka", redom.// Tako da je potrebno to resiti.

// IspitniRok se spaja sa Ispit preko IspitniRokId,// koji je u IspitId stavljen kao polje "id_roka"// Zato koristimo @MapsId anotaciju, koja prihvata naziv polja// u @EmbeddedId klasi IspitniRokId@MapsId("id_roka")// Sada specifikujemo kako se tacno vrsi "spajanje",// tj. kako se formira ogranicenje stranog kljuca.// Za to koristimo JoinColums, posto se spajanje vrsi po dve kolone,// odnosno koriscenjem dva polja iz klase@JoinColumns({

@JoinColumn(name = "godina_roka", referencedColumnName = "godina"),@JoinColumn(name = "oznaka_roka", referencedColumnName = "oznaka")

})// Na kraju, specifikujemo tip veze@ManyToOneprivate IspitniRok ispitniRok;

// Get/set metodi

public IspitId getId_ispita() {return id_ispita;

}

public void setId_ispita(IspitId id_ispita) {this.id_ispita = id_ispita;

}

public Integer getOcena() {return ocena;

}

public void setOcena(Integer ocena) {this.ocena = ocena;

}

public String getStatus() {return status;

}

public void setStatus(String status) {this.status = status;

}

Page 359: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 359

public Student getStudent() {return student;

}

public void setStudent(Student student) {this.student = student;

}

}

Prvo što vidimo jeste da klasa Ispit sadrži složeni ključ IspitId. Dajmo i definiciju oveklase:

Kod 13.16: Primeri/cas12/cas12_7/src/hibernateVstud/IspitId.javapackage hibernateVstud;

import java.io.Serializable;import java.util.Objects;

import javax.persistence.Column;

// Klasa predstavlja slozeni kljuc za Ispit.// Primetimo da ovaj put nismo anotirali klasu anotacijom @Embeddable,// kao u prvom pristupu kreiranja slozenih kljuceva.public class IspitId implements Serializable {

private static final long serialVersionUID = 1L;

// Slozeni kljuc tabele "ispit" sadrzi primarni kljuc tabele "ispitni_rok",// kao i kolone "indeks" i "id_predmeta"

private IspitniRokId id_roka;

@Column(name = "indeks")private Integer indeks;

@Column(name = "id_predmeta")private Integer id_predmeta;

// Podrazumevani konstruktor za Serializablepublic IspitId() {}

public IspitId(IspitniRokId id_roka, Integer indeks, Integer id_predmeta) {this.id_roka = id_roka;this.indeks = indeks;this.id_predmeta = id_predmeta;

}

// Get/set metodi

public IspitniRokId getId_roka() {return id_roka;

}

public void setId_roka(IspitniRokId id_roka) {this.id_roka = id_roka;

}

Page 360: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

360 Glava 13. Okruženje za razvoj Hibernate

public Integer getIndeks() {return indeks;

}

public void setIndeks(Integer indeks) {this.indeks = indeks;

}

public Integer getId_predmeta() {return id_predmeta;

}

public void setId_predmeta(Integer id_predmeta) {this.id_predmeta = id_predmeta;

}

// Prevazilazenje metoda za odredjivanje jednakosti kljuceva

@Overridepublic boolean equals(Object o) {

if (this == o) {return true;

}

if (!(o instanceof IspitId)) {return false;

}

IspitId other = (IspitId)o;

return Objects.equals(this.getId_roka(), other.getId_roka())&& Objects.equals(this.getIndeks(), other.getIndeks())&& Objects.equals(this.getId_predmeta(), other.getId_predmeta()

);}

@Overridepublic int hashCode() {

return Objects.hash(this.getId_roka(), this.getIndeks(), this.getId_predmeta());

}}

Ono što primećujemo jeste da u okviru ovog primarnog ključa se nalazi drugi primarniključ i to za klasu IspitniRok, odnosno, klasa IspitniRokId. Ovde vidimo da možemoklase koje predstavljaju primarne ključeve nekih klasa (kao što je IspitniRokId) koristitiu klasama koje predstavljaju primarne ključeve drugih klasa (kao što je IspitId), ali samoako su oni kreirane prvim pristupom kreiranja stranih ključeva — pomoću anotacija @Idi @Embeddable. Sad nam je jasno zašto smo upravo taj pristup koristili za IspitniRokId.

Vratimo se nazad na klasu Ispit. Nakon deklarisanja polja ocena i status, potrebno jerešiti asocijativne veze ka klasama Student i IspitniRok.

Veza ka klasi Student je dovoljno jednostavna — jedan ispit pripada tačno jednom stu-dentu, dok jedan student može imati više ispita, dakle, veza je više-ka-jedan, odnosno,koristimo anotaciju @ManyToOne (ovaj zaključan je donesen iz ugla klase Ispit). Dodatno,koristimo anotaciju @JoinColumn da bismo, između ostalog, postavili svojstva insertablei updatable na vrednost false, sa narednim značenjem:

Page 361: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 361

• Svojstvo insertable uzima podrazumevano vrednost true, a ukoliko se postavi nafalse, onda anotirano polje se neće nalaziti u INSERT naredbama generisanim odstrane Hibernate alata (drugim rečima, neće biti trajno upisano u bazu podataka).

• Svojstvo updatable uzima podrazumevano vrednost true, a ukoliko se postavi nafalse, onda anotirano polje se neće nalaziti u UPDATE naredbama generisanim odstrane Hibernate alata (drugim rečima, neće biti promenjeno jednom kada se trajnoupiše u bazu podataka).

Jednostavnije rečeno, ne želimo da menjamo podatke u tabeli DOSIJE menjanjem poljastudent iz klase Ispit (čime ga obeležavamo da je samo za čitanje (engl. readonly)).

Druga veza je prema klasi IspitniRok. Ukoliko pogledamo kako je sve do sada postavljeno,videćemo da je ovo instanca problema prikazana u podsekciji 13.9.6. Da se podsetimo,problem je u tome što se u tabeli ISPIT nalazi složeni strani ključ ka tabeli ISPITNI_ROK,pri čemu kolone složenog stranog ključa učestvuju kao deo primarnog ključa. Rešenje jeu kreiranju polja klase IspitniRok i odgovarajućim anotiranjem:

• Koristimo anotaciju @MapsId da ignorišemo kolone zadate poljem id_roka iz primar-nog ključa klase IspitId. Umesto toga, koristićemo polja iz objekta klase IspitniRokkoji anotiramo.

• Koristimo anotaciju @JoinColumns da definišemo po kojim kolonama se vrši odgovara-juće preslikavanje za složeni strani ključ. Vrednost ove anotacije je lista @JoinColumnanotacija, za svaku kolonu u složenom stranom ključu.

• Koristimo anotaciju @ManyToOne da definišemo tip preslikavanja. S obzirom da višeispita pripada jednom ispitnom roku, a da jedan ispitni rok sadrži više ispita, vezaje više-ka-jedan (opet, posmatrano iz ugla klase Ispit koju trenutno analiziramo).

Naravno, ovo podrazumeva izmenu i u klasi IspitniRok, gde sada definišemo vezu iz-među ispitnih rokova i ispita — jedan ispitni rok ima više ispita, te koristimo anotaciju@OneToMany za polje tipa List<Ispit>. S obzirom da je ova veza dvosmerna, moramo rećikoja klasa je odgovorna za održavanje takve veze (tj. za održavanje referencijalnog inte-griteta stranim ključem). To je moguće uraditi postavljanjem opcije mappedBy, kao što jei urađeno u klasi IspitniRok:

Kod 13.17: Primeri/cas12/cas12_7/src/hibernateVstud/IspitniRok.javapackage hibernateVstud;

import java.util.ArrayList;import java.util.List;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.OneToMany;import javax.persistence.Table;

@Entity@Table(name = "ispitni_rok")public class IspitniRok {

// Primarni kljuc

@Idprivate IspitniRokId id = null;

// Ostale kolone

Page 362: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

362 Glava 13. Okruženje za razvoj Hibernate

@Column(name = "naziv", nullable = false)private String Naziv;

@Column(name = "pocetak_prijavljivanja", nullable = false)private String Pocetak;

@Column(name = "kraj_prijavljivanja", nullable = false)private String Kraj;

@Column(name = "tip", nullable = false)private String Tip = "B";

// Kreiranje veze izmedju IspitniRok i Ispit.// S obzirom da je veza izmedju ovih klasa dvosmerna,// onda samo jedna klasa moze biti odgovorna za vezu,// sto se postize navodjenjem opcije mappedBy@OneToMany(mappedBy = "ispitniRok")List<Ispit> ispiti = new ArrayList<>();

// Autogenerisani Get/Set metodi

public IspitniRokId getId() {return id;

}

public void setId(IspitniRokId id) {this.id = id;

}

public String getNaziv() {return Naziv;

}

public void setNaziv(String naziv) {Naziv = naziv;

}

public String getPocetak() {return Pocetak;

}

public void setPocetak(String pocetak) {Pocetak = pocetak;

}

public String getKraj() {return Kraj;

}

public void setKraj(String kraj) {Kraj = kraj;

}

public String getTip() {return Tip;

}

public void setTip(String tip) {if (tip == null) {

Tip = "B";return;

Page 363: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 363

}Tip = tip;

}

public List<Ispit> getIspiti() {return ispiti;

}

public void setIspiti(List<Ispit> ispiti) {this.ispiti = ispiti;

}

}

Konačno, da bismo završili implementaciju, potrebno je da registrujemo anotirane klaseu klasi HibernateUtil i kreiramo metod u klasi Main koji testira implementirane klase imetode:

Kod 13.18: Primeri/cas12/cas12_7/src/hibernateVstud/HibernateUtil.javapackage hibernateVstud;

import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;

public class HibernateUtil {private static SessionFactory sessionFactory = null;

static {try {

Configuration con = new Configuration();con.configure("hibernate.cfg.xml")

.addAnnotatedClass(Smer.class)

.addAnnotatedClass(IspitniRok.class)

.addAnnotatedClass(Student.class)

.addAnnotatedClass(Ispit.class);

sessionFactory = con.buildSessionFactory();} catch (Throwable e) {

System.err.println("Session factory error");e.printStackTrace();

System.exit(1);}

}

public static SessionFactory getSessionFactory() {return sessionFactory;

}

}

Kod 13.19: Primeri/cas12/cas12_7/src/hibernateVstud/Main.javapackage hibernateVstud;

import java.util.Collections;import java.util.Iterator;import java.util.Scanner;//import java.util.Iterator;import java.util.List;

Page 364: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

364 Glava 13. Okruženje za razvoj Hibernate

import org.hibernate.Query;import org.hibernate.SQLQuery;import org.hibernate.Session;import org.hibernate.Transaction;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();deleteSmer();insertIspitniRok();deleteIspitniRok();readIspitniRok();

Scanner ulaz = new Scanner(System.in);System.out.println("Unesite prvo godinu, pa oznaku za ispitni rok: ");int godina = ulaz.nextInt();String oznaka = ulaz.next();

readIspitniRok(godina, oznaka);

ulaz.close();

readSmeroviIStudenti();

System.out.println("Zavrsetak rada\n");HibernateUtil.getSessionFactory().close();

}

public static void insertSmer() {Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

smer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

System.out.println("Cuvanje smera nije uspelo! Transakcija seponistava!");

if (TR != null) {TR.rollback();

}} finally {

Page 365: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 365

session.close();}

}

public static void deleteSmer(){Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(smer, 300);session.delete(smer);

System.out.println("Smer obrisan");

TR.commit();} catch (Exception e) {

System.err.println("Brisanje smera nije uspelo! Ponistavanjetransakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

private static void insertIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();

IspitniRokId id = new IspitniRokId(2019, "jun");ir.setId(id);ir.setNaziv("Jun 2019");ir.setPocetak("6/1/2019");ir.setKraj("6/22/2018");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(ir);

System.out.println("Ispitni rok je sacuvan");TR.commit();

} catch (Exception e) {System.err.println("Cuvanje ispitnog roka nije uspelo! Ponistavanje

transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

Page 366: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

366 Glava 13. Okruženje za razvoj Hibernate

public static void deleteIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();IspitniRokId id = new IspitniRokId(2019, "jun");

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(ir, id);session.delete(ir);

System.out.println("Ispitni rok je obrisan");TR.commit();

} catch (Exception e) {System.err.println("Brisanje ispitnog roka nije uspelo!

Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readIspitniRok() {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

SQLQuery query = session.createSQLQuery("SELECT ∗ " +"FROM ispitni_rok");

query.addEntity(IspitniRok.class);List<IspitniRok> ispitniRokovi =

Collections.checkedList(query.list(), IspitniRok.class);

Query upit2 = session.createQuery("from IspitniRok");ispitniRokovi =

Collections.checkedList(upit2.list(), IspitniRok.class);

for(IspitniRok ir : ispitniRokovi){System.out.println(ir.getNaziv());

}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem rokova!Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

Page 367: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.9 Asocijativne veze i strani ključevi 367

}

@SuppressWarnings("unchecked")public static void readIspitniRok(Integer godina, String oznaka) {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

Query query = session.createQuery("from IspitniRok ir " +"where ir.id.godina = :god " +"and ir.id.oznaka = :ozn");

query.setParameter("god", godina);query.setParameter("ozn", oznaka);

List<IspitniRok> ispitniRokovi = query.list();Iterator<IspitniRok> iterator = ispitniRokovi.iterator();while(iterator.hasNext()){

IspitniRok ir = iterator.next();System.out.println("Ispitni rok: " + ir.getNaziv());

}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem rokova!Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readSmeroviIStudenti() {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

// Kreiramo HQL upit koji izdvaja sve smeroveQuery smeroviQuery = session.createQuery("from Smer");// Dohvatamo rezultat u listu smerovi,// i proveravamo da li su svi elementi objekti klase SmerList<Smer> smerovi =

Collections.checkedList(smeroviQuery.list(), Smer.class);

// Kreiramo HQL upit koji izdvaja sve studente// na smeru ciji ce identifikator biti postavljen// na mesto imenovane parametarske oznake "id".// S obzirom da ovo radimo za svaki smer,// dohvatanje rezultata moramo da ugnezdimo unutar petlje// koja prolazi smerovima.// Drugim recima, koristimo ugnezdjene kursore.Query studentiQuery = session.createQuery(

Page 368: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

368 Glava 13. Okruženje za razvoj Hibernate

"from Student " +"where id_smera = :id");

// Spoljasnja petlja: ispisivanje smerovafor (Smer smer : smerovi) {

String naziv = smer.getNaziv().trim();int idSmera = smer.getId_smera();

System.out.println("\n\nSMER: " + naziv);

// Postavljanje vrednosti parametarske oznake za unutrasnjupetlju

studentiQuery.setParameter("id", idSmera);studentiQuery.setMaxResults(5);

// Dohvatanje studenata za tekuci smerList<Student> studenti =

Collections.checkedList(studentiQuery.list(), Student.class);

// Unutrasnja petlja: ispisivanje studenata na smerufor (Student student : studenti) {

int indeks = student.getIndeks();String ime = student.getIme().trim();String prezime = student.getPrezime().trim();double prosek = student.prosek();

System.out.println("Student: " + indeks + ", " +ime + ", " + prezime + ", " + prosek);

}}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem rokova!Ponistavanje transakcije!");

if (TR != null) {TR.rollback();

}} finally {

session.close();}

// Za vezbu: razmisliti kako je moguce uraditi ovaj zadatak// bez koriscenja ugnezdjenih kursora// (tj. bez koriscenja upita koji pronalazi studente za zadati id_smera

)}

}

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja

Korišćenjem interfejsa org.hibernate.Criteria moguće je kreirati upite programerski —kreiranjem i kombinovanjem instanci org.hibernate.criterion.∗. U ovoj sekciji ćemodemonstrirati kako je moguće koristiti ovaj API za izražavanje selekcije, restrikcije, pro-jekcije i spajanja.

Page 369: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 369

Naredni upit dohvata sve instance klase Item:org.hibernate.Criteria criteria = session.createCriteria(Item.class);List<Item> items = criteria.list();

Iz ovog jednostavnog koda vidimo da se instanca org.hibernate.Criteria kreira kori-šćenjem metoda createCriteria() nad objektom klase Session. Moguće je jednostavnouređivati instance korišćenjem metoda addOrder(), koji je moguće ulančavati, kao u na-rednom primeru:List<User> users =

session.createCriteria(User.class).addOrder(Order.asc("firstname")).addOrder(Order.asc("lastname")).list();

13.10.1 Restrikcija

Naredni upit dohvata sve instance klase Item čiji je naziv jednak ”Foo”:List<Item> items =

session.createCriteria(Item.class).add(Restrictions.eq("name", "Foo")).list();

Interfejs Restrictions predstavlja ”fabriku” za individualne Criterion koje možemo do-davati Criteria. Na polja se može jednostavno referisati zadavanjem njihovog naziva kroznisku — u prethodnom primeru "name" označava polje Item −> name.

U prethodnom primeru smo videli korišćenje metoda eq() koji postavlja restrikciju jedna-kosti između dve vrednosti. Na raspolaganju nam je i metod like() koji odgovara klauziLIKE u SQL-u. Naredni primer dohvata sve User čije korisničko ime počinje karakterom j:List<User> users =

session.createCriteria(User.class).add(Restrictions.like("username", "j", MatchMode.START)

.ignoreCase()).list();

Treći argument metoda, MatchMode.START ekvivalentan je j% u SQL-u. Drugi modovipoklapanja su EXACT, END i EXACT.

Još neki metodi koji su nam dostupni su demonstrirani narednim primerom:Criteria cr = session.createCriteria(Employee.class);

// To get records having salary more than 2000cr.add(Restrictions.gt("salary", 2000));

// To get records having salary less than 2000cr.add(Restrictions.lt("salary", 2000));

// To get records having fistName starting with zaracr.add(Restrictions.like("firstName", "zara%"));

// Case sensitive form of the above restriction.cr.add(Restrictions.ilike("firstName", "zara%"));

// To get records having salary in between 1000 and 2000

Page 370: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

370 Glava 13. Okruženje za razvoj Hibernate

cr.add(Restrictions.between("salary", 1000, 2000));

// To check if the given property is nullcr.add(Restrictions.isNull("salary"));

// To check if the given property is not nullcr.add(Restrictions.isNotNull("salary"));

// To check if the given property is emptycr.add(Restrictions.isEmpty("salary"));

// To check if the given property is not emptycr.add(Restrictions.isNotEmpty("salary"));

Kreiranje logičkih uslova se može vršiti na sledeći način:Criteria cr = session.createCriteria(Employee.class);

Criterion salary = Restrictions.gt("salary", 2000);Criterion name = Restrictions.ilike("firstNname","zara%");

// To get records matching with OR conditionsLogicalExpression orExp = Restrictions.or(salary, name);cr.add( orExp );

// To get records matching with AND conditionsLogicalExpression andExp = Restrictions.and(salary, name);cr.add( andExp );

List results = cr.list();

Ukoliko je potrebno da postavimo restrikciju nad nekim ugnežđenim poljem, možemo ko-ristiti tačka-notaciju. Na primer, ako klasa Korisnik sadrži polje koje je instanca klaseAdresa i želimo da izdvojimo sve korisnike koji žive u Beogradu, možemo koristiti restrik-ciju:List<Korisnik> korisnici =

session.createCriteria(Korisnik.class).add(Restrictions.eq("kucnaAdresa.grad", "Beograd")).list();

13.10.2 Ograničavanje skupa rezultata

Postoje dva metoda koja možemo koristiti za ograničavanje skupa rezultata:

• public Criteria setFirstResult(int firstResult) — Ovaj metod uzima celi brojkoji predstavlja indeks prvog reda u rezultatu, počevši od 0.

• public Criteria setMaxResults(int maxResults) — Ovim metodom se Hibernate-u signalizira da dohvati najviše maxResults objekata u rezultatu.

13.10.3 Projekcija i agregacija

Naredni upit izdvaja identifikator, korisničko ime i kućnu adresu svih Korisnika:List<Object[]> result =

session.createCriteria(Korisnik.class).setProjection(Projections.projectionList()

Page 371: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 371

.add(Projections.property("id"))

.add(Projections.property("korisnickoIme"))

.add(Projections.property("kucnaAdresa"))).list();

Rezultat ovakvog upita je Lista Object[], tj. po jedan niz Object vrednosti za svakutorku koja se izdvaja. U ovom slučaju, svaki niz sadrži torku objekata tipova Integer,String i Adresa.

Hibernate sadrži i agregacije. Naredni upit izdvaja broj prezimena Korisnika:List<Object[]> result =

session.createCriteria(Korisnik.class).setProjection(Projections.projectionList()

.add(Projections.groupProperty("prezime"))

.add(Projections.rowCount())).list();

Metod rowCount() je ekvivalentan funkciji COUNT() u SQL-u. Pored prebrojavanja, mo-žemo koristiti i razne druge funkcije, na primer, uprosečavanje. Naredni upit izdvajaprosečnu vrednost Licitacija entiteta, grupisane po Predmetima:List<Object[]> result =

session.createCriteria(Licitacija.class).setProjection(Projections.projectionList()

.add(Projections.groupProperty("predmet"))

.add(Projections.avg("vrednost"))).list();

Još neki metodi su ilustrovani narednim primerom:Criteria cr = session.createCriteria(Employee.class);

// To get total row count.cr.setProjection(Projections.rowCount());

// To get average of a property.cr.setProjection(Projections.avg("salary"));

// To get distinct count of a property.cr.setProjection(Projections.countDistinct("firstName"));

// To get maximum of a property.cr.setProjection(Projections.max("salary"));

// To get minimum of a property.cr.setProjection(Projections.min("salary"));

// To get sum of a property.cr.setProjection(Projections.sum("salary"));

13.10.4 Spajanja

Unutrašnja spajanja je moguće izvesti ugnežđenim Criteria objektima:Criteria licitacijeCrit =

session.createCriteria(Licitacija.class);

// Spajanje klasa Licitacija i Predmet

Page 372: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

372 Glava 13. Okruženje za razvoj Hibernate

Criteria licPredCrit =licitacijeCrit.createCriteria("predmet")

// Dodavanje restrikcije na spajanje.add(Restrictions.isNotNull("cena"));

// Spajanje prethodnog rezultata i klase KorisnikCriteria LicPredKorisnikCrit =

licPredCrit.createCriteria("prodavac")// Dodavanje restrikcije na spajanje.add(Restrictions.eq("korisnickoIme", "johndoe"));

List<Licitacija> rezultat = LicPredKorisnikCrit.list();

Ovaj upit, iako je mogao da bude u jednoj liniji, razbijen je na više delova radi jasnijeg ob-jašnjenja. Prvo, kreiramo Criteria nad klasom Licitacija. Nakon toga vršimo spajanjeklasa Licitacija i Predmet tako što nad prethodno kreiranom Criteria pozivamo metodcreateCriteria(). Za razliku od prvog istoimenog metoda, ovaj metod prihvata nazivpolja iz klase Licitacija koji predstavlja instancu klase Predmet sa kojom se spaja. Na-kon toga, taj rezultat spajamo sa klasom Korisnik preko polja proizvod koja predstavljainstancu te klase. Dalje restrikcije se postavljaju nakon svakog spajanja i biće prevedeneu odgovarajuće klauze spojene operatorom AND u WHERE klauzi generisanog upita.

U ”jednoj liniji”, ovaj upit bi mogao da se napiše kao:List<Licitacija> rezultat =

session.createCriteria(Licitacija.class).createCriteria("predmet")

.add(Restrictions.isNotNull("cena")).createCriteria("prodavac")

.add(Restrictions.eq("korisnickoIme", "johndoe")).list();

Alternativno, unutrašnja spajanja je moguće kreirati metodom createAlias() nad Criteria. Prethodni upit je ekvivalentan narednom:List<Bid> result =

session.createCriteria(Licitacija.class)// Spajanje sa Predmet.createCriteria("predmet")// Spajanje sa Korisnik.createAlias("prodavac", "k")

.add(Restrictions.and(Restrictions.eq("k.korisnickoIme", "johndoe"),Restrictions.isNotNull("cena")

)).list();

Može se desiti da Hibernate vrati duplikate instanci. Nećemo ulaziti u to zašto se dešava,ali prikazaćemo kako ih je moguće eliminisati:List<Item> result =

session.createCriteria(Item.class)// neke operacije koje proizvode duplikate// ....setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();

Page 373: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 373

Primer 13.8 — Čas 12 — 08. Dopuniti prethodni primer tako da implementira narednizahtev:

• Za zadati indeks studenta ispisati nazive svih položenih predmeta i dobijene ocene.Implementirati dva metoda — jedan koji ne koristi Hibernate Criteria API i drugikoji ga koristi.

Oba metoda koja budemo implementirali će imati sličnu ideju — učitaćemo studenta sazadatim indeksom da bismo dobili informacije o njemu. Međutim, prvi metod će koristitipovučene informacije iz tabela ISPIT i PREDMET (smeštene u klasama Ispit i Predmet,redom), dok će drugi koristiti isključivo Hibernate Criteria API za dohvatanje podatakana osnovu klase Ispit.

S obzirom da su nam neophodne informacije iz tabele PREDMET, napravimo klasu Predmetkoja će izvući informacije iz baze podataka za slogove iz te tabele:

Kod 13.20: Primeri/cas12/cas12_8/src/hibernateVstud/Predmet.javapackage hibernateVstud;

import java.util.ArrayList;import java.util.List;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.OneToMany;import javax.persistence.Table;

@Entity@Table(name = "predmet")public class Predmet {

// Primarni kljuc@Id@Column (name = "id_predmeta")private Integer idPredmeta;

// Ostale kolone@Column (name = "naziv")private String nazivPredmeta;

// Kreiranje veze izmedju klasa Predmet i Ispit@OneToMany(mappedBy = "predmet")private List<Ispit> ispiti = new ArrayList<>();

// Get/set metodi

public Integer getIdPredmeta() {return idPredmeta;

}

public void setIdPredmeta(Integer idPredmeta) {this.idPredmeta = idPredmeta;

}

public String getNaziv() {return nazivPredmeta;

}

Page 374: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

374 Glava 13. Okruženje za razvoj Hibernate

public void setNaziv(String naziv) {this.nazivPredmeta = naziv;

}

public List<Ispit> getIspiti() {return ispiti;

}

public void setIspiti(List<Ispit> ispiti) {this.ispiti = ispiti;

}

}

Prirodno, potrebno je da ažuriramo klasu Ispit da bismo definisali vezu između izmeđunje i nove klase Predmet:

Kod 13.21: Primeri/cas12/cas12_8/src/hibernateVstud/Ispit.javapackage hibernateVstud;

import javax.persistence.Column;import javax.persistence.EmbeddedId;import javax.persistence.Entity;import javax.persistence.JoinColumn;import javax.persistence.JoinColumns;import javax.persistence.ManyToOne;import javax.persistence.MapsId;import javax.persistence.Table;

@Entity@Table(name = "ispit")public class Ispit {

// Primarni kljuc

@EmbeddedIdprivate IspitId id_ispita;

// Ostale kolone

@Columnprivate Integer ocena;

@Column(name="status_prijave")private String status;

// Resavanje asocijativnih veza izmedju klasa

// Kreiranje veze izmedju klasa Ispit i Predmet@ManyToOne@JoinColumn(name = "id_predmeta",

referencedColumnName = "id_predmeta",insertable = false,updatable = false)

private Predmet predmet;

@ManyToOne@JoinColumn(name = "indeks",

referencedColumnName = "indeks",insertable = false,

Page 375: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 375

updatable = false)private Student student;

@MapsId("id_roka")@JoinColumns({

@JoinColumn(name = "godina_roka", referencedColumnName = "godina"),@JoinColumn(name = "oznaka_roka", referencedColumnName = "oznaka")

})@ManyToOneprivate IspitniRok ispitniRok;

// Get/set metodi

public IspitId getId_ispita() {return id_ispita;

}

public void setId_ispita(IspitId id_ispita) {this.id_ispita = id_ispita;

}

public Integer getOcena() {return ocena;

}

public void setOcena(Integer ocena) {this.ocena = ocena;

}

public String getStatus() {return status;

}

public void setStatus(String status) {this.status = status;

}

public Student getStudent() {return student;

}

public void setStudent(Student student) {this.student = student;

}

public Predmet getPredmet() {return predmet;

}

public void setPredmet(Predmet predmet) {this.predmet = predmet;

}

}

Finalno, dodajemo klasu Predmet na spisak anotiranih klasa i kreiramo metode koji imple-mentiraju traženi zahtev:

Kod 13.22: Primeri/cas12/cas12_8/src/hibernateVstud/HibernateUtil.javapackage hibernateVstud;

Page 376: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

376 Glava 13. Okruženje za razvoj Hibernate

import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;

public class HibernateUtil {private static SessionFactory sessionFactory = null;

static {try {

Configuration con = new Configuration();con.configure("hibernate.cfg.xml")

.addAnnotatedClass(Smer.class)

.addAnnotatedClass(IspitniRok.class)

.addAnnotatedClass(Student.class)

.addAnnotatedClass(Ispit.class)

.addAnnotatedClass(Predmet.class);

sessionFactory = con.buildSessionFactory();} catch (Throwable e) {

System.err.println("Session factory error");e.printStackTrace();

System.exit(1);}

}

public static SessionFactory getSessionFactory() {return sessionFactory;

}

}

Kod 13.23: Primeri/cas12/cas12_8/src/hibernateVstud/Main.javapackage hibernateVstud;

import java.util.Collections;import java.util.Comparator;import java.util.Iterator;import java.util.Scanner;//import java.util.Iterator;import java.util.List;

import org.hibernate.Criteria;import org.hibernate.Query;import org.hibernate.SQLQuery;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.criterion.MatchMode;import org.hibernate.criterion.Order;import org.hibernate.criterion.Restrictions;

public class Main {

public static void main(String[] args) {System.out.println("Pocetak rada\n");

insertSmer();deleteSmer();insertIspitniRok();deleteIspitniRok();

Page 377: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 377

readIspitniRok();

Scanner ulaz = new Scanner(System.in);System.out.println("Unesite prvo godinu, pa oznaku za ispitni rok: ");int godina = ulaz.nextInt();String oznaka = ulaz.next();

readIspitniRok(godina, oznaka);

ulaz.close();

readSmeroviIStudenti();readPolozeniPredmeti(20100050);readPolozeniPredmetiCriteria(20100050);

System.out.println("\nZavrsetak rada\n");HibernateUtil.getSessionFactory().close();

}

public static void insertSmer() {Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

smer.setId_smera(300);smer.setOznaka("MATF_2019");smer.setNaziv("Novi MATF smer u 2019. godini");smer.setSemestara(8);smer.setBodovi(240);smer.setNivo(110);smer.setZvanje("Diplomirani informaticar");smer.setOpis("Novi smer na Matematickom fakultetu");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(smer);TR.commit();

System.out.println("Smer je sacuvan");} catch (Exception e) {

System.out.println("Cuvanje smera nije uspelo! Ponistavanjetransakcije: " + e.getMessage());

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteSmer(){Session session = HibernateUtil.getSessionFactory().openSession();Smer smer = new Smer();

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(smer, 300);

Page 378: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

378 Glava 13. Okruženje za razvoj Hibernate

session.delete(smer);

System.out.println("Smer obrisan");

TR.commit();} catch (Exception e) {

System.err.println("Brisanje smera nije uspelo! Ponistavanjetransakcije: " + e.getMessage());

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

private static void insertIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();

IspitniRokId id = new IspitniRokId(2019, "jun");ir.setId(id);ir.setNaziv("Jun 2019");ir.setPocetak("6/1/2019");ir.setKraj("6/22/2018");

Transaction TR = null;try {

TR = session.beginTransaction();

session.save(ir);

System.out.println("Ispitni rok je sacuvan");TR.commit();

} catch (Exception e) {System.err.println("Cuvanje ispitnog roka nije uspelo! Ponistavanje

transakcije: " + e.getMessage());

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void deleteIspitniRok() {Session session = HibernateUtil.getSessionFactory().openSession();

IspitniRok ir = new IspitniRok();IspitniRokId id = new IspitniRokId(2019, "jun");

Transaction TR = null;try {

TR = session.beginTransaction();

session.load(ir, id);session.delete(ir);

Page 379: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 379

System.out.println("Ispitni rok je obrisan");TR.commit();

} catch (Exception e) {System.err.println("Brisanje ispitnog roka nije uspelo!

Ponistavanje transakcije: " + e.getMessage());

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readIspitniRok() {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

SQLQuery query = session.createSQLQuery("SELECT ∗ " +"FROM ispitni_rok");

query.addEntity(IspitniRok.class);List<IspitniRok> ispitniRokovi =

Collections.checkedList(query.list(), IspitniRok.class);

Query upit2 = session.createQuery("from IspitniRok");ispitniRokovi =

Collections.checkedList(upit2.list(), IspitniRok.class);

for(IspitniRok ir : ispitniRokovi){System.out.println(ir.getNaziv());

}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem rokova!Ponistavanje transakcije: " + e.getMessage());

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readIspitniRok(Integer godina, String oznaka) {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

Query query = session.createQuery("from IspitniRok ir " +"where ir.id.godina = :god " +

Page 380: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

380 Glava 13. Okruženje za razvoj Hibernate

"and ir.id.oznaka = :ozn");

query.setParameter("god", godina);query.setParameter("ozn", oznaka);

List<IspitniRok> ispitniRokovi = query.list();Iterator<IspitniRok> iterator = ispitniRokovi.iterator();while(iterator.hasNext()){

IspitniRok ir = iterator.next();System.out.println("Ispitni rok: " + ir.getNaziv());

}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem rokova!Ponistavanje transakcije: " + e.getMessage());

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

@SuppressWarnings("unchecked")public static void readSmeroviIStudenti() {

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

Query smeroviQuery = session.createQuery("from Smer");List<Smer> smerovi =

Collections.checkedList(smeroviQuery.list(), Smer.class);

Query studentiQuery = session.createQuery("from Student " +"where id_smera = :id");

for (Smer smer : smerovi) {String naziv = smer.getNaziv().trim();int idSmera = smer.getId_smera();

System.out.println("\n\nSMER: " + naziv);

studentiQuery.setParameter("id", idSmera);studentiQuery.setMaxResults(5);

List<Student> studenti =Collections.checkedList(studentiQuery.list(), Student.

class);

for (Student student : studenti) {int indeks = student.getIndeks();String ime = student.getIme().trim();String prezime = student.getPrezime().trim();double prosek = student.prosek();

System.out.println("Student: " + indeks + ", " +

Page 381: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 381

ime + ", " + prezime + ", " + prosek);}

}

TR.commit();} catch (Exception e) {

System.err.println("Postoji problem sa izlistavanjem studenata nasmerovima! Ponistavanje transakcije: " + e.getMessage());

if (TR != null) {TR.rollback();

}} finally {

session.close();}

}

public static void readPolozeniPredmeti(Integer indeks){Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

// Ucitavanje podataka o studentu na osnovu primarnog kljuca −indeks

Student student = session.load(Student.class, indeks);String ime = student.getIme().trim();String prezime = student.getPrezime().trim();System.out.println("\n\nStudent: " + indeks + ", " +

ime + " " + prezime + "\n");

// Poziv metoda getIspiti() radi dobijanja svih ispita tog studentaList<Ispit> ispiti = student.getIspiti();// Sortiranje liste ispita po nazivu predmeta rastuceCollections.sort(ispiti, new Comparator<Ispit>() {

@Overridepublic int compare(Ispit o1, Ispit o2) {

return o1.getPredmet().getNaziv().compareTo(o2.getPredmet().getNaziv());

}});

int i = 1;for (Ispit ispit : ispiti) {

// Ispisivanje samo polozenih ispitaif(ispit.getStatus().equalsIgnoreCase("o") && ispit.getOcena()

> 5) {Predmet predmet = ispit.getPredmet();System.out.println("Ispit " + i + ": " +

predmet.getNaziv().trim());++i;

}}

TR.commit();} catch (Exception e) {

System.out.println("Postoji problem sa izlistavanjem polozenihispita za studenta! Ponistavanje transakcije: " + e.getMessage());

if (TR != null) {

Page 382: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

382 Glava 13. Okruženje za razvoj Hibernate

TR.rollback();}

} finally {session.close();

}}

@SuppressWarnings("unchecked")public static void readPolozeniPredmetiCriteria(Integer indeks){

Session session = HibernateUtil.getSessionFactory().openSession();Transaction TR = null;

try {TR = session.beginTransaction();

// Ucitavanje podataka o studentu na osnovu primarnog kljuca −indeks

Student student = session.load(Student.class, indeks);String ime = student.getIme().trim();String prezime = student.getPrezime().trim();System.out.println("\n\nStudent: " + indeks + ", " +

ime + " " + prezime + "\n");

// Ovoga puta, umesto da koristimo dohvacene informacije iz bazepodataka

// koje su skladistene u polje ispiti klase Student,// demonstriracemo Criteria API za dohvatanje vrednosti.// Poenta je u kombinovanju raznih uslova// radi izdvajanja potrebnih informacija.

// Kreiramo ogranicenja nad klasom IspitCriteria c = session.createCriteria(Ispit.class);

// Restrikcije:// Dodajemo uslov "ocena > 5"c.add(Restrictions.gt("ocena", 5));// Dodajemo uslov "status_prijave = 'o'"c.add(Restrictions.like("status", "o", MatchMode.EXACT));// Dodajemo uslov "indeks = :indeks"c.add(Restrictions.eq("id_ispita.indeks", indeks));

// Spajamo sa klasom Predmet po polju predmet u klasi Ispitc = c.createCriteria("predmet");

// Sortiramo po nazivu predmeta rastucec.addOrder(Order.asc("nazivPredmeta"));

// Izvrsavamo kriterijum i dohvatamo podatkeList<Ispit> ispiti = c.list();int i = 1;for (Ispit ispit : ispiti) {

Predmet predmet = ispit.getPredmet();System.out.println("Ispit " + i + ": " +

predmet.getNaziv().trim());++i;

}

TR.commit();} catch (Exception e) {

System.out.println("Postoji problem sa izlistavanjem polozenihispita za studenta! Ponistavanje transakcije: " + e.getMessage

Page 383: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

13.10 Napredno kreiranje upita pomoću Hibernate Criteria API-ja 383

());if (TR != null) {

TR.rollback();}

} finally {session.close();

}}

}

Page 384: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 385: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Dodatak

Page 386: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 387: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

A. Opis baze VSTUD

create table nivo_kvalifikacije (id_nivoa smallint not null,naziv varchar(200) not null,stepen varchar(10) not null,primary key(id_nivoa)

);

create table smer (id_smera integer not null,oznaka varchar(10) not null,naziv varchar(200) not null,semestara smallint not null with default 6constraint chk_semestara check(

semestara between 1 and 10),bodovi smallint not null with default 180constraint chk_bodovi check(

bodovi between 30 and 300),id_nivoa smallint not null,zvanje varchar(200) not null with default,opis long varchar,primary key(id_smera),foreign key fk_smer_nivo(id_nivoa)

references nivo_kvalifikacije,constraint uk_sifra unique(oznaka)

);

create table dosije (indeks integer not null,id_smera integer not null,ime varchar(25) not null,prezime varchar(25) not null,pol char not null,jmbg char(13) not null,

Page 388: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

ii Glava A. Opis baze VSTUD

datum_rodjenja date,mesto_rodjenja varchar(100),drzava_rodjenja varchar(100),ime_oca varchar(50),ime_majke varchar(50),ulica_stanovanja varchar(100),kucni_broj varchar(20),mesto_stanovanja varchar(100),postanski_broj varchar(20),drzava_stanovanja varchar(100),telefon varchar(25),mobilni_telefon varchar(25),email varchar(50),"www uri" varchar(100),datum_upisa date not null,primary key (indeks),foreign key fk_dosije_smer(id_smera)

references smer);

create table upis_godine (indeks integer not null,godina smallint not nullconstraint chk_godina check(

godina between 1900 and 2025),datum_upisa date not null,upisano_bodova smallint not nullconstraint chk_upisbod check(

upisano_bodova between 0 and 125),datum_overe date,overeno_bodova smallint,constraint chk_overa check(

(overeno_bodova is nulland datum_overe is null)

or(overeno_bodova is not null

and datum_overe is not nulland datum_overe >= datum_upisaand overeno_bodova between 0 and upisano_bodova)

),primary key (indeks,godina),foreign key fk_upis_dosije(indeks)

references dosije);

create table status (indeks integer not null,datum date not null,status varchar(20) not nullconstraint chk_status check(

status in ('budzet','samofinansiranje','diplomirao','mirovanje','ispisan'

)),primary key (indeks, datum, status),

Page 389: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

iii

foreign key fk_dosije(indeks)references dosije

);

create table predmet (id_predmeta integer not null,sifra varchar(20) not null,naziv varchar(200) not null,broj_semestara smallint not null with default 1constraint chk_broj_semestara check(

broj_semestara between 1 and 10),bodovi smallint not nullconstraint chk_bodovi check(

bodovi between 1 and 50),primary key(id_predmeta),constraint uk_sifra unique(sifra)

);

create table uslovni_predmet (id_predmeta integer not null,id_uslovnog integer not null,primary key(id_predmeta,id_uslovnog),foreign key fk_upr_predmet(id_predmeta)

references predmet,foreign key fk_upr_uslovni(id_uslovnog)

references predmet);

create table obavezan_predmet (id_smera integer not null,id_predmeta integer not null,semestar integer not null with default 1constraint chk_semestar check(

semestar between 1 and 10),primary key(id_smera,id_predmeta),foreign key fk_obp_smer(id_smera)

references smer,foreign key fk_obp_predmet(id_predmeta)

references predmet);

create table semestar (godina smallint not null,semestar smallint not nullconstraint chk_semestar check(

semestar in (1,2)),primary key(godina,semestar)

);

create table kurs (id_predmeta integer not null,godina smallint not null,semestar smallint not null,primary key(id_predmeta,godina,semestar),foreign key fk_kurs_predmet(id_predmeta)

references predmet,foreign key fk_kurs_semestar(godina,semestar)

Page 390: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

iv Glava A. Opis baze VSTUD

references semestar);

create table upisan_kurs (indeks integer not null,id_predmeta integer not null,godina smallint not null,semestar smallint not null,primary key(indeks,id_predmeta,godina,semestar),foreign key fk_prk_kurs(id_predmeta,godina,semestar)

references kurs,foreign key fk_prk_godina(indeks,godina)

references upis_godine);

create table ispitni_rok (godina smallint not null,oznaka varchar(20) not null,naziv varchar(50) not null,pocetak_prijavljivanja date not null,kraj_prijavljivanja date not null,tip char not null with default 'B'−− '1' − samo predmeti iz 1. semestra−− '2' − samo predmeti iz 2. semestra−− 'B' − predmeti iz oba semestra−− 'X' − samo po jedan predmet, ako je poslednji nepolozenconstraint chk_tiproka check(

tip in ('1','2','B','X')),primary key(godina,oznaka)

);

create table ispit (indeks integer not null,id_predmeta integer not null,godina integer not null,semestar integer not null,godina_roka smallint not null,oznaka_roka char(5) not null,datum_prijave date not null,nacin_prijave varchar(16) not null,broj_polaganja integer not null,status_prijave char not null with default 'p',−− status prijave moze biti−− p − prijavljen−− n − nije izasao−− o − polagao−− d − diskvalifikovan−− x − ponistenconstraint chk_status check(

status_prijave in ( 'p', 'n', 'o', 'd', 'x' )),datum_pismenog date,bodovi_pismenog smallint,datum_usmenog date,bodovi_usmenog smallint,bodovi smallint,ocena smallint,constraint chk_ocena check(

(status_prijave in ('p','n')and bodovi is null

Page 391: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

v

and ocena is null)or(status_prijave in ('d')

and bodovi=0and ocena=5)

or(status_prijave in ('o','x')

and bodovi between 0 and 100and ocena between 5 and 10)

),constraint chk_bodovi check(

bodovi is nullor (

bodovi_pismenog is not nulland datum_pismenog is not nulland bodovi_usmenog is nulland datum_usmenog is nulland bodovi = bodovi_pismenog

)or (

bodovi_pismenog is nulland datum_pismenog is nulland bodovi_usmenog is not nulland datum_usmenog is not nulland bodovi = bodovi_usmenog

)or (

bodovi_pismenog is not nulland datum_pismenog is not nulland bodovi_usmenog is not nulland datum_usmenog is not nulland bodovi = bodovi_pismenog + bodovi_usmenog

)),nastavnik varchar(100),napomena varchar(1000),primary key(indeks,id_predmeta,godina_roka,oznaka_roka),foreign key fk_ispit_isprok(godina_roka,oznaka_roka)

references ispitni_rok,foreign key fk_ispit_upiskurs(indeks,id_predmeta,godina,semestar)

references upisan_kurs);

Page 392: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 393: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

B. Opis baze MSTUD

create table dosije (indeks integer not null,ime varchar(20) not null,prezime varchar(25) not null,datum_upisa date ,datum_rodjenja date ,mesto_rodjenja varchar(100) ,primary key (indeks)

);create table predmet (

id_predmeta integer not null,sifra varchar(5) not null,naziv varchar(40) not null,bodovi smallint not null,primary key(id_predmeta)

);create table ispitni_rok (

godina_roka smallint not null,oznaka_roka varchar(5) not null,naziv varchar(15) not null,primary key (godina_roka, oznaka_roka)

);create table ispit (

indeks integer not null ,id_predmeta integer not null ,godina_roka smallint not null ,oznaka_roka char(5) not null ,ocena smallint not null with default 5 ,datum_ispita date ,bodovi smallint ,primary key (indeks, id_predmeta, godina_roka, oznaka_roka) ,foreign key (godina_roka, oznaka_roka) references ispitni_rok,foreign key (indeks) references dosije ,foreign key (id_predmeta) references predmet) ;

Page 394: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 395: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Literatura

[Che+10] Whei-Jen Chen et al. DB2 Express-C: The Developer Handbook for XML, PHP,C/C++, Java, and .NET. First Edition. IBM Corporation, 2010.

[F C+10] Raul F. Chong et al. Getting Started with DB2 Application Development - Idealfor Application Developers and Administrators. First Edition. IBM Corpora-tion, 2010.

[IBM13] IBM. IBM DB2 10.5 for Linux, UNIX, and Windows - Developing EmbeddedSQL Applications. IBM Corporation, 2013. url: ftp://ftp.software.ibm.com / ps / products / db2 / info / vr105 / pdf / en _ US / DB2DevEmbeddedSQL -db2a1e1050.pdf.

[IBM] IBM. IBM Knowledge Center - IBM DB2 10.5 for Linux, Unix and Windows do-cumentation. [Online]. url: https://www.ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/com.ibm.db2.luw.kc.doc/welcome.html.

[Rad18] Nina Radojičić Matić. Programiranje Baza Podataka. [Online]. 2018. url: http://poincare.matf.bg.ac.rs/~nina/PBP.html.

Page 396: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 397: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

Indeks

D

DB2 naredba . . . . . . . . . . . . . . . . . . . . . . . . . . 23BEGIN COMPOUND . . . . . . . . . . . . . 80ATOMIC, 80NOT ATOMIC, 80STATIC, 80STOP AFTER FIRST, 81

BEGIN DECLARE SECTION. . . . .24COMMIT . . . . . . . . . . . . . . . . . . 81, 82, 90CONNECT . . . . . . . . . . . . . . . . . . . . . . 153CONNECT (Type 1), 153CONNECT (Type 2), 153

END DECLARE SECTION . . . . . . . 24EXECUTE IMMEDIATE . . . . . . . . 128INCLUDE. . . . . . . . . . . . . . . . . . . . . . . . .24LOCK TABLE . . . . . . . . . . . . . . . . . . . 123ROLLBACK. . . . . . . . . . . . . . . . . . .82, 91SAVEPOINT. . . . . . . . . . . . . . . . . . . . . . 89SET CURRENT ISOLATION. . . . 112SET CURRENT LOCK TIMEOUT103WHENEVER . . . . . . . . . . . . . . . . . . . . . 36

db2dclgn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33Distribuirane baze podataka . . . . . . . . . . 153

G

Greška . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36Tip greškeNOT FOUND, 36, 81

SQLERROR, 36SQLWARNING, 36

J

Jedinica posla . . . . . . . . . . . . . . . . . . . . . . . . . 98

K

Katanac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99Konverzija . . . . . . . . . . . . . . . . . . . . . . . 100

Kursor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51Deklaracija kursora . . . . . . . . . . . . . . . . 52Dohvatanje podataka iz kursora . . . 53Otvaranje kursora . . . . . . . . . . . . . . . . . 52Tip kursoraČitajući, 52Ažurirajući, 52Brišući, 52Dvosmisleni, 52

Ugnežđeni kursor . . . . . . . . . . . . . . . . . . 74Zatvaranje kursora . . . . . . . . . . . . . . . . 53

M

Matična promenljiva . . . . . . . . . . . . . . . . . . . 15Indikatorska promenljiva . . . . . . . . . . 31Tipovi promenljive . . . . . . . . . . . . . . . . 24

Mrtva petlja . . . . . . . . . . . . . . . . . . . . . . . . . . 102

Page 398: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,

xii INDEKS

N

Niska naredbe . . . . . . . . . . . . . . . . . . . . . . . . 130Nivo izolovanosti . . . . . . . . . . . . . . . . . . . . . 110

P

Paket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15Parametarska oznaka . . . . . . . . . . . . . . . . . . 16Parametarske oznake . . . . . . . . . . . . . . . . . 131Prevođenje programa

C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27Pripremljena naredba. . . . . . . . . . . . . . . . .130Programiranje baza podataka

Programiranje na klijentu . . . . . . . . . 13Programiranje na serveru . . . . . . . . . . 13

S

Složena SQL naredba . . . . . . . . . . . . . . . . . . 79SQL upit

Izvršenje upita . . . . . . . . . . . . . . . . . . . . 16Plan izvršavanja upita . . . . . . . . . . . . . 16Priprema upita . . . . . . . . . . . . . . . . . . . . 16Tip upitaDinamički SQL upit, 16, 127Statički SQL upit, 15

SQL-ugnežđena aplikacija. . . . . . . . . . . . . .14SQLCA . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24, 39

sqlaintp . . . . . . . . . . . . . . . . . . . . . . . . . . . 43SQLCODE . . . . . . . . . . . . . . . . . . . . . . . . 40SQLSTATE . . . . . . . . . . . . . . . . . . . . . . . 40struct sqlca . . . . . . . . . . . . . . . . . . . . . . . . 41

SQLDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

T

Transakcija . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79Pohranjivanje . . . . . . . . . . . . . . 52, 82, 90Poništavanje . . . . . . . . . . . . . . . . . . . 82, 91Tačka čuvanja . . . . . . . . . . . . . . . . . . . . . 89Kreiranje, 89

V

Vezivanje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

Z

Zaključavanje . . . . . . . . . . . . . . . . . . . . . . . . . . 97

Page 399: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,
Page 400: Kroz programske jezike C i Java –poincare.matf.bg.ac.rs/~aspasic/download/pbp.pdf · 2020. 4. 2. · – Kroz programske jezike C i Java ... Skripta”. Svi komentari, sugestije,