dezvoltarea aplicatiilor de baze de date cu interfata grafica in c++

256

Upload: livius969

Post on 02-Dec-2015

284 views

Category:

Documents


8 download

DESCRIPTION

Dezvoltarea completa a aplicatiilor desktop utilizand numai resurse de tip open-source. Cartea cuprinde : SQL , plpgaSQL, C, C++, utilizare biblioteci wxWidgets, utilizare biblioteci Haru (contructia in C a rapoartelor PDF) etc.

TRANSCRIPT

Page 1: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++
Page 2: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

DEZVOLTAREA APLICAŢIILOR DE BAZEDE DATE POSTGRESQL CU INTERFAŢĂ

GRAFICĂ ÎN C++

DEZVOLTARE ÎN OPEN SOURCE

Page 3: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

Procesare computerizată a textului şi imaginii

Procesare text: LIVIU ŞERBĂNESCURedactor: Viorica Cerasela POSTOLACHE

Editura Fair PartnersSector 2, Bucureştitelefon: 021.346.05.23e-mail: [email protected]://www.fairpartners.ro

Descrierea CIP a Bibliotecii Naţionale a RomânieiŞERBĂNESCU, LIVIU

Dezvoltarea aplicaţiilor de baze de date PostgreSQL cu interfaţă grafică în C++ / Liviu Şerbănescu. - Bucureşti : Fair Partners, 2014

Bibliogr.ISBN 978-606-718-006-0

004.43

Page 4: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

lector dr.ing. Liviu ŞERBĂNESCU

DEZVOLTAREA APLICAŢIILOR DE BAZEDE DATE POSTGRESQL CU INTERFAŢĂ

GRAFICĂ ÎN C++

DEZVOLTARE ÎN OPEN SOURCE

Editura FAIR PARTNERSBucureşti, 2014

Page 5: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

Manuale. Tratate. Monografii (vol. 142)

Editor şef:

prof. univ. dr. MIHAI POSTOLACHEUniversitatea ”Politehnica” din Bucureşti

Referenţi ştiinţifici:

prof. univ. dr. ing. ANGELICA BACIVAROVUniversitatea ”Politehnica” din Bucureşti

conf. univ. dr. ing. CIPRIAN LUPUUniversitatea ”Politehnica” din Bucureşti

©2014 Liviu Şerbănescu

Page 6: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

CUPRINS

I.Introducere............................................................................................10 1.Baze de date şi sisteme de gestiune a bazelor de date...................................10 2.Structura PostgreSQL. Interfaţa pgAdmin3.......................................................11 2.1.Structura PostgreSQL...............................................................................................11 2.2.Interfaţa pgAdmin3..................................................................................................13

3.Mediul CodeLite pentru dezvoltarea aplicaţiilor în C/C++..............................14

II.Limbajul SQL........................................................................................17 1.Tabele persistente şi tabele temporare.............................................................17 1.1.Crearea tabelelor......................................................................................................17 1.2.Ştergerea tabelelor...................................................................................................19 1.3.Tabele temporare......................................................................................................19

2.Operaţii de editare ce implică un singur tabel..................................................20 2.1.Adăugarea înregistrărilor într-un tabel..................................................................20 2.2.Tipuri de date frecvent utilizate..............................................................................21 2.3.Adăugarea mai multor înregistrări dintr-un alt tabel..........................................21 2.4.Importul datelor în tabel..........................................................................................22 2.5.Actualizarea datelor dintr-un tabel........................................................................23 2.6.Ştergerea înregistrărilor dintr-un tabel..................................................................24

3.Operaţii de interogare ce implică un singur tabel............................................24 3.1.Preluarea datelor din tabel......................................................................................25 3.2.Căutarea parţială în şirurile de caractere..............................................................26 3.3.Funcţii de agregare...................................................................................................26 3.4.Operatorul CAST....................................................................................................... 28 3.5.Expresii condiţionale.................................................................................................28 3.6.Comenzi SQL ce nu implică tabele..........................................................................29

4.Tipuri de asocieri între înregistrările unor tabele.............................................29 4.1.Asocierea de tip unu la unu (1:1).............................................................................30 4.2.Asocierea de tip unu la mai mulţi (1:N)..................................................................30 4.3.Asocierea de tip mulţi la mulţi (M:N)......................................................................31 4.4.Crearea cheilor primare şi a cheilor externe..........................................................31 4.5.Asigurarea integrităţii referenţiale........................................................................31

5.Operaţii de editare cu mai multe tabele.............................................................32 5.1.Actualizarea datelor din tabele prin utilizarea unor date din alte tabele.........32 5.2.Ştergerea înregistrărilor din tabele prin utilizarea unor date din alte tabele...32

6.Operaţii de interogare cu mai multe tabele. Vederi........................................33 6.1.Combinarea interogărilor (UNION, EXCEPT, INTERSECT)...................................33 6.2.Interogarea mai multor tabele................................................................................34

7.Subinterogări...........................................................................................................38 8.Operaţii cu tablouri de date..................................................................................39 8.1.Tablouri unidimensionale.........................................................................................39

5

Page 7: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

8.2.Tablouri multidimensionale.....................................................................................40 8.3.Căutarea în tablouri..................................................................................................40

9.Operaţii cu date de tip XML..................................................................................41 10.Funcţii PostgreSQL...............................................................................................42 10.1.Operaţii cu data calendaristică.............................................................................42 10.2.Operaţii cu dată de tip oră, minut, secundă şi miimi de secundă......................43 10.3.Date de tip UUID / GUID.........................................................................................44 10.4.Funcţii pentru înlocuirea caracterelor. Căutarea cu şi fără diacritice..............44

11.Tranzacţii. Interogări multiserver......................................................................46 12.Teste rezolvate – gestiune bibliotecă...............................................................48

III.Programarea la nivel de server – plpgSQL.................................52 1.Funcţii de tipul SQL.................................................................................................52 1.1.Funcţii de tip SQL ce nu preiau şi nu întorc nimic..................................................52 1.2.Funcţii SQL ce nu preiau nimic şi întorc un set de înregistrări.............................53 1.3.Funcţii SQL cu transfer prin argument şi cu returnare subset de înregistrări. . .54 1.4.Funcţii SQL cu transfer prin argument şi cu returnare de tip boolean...............55

2.Funcţii de tipul plpgSQL.........................................................................................55 3.Declararea variabilelor. Secvenţe de decizie.....................................................56 4.Parametri de intrare şi ieşire.................................................................................56 5.Implementarea notificărilor..................................................................................58 6.Structuri repetitive.................................................................................................59 7.Construcţia dinamică a interogărilor...................................................................61 8.Funcţii de tip trigger...............................................................................................63 9.Definirea de noi tipuri de date şi supraîncărcarea operatorilor SQL............66 10.Teste rezolvate......................................................................................................71 10.1.Funcţie pentru contorizarea timpilor de parcare................................................71 10.2.Calculul debitelor medii zilnice.............................................................................72

IV.Introducere în limbajul C.................................................................73 1.Organizarea programelor......................................................................................73 1.1.Structura unui program în limbajul C/C++.............................................................74

2.Variabile, alocări, tipuri de date, operatori C/C++............................................74 2.1.Noţiunile de variabilă şi constantă.........................................................................74 2.2.Tipuri de alocare a variabilelor................................................................................75 2.3.Tipuri de variabile......................................................................................................75 2.4.Operatorii C/C++....................................................................................................... 76 2.5.Teste........................................................................................................................... 77

3.Implementarea structurilor de control...............................................................77 3.1.Implementarea structurii secvenţiale.....................................................................77 3.2.Implementarea structurii de decizie (alternative, de selecţie)............................78 3.3.Implementarea structurilor repetitive (ciclice)......................................................80

4.Tablouri şi pointeri. Aritmetica pointerilor........................................................83 4.1.Alocarea dinamică. Noţiunea de pointer................................................................83

6

Page 8: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.2.Noţiunea de tablou...................................................................................................84 4.3.Alocarea dinamică a memoriei................................................................................85 4.4.Aritmetica pointerilor...............................................................................................88 4.5.Teste........................................................................................................................... 88

5.Funcţii. Aria de vizibilitate a variabilelor.............................................................89 5.1.Noţiunea de funcţie..................................................................................................89 5.2.Structura unei funcţii................................................................................................90 5.3.Declararea, explicitarea şi apelul funcţiilor...........................................................90 5.4.Domeniul de vizibilitate al variabilelor..................................................................91

6.Transferul parametrilor în cadrul funcţiilor.......................................................92 6.1.Transferul parametrilor prin valoare......................................................................92 6.2.Transferul parametrilor prin adresă.......................................................................93 6.3.Transferul parametrilor prin referinţă...................................................................93 6.4.Funcţii cu număr variabil de argumente................................................................95

7.Structuri de date. Liste...........................................................................................96 7.1.Noţiunea de structură..............................................................................................96 7.2.Declaraţii de tip......................................................................................................... 96 7.3.Liste............................................................................................................................. 97

8.Funcţii recursive. Parcurgerea arborilor...........................................................101 9.Funcţii uzuale din bibliotecile C. Lucrul cu fişiere text..................................103 9.1.Operaţii cu şiruri de caractere...............................................................................103 9.2.Operaţii cu funcţii din biblioteca matematică....................................................104 9.3.Operaţii cu fişiere....................................................................................................105

10.Implementarea unui analizor sintactic pentru expresii matematice........105

V.Programarea orientată pe obiecte Limbajul C++....................109 1.Clase şi moşteniri..................................................................................................109 1.1.Noţiunea de clasă şi obiect....................................................................................109 1.2.Operatori specifici C++...........................................................................................109 1.3.Noţiunea de moştenire...........................................................................................110

2.Constructori şi destructori..................................................................................110 2.1.Constructori............................................................................................................. 110 2.2.Destructori...............................................................................................................111 2.3.Exemple.................................................................................................................... 111 2.4.Exemple privind ordinea de apel a constructorilor şi destructorilor................113

3.Modificatori şi specificatori de acces. Exemple..............................................115 3.1.Modificatori şi specificatori de acces....................................................................115 3.2.Exemplu privind accesul.........................................................................................116

4.Funcţii de tip friend şi de tip static....................................................................118 4.1.Funcţii de tipul friend.............................................................................................118 4.2.Exemplu cu funcţie de tip friend...........................................................................118 4.3.Membrii statici......................................................................................................... 119 4.4.Exemplu cu date de tip static şi funcţii de tip static...........................................120

5.Polimorfism, funcţii virtuale...............................................................................121

7

Page 9: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.1.Obiecte polimorfice................................................................................................121 5.2.Variabile de tip pointer care punctează la clasele derivate..............................121 5.3.Funcţii virtuale........................................................................................................ 121 5.4.Exemple – polimorfism şi clase abstracte............................................................122

6.Moştenirea multiplă.............................................................................................124 6.1.Exemplu pentru moştenire multiplă simplă.........................................................125 6.2.Exemplu privind moştenirea de tip diamant........................................................125

7.Supraîncărcarea operatorilor..............................................................................126 7.1.Restricţii privind supraîncărcarea operatorilor...................................................126 7.2.Sintaxa formei de apel...........................................................................................127 7.3.Exemple privind supraîncărcarea operatorilor....................................................127

8.Fluxuri de intrare/ieşire.......................................................................................133 8.1.Fluxuri de intrare/ieşire şi obiecte standard........................................................133 8.2.Operaţii de intrare/ieşire cu fişiere.......................................................................134

9.Introducere în funcţii şi clase template............................................................135 10.Tratarea excepţiilor............................................................................................137

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor.........138 1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++................138 1.1.Structura unei aplicaţii...........................................................................................138 1.2.Gestiunea evenimentelor.......................................................................................141 1.3.Utilizarea claselor generate de template-uri......................................................143 1.4. Exemplu cu primitive grafice şi evenimente.......................................................148

2.Interfaţarea client-server PostgreSQL în limbajul C/C++..............................152 2.1.Descrierea bibliotecii libpq....................................................................................152 2.2.Exemplu privind apelul funcţiilor libpq în cadrul unui cod C standard.............155 2.3.Exemplu privind utilizarea bibliotecii libpq în cadrul wxWidgets.....................156

3.Generarea în limbajul C a rapoartelor în fişiere format PDF........................161 3.1.Introducere în utilizarea bibliotecii libHARU.......................................................161 3.2.Funcţii uzuale oferite de bibliotecă......................................................................161 3.3.Exemplu de construcţie a unui fişier PDF.............................................................164

VII.Dezvoltarea unor module pentru logistica stocurilor.........168 1.Arhitectura aplicaţiei – LogX...............................................................................168 1.1.Structura de bază a aplicaţiei................................................................................168 1.2.Fluxul informaţional...............................................................................................170 1.3.Structura tabelelor PostgreSQL............................................................................172

2.Dezvoltarea modulelor SQL/plpgSQL...............................................................175 2.1.Dezvoltarea modulelor SQL/plpgSQL pentru editare........................................175 2.2.Dezvoltarea modulelor plpgSQL pentru rapoarte..............................................176

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul.......177 3.1.Fereastra de acces iFACC.......................................................................................177 3.2.Fereastra ce conţine panoul cu butoane iFPB.....................................................179 3.3.Fereastra de editare intrări (recepţii) iFEI...........................................................181 3.4.Fereastra de editare ieşiri/livrări iFEBP...............................................................185

8

Page 10: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.5.Fereastra editare/selecţie nomenclator iFNOM.................................................188 3.6.Fereastra pentru rapoarte / selecţie stoc iFSTSEL..............................................191

4.Dezvoltarea interfeţei SQL/plpgSQL – controale grafice.............................197 4.1.Clasa lxCtrl............................................................................................................... 198 4.2.Clasa lxComboBox..................................................................................................199 4.3.Clasa lxDPC..............................................................................................................199 4.4.Clasa lxEditN........................................................................................................... 200 4.5.Clasa lxEditT............................................................................................................ 201 4.6.Clasa lxGrid.............................................................................................................. 201

5.Integrarea modulelor aplicaţiei LogX...............................................................203

ANEXE......................................................................................................206 1.Secvenţe din sintaxa SQL/postgreSQL simplificată.......................................206 2.Principalele tipuri de variabile în limbajul C.....................................................210 3.Operatori C/C++....................................................................................................211 4.Codul sursă SQL pentru aplicaţia LogX.............................................................213 5.Codul sursă pentru biblioteca LX.......................................................................223 6.Codul sursă pentru aplicaţia LogX.....................................................................230

Bibliografie.............................................................................................254

9

Page 11: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

I.Introducere

I. IntroducereNotă: Toate aplicaţiile necesare realizării testelor şi dezvoltării aplicaţiei din această carte sunt open sources şi de asemenea sunt de tip cross-platform (rulează pe sisteme UNIX/Linux, Windows şi MAC). Cartea se limitează la dezvoltarea aplicaţiilor de tip desktop, aplicaţii ce prezintă un grad de siguranţă ridicat comparativ cu aplicaţiile de tip WEB.

1. Baze de date şi sisteme de gestiune a bazelor de date

Informaţiile, indiferent de structura acestora, pot fi stocate pe diverse suporturi fizice. Cel mai simplu mod de stocare şi acces a informaţiilor îl asigură fişierele de tip text (sunt recunoscute/interpretate codurile pentru spaţiu, tab şi linie nouă). În acest caz informaţiile nu sunt corelate şi nu se oferă funcţii de acces la date, iar dimensiunea fişierelor este limitată de tipul partiţiei suportului de stocare. Există numeroase moduri de a stoca informaţiile, însă puţine dintre acestea s-au impus în timp.

Termenul de bază de date (database) reprezintă o colecţie de informaţii corelate, relaţiile logice dintre aceste informaţii şi tehnicile de prelucrare corespunzătoare (căutare, sortare, ştergere, inserare, modificare etc.).

Sistemul de gestiune a bazelor de date S.G.B.D. (Database Management System − DBMS) reprezintă sistemul de programe care permite accesarea şi realizarea de operaţii asupra bazei de date de către utilizatori (ex.: aplicaţia software PostgreSQL).

Cel mai răspândit model de baze de date este modelul relaţional (pentru volum mare de date şi tipuri de date simple) − structura de bază a datelor este aceea de relaţie–tabel, limbajul SQL (Structured Query Language) este specializat în comenzi de manipulare la nivel de tabel.

Majoritatea SGBD-urilor asigură lucrul cu sisteme multi-utilizator. Putem avea baze de date centralizate (toate datele, inclusiv SGBD, sunt memorate pe un singur host) sau baze de date distribuite (atât datele, cât şi SGBD-ul sunt memorate pe mai multe host-uri, conectate printr-o reţea de comunicaţie).➢ Arhitectura client-server (cele actuale) cuprinde:

✗ Serverul (back-end): SGBD-ul şi baza de date;✗ Clienţii (front-end): program (programe) de aplicaţie ce

asigură interfaţarea utilizator–bază de date.➢ Arhitectură locală (sistemele vechi utilizează fişiere comune

mapate în interiorul reţelei) – pentru controlul accesului se folosesc fişiere sistem, iar întreruperea conexiunii avea

10

Page 12: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Baze de date şi sisteme de gestiune a bazelor de date

repercusiuni asupra integrităţii datelor.O bază de date trebuie să asigure:

✔ abstractizarea datelor (date unice); ✔ integrarea datelor (controlul corelaţiei datelor);✔ integritatea datelor (respectarea restricţiile de

integritate a datelor pe parcursul operaţiilor SQL);✔ securitatea datelor (controlul accesului la baza de date);✔ partajarea datelor (datele pot fi accesate de mai mulţi

utilizatori, eventual în acelaşi timp). Un SGBD trebuie să asigure următoarele activităţi:

✗ definirea şi descrierea structurii bazei de date – se realizează printr-un limbaj propriu, limbaj de definire a datelor (LDD);

✗ încărcarea datelor în baza de date – se realizează prin comenzi în limbaj propriu (limbaj de manipulare a datelor (LMD));

✗ accesul la date – se realizează prin comenzi specifice din limbajul de manipulare a datelor (SQL). Accesul la date se referă la operaţiile de interogare şi actualizare.Interogarea presupune vizualizarea, consultarea, editarea de situaţii de ieşire (rapoarte, liste, regăsiri punctuale).Actualizarea presupune trei operaţiuni: adăugare, modificare efectuată prin respectarea restricţiilor de integritate ale BD şi ştergere;

✗ întreţinerea bazei de date – se realizează prin utilitare proprii ale SGBD;

✗ securitatea datelor – se referă la asigurarea confidenţi-alităţii datelor prin autorizarea şi controlul accesului la date pe mai multe nivele, criptarea datelor.

2. Structura PostgreSQL. Interfaţa pgAdmin3

2.1. Structura PostgreSQL

PostgreSQL utilizează un model client/server. O sesiune PostgreSQL constă în mai multe procese:➢ Un proces server, care gestionează fişierele bazei de date,

acceptă conexiuni la bazele de date dinspre aplicaţiile client, realizează acţiunile cerute de client pe bazele de date. Serverul de baze de date se numeşte postgres;

➢ Aplicaţia client a utilizatorului care doreşte să execute operaţii în cadrul bazei de date. Aplicaţiile client pot fi aplicaţii de tip web sau aplicaţii de tip desktop.

Pentru ca un client să se conecteze la server-ul de baze de date sunt necesari următorii parametri de conectare: IP-ul server-

11

Page 13: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

I.Introducere

ului pe care se află server-ul PostgreSQL, portul pe care rulează server-ul PostgreSQL (implicit este 5432), numele bazei de date ce va fi accesată, numele utilizatorului (alias-ul) şi parola.

Serverul PostgreSQL poate gestiona conexiuni multiple concurente de la clienţi. Pentru aceasta el porneşte câte un nou proces pentru fiecare conexiune. Din acel moment, clientul şi un proces al server-ului comunică fără intervenţia procesului iniţial postgres. Astfel procesul principal al server-ului continuă să aştepte noi clienţi. PostgreSQL foloseşte un model client/server numit proces per-user. O sesiune Postgres constă din cooperarea următoarelor procese (programe): un proces, rezident în memorie, de supervizare (postmaster), aplicaţia frontend a userului şi unul sau mai multe servere backend de baze de date (procesul postgres). Un singur proces postmaster conduce o colecţie de baze de date pe o singură gazdă. Aplicaţiile frontend care doresc să acceseze o bază de date printr-o instalare apelează la funcţiile din cadrul librăriei libpq.

Atât serverul SGBD postgreSQL, cât şi interfaţa de tip desktop pgAdmin3 pot fi descărcate de la adresa www.postgresql.org.

În momentul instalării, PostgreSQL îşi creează un cont postgres care nu este şters la dezinstalare. O nouă reinstalare fără ştergerea contului postgres (se poate şterge ca orice alt cont de pe calculator) va cere vechea parolă pentru contul postgres.

Fiecare server PostgreSQL are asignat:☑ Un IP static specific calculatorului/staţiei. În cazul

accesării server-ului PostgreSQL chiar de pe calculatorul pe care rulează server-ul, acest IP va fi localhost (de ex.: 127.0.0.1);

☑ Un port (implicit 5432) ce reprezintă un număr ataşat proceselor ce implementeză SGBD-ul PostgreSQL (se poate modifica în fişierul de configurare). Aceste porturi sunt gestionate de sistemul de operare;

☑ O parolă de administrare la nivel SGBD.În ceea ce priveşte bazele de date:

➢ Un server de baze de date poate gestiona mai multe baze de date;➢ Fiecare bază de date poate avea propria parolă de administrare; ➢ Fiecare bază de date poate avea propriul encoding (implicit UTF8);➢ Fiecare bază de date poate avea propriul tablespace (implicit

pg_default). Acesta oferă posibilitatea stocării bazei de date pe mai multe suporturi fizice sau pe mai multe staţii de lucru;

➢ De obicei, o aplicaţie corespunde unei singure baze de date cu excepţia cazurilor când sunt importate date din afara aplicaţiei;

➢ Fiecare server are o bază de date implicită, denumită postgres, utilizată pentru administrare;

➢ Fiecare bază de date cuprinde una sau mai multe scheme. Schemele grupează mai multe obiecte, inclusiv tabele;

➢ Fiecare bază de date conţine câte o schemă (grupare de obiecte)

12

Page 14: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Structura PostgreSQL. Interfaţa pgAdmin3

denumită public. Utilizarea schemei public nu necesită prefixarea denumirii obiectelor cu denumirea schemei (public.nume_obiect).

În vederea accesului, avem grupuri de acces şi utlizatori, ambele sunt referite prin comanda ROLE (diferenţa constă în faptul că doar utilizatorii se pot conecta la server). ➢ Un grup de acces cuprinde mai mulţi utlilizatori;➢ Drepturile de acces sunt la nivel de tabel sau alt obiect, schemă

sau bază de date;➢ Drepturile de acces se pot atribui fie grupurilor de acces, fie

utilizatorilor individuali;➢ Odată ce a fost asignat un drept de acces pentru un grup, toţi

utilizatorii din acel grup vor avea acel drept;➢ Elementele dintr-un server (baze de date, tabele, funcţii,

secvenţe, vederi, coloane, reguli, indecşi, operatori, scheme etc.) sunt denumite generic obiecte.

2.2. Interfaţa pgAdmin3

Utilitarul pgAdmin3 este o interfaţă de tip desktop (pentru web există phppgAdmin) ce permite gestionarea server-ului de baze de date PostgreSQL. Acesta este utilizat doar pentru întreţinerea bazelor de date, el nu este necesar în rularea unei aplicaţii de baze de date.

Versiunile mai noi ale pgAdmin3 nu sunt compatibile cu toate versiunile vechi de postgreSQL, de exemplu pgAdmin3 (sau altfel scris pgAdmin III) versiunea 1.18 nu este compatibil cu versiunile PostgreSQL mai vechi decât versiunea 8.4.

În continuare sunt prezentate pe scurt principalele ferestre din cadrul interfeţei pgAdmin3.

☑ Fereastra Object browswer cuprinde ierarhia de obiecte din cadrul PostgreSQL. În vârful ierarhiei se află obiectul server, urmat de bazele de date împreună cu utilizatorii şi grupurile de acces. Bazele de date se ramifică pe următorul nivel în scheme, iar acestea se ramifică în tabele, funcţii, secvenţe, operatori etc. La rândul lor, tabelele se ramifică în coloane etc. În File>Options...>Browser>Display se pot seta obiectele care să fie afişate sau nu. Prin realizarea unui click pe butonul dreapta al mouse-ului, având obiectul selectat, se pot stabili proprietăţile obiectului. Opţiunea de vizualizare a tabelelor permite editarea acestora, cu condiţia să existe definită o cheie primară pentru acel tabel. Prin selecţia bazei de date şi click pe butonul dreapta se poate realiza back-upul bazei de date sau restaurarea acesteia. Dacă salvarea datelor se realizează pentru a fi utilizată de un alt server PostgreSQL, recomand ca acesta să fie în format plain (în cod SQL), iar la salvare să fie bifată opţiunea Use insert comands;

13

Page 15: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

I.Introducere

☑ Fereastra SQL pane afişează codul SQL corespunzător creării obiectului selectat. Această fereastră este utilă pentru înţelegerea modului de construcţie al obiectelor. De obicei, pentru construcţia obiectului nu este necesar întregul cod afişat, acesta conţinând şi partea implicită din cadrul comenzii de creare a obiectului;

☑ Prin selecţia File>Open postgresql.conf şi căutarea efectivă a fişierului postgresql.conf în directorul data, se deschide fişierul ce permite setările pentru server-ul de date (ex.: regional setting, numărul maxim de conexiuni simultane, portul utilizat etc.);

☑ Prin selecţia File>Open postgresql.conf şi căutarea efectivă a fişierului pg_hba.conf în directorul data, se deschide fişierul ce permite întroducerea adreselor de IP pentru clienţii ce accesează serverul. Orice adresă pentru IPv4 este urmată de ”/32”. Dacă dorim să dăm acces unei reţele, se introduce adresa de reţea urmată de simbolul “/” şi de numărul de biţi semnificativi pentru adresa reţelei. Prin punerea simbolului “*” se oferă acces pentru orice host de la orice adresă IP, însă acest lucru nu este recomandat;

☑ Fereastra Query este fereastra de lucru, este fereastra în care lansăm comenzile SQL şi urmărim rezultatele (se poate lansa şi prin Ctrl+E). Este deosebit de utilă pentru întreţinerea bazelor de date. În această fereastră putem construi bazele de date şi de asemenea le putem testa. Săgeata verde este pentru lansarea comenzilor din fereastră sau din blocul selectat (în caz de selecţie vor fi executate doar comenzile din blocul selectat). Comenzile sunt separate între ele prin simbolul semicolon “;”.

3. Mediul CodeLite pentru dezvoltarea aplicaţiilor în C/C++

O aplicaţie C/C++ poate fi scrisă utilizând orice editor de texte, cu condiţia ca acel editor să nu adauge simboluri specifice acestuia în fişierele cu cod C/C++. Editoarele specializate pentru limbaje de programare oferă facilităţi de editare specifice limbajului. De exemplu, în momentul în care scriem numele unui obiect şi vrem să facem referire la un element din cadrul obiectului, apare automat lista cu elementele din cadrul obiectului şi dezvoltatorul de aplicaţie doar selectează acel obiect (în cadrul CodeLite, colecţia cu aceste date se realizează prin seleţia Workspace>Retag workspace, iar datele cu aceste corespondenţe sunt memorate în fişierul temporar cu extensia *.tag). Mediile pentru dezvoltarea aplicaţiilor pe lângă editor conţin legături cu rutinele pentru compilare şi link-editare precum şi bibliotecile standard (en.cppreference.com/w/ sau www.delorie.com/djgpp/doc/libc/)

14

Page 16: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Mediul CodeLite pentru dezvoltarea aplicaţiilor în C/C++

CodeLite utilizează pentru compilare şi link-editare utilitarul g++, comun şi altor medii de dezvoltare cross-platform.

Din punct de vedere al aplicaţiei, se defineşte un workspace (spaţiu de lucru) în care sunt salvate fişierele, iar în cadrul unui workspace avem proiecte (projects), fiecare proiect corespunde unei aplicaţii sau biblioteci. Fiecare proiect este alcătuit din unul sau mai multe fişiere (de obicei fişiere sursă). În momentul în care realizăm dublu-click pe pictograma cu numele proiectului aceasta va deveni verde, iar în acel moment proiectul este selectat.

Din punct de vedere al organizării ferestrelor, distingem în stânga o fereastră de gestiune pentru workspace-ul curent, o fereastră în dreapta unde sunt deschise fişierele cu codul sursă şi o fereastră în partea de jos în care sunt detaliate rezulatele în urma diverselor acţiuni, inclusiv mesajele generate în urma compilării şi link-editării proiectului.

Pentru compilarea şi link-editarea unui proiect, urmată de lansarea aplicaţiei rezultate se utilizează comanda Ctrl + F9.

Mediul CodeLite oferă posibilitatea utilizării unui debug-er pentru a putea urmări evoluţia conţinutului variabilelor pas cu pas. În acest sens, se stabileşte o linie de întrerupere în aplicaţie (clik în dreapta numărului liniei) şi se apasă tasta F5 sau săgeata verde (timpii de aşteptare cresc semnificativ). În modul debug-er se poate intra în funcţii (Step in) sau se poate ieşi din acestea (Step out). Se observă apariţia unei ferestre Debuger ce conţine mai multe tab-uri. Unul de aceste taburi este Locals şi conţine variabilele din zona de întrerupere. În tab-ul Watches putem vizualiza anumite variabile sau putem evalua expresii. În tab-ul Call Stack putem vizualiza stiva din cadrul aplicaţiei pentru acel moment (în limbajul C stiva este de tip LIFO – ultimul intrat, primul ieşit).

La nivelul unui proiect se pot crea directoare virtuale (acestea nu există pe suportul fizic) pentru a grupa pe categorii fişierele (ex.: include, source, res etc.).

Mediul de lucru CodeLite se poate descărca de la adresa http://codelite.org/, iar după instalarea acestuia se instalează biblioteca wxWidgets de la adresa https://www.wxwidgets.org/ (la instalarea sub S.O. Windows se va limita denumirea directorului la wxwidgets – fără celelalte puncte, spaţii etc.). De asemenea poate fi utilă descărcarea utilitarului FormBuilder de la adresa http://sourceforge.net/projects/wxformbuilder/ .

Pentru aplicaţiile de tip consolă (cele în care funcţia main() apare explicit), când se creează un nou proiect se selectează: NewProject> Console> SimpleExecutable(g++). Pentru aplicaţii în care utilizăm wxWidgets, vom selecta: NewProject> GUI> Executable(wxWidgets enabled), iar dacă utilizăm şi

15

Page 17: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

I.Introducere

wxFormBuider vom selecta: NewProject> GUI> Executable(wxWidgets + wxFB frame). În ultimul caz vom selecta din cadrul proiectului nou fişierul resources/gui.fbp şi vom efectua dublu click pe acesta pentru deschiderea acestuia în wxFormBuilder. După efectuarea modificărilor în wxFormBuilder, se va apăsa tasta F8 pentru generarea codului corespunzător interfeţei create. Practic, vom deriva această clasă creată de wxFormBuider şi vom lucra cu clasa derivată.

16

Page 18: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

II. L i m b a j u l SQLNotă: Pentru o înţelegere mai bună, recomand scrierea comenzilor SQL (din dreptunghiurile cu colţuri rotunjite) în fereastra pentru execuţia comenzilor SQL din PgAdmin3 şi testarea acestora prin modificarea datelor şi/sau a structurii comenzilor.

În PostgreSQL schemele, tabelele, coloanele, secvenţele, vederile, cheile etc. sunt considerate obiecte, fiecare având un număr unic asociat (OID). Limbajul SQL este “case insensitive” (nu ţine cont de literă mare sau mică) însă denumirile obiectelor sunt “case sensitive”. Denumirile obiectelor ce conţin litere mari vor fi trecute între ghilimele.

1. Tabele persistente şi tabele temporare

Tabelele sunt entităţi logice de reprezentare a informaţiei, stocate asemănător foilor de calcul tabelare. Pentru bazele de date avansate, ele nu au o corespondenţă fizică cu un anumit fişier. Coloanele dintr-un tabel corespund câmpurilor (fields) din cadrul bazelor de date, iar rândurile/liniile din tabel corespund înregistrărilor (records). Crearea unei baze de date începe cu definirea şi crearea tabelelor necesare.

1.1. Crearea tabelelor

În PostgreSQL tabelele aparţin unei scheme, dacă nu este specificată schema, atunci se face referire automată la schema public (schemă implicită). Două scheme din cadrul aceleiaşi baze de date pot să conţină tabele cu denumiri identice.

Referirea la un tabel se va face prin nume_schemă. nume_tabel. Dacă schema este public, atunci nu mai este necesar numele schemei.

Începem prin crearea unui tabel cu două coloane, prima coloană va conţine date de tip întreg (tipul int sau integer), iar a doua va conţine date de tip alfanumeric (şir de caractere) având maxim 20 de caractere. Comanda DROP şterge obiectul, iar opţiunea CASCADE specifică faptul că sunt şterse şi legăturile acestui obiect cu alte obiecte.

Sintaxa (simplificată):

17

DROP SCHEMA IF EXISTS pic CASCADE; create schema pic;create table pic.t1(a int, b varchar(20));

DROP SCHEMA IF EXISTS pic CASCADE; create schema pic;create table pic.t1(a int, b varchar(20));

Page 19: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

Notă: parantezele drepte din expresie indică o expresie opţională, iar acoladele o secvenţă ce se repetă şi este separată prin virgulă. De asemenea simbolul “|” semnifică “sau”, iar column_constraint [ ... ] poate fi:

unde:• PRIMARY KEY reprezintă cheia primară de ordonare (câmpul sau

câmpurile după care se face ordonarea);• NOT NULL semnifică faptul că nu se acceptă valori vide (fără

date) pentru câmpul respectiv;• CHECK permite verificări suplimentare (de exemplu: temp_max<50).Ex.: Crearea unui tabel cu denumirea parm în cadrul schemei c2, câmpul data este de tipul dată calendaristică și va fi inițializat cu data curentă atunci când se adaugă o nouă înregistrare, la fel se procedează și pentru câmpul moment, câmp ce conţine ora, minutul secunda și fracţiunea de secundă. Tabelul conține valorile măsurate dintr-un proces.

Notă: Câmpul sau câmpurile care constituie cheia primară nu pot avea valori NULL

Operatorul rezoluţie “::” este utilizat pentru specificarea tipului unui câmp. Tipul int este acelaşi cu integer.Cheia primară poate fi constituită din unul sau mai multe câmpuri, iar declaraţia acesteia are forma:

18

CREATE TABLE pic.parm(data date DEFAULT CURRENT_DATE, moment time DEFAULT CURRENT_TIME, modul varchar(10), pct varchar(50),par varchar(15),val numeric,um char(10), idx serial PRIMARY KEY);

CREATE TABLE pic.parm(data date DEFAULT CURRENT_DATE, moment time DEFAULT CURRENT_TIME, modul varchar(10), pct varchar(50),par varchar(15),val numeric,um char(10), idx serial PRIMARY KEY);

CREATE [TEMPORARY|TEMP] TABLE table_name ([{ column_name data_type [ column_constraint [ ... ] ]}])

CREATE [TEMPORARY|TEMP] TABLE table_name ([{ column_name data_type [ column_constraint [ ... ] ]}])

[ CONSTRAINT constraint_name ] {NOT NULL|NULL|UNIQUE index_parameters| PRIMARY KEY index_parameters | CHECK ( expression )}

[ CONSTRAINT constraint_name ] {NOT NULL|NULL|UNIQUE index_parameters| PRIMARY KEY index_parameters | CHECK ( expression )}

CREATE TABLE pic.hidro( afluent character varying(80), temp_min integer, nivel_min int, temp_max integer, nivel_max int, precipitatii numeric, datac date, CONSTRAINT k_hidro PRIMARY KEY(afluent, datac), CONSTRAINT hidro_check CHECK (temp_min < temp_max), CONSTRAINT hidro_precipitatii_check CHECK (precipitatii >= 0::numeric), CONSTRAINT hidro_temp_max_check CHECK (temp_max < 50));

CREATE TABLE pic.hidro( afluent character varying(80), temp_min integer, nivel_min int, temp_max integer, nivel_max int, precipitatii numeric, datac date, CONSTRAINT k_hidro PRIMARY KEY(afluent, datac), CONSTRAINT hidro_check CHECK (temp_min < temp_max), CONSTRAINT hidro_precipitatii_check CHECK (precipitatii >= 0::numeric), CONSTRAINT hidro_temp_max_check CHECK (temp_max < 50));

Page 20: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Tabele persistente şi tabele temporare

Crearea unui tabel cu structură identică se va realiza prin instrucţiunile:

1.2. Ştergerea tabelelor

Tabelele pot fi şterse (atenţie: inclusiv structura acestora) prin utilizarea instrucţiunii DROP TABLE.

Ex.: Sintaxa: Se recomandă testarea verificării existenţei tabelului

înainte ca acesta să fie şters, altfel dacă tabelul nu există, execuţia instrucţiunii DROP va genera o eroare şi va fi oprită execuţia întregului bloc de instrucţiuni.Ex.:

Sintaxa:

1.3. Tabele temporare

Acestea NU sunt sub o anumită schemă, sunt VIZIBILE DOAR de către utilizatorul care le-a şi creat. Tabelul temporar se şterge automat în momentul delogării utilizatorului/închiderii conexiunii. Este recomandat ca iniţial să verificăm dacă tabelul există, iar

Ex.:

Pentru testarea vizibilităţii tabelului temporar se poate realiza testul următor:

La reconectare, tabelul temporar nu mai există, în momentul

19

DROP TABLE pic.tabelDROP TABLE pic.tabel DROP TABLE tablenameDROP TABLE tablename

DROP TABLE IF EXISTS pic.tabel DROP TABLE IF EXISTS pic.tabel

DROP TABLE IF EXISTS tablenameDROP TABLE IF EXISTS tablename

create table pic.hidro2 as table pic.hidro;create table pic.hidro2 as table pic.hidro;

CONSTRAINT nume_cheie_primara PRIMARY KEY(câmp1,câmp2,câmp3,..)CONSTRAINT nume_cheie_primara PRIMARY KEY(câmp1,câmp2,câmp3,..)

DROP TABLE IF EXISTS tx1;CREATE TEMPORARY TABLE tx1(a serial, b int);--sauDROP TABLE IF EXISTS tx1;CREATE TEMP TABLE tx1(a serial, b int);

DROP TABLE IF EXISTS tx1;CREATE TEMPORARY TABLE tx1(a serial, b int);--sauDROP TABLE IF EXISTS tx1;CREATE TEMP TABLE tx1(a serial, b int);

DROP TABLE IF EXISTS tx1;CREATE TEMPORARY TABLE tx1(a serial, b int);-- sau CREATE TEMP TABLE tx1(a serial, b int);INSERT INTO tx1(b) VALUES (12),(22),(1),(2);SELECT * FROM tx1; SELECT USER;-- afiseaza utilizatorul curent-- crează un nou utilizator bubuDROP ROLE IF EXISTS bubu; –- se presupune că există acest dreptCREATE ROLE bubu PASSWORD '1234';SET ROLE bubu; -– sau delogare şi logare cu noul utilizator SELECT USER; SELECT * FROM tx1; --tabelul tx1 nu mai există-- delogare si logare cu vechiul utilizator sauSET ROLE postgres –- sau utilizatorul afişat la începutSELECT USER; SELECT * FROM tx1;

DROP TABLE IF EXISTS tx1;CREATE TEMPORARY TABLE tx1(a serial, b int);-- sau CREATE TEMP TABLE tx1(a serial, b int);INSERT INTO tx1(b) VALUES (12),(22),(1),(2);SELECT * FROM tx1; SELECT USER;-- afiseaza utilizatorul curent-- crează un nou utilizator bubuDROP ROLE IF EXISTS bubu; –- se presupune că există acest dreptCREATE ROLE bubu PASSWORD '1234';SET ROLE bubu; -– sau delogare şi logare cu noul utilizator SELECT USER; SELECT * FROM tx1; --tabelul tx1 nu mai există-- delogare si logare cu vechiul utilizator sauSET ROLE postgres –- sau utilizatorul afişat la începutSELECT USER; SELECT * FROM tx1;

Page 21: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

închiderii conexiunii/delogării acesta este distrus. Se pot crea legături cu celelalte tabele (foreign key).

În PostgreSQL atât utilizatorii, cât şi grupurile de acces poartă denumirea de ROLE, deosebirea între acestea constă în atributul can login pentru utilizatori (grupurile nu se pot loga şi nu au parolă/cod acces).Notă: În momentul distrugerii tabelului temporar, acesta nu trebuie să fie tabel master faţă de tabelele persistente din cadrul schemelor. Tabelele temporare de tip master pot fi în relaţii master-slave doar cu tabelele temporare.

2. Operaţii de editare ce implică un singur tabel

2.1. Adăugarea înregistrărilor într-un tabel

Operaţia prin care sunt adăugate înregistrări într-un tabel se realizează prin instrucţiunea INSERT.

Sintaxa simplificată:

Pentru verificare s-a utilizat instrucţiunea: SELECT * from c1.t2; ceea ce are ca rezultat afişarea tuturor câmpurilor şi înregistrărilor din cadrul tabelului.

În ultima linie de inserare din Ex.2, numărul, tipul şi ordinea valorilor introduse trebuie să corespundă cu cea din CREATE TABLE pentru c2.t1

20

INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }

INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }

CREATE TABLE pic.t2(a1 serial PRIMARY KEY,b1 varchar(20) DEFAULT 'V1',c1 date DEFAULT CURRENT_DATE, d1 time DEFAULT CURRENT_TIME); --adauga doua inregistrariINSERT INTO pic.t2(b1) VALUES ('un test1'),('un test2');--pentru verificareSELECT * from pic.t2;

CREATE TABLE pic.t2(a1 serial PRIMARY KEY,b1 varchar(20) DEFAULT 'V1',c1 date DEFAULT CURRENT_DATE, d1 time DEFAULT CURRENT_TIME); --adauga doua inregistrariINSERT INTO pic.t2(b1) VALUES ('un test1'),('un test2');--pentru verificareSELECT * from pic.t2;

DROP TABLE IF EXISTS pic.t1; CREATE TABLE pic.t1(a1 serial PRIMARY KEY, a2 varchar(20), a3 int);--adauga trei inregistrări INSERT INTO pic.t1(a2,a3) VALUES ('A1',11),('C1',22),('B1',33);--sau INSERT INTO pic.t1 VALUES (101,'A1',11),(102,'C1',22),(103,'B1',33);--pentru verificareSELECT * FROM pic.t1;

DROP TABLE IF EXISTS pic.t1; CREATE TABLE pic.t1(a1 serial PRIMARY KEY, a2 varchar(20), a3 int);--adauga trei inregistrări INSERT INTO pic.t1(a2,a3) VALUES ('A1',11),('C1',22),('B1',33);--sau INSERT INTO pic.t1 VALUES (101,'A1',11),(102,'C1',22),(103,'B1',33);--pentru verificareSELECT * FROM pic.t1;

Page 22: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Operaţii de editare ce implică un singur tabel

2.2. Tipuri de date frecvent utilizate

Considerăm un exemplu în care apar câteva tipuri de date uzuale

Tipul serial este echivalent cu tipul autoincrement din alte sisteme de gestiune a bazelor de date, practic câmpul este de tip integer şi are asociat un obiect de tip sequence.

2.3. Adăugarea mai multor înregistrări dintr-un alt tabel

Presupunem că există un alt tabel, denumit hidro2 cu o structură asemănătoare cu primul tabel (hidro):

În cazul în care cele două tabele au aceeaşi structură de date şi aceeaşi ordine a câmpurilor, se poate omite detalierea câmpurilor din cadrul instrucţiunii INSERT INTO.

21

INSERT INTO pic.hidro2(afluent,temp_min,temp_max, precipitatii,datac) SELECT afluent,temp_min,temp_max,precipitatii, datac FROM pic.hidro WHERE datac > '20.11.2007';

INSERT INTO pic.hidro2(afluent,temp_min,temp_max, precipitatii,datac) SELECT afluent,temp_min,temp_max,precipitatii, datac FROM pic.hidro WHERE datac > '20.11.2007';

DELETE FROM pic.hidro WHERE datac > '20.11.2007';-- ENTERINSERT INTO pic.hidro SELECT * FROM pic.hidro2 WHERE datac > '20.11.2007';

DELETE FROM pic.hidro WHERE datac > '20.11.2007';-- ENTERINSERT INTO pic.hidro SELECT * FROM pic.hidro2 WHERE datac > '20.11.2007';

INSERT INTO pic.hidro(afluent,precipitatii,datac, temp_min,temp_max) VALUES ('Tuşnad', 0.25, '30.12.2007', 4, 8),('Tuşnad', 0.25, '31.12.2007', 5, 8),('Malnaş', NULL, '31.12.2007',3,9), ('Sebeş', 0.11, '29.12.2007',4, 8),('Sebeş', 0.11, '30.12.2007',3, 7);

INSERT INTO pic.hidro(afluent,precipitatii,datac, temp_min,temp_max) VALUES ('Tuşnad', 0.25, '30.12.2007', 4, 8),('Tuşnad', 0.25, '31.12.2007', 5, 8),('Malnaş', NULL, '31.12.2007',3,9), ('Sebeş', 0.11, '29.12.2007',4, 8),('Sebeş', 0.11, '30.12.2007',3, 7);

DROP TABLE IF EXISTS pic.t3;CREATE TABLE pic.t3(a int,b numeric,c boolean,d varchar(20), e char(20), f text, g date, h time, i timestamp, j uuid, k xml, l bytea, m serial PRIMARY KEY); --şirurile de caractere şi data calendaristică se introduc între apostrof.INSERT INTO pic.t3(a,b,c,d,f,g,h,k) VALUES (34,56.89,false, 'abcde','xyz','2012-08-31','11:23:51.0','<test>abcd</test>');SELECT * FROM pic.t3;--întoarce data,ora curenta,utlizatorselect CURRENT_DATE, CURRENT_TIME,CURRENT_USER;INSERT INTO pic.t3(a,b,c,d,f,g,h,k) VALUES (10,1.2,true,'un sir',NULL,CURRENT_DATE,CURRENT_TIME,NULL), (11,NULL,NULL,'alt sir',NULL,NULL,NULL, '<test1><t1>tttx</t1><t2>tty</t2></test1>');-- in caz de eroare nu se modifica nici un camp-- dacă şirul XML conţine erori înregistrarea nu va fi validată/salvatăINSERT INTO pic.t3(a,b,c,d,f,g,h,k) VALUES (11,NULL,NULL,'alt sir',NULL,NULL,NULL, '<test1><t1>tttx</t1><t2>tty</xt2></test1>');-- apare o EROARE deoarece sirul XML NU este CORECT

DROP TABLE IF EXISTS pic.t3;CREATE TABLE pic.t3(a int,b numeric,c boolean,d varchar(20), e char(20), f text, g date, h time, i timestamp, j uuid, k xml, l bytea, m serial PRIMARY KEY); --şirurile de caractere şi data calendaristică se introduc între apostrof.INSERT INTO pic.t3(a,b,c,d,f,g,h,k) VALUES (34,56.89,false, 'abcde','xyz','2012-08-31','11:23:51.0','<test>abcd</test>');SELECT * FROM pic.t3;--întoarce data,ora curenta,utlizatorselect CURRENT_DATE, CURRENT_TIME,CURRENT_USER;INSERT INTO pic.t3(a,b,c,d,f,g,h,k) VALUES (10,1.2,true,'un sir',NULL,CURRENT_DATE,CURRENT_TIME,NULL), (11,NULL,NULL,'alt sir',NULL,NULL,NULL, '<test1><t1>tttx</t1><t2>tty</t2></test1>');-- in caz de eroare nu se modifica nici un camp-- dacă şirul XML conţine erori înregistrarea nu va fi validată/salvatăINSERT INTO pic.t3(a,b,c,d,f,g,h,k) VALUES (11,NULL,NULL,'alt sir',NULL,NULL,NULL, '<test1><t1>tttx</t1><t2>tty</xt2></test1>');-- apare o EROARE deoarece sirul XML NU este CORECT

Page 23: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

Dacă se inserează toate câmpurile, în ordinea dată la crearea

tabelului, nu mai este necesară specificarea acestora.

2.4. Importul datelor în tabel

Se pot copia fişiere întregi cu date într-un tabel. Aceste fişiere, de regulă, sunt fişiere format CSV (comma-separated values) − fişierele text având valorile separate prin virgulă, iar valorile ce conţin caracterul “,” sunt scrise între ghilimele.

În acest exemplu, tabelul hidro este populat cu datele din fişierul temphidro.csv. Sintaxa simplificată:

unde: ✗ DELIMITER specifică un alt delimitator între valorile din

fişierul CSV (implicit fiind virgula);✗ NULL specifică şirul ce reprezintă valoarea NULL (implicit

nu se scrie nimic – adică după virgulă urmează tot virgulă);✗ CSV specifică faptul că este vorba de un fişier format CSV

(pot exista transferuri şi cu fişiere binare sau alte fişiere text – aceste cazuri nu sunt tratate în prezentul curs);

✗ HEADER specifică dacă primul rând din cadrul fişierului format CSV este reprezentat de numele coloanelor/câmpurilor;

✗ QUOTE specifică caracterele între care sunt puse valorile ce conţin şi caracterul separator (implicit caracterul “).

De obicei, această comandă este utilizată la preluarea iniţială a datelor, date existente în alte baze de date sau în fişiere de tip XLS sau text. Comanda COPY adaugă noile date la cele vechi. Există şi comanda (asemănătoare) pentru export a datelor dintr-un tabel sau rezultat al unei interogări într-un fisier CSV.

Fişierele CSV trebuie să se afle pe suportul fizic de

22

COPY pic.hidro FROM ’D:/test/temphidro.csv’ WITH csv;COPY pic.hidro FROM ’D:/test/temphidro.csv’ WITH csv;

COPY tablename [ ( column [, ...] ) ] FROM ’filename’ [[ WITH ] [ DELIMITER [ AS ] ’delimiter’ ] [ NULL [ AS ] ’null string’ ] [ CSV [ HEADER ] [ QUOTE [ AS ] ’quote’ ]

COPY tablename [ ( column [, ...] ) ] FROM ’filename’ [[ WITH ] [ DELIMITER [ AS ] ’delimiter’ ] [ NULL [ AS ] ’null string’ ] [ CSV [ HEADER ] [ QUOTE [ AS ] ’quote’ ]

DROP TABLE IF EXISTS pic.t4;CREATE TABLE pic.t4(regiune varchar(50),localitate varchar(50), nr_locuitori int, CONSTRAINT k_t4 PRIMARY KEY(regiune,localitate));INSERT INTO pic.t4 VALUES('R1','LR1',100),('R1','LR2',15), ('R1','L3',20),('R2','L1',150),('R2','LX2',25),('R2','L3',10), ('R2','L4',5),('R3','LR1',100),('R3','L2',15); SELECT * FROM pic.t4;

DROP TABLE IF EXISTS pic.t4;CREATE TABLE pic.t4(regiune varchar(50),localitate varchar(50), nr_locuitori int, CONSTRAINT k_t4 PRIMARY KEY(regiune,localitate));INSERT INTO pic.t4 VALUES('R1','LR1',100),('R1','LR2',15), ('R1','L3',20),('R2','L1',150),('R2','LX2',25),('R2','L3',10), ('R2','L4',5),('R3','LR1',100),('R3','L2',15); SELECT * FROM pic.t4;

Page 24: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Operaţii de editare ce implică un singur tabel

stocare (ex.:HDD) în aria de vizibilitate a contului postgres (cont creat automat la instalarea server-ului bazei de date PostgreSQL).

2.5. Actualizarea datelor dintr-un tabel

Actualizarea/modificarea datelor deja existente (chiar dacă celula din tabel nu are valori, adică este NULL) se realizează cu instrucţiunea UPDATE.

Comanda UPDATE actualizează valorile din tabelul dat, pentru înregistrările rezultate în urma aplicării condiţiei din cadrul WHERE, cu valorile şi pentru câmpurile explicitate în secţiunea SET.

Sunt modificate doar valorile câmpurilor date de SET pentru înregistrările date de WHERE

Sintaxa simplificată:

unde:✗ ONLY este utilizat în cazul tabelelor ierarhizate pentru a

nu modifica şi înregistrările din “tabelele copil” ce depind de tabelul respectiv (nu sunt tratate în această carte);

✗ FROM specifică alte tabele utilizate în condiţia WHERE;✗ DEFAULT – preia valorile implicite sau NULL dacă nu sunt

specificate.Presupunem că vrem să utilizăm datele dintr-un alt tabel în vederea actualizării. În acest sens, constituim următorul tabel:

În acest caz, comanda de actualizare va fi:

Alte exemple de utilizare:

23

UPDATE pic.hidro2 SET temp_min = temp_min-1, temp_max = temp_min + 20, precipitatii = 0WHERE (afluent = 'Malnaş') AND (datac > '1.07.2007') AND (datac < '31.08.2008');

UPDATE pic.hidro2 SET temp_min = temp_min-1, temp_max = temp_min + 20, precipitatii = 0WHERE (afluent = 'Malnaş') AND (datac > '1.07.2007') AND (datac < '31.08.2008');

UPDATE [ ONLY ] table [ [ AS ] alias ]SET{ column = {expression | DEFAULT}} [,...][FROM fromlist][WHERE condition]

UPDATE [ ONLY ] table [ [ AS ] alias ]SET{ column = {expression | DEFAULT}} [,...][FROM fromlist][WHERE condition]

UPDATE pic.hidro SET temp_min = temp_min - 1, temp_max = temp_min + 20, precipitatii = DEFAULTFROM pic.rauriWHERE(hidro.afluent = rauri.afluent )AND(data >'1.07.2007') AND (data<'31.08.2007');

UPDATE pic.hidro SET temp_min = temp_min - 1, temp_max = temp_min + 20, precipitatii = DEFAULTFROM pic.rauriWHERE(hidro.afluent = rauri.afluent )AND(data >'1.07.2007') AND (data<'31.08.2007');

drop table if exists pic.rauri;CREATE TABLE pic.rauri(rau varchar(100), afluent varchar(80), CONSTRAINT k_rauri PRIMARY KEY(rau,afluent));INSERT INTO pic.rauri VALUES('Argeş','Neajlov'),('Olt','Malnaş'),('Olt','Hurez'),('Olt','Sebeş'),('Olt','Tuşnad'),('Argeş','Tutana'),('Mureş','Târnava'),('Mureş','Borzia'),('Mureş','Fântânele');

drop table if exists pic.rauri;CREATE TABLE pic.rauri(rau varchar(100), afluent varchar(80), CONSTRAINT k_rauri PRIMARY KEY(rau,afluent));INSERT INTO pic.rauri VALUES('Argeş','Neajlov'),('Olt','Malnaş'),('Olt','Hurez'),('Olt','Sebeş'),('Olt','Tuşnad'),('Argeş','Tutana'),('Mureş','Târnava'),('Mureş','Borzia'),('Mureş','Fântânele');

Page 25: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

2.6. Ştergerea înregistrărilor dintr-un tabel

Se pot şterge înregistrări din tabeleEx.: şterge toate înregistrările din tabelul

hidro.Ex.: şterge toate

înregistrările anterioare datei specificate. Sintaxa simplificată:

unde USING specifică alte tabele utilizate în condiţia WHERE.De exemplu, dorim să ştergem toate înregistrările ce conţin afluenţii Oltului:

3. Operaţii de interogare ce implică un singur tabel

Instrucţiunea SELECT permite formularea unei varietăţi de comenzi SQL chiar şi fără a implica tabele.

24

DELETE FROM pic.hidro ;DELETE FROM pic.hidro ;

DELETE FROM pic.hidro WHERE data < '20.11.2007';DELETE FROM pic.hidro WHERE data < '20.11.2007';

DELETE FROM table[USING usinglist][WHERE condition]DELETE FROM table[USING usinglist][WHERE condition]

DELETE FROM pic.hidro2 USING pic.rauriWHERE hidro2.afluent = rauri.afluent AND rauri.rau='Olt';

DELETE FROM pic.hidro2 USING pic.rauriWHERE hidro2.afluent = rauri.afluent AND rauri.rau='Olt';

Select 5; -- afisează valoarea 5SeLecT 5+4; -- afişează rezultatul expresiei : 9 --instrucţiunile SQL nu depind de litera mare sau mică (case insensitive)Select 3 + 5; -- operatorul de adunareselect '3'||'5'; --concatenare şiruriSELECT 17 >> 2; -- afişează rezultatul operaţiei de deplasare

-- cu 2 biţi la dreapta valorii 17select current_date-5; --afişează data calendaristică cu 5 zile în urmă

Select 5; -- afisează valoarea 5SeLecT 5+4; -- afişează rezultatul expresiei : 9 --instrucţiunile SQL nu depind de litera mare sau mică (case insensitive)Select 3 + 5; -- operatorul de adunareselect '3'||'5'; --concatenare şiruriSELECT 17 >> 2; -- afişează rezultatul operaţiei de deplasare

-- cu 2 biţi la dreapta valorii 17select current_date-5; --afişează data calendaristică cu 5 zile în urmă

-- pune valoarea 14 acolo unde câmpul a2 are valoarea 'C1'update pic.t1 SET a3 = 14 WHERE a2 = 'C1';-- poate să nu fie afectata nicio inregistrare sau -- pot fi modificate toate înreg.-- ORDONARE după mai multe coloaneselect * from pic.t1 order by a1 ASC, a2 DESC;-- se poate seta si cu valoarea NULLUPDATE pic.t1 SET a3 = NULL WHERE a2='B1' AND a3 > 100; UPDATE pic.t1 SET a3 = 77 WHERE a3 IS NULL;-- adauga valoarea 1 la toate inregistrarile al caror camp a3 conţine -- o valoare impară (a3%2 este diferit de zero, adica TRUE)UPDATE pic.t1 SET a3 = a3 + 1 WHERE a3 % 2 <> 0;-- concatenareUPDATE pic.t1 SET a2 = a2 || '_Q' WHERE a3 <= 100;

-- pune valoarea 14 acolo unde câmpul a2 are valoarea 'C1'update pic.t1 SET a3 = 14 WHERE a2 = 'C1';-- poate să nu fie afectata nicio inregistrare sau -- pot fi modificate toate înreg.-- ORDONARE după mai multe coloaneselect * from pic.t1 order by a1 ASC, a2 DESC;-- se poate seta si cu valoarea NULLUPDATE pic.t1 SET a3 = NULL WHERE a2='B1' AND a3 > 100; UPDATE pic.t1 SET a3 = 77 WHERE a3 IS NULL;-- adauga valoarea 1 la toate inregistrarile al caror camp a3 conţine -- o valoare impară (a3%2 este diferit de zero, adica TRUE)UPDATE pic.t1 SET a3 = a3 + 1 WHERE a3 % 2 <> 0;-- concatenareUPDATE pic.t1 SET a2 = a2 || '_Q' WHERE a3 <= 100;

Page 26: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Operaţii de interogare ce implică un singur tabel

3.1. Preluarea datelor din tabel

Preluarea datelor din tabel (interogarea bazei de date) se realizează prin utilizarea instrucţiunii SELECT.Notă: Nu contează dacă codul SQL este scris pe un singur rând sau pe mai multe rânduri şi nici dacă între cuvinte există un spaţiu sau mai multe. Se recomandă scrierea astfel încât codul să se citească cât mai uşor. Comenzile transmise către server sunt separate prin “semicolon” (;).Ex.:preia întregul tabel hidro

(Operatorul * specifică preluarea tuturor câmpurilor)Ex.:preia doar câmpurile specificate în interogare

✗ preia numai ce îndeplineşte condiţiile din cadrul “WHERE” (condiţii la nivel de înregistrare)

✗ ordonează datele descrescător

✗ grupează datele după anumite câmpuri în vederea realizării anumitor operaţii (ex.:calc. mediei temp. min.)

✗ aplică condiţii la nivel de grup (ex.:doar oraşele cu media temp. min. > 5)

✗ aplică condiţii/restricţii atât la nivel de grup, cât şi la nivel de înregistrare

Notă: Toate câmpurile din cadrul SELECT trebuie să se regăsească în GROUP BY, altfel nu este posibilă gruparea acestora.

✗ efectuează operaţii între câmpuri şi afişează rezultatul într-un câmp nou

✗ întoarce un număr maxim de înregistrări (ex.: primele 10 obţinute în urma ordonării)

25

SELECT * FROM pic.hidro;SELECT * FROM pic.hidro;

SELECT afluent, datac FROM pic.hidro;SELECT afluent, datac FROM pic.hidro;

SELECT afluent, datac, precipitatii FROM pic.hidro WHERE((temp_min >=0 ) AND (temp_max <10 )) OR (precipitatii>0)ORDER BY datac DESC, afluent;

SELECT afluent, datac, precipitatii FROM pic.hidro WHERE((temp_min >=0 ) AND (temp_max <10 )) OR (precipitatii>0)ORDER BY datac DESC, afluent;

SELECT afluent, avg(temp_min) FROM pic.hidro GROUP BY afluent;SELECT afluent, avg(temp_min) FROM pic.hidro GROUP BY afluent;

SELECT afluent, avg(temp_min) FROM pic.hidro GROUP BY afluent HAVING avg(temp_min) > 5;

SELECT afluent, avg(temp_min) FROM pic.hidro GROUP BY afluent HAVING avg(temp_min) > 5;

SELECT afluent, avg(temp_min) WHERE data > '20.11.2007' FROM pic.hidro GROUP BY afluent HAVING avg(temp_min) > 5;

SELECT afluent, avg(temp_min) WHERE data > '20.11.2007' FROM pic.hidro GROUP BY afluent HAVING avg(temp_min) > 5;

SELECT afluent, temp_min, temp_max, (temp_min+temp_max)/2.0 AS media FROM pic.hidro;

SELECT afluent, temp_min, temp_max, (temp_min+temp_max)/2.0 AS media FROM pic.hidro;

SELECT afluent, data, precipitatii FROM pic.hidro ORDER BY data, afluent LIMIT 10;

SELECT afluent, data, precipitatii FROM pic.hidro ORDER BY data, afluent LIMIT 10;

Page 27: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

3.2. Căutarea parţială în şirurile de caractere

Căutarea parţială în şirurile de caractere este asigurată de funcţiile LIKE (case sensitive) şi ILIKE (case insensitive).Sintaxa (simplificată):

3.3. Funcţii de agregare

Funcţiile de agregare permit operaţiile de mai jos pe grupuri de înregistrări. Un exemplu de structură a comenzii privind utilizarea funcţiilor de agregare este:

Câmpurile din cadrul instrucţiunii SELECT trebuie să se regăsească în instrucţiunea GROUP BY.

Funcţii de agregare ce pot fi aplicate asupra câmpurilor în

26

SELECT câmpGrup1,…,câmpGrupS etc,funcţieAgregare1,...funcţieAgregareT FROM tabele WHERE filtru la nivel de înregistrare şi legături între tabele GROUP BY câmpGrup1, …,câmpGrupS HAVING filtru la nivel de grup;

SELECT câmpGrup1,…,câmpGrupS etc,funcţieAgregare1,...funcţieAgregareT FROM tabele WHERE filtru la nivel de înregistrare şi legături între tabele GROUP BY câmpGrup1, …,câmpGrupS HAVING filtru la nivel de grup;

DROP TABLE IF EXISTS pic.t5; create table pic.t5(a1 serial PRIMARY KEY,a2 varchar(20),a3 int); INSERT INTO pic.t5(a2,a3) VALUES ('A1',11),('C1',22),('B1',33); SELECT * FROM pic.t5; SELECT t5.* FROM pic.t5; SELECT a1,a2,a3 FROM pic.t5; SELECT t5.a1, t5.a2, t5.a3 FROM pic.t5; SELECT t5.a2 FROM pic.t5; SELECT a1,a2,a3 FROM pic.t5 ORDER BY a2; SELECT a1,a2,a3 FROM pic.t5 ORDER BY a2 DESC,a1 ASC ; INSERT INTO pic.t5(a2,a3) VALUES ('B1',21),('B2',24),('D1',30);--afiseaza doar inregistrarile al caror camp a2 incepe cu lit.BSELECT * FROM pic.t5 WHERE a2 LIKE 'B%';-- daca nu tine cont de litera mare mica (case insensitive)SELECT * FROM pic.t5 WHERE a2 ILIKE 'b%';--afişează toate înreg. care incep cu B sau b si ptr.care a3<30SELECT * FROM pic.t5 WHERE a2 ILIKE 'b%' AND a3<30;SELECT * FROM pic.t5 WHERE a3<30 AND a2 ILIKE 'b%';SELECT * FROM pic.t5 WHERE (a2 ILIKE 'b%') AND (a3<30);

DROP TABLE IF EXISTS pic.t5; create table pic.t5(a1 serial PRIMARY KEY,a2 varchar(20),a3 int); INSERT INTO pic.t5(a2,a3) VALUES ('A1',11),('C1',22),('B1',33); SELECT * FROM pic.t5; SELECT t5.* FROM pic.t5; SELECT a1,a2,a3 FROM pic.t5; SELECT t5.a1, t5.a2, t5.a3 FROM pic.t5; SELECT t5.a2 FROM pic.t5; SELECT a1,a2,a3 FROM pic.t5 ORDER BY a2; SELECT a1,a2,a3 FROM pic.t5 ORDER BY a2 DESC,a1 ASC ; INSERT INTO pic.t5(a2,a3) VALUES ('B1',21),('B2',24),('D1',30);--afiseaza doar inregistrarile al caror camp a2 incepe cu lit.BSELECT * FROM pic.t5 WHERE a2 LIKE 'B%';-- daca nu tine cont de litera mare mica (case insensitive)SELECT * FROM pic.t5 WHERE a2 ILIKE 'b%';--afişează toate înreg. care incep cu B sau b si ptr.care a3<30SELECT * FROM pic.t5 WHERE a2 ILIKE 'b%' AND a3<30;SELECT * FROM pic.t5 WHERE a3<30 AND a2 ILIKE 'b%';SELECT * FROM pic.t5 WHERE (a2 ILIKE 'b%') AND (a3<30);

SELECT [ ALL | DISTINCT ] * | expression [ AS output_name ] [ FROM from_item [, ...] ] [ WHERE condition ] [ GROUP BY expression [, ...] ] [ HAVING condition [, ...] ] [ ORDER BY expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ]] [ LIMIT { count | ALL } ]

SELECT [ ALL | DISTINCT ] * | expression [ AS output_name ] [ FROM from_item [, ...] ] [ WHERE condition ] [ GROUP BY expression [, ...] ] [ HAVING condition [, ...] ] [ ORDER BY expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ]] [ LIMIT { count | ALL } ]

Ex. expresie LIKE Rezultat'abcd' LIKE 'abcd' true'abcd' LIKE 'a%' true'abcd' LIKE '_b__' true'abcd' LIKE 'abc' false'abcd' LIKE '_b%' true'abcd' LIKE '__b%' falseNota:În loc de 'abcd' va fi denumirea câmpului

Ex. expresie LIKE Rezultat'abcd' LIKE 'abcd' true'abcd' LIKE 'a%' true'abcd' LIKE '_b__' true'abcd' LIKE 'abc' false'abcd' LIKE '_b%' true'abcd' LIKE '__b%' falseNota:În loc de 'abcd' va fi denumirea câmpului

Page 28: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Operaţii de interogare ce implică un singur tabel

cadrul SELECT:• avg(expresie): media aritmetică a expresiei;• count(expresie): numărul de înregistrări pentru care valoarea expresiei nu este

nulă, de ex. count(*):total înregistrări;• max(expresie): valoarea maximă pentru expresie;• min(expresie): valoarea minimă pentru expresie;• sum(expresie): suma expresiei;Notă: (expresie) poate fi un câmp sau rezultatul unor operaţii aplicate mai multor câmpuriEx.1:

Ex.2:

Ex.3:

27

-- SUMA SELECT sum(a3) from pic.t1; select sum(a3) as x from pic.t1;--MEDIA ARITMETICA select avg(a3) as media from pic.t1;-- numărul total de înreg. select count(*) as nr_t from pic.t1;

-- SUMA SELECT sum(a3) from pic.t1; select sum(a3) as x from pic.t1;--MEDIA ARITMETICA select avg(a3) as media from pic.t1;-- numărul total de înreg. select count(*) as nr_t from pic.t1;

/*suma după câmpul a2 atunci când acesta începe cu B sau b*/SELECT a2,SUM(a3) AS suma FROM pic.t1 WHERE a2 ILIKE 'b%' GROUP BY a2;-- calculeaza media aritmetica ptr. a3 grupata dupa a2SELECT a2, AVG(a3) AS media FROM pic.t1 GROUP BY a2;-- determina val max ptr. a3 grupata dupa a2SELECT a2, MAX(a3) AS maximum FROM pic.t1 GROUP BY a2;-- determina val max ptr a3 ptr. intregul tabelSELECT MAX(a3) AS maximum2 FROM pic.t1;-- calc. numarul de inregistrariSELECT COUNT(*) FROM pic.t1;--calc. nr.valori identice pentru câmpul a2, grupate după a2SELECT a2,COUNT(a2) as nr_val_identice FROM pic.t1 GROUP BY a2;

/*suma după câmpul a2 atunci când acesta începe cu B sau b*/SELECT a2,SUM(a3) AS suma FROM pic.t1 WHERE a2 ILIKE 'b%' GROUP BY a2;-- calculeaza media aritmetica ptr. a3 grupata dupa a2SELECT a2, AVG(a3) AS media FROM pic.t1 GROUP BY a2;-- determina val max ptr. a3 grupata dupa a2SELECT a2, MAX(a3) AS maximum FROM pic.t1 GROUP BY a2;-- determina val max ptr a3 ptr. intregul tabelSELECT MAX(a3) AS maximum2 FROM pic.t1;-- calc. numarul de inregistrariSELECT COUNT(*) FROM pic.t1;--calc. nr.valori identice pentru câmpul a2, grupate după a2SELECT a2,COUNT(a2) as nr_val_identice FROM pic.t1 GROUP BY a2;

--numărul de locuitori din fiecare regiuneSELECT regiune, SUM(nr_locuitori) as nrRegLoc FROM pic.t4 GROUP BY regiune;/* campurile din GROUP BY vor fi campurile din cadrul SELECT (cu exceptia functiilor de agregare)*/--afiseaza DOAR regiunile ce au peste 150 de locuitoriSELECT regiune, SUM(nr_locuitori) as nrRegLoc FROM pic.t4 GROUP BY regiune HAVING SUM(nr_locuitori) > 150; -- WHERE se referă la FIECARE înregistrare în parte-- HAVING se referă la rezultatul unei funcţii de agregare --(sum,avg,count,min,max,etc)SELECT localitate FROM pic.t4;-- se va elimina afisarea de mai multe ori a înregistrărilor identiceSELECT DISTINCT localitate FROM pic.t4; -- DISTINCT - elimină inregistrările multiple -- pastreaza o singura inregistrare

--numărul de locuitori din fiecare regiuneSELECT regiune, SUM(nr_locuitori) as nrRegLoc FROM pic.t4 GROUP BY regiune;/* campurile din GROUP BY vor fi campurile din cadrul SELECT (cu exceptia functiilor de agregare)*/--afiseaza DOAR regiunile ce au peste 150 de locuitoriSELECT regiune, SUM(nr_locuitori) as nrRegLoc FROM pic.t4 GROUP BY regiune HAVING SUM(nr_locuitori) > 150; -- WHERE se referă la FIECARE înregistrare în parte-- HAVING se referă la rezultatul unei funcţii de agregare --(sum,avg,count,min,max,etc)SELECT localitate FROM pic.t4;-- se va elimina afisarea de mai multe ori a înregistrărilor identiceSELECT DISTINCT localitate FROM pic.t4; -- DISTINCT - elimină inregistrările multiple -- pastreaza o singura inregistrare

Page 29: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

Un exemplu de utilizare simultană a instrucţiunilor HAVING şi WHERE − afişează numărul total de locuitori pe regiuni, luând în considerare numai localităţile a căror denumire se termină cu 1 şi care nu depăşesc 120 locuitori pe regiune.

S-a realizat mai întâi filtrarea, dată prin instrucţiunea WHERE, la nivel de înregistrare şi apoi s-au realizat sumele la nivel de grup.

3.4. Operatorul CAST

Este utilizat pentru conversia tipurilor de date, în vederea evaluării unor expresii în care intră datele respective sau pentru adăugarea acestora în tabele ce au un alt format de date.

Un caz aparte de cast este funcţia to_date(text, text), care realizează conversia din şir de caractere în format de tip dată calendaristică.

Aceeaşi operaţie este asigurată de utilizarea operatorului rezoluţie “::”. Exemplul de mai sus devine:

Un alt exemplu în care sunt prezentate în paralel cele două forme:

3.5. Expresii condiţionale

Dacă valoarea dintr-un câmp depinde de alte valori din alte câmpuri după reguli de tipul if then else, atunci se poate utiliza următoarea construcţie.

28

INSERT INTO pic.hidro(afluent, datac) VALUES('Tutana', to_date('29.05.1996','dd.mm.yyyy'));

INSERT INTO pic.hidro(afluent, datac) VALUES('Tutana', to_date('29.05.1996','dd.mm.yyyy'));

CAST ( expression AS type )CAST ( expression AS type )

SELECT afluent, cast(temp_min as numeric), cast(precipitatii as integer) as prec_int, cast(temp_max as varchar(15)) FROM pic.hidro;

SELECT afluent, cast(temp_min as numeric), cast(precipitatii as integer) as prec_int, cast(temp_max as varchar(15)) FROM pic.hidro;

SELECT afluent, temp_min::numeric, precipitatii::integer as prec_int, temp_max::varchar(15) FROM pic.hidro;

SELECT afluent, temp_min::numeric, precipitatii::integer as prec_int, temp_max::varchar(15) FROM pic.hidro;

select cast('3' as integer) + cast('5' as integer);--echivalent cuselect '3'::integer + '5'::integer;---------------------------------------------select '2013-12-07'::date + 5;--echivalent cuselect cast('2013-12-07' as date) + 5;

select cast('3' as integer) + cast('5' as integer);--echivalent cuselect '3'::integer + '5'::integer;---------------------------------------------select '2013-12-07'::date + 5;--echivalent cuselect cast('2013-12-07' as date) + 5;

SELECT regiune, SUM(nr_locuitori) as nrRegLoc FROM pic.t4 WHERE localitate LIKE '%1' GROUP BY regiune HAVING SUM(nr_locuitori) <= 120;

SELECT regiune, SUM(nr_locuitori) as nrRegLoc FROM pic.t4 WHERE localitate LIKE '%1' GROUP BY regiune HAVING SUM(nr_locuitori) <= 120;

Page 30: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Operaţii de interogare ce implică un singur tabel

Sintaxa simplificată:

Rezultatul expresiei este pus în noul câmp evaluare.

3.6. Comenzi SQL ce nu implică tabele

Sunt prezentate câteva comenzi SQL ce nu implică tabele:

4. Tipuri de asocieri între înregistrările unor tabele

Într-o bază de date relaţională tabelele sunt corelate, pentru ca datele memorate în tabele diferite să poată fi asociate corect atunci când din baza de date se solicită anumite informaţii. Se pot realiza asocieri între datele din tabele după criterii de funcţionalitate sau structură a datelor. Asocierile sunt posibile în faza de definire a structurii tabelelor. Câmpurile comune prin care se face corelarea sunt date de cheia primară (PRIMARY KEY) pentru un tabel şi, respectiv, chei externe (FOREIGN KEY) pentru tabelele asociate.

Orice tabel poate să cuprindă unul sau mai multe câmpuri, care intră în componenţa unei chei primare, utilizată pentru dife-renţierea unei înregistrări de celelalte. Asocierea a două tabele

29

CASE WHEN condition THEN result [WHEN ...] [ELSE result]END

CASE WHEN condition THEN result [WHEN ...] [ELSE result]END

SELECT (temp_min+temp_max)/2.0 as temp_medie, CASE WHEN( (temp_min+temp_max)/2.0 ) <=10 THEN 'F.RECE' WHEN( ((temp_min+temp_max)/2.0 ) > 10 )AND (((temp_min+temp_max)/2.0 ) <15 ) THEN 'RECE' WHEN ((temp_min+temp_max)/2.0 ) > 25 THEN 'CALDA' ELSE 'NORMALA' END AS evaluareFROM pic.hidro

SELECT (temp_min+temp_max)/2.0 as temp_medie, CASE WHEN( (temp_min+temp_max)/2.0 ) <=10 THEN 'F.RECE' WHEN( ((temp_min+temp_max)/2.0 ) > 10 )AND (((temp_min+temp_max)/2.0 ) <15 ) THEN 'RECE' WHEN ((temp_min+temp_max)/2.0 ) > 25 THEN 'CALDA' ELSE 'NORMALA' END AS evaluareFROM pic.hidro

SELECT 3; -- afişează 3SELECT 3+2; --afişează 5select CURRENT_DATE; --data curenta -- de tip dateselect CURRENT_TIME; --ora curenta -- de tip timeselect CURRENT_DATE+CURRENT_TIME; -- rezultatul este de tip timestampSELECT CURRENT_DATE+1; -- ziua urmatoare de tip dateSELECT CURRENT_DATE-1; -- ziua anterioaraSELECT CURRENT_TIME+'2:3'::time; -- peste 2 ore si 3 minute (timestamp)SELECT CURRENT_TIME-'2:3'::time; -- acum 2 ore si 3 minuteSELECT '2012-05-27'::date - '2:15'::time; --rezultat timestamp ziua 26.05.2012 ora 21:45SELECT '2:23'::time - '1:15'::time; --rezultat de tip interval

SELECT 3; -- afişează 3SELECT 3+2; --afişează 5select CURRENT_DATE; --data curenta -- de tip dateselect CURRENT_TIME; --ora curenta -- de tip timeselect CURRENT_DATE+CURRENT_TIME; -- rezultatul este de tip timestampSELECT CURRENT_DATE+1; -- ziua urmatoare de tip dateSELECT CURRENT_DATE-1; -- ziua anterioaraSELECT CURRENT_TIME+'2:3'::time; -- peste 2 ore si 3 minute (timestamp)SELECT CURRENT_TIME-'2:3'::time; -- acum 2 ore si 3 minuteSELECT '2012-05-27'::date - '2:15'::time; --rezultat timestamp ziua 26.05.2012 ora 21:45SELECT '2:23'::time - '1:15'::time; --rezultat de tip interval

Page 31: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

(tabel părinte şi tabel copil)/master-slave se face printr-un câmp special cu o trimitere la cheia primară a tabelului subordonat (tabelul copil).

O bază de date poate fi formată din mai multe tabele având diferite legături între acestea. Tipurile de legături dintre două tabele pot fi:

● asocierea (legătura) de tip unu la unu (1:1) – unei înregistrări dintr-un tabel îi corespunde o singură înregistrare în celălalt tabel;

● asocierea (legătura) de tip unu la mai mulţi (1:M) – unei înregistrări dintr-un tabel îi corespund mai multe înregistrări în celălalt tabel;

● asocierea (legătura) de tip mulţi la mulţi (M:N) – un grup cu mai multe înregistrări dintr-un tabel corespunde cu alt grup format din mai multe înregistrări din celălalt tabel.

4.1. Asocierea de tip unu la unu (1:1)

Înregistrările din două tabele se află în asocierea unu la unu dacă unei înregistrări dintr-un tabel îi corespunde (sau nu) o singură înregistrare din celălalt tabel. Legătura dintre cele două tabele se face pe baza cheilor primare.

Acest tip de asociere este utilizată mai rar. Există, totuşi, cazuri în care este necesară şi utilă stabilirea unei astfel de relaţii.

4.2. Asocierea de tip unu la mai mulţi (1:N)

Două tabele A şi B se află în asociere 1:N dacă unei înregistrări din tabelul A îi corespund mai multe înregistrări în tabelul B. Cheia primară din tabelul părinte (A) se adaugă în tabelul copil (B) sub forma unei chei externe.

30

Figura II-1: Exemplu de asociere 1:1

ANGAJATIcnpsectiacolectivul

DATE PERSONALEcnpteladresa

1:1

Figura II-2: Exemplu de asociere 1:N

JUDETnumesuprafatapopulatie

LOCALITATEdenumiresuprafatapopulatiepozitie_geogr.

1:N

Page 32: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Tipuri de asocieri între înregistrările unor tabele

4.3. Asocierea de tip mulţi la mulţi (M:N)

Mai multor înregistrări dintr-un tabel le corespund mai multe înregistrări în cealălalt tabel. În vederea implementării practice, se adaugă un tabel suplimentar, care va conţine cheile primare ale tabelelor iniţiale şi câmpuri referitoare la asocierea dintre tabelele părinţi. Cheia primară din tabela intermediară va fi o cheie compusă.

4.4. Crearea cheilor primare şi a cheilor externe

Cheia primară din tabel impune unicitatea valorilor câmpurilor din cadrul cheii primare pentru fiecare înregistrare. Specificarea cheii primare se face cu modificatorul PRIMARY KEY. Cheia străină/externă se declară prin modificatorul FOREIGN KEY.

Atât pentru PRIMARY KEY, cât şi pentru FOREIGN KEY putem avea unul sau mai multe câmpuri, separate prin virgulă.

4.5. Asigurarea integrităţii referenţiale

Una dintre problemele importante ale unei baze de date este asigurarea consistenţei şi corelării datelor. Pentru aceasta putem impune respectarea unei restricţii la adăugarea sau eliminarea înregistrărilor în tabelele corelate. Aplicarea acestor restricţii ne dă posibilitatea să asigurăm o proprietate importantă a bazelor de date relaţionale, numită integritate referenţială.

31

Figura II-3: Exemplu de asociere M:N

AUTORInumetitluedituraan_aparitie

BIBLIOTECAcotatitluautor1edituraan_aparitie

M:N

CREATE TABLE pic.hidro( afluent character varying(80),temp_min integer, nivel_min int, temp_max integer, nivel_max int, precipitatii numeric, datac date, CONSTRAINT k_hidro PRIMARY KEY(afluent, datac), CONSTRAINT f_rauri FOREIGN KEY(rau) REFERENCES pic.rauri(rau));

CREATE TABLE pic.hidro( afluent character varying(80),temp_min integer, nivel_min int, temp_max integer, nivel_max int, precipitatii numeric, datac date, CONSTRAINT k_hidro PRIMARY KEY(afluent, datac), CONSTRAINT f_rauri FOREIGN KEY(rau) REFERENCES pic.rauri(rau));

drop table if exists pic.rauri;CREATE TABLE pic.rauri(rau varchar(100), afluent varchar(80), CONSTRAINT k_rauri PRIMARY KEY(rau,afluent));INSERT INTO pic.rauri VALUES('Argeş','Neajlov'),('Olt','Malnaş'),('Olt','Hurez'),('Olt','Sebeş'),('Olt','Tuşnad'),('Argeş','Tutana'),('Mureş','Târnava'),('Mureş','Borzia'),('Mureş','Fântânele');

drop table if exists pic.rauri;CREATE TABLE pic.rauri(rau varchar(100), afluent varchar(80), CONSTRAINT k_rauri PRIMARY KEY(rau,afluent));INSERT INTO pic.rauri VALUES('Argeş','Neajlov'),('Olt','Malnaş'),('Olt','Hurez'),('Olt','Sebeş'),('Olt','Tuşnad'),('Argeş','Tutana'),('Mureş','Târnava'),('Mureş','Borzia'),('Mureş','Fântânele');

Page 33: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

Aceste restricţii se referă la ştergerea datelor, la inserarea/adăugarea datelor sau modificarea lor.

Operaţiile de ştergere şi inserare au în clauza WHERE şi câmpurile ce constituie cheile primare. De asemenea, operaţia de adăugare impune specificarea obligatorie a câmpurilor din cheia primară, acestea fiind diferite de NULL şi fiind unice în cadrul tabelului.

5. Operaţii de editare cu mai multe tabele

Operaţiile de inserare au ca destinaţie întotdeauna un singur tabel, indiferent dacă sursa este explicită (cu operatorul VALUES) sau rezultă dintr-o interogare (cu operatorul SELECT), operaţie ce poate să implice unul sau mai multe tabele.

5.1. Actualizarea datelor din tabele prin utilizarea unor date din alte tabele

Forma generală simplificată:

Ex.:mărim valoarea lui t3.b cu valoarea din t4.d pentru care t3.a = t4.c

5.2. Ştergerea înregistrărilor din tabele prin utilizarea unor date din alte tabele

Forma generală simplificată:

Ex.:Ştergem din tabelul t3 înregistrările a căror valoare din câmpul a se regăseşte şi în tabelul t4 (a=c) şi a căror valoare din câmpul d este mai mică decât valoarea 30.

32

create table pic.t11(a varchar(10), b int);create table pic.t12(c varchar(10), d int);INSERT INTO pic.t11 VALUES('ABC11',10),('ACD12',20),('BCD13',30);INSERT INTO pic.t12 VALUES('AXC11',11),

('ACD12',25),('BD19',30),('XCD18',45);select * from pic.t11;--echivalent cu:select t11.* from pic.t11;--echivalent cu:select a,b from pic.t11;--echivalent cu:select t11.a, t11.b from pic.t11;-- echivalent cu:select tx.a,tx.b from pic.t11 tx;--tx se comporta ca un alias ptr.tabelul t11

create table pic.t11(a varchar(10), b int);create table pic.t12(c varchar(10), d int);INSERT INTO pic.t11 VALUES('ABC11',10),('ACD12',20),('BCD13',30);INSERT INTO pic.t12 VALUES('AXC11',11),

('ACD12',25),('BD19',30),('XCD18',45);select * from pic.t11;--echivalent cu:select t11.* from pic.t11;--echivalent cu:select a,b from pic.t11;--echivalent cu:select t11.a, t11.b from pic.t11;-- echivalent cu:select tx.a,tx.b from pic.t11 tx;--tx se comporta ca un alias ptr.tabelul t11

UPDATE pic.t11 SET b=t11.b+t12.d FROM pic.t12 WHERE t11.a=t12.c;UPDATE pic.t11 SET b=t11.b+t12.d FROM pic.t12 WHERE t11.a=t12.c;

UPDATE table [ [ AS ] alias ]SET { column = { expression | DEFAULT } } [, ...][ FROM fromlist ] [ WHERE condition ]

UPDATE table [ [ AS ] alias ]SET { column = { expression | DEFAULT } } [, ...][ FROM fromlist ] [ WHERE condition ]

DELETE FROM table [ USING usinglist ][ WHERE condition ]DELETE FROM table [ USING usinglist ][ WHERE condition ]

Page 34: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Operaţii de editare cu mai multe tabele

6. Operaţii de interogare cu mai multe tabele. Vederi

6.1. Combinarea interogărilor (UNION, EXCEPT, INTERSECT)

a) UNIUNEA: concatenarea tabelelor (operaţie pe verticală – la nivel de înregistrări)

În mod implicit prin uniunea celor două interogări, înregistrările multiple, identice, vor apărea o singură dată (echivalent cu utilizarea instrucţiunii DISTINCT). Prin utilizarea comenzii ALL, acestea nu vor mai fi eliminate. De exemplu:

sau:

Putem avea:

Denumirea câmpului rezultat va fi cea din prima interogare.Înregistrările multiple vor apărea o singură dată. Este

echivalent cu a scrie:

Notă: Atenţie la operatorul semicolon ; deoarece acesta semnifică sfârşitul şirului ce constituie comanda SQL.Ex.: Afişarea doar a valorilor mai mari de 20:

echivalent cu a scrie:

b) INTERSECŢIA: intersecţia dintre două tabele cu aceeaşi structură (operaţie pe verticală – la nivel de înregistrări)

33

interogare#1 UNION [ALL] interogare#2interogare#1 UNION [ALL] interogare#2

SELECT afluent FROM pic.hidro UNION SELECT afluent FROM pic.rauri

SELECT afluent FROM pic.hidro UNION SELECT afluent FROM pic.rauri

interogare#1 UNION interogare#2 ... UNION interogare#ninterogare#1 UNION interogare#2 ... UNION interogare#n

SELECT a,b FROM pic.t11 UNION SELECT c,d FROM pic.t12;

SELECT a,b FROM pic.t11 UNION SELECT c,d FROM pic.t12;

SELECT c,d FROM pic.t12 UNION SELECT a,b FROM pic.t11;

SELECT c,d FROM pic.t12 UNION SELECT a,b FROM pic.t11;

SELECT a,b FROM pic.t11 WHERE b>20 UNION SELECT c,d FROM pic.t12 WHERE d>20;

SELECT a,b FROM pic.t11 WHERE b>20 UNION SELECT c,d FROM pic.t12 WHERE d>20;

select par.x, par.y from(select a as x,b as y from pic.t11UNIONselect c as x, d as y from pic.t12) par WHERE par.y > 20;

select par.x, par.y from(select a as x,b as y from pic.t11UNIONselect c as x, d as y from pic.t12) par WHERE par.y > 20;

DELETE FROM pic.t11 USING pic.t12 WHERE t11.a=t12.c AND t12.d<30;DELETE FROM pic.t11 USING pic.t12 WHERE t11.a=t12.c AND t12.d<30;

Page 35: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

Prin utilizarea comenzii INTERSECT, vor fi selectate doar înregistrările comune din cadrul interogărilor, de exemplu:

c) DIFERENŢA: diferenţa între două tabele cu aceeaşi structură (operaţie pe verticală – la nivel de înregistrări)

Prin utilizarea comenzii EXCEPT vor fi selectate doar înregistrările care se regăsesc în rezultatul primei interogări, dar care nu se regăsec şi în rezultatul celei de a doua interogări.

În toate cazurile, câmpurile din cadrul selecţiilor trebuie să fie de acelaşi tip, altfel fiind necesară convertirea acestora la tipul respectiv prin utilizarea operatorului CAST.

Pentru ordonarea rezultatului introducem un alias (în acest caz se numeşte par) pentru tabelul rezultat.

6.2. Interogarea mai multor tabele

6.2.1. Clauza JOIN

Atunci când în clauza FROM a unei comenzi SELECT apar mai multe tabele, se realizează produsul cartezian al acestora. De aceea numărul de linii rezultat creşte considerabil, fiind necesară restricţionarea acestora cu clauza WHERE.

Atunci când este necesară obţinerea de informaţii din mai multe tabele, se utilizează clauza JOIN. În acest fel liniile dintr-un tabel pot fi puse în legătură cu cele din alt tabel, conform valorilor comune ale unor coloane.

34

interogare#1 INTERSECT [ALL] interogare#2interogare#1 INTERSECT [ALL] interogare#2

SELECT afluent FROM pic.hidro INTERSECT SELECT afluent FROM pic.rauri;

SELECT afluent FROM pic.hidro INTERSECT SELECT afluent FROM pic.rauri;

SELECT afluent FROM pic.rauri EXCEPT SELECT afluent FROM pic.hidro;

SELECT afluent FROM pic.rauri EXCEPT SELECT afluent FROM pic.hidro;

interogare#1 EXCEPT [ALL] interogare#2interogare#1 EXCEPT [ALL] interogare#2

SELECT a,b FROM pic.t11 EXCEPT SELECT c,d FROM pic.t12;-- t12 except t11 select c,d from pic.t12 except select a,b from pic.t11;

SELECT a,b FROM pic.t11 EXCEPT SELECT c,d FROM pic.t12;-- t12 except t11 select c,d from pic.t12 except select a,b from pic.t11;

select par.x,par.y FROM(select c as x,d as y from pic.t12exceptselect a as x,b as y from pic.t11) par ORDER BY par.x;

select par.x,par.y FROM(select c as x,d as y from pic.t12exceptselect a as x,b as y from pic.t11) par ORDER BY par.x;

Page 36: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Operaţii de interogare cu mai multe tabele. Vederi

Clauza JOIN este utilizată pentru preluarea informaţiilor din două sau mai multe tabele, în condiţiile existenţei unor legături logice între anumite câmpuri din cadrul tabelelor.

JOIN întoarce înregistrările ce respectă condiţiile impuse de JOIN între tabele. JOIN nu se referă la intersecţii, ci la produse carteziene. Diversele tipuri de JOIN, reduc produsele, punând diverse condiţii pe una sau mai multe mulţimi.

Presupunem că avem un tabel T1 cu N înregistrări şi un tabel T2 cu M înregistrări.Clauza CROSS JOIN are forma: T1 CROSS JOIN T2 şi întoarce pentru fiecare înregistrare din T1 toate înregistrările din T2. Tabelul rezultat va avea NxM înregistrări. Sintaxa este:

Clauzele INNER şi OUTER sunt opţionale. INNER este implicit, iar LEFT, RIGHT sau FULL implică OUTER.

Clauza ON este asemănătoare cu WHERE. Principalele forme ale clauzei JOIN:

✔ INNER JOIN (joncţiune internă – de tip egalitate) - pentru fiecare rând (înregistrare) R1 din tabelul T1, tabelul rezultat în urma aplicării clauzei JOIN va avea o înregistrare din tabelul R2 care îndeplineşte condiţia de joncţiune cu R1.

Ex.:

echivalent d.p.d.v. al scrierii cu:

sau

35

T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON boolean_expression

T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON boolean_expression

T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( join column list )

T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( join column list )

T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2

SELECT v.afluent, v.datac FROM pic.hidro v INNER JOIN pic.rauri m ON v.afluent=m.afluent;

SELECT v.afluent, v.datac FROM pic.hidro v INNER JOIN pic.rauri m ON v.afluent=m.afluent;

SELECT v.afluent, v.datac FROM pic.hidro v, pic.rauri m WHERE v.afluent=m.afluent;

SELECT v.afluent, v.datac FROM pic.hidro v, pic.rauri m WHERE v.afluent=m.afluent;

-- 2 tabele FARA legatura intre ele !!!select t11.*, t12.* FROM pic.t11, pic.t12;-- rezultat: PRODUSUL CARTEZIAN (nr_inreg_t11 X nr_inreg_t12)-- o conditie de legatura intre tabele:select t11.*, t12.* from pic.t11, pic.t12 WHERE t11.a=t12.c;-- având în vedere den. diferite ale campurilor se poate scrie: select t11.*, t12.* from pic.t11, pic.t12 WHERE a=c;-- echivalent cu a scrie:select t11.*, t12.* from pic.t11 INNER JOIN pic.t12 ON t11.a=t12.c;--sauselect t11.*, t12.* from pic.t12 INNER JOIN pic.t11 ON t11.a=t12.c;

-- 2 tabele FARA legatura intre ele !!!select t11.*, t12.* FROM pic.t11, pic.t12;-- rezultat: PRODUSUL CARTEZIAN (nr_inreg_t11 X nr_inreg_t12)-- o conditie de legatura intre tabele:select t11.*, t12.* from pic.t11, pic.t12 WHERE t11.a=t12.c;-- având în vedere den. diferite ale campurilor se poate scrie: select t11.*, t12.* from pic.t11, pic.t12 WHERE a=c;-- echivalent cu a scrie:select t11.*, t12.* from pic.t11 INNER JOIN pic.t12 ON t11.a=t12.c;--sauselect t11.*, t12.* from pic.t12 INNER JOIN pic.t11 ON t11.a=t12.c;

Page 37: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

✔ LEFT OUTER JOIN (joncţiune externă la stânga)LEFT OUTER JOIN − preia toate înregistrările din tabelul din

stânga, iar din tabelul din dreapta va prelua doar cele pentru care este adevărată condiţia de legătură, restul câmpurilor provenite din tabelul din dreapta sunt completate cu NULL (câmp gol), unirea celor două tabele se face PE ORIZONTALĂsau

LEFT OUTER JOIN − realizează, în primul rând, o joncţiune internă. Apoi, fiecare rând din T1 (T1 stânga, T2 dreapta) care nu satisface joncţiunea cu T2 este adăugat, având valori NULL pentru câmpurile corespondente din T2. Tabelul rezultat va avea, cel puţin rândurile din tabelul T1. De exemplu:

✔ RIGHT OUTER JOIN (joncţiune externă la stânga) RIGHT OUTER JOIN realizează, pentru început, o joncţiune internă. Apoi, fiecare rând din T2 (T1 stânga, T2 dreapta) care nu satisface joncţiunea cu T1 este adăugat având valori NULL pentru câmpurile corespondente din T1. Tabelul rezultat va avea, cel puţin rândurile din tabelul T2.sau

RIGHT OUTER JOIN − preia toate înregistrările din tabelul din dreapta, iar din tabelul din stânga va prelua doar cele pentru care este adevărată condiţia de legătură, restul câmpurilor provenite din tabelul din stânga sunt completate cu NULL (câmp gol) − unirea celor două tabele se face PE ORIZONTALĂ. De exemplu:

✔ FULL OUTER JOIN (joncţiune totală)

FULL OUTER JOIN, pentru început, realizează o joncţiune internă, apoi fiecare rând din T2 (T1 stânga, T2 dreapta) care nu satisface joncţiunea cu T1 este adăugat având valori NULL pentru câmpurile corespondente din T1. În final, fiecare rând din T2 (T1 stânga, T2 dreapta) care nu satisface joncţiunea cu T1 este adăugat, având valori NULL pentru câmpurile corespondente din T1. sau

FULL OUTER JOIN − preia toate înregistrările din tabelul din stânga şi toate înregistrările din tabelul din dreapta.

36

SELECT v.afluent,v.datac FROM pic.hidro v LEFT OUTER JOIN pic.rauri m ON v.afluent=m.afluent;

SELECT v.afluent,v.datac FROM pic.hidro v LEFT OUTER JOIN pic.rauri m ON v.afluent=m.afluent;

SELECT v.afluent, v.datac, m.rau FROM pic.hidro v RIGHT OUTER JOIN pic.rauri m ON v.afluent = m.afluent;

SELECT v.afluent, v.datac, m.rau FROM pic.hidro v RIGHT OUTER JOIN pic.rauri m ON v.afluent = m.afluent;

select t11.*,t12.* FROM pic.t11 LEFT OUTER JOIN pic.t12 ON t11.b=t12.d;

select t11.*,t12.* FROM pic.t11 LEFT OUTER JOIN pic.t12 ON t11.b=t12.d;

select t11.*, t12.* FROM pic.t11 RIGHT OUTER JOIN pic.t12 ON t11.a=t12.c;

select t11.*, t12.* FROM pic.t11 RIGHT OUTER JOIN pic.t12 ON t11.a=t12.c;

Page 38: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Operaţii de interogare cu mai multe tabele. Vederi

Înregistrările pentru care există condiţia de legătură cu valoarea de adevăr TRUE vor apărea o singură dată (rândul stânga-dreapta va fi complet). Pentru celelalte înregistrări pentru care nu există condiţie de legătură cu valoarea TRUE va fi completat doar tabelul de care aparţin, în celălalt tabel vor avea valoarea NULL.

De asemenea, se pot lega mai multe clauze de tipul ON într-o instrucțiune de tipul JOIN, utilizând, de exemplu, sintaxa:

O operație de tip LEFT JOIN sau RIGHT JOIN se poate imbrica într-o operație de tipul INNER JOIN, dar o operație de tipul INNER JOIN nu se poate imbrica într-o operație de tipul LEFT JOIN sau RIGHT JOIN.

6.2.2. DIFERENŢA ÎNTRE DOUĂ TABELE

Diferenţa între două tabele cu aceeaşi structură (operaţie pe vericală) − apar toate înregistrările din primul tabel minus/cu excepţia celor comune pentru cele două tabele

Pentru utilizarea comenzii SQL EXCEPT este necesar ca cele două tabele să aibă aceeaşi structură a câmpurilor.

37

SELECT v.afluent, v.datac, m.rau FROM pic.hidro v FULL OUTER JOIN pic.rauri m ON v.afluent=m.afluent;

SELECT v.afluent, v.datac, m.rau FROM pic.hidro v FULL OUTER JOIN pic.rauri m ON v.afluent=m.afluent;

SELECT câmpuri FROM tabel1 INNER JOIN tabel2 ( (ON tabel1.câmp1 operator de comparație tabel2.câmp1 AND ON tabel1.câmp2 operator de comparație tabel2.câmp2) OR ON tabel1.câmp3 operator de comparație tabel2.câmp3) ;

SELECT câmpuri FROM tabel1 INNER JOIN tabel2 ( (ON tabel1.câmp1 operator de comparație tabel2.câmp1 AND ON tabel1.câmp2 operator de comparație tabel2.câmp2) OR ON tabel1.câmp3 operator de comparație tabel2.câmp3) ;

select t11.*,t12.* FROM pic.t11 FULL OUTER JOIN pic.t12 ON t11.a = t12.c;

select t11.*,t12.* FROM pic.t11 FULL OUTER JOIN pic.t12 ON t11.a = t12.c;

DROP TABLE IF EXISTS pic.t13; DROP TABLE IF EXISTS pic.t14;create table pic.t13(a varchar(10), b int);create table pic.t14(c varchar(10), d int);INSERT INTO pic.t13 VALUES('ABC11',10),('ACD12',20),('BCD13',30);INSERT INTO pic.t14 VALUES('AXC11',15),('ACD12',20),

('BCD13',35),('XCD18',45);-- t13 except t14select * from pic.t13; select * from pic.t14;SELECT a,b FROM pic.t13 EXCEPT SELECT c,d FROM pic.t14; -- sauSELECT a,b FROM pic.t13EXCEPT SELECT c,d FROM pic.t14;-- t14 except t13select c,d from pic.t14 except select a,b from pic.t13;

DROP TABLE IF EXISTS pic.t13; DROP TABLE IF EXISTS pic.t14;create table pic.t13(a varchar(10), b int);create table pic.t14(c varchar(10), d int);INSERT INTO pic.t13 VALUES('ABC11',10),('ACD12',20),('BCD13',30);INSERT INTO pic.t14 VALUES('AXC11',15),('ACD12',20),

('BCD13',35),('XCD18',45);-- t13 except t14select * from pic.t13; select * from pic.t14;SELECT a,b FROM pic.t13 EXCEPT SELECT c,d FROM pic.t14; -- sauSELECT a,b FROM pic.t13EXCEPT SELECT c,d FROM pic.t14;-- t14 except t13select c,d from pic.t14 except select a,b from pic.t13;

Page 39: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

7. Subinterogări

Subinterogările permit crearea unui tabel în cadrul unei interogări. Acestea sunt scrise între paranteze rotunde şi au un ALIAS.

Subinterogările scalare sunt interogările care întorc un singur rând şi o singură coloană. Ele se scriu între paranteze rotunde. În cazul în care subinterogarea întoarce mai multe înregistrări, vom avea eroare. În cazul în care nu întoarce nicio înregistrare, valoarea rezultată a interogării este considerată NULL. În exemplul următor sunt afişaţi toţi afluenţii din tabelul pic.rauri şi mediile precipitaţilor acolo unde acestea au fost introduse:

Expresii specifice subinterogărilor: EXISTS − întoarce true dacă subinterogarea

are ca rezultat cel puţin o înregistrare, altfel întoarce false;

IN − caz în care subinterogarea întoarce o singură coloană. Verifică dacă expresia se află în rezultatul subinterogării sau − caz în care subinterogarea întoarce acelaşi număr de coloane ca şi constructorul înregistrare (row constructor).

Notă: Constructorul de înregistrare formează o înregistrare utilizând cuvântul ROW, de ex.: .

Un alt exemplu:

NOT IN – asemănătoare cu IN, dar cu rezultatul negat. ALL – caz în care subinterogarea

întoarce o singură coloană – verifică dacă expresia satisface condiţia pentru fiecare înregistrare din subinterogare sau – caz în care

subinterogarea întoarce acelaşi număr de coloane ca şi constructorul de înregistrare row constructor.

Ex.: Adaugă în pic.t13, înregistrările din pic.t14 pentru care valoarea câmpului NU se regăseşte în pic.t13

38

EXISTS (subquery)EXISTS (subquery)

expression IN (subquery)expression IN (subquery)

Row constructor IN (subquery)Row constructor IN (subquery)

ROW(12,14,'TEST')ROW(12,14,'TEST')

expression ALL (subquery)expression ALL (subquery)

Row constructor ALL (subquery)Row constructor ALL (subquery)

SELECT rau, afluent, (SELECT avg(precipitatii) FROM pic.hidro WHERE rauri.afluent = hidro.afluent) AS media FROM pic.rauri;

SELECT rau, afluent, (SELECT avg(precipitatii) FROM pic.hidro WHERE rauri.afluent = hidro.afluent) AS media FROM pic.rauri;

SELECT ROW(3,9,'Malnaş') IN(SELECT temp_min,temp_max,afluent FROM pic.hidro) AS VERIFICA;

SELECT ROW(3,9,'Malnaş') IN(SELECT temp_min,temp_max,afluent FROM pic.hidro) AS VERIFICA;

Page 40: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Subinterogări

Ex.: Actualizează valorile b pentru înregistrările a căror valoare din câmpul a începe cu litera x. Valoarea cu care se înlocuieşte este suma tuturor valorilor câmpului d din tabelul pic.t14

8. Operaţii cu tablouri de date

Tablourile de date sunt structuri secvenţiale cu un anumit tip de dată. Acestea pot fi cu o dimensiune (vectori) sau cu mai multe dimensiuni.

În exemplul de mai sus, câmpul a este un şir cu maxim 3 caractere, iar b este un vector cu 3 şiruri de tip varchar cu lungime nedefinită (tip text).

Fiecare tablou se află în câte o celulă a "tabelului".

În exemplul de mai sus, câmpul b este un vector cu un număr nedefinit de celule, iar fiecare celulă din cadrul vectorului conţine câte un şir cu maxim 10 caractere. Câmpul c este un vector cu dimensiune necunoscută, fiecare element din cadrul vectorului fiind de tip întreg.

8.1. Tablouri unidimensionale

Pentru tablourile unidimensionale (vectori) nu este necesară specificarea dimensiunii acestora. Popularea cu date se poate realiza în mai multe moduri.

O primă variantă este prezentată în ceea ce urmează:

39

INSERT INTO pic.t13 select par1.x, t14.d as y FROM (SELECT t14.c as x from pic.t14 except select t13.a as x from pic.t13 )par1, pic.t14 WHERE par1.x = t14.c;

INSERT INTO pic.t13 select par1.x, t14.d as y FROM (SELECT t14.c as x from pic.t14 except select t13.a as x from pic.t13 )par1, pic.t14 WHERE par1.x = t14.c;

update pic.t13 set b = (select sum(t14.d) from pic.t14) where a ilike 'x%';

update pic.t13 set b = (select sum(t14.d) from pic.t14) where a ilike 'x%';

create temporary table tx(a varchar(3), b varchar[3]);create temporary table tx(a varchar(3), b varchar[3]);

create table pic.t15(a serial primary key, b varchar(10)[], c int[]);create table pic.t15(a serial primary key, b varchar(10)[], c int[]);

INSERT INTO pic.t15(b,c) VALUES('{"A01","A02","A03"}','{12, 14,9,7,5}'),

-- b cu 3 elemente si c cu 5 elemente('{"A01","A02","A03","A04"}','{9,7}'),

-- b cu 4 elemente si c cu 2 elemente('{"A04"}','{9,7,9,9,9,9}');

-- b cu un element si c cu 6 elemente

INSERT INTO pic.t15(b,c) VALUES('{"A01","A02","A03"}','{12, 14,9,7,5}'),

-- b cu 3 elemente si c cu 5 elemente('{"A01","A02","A03","A04"}','{9,7}'),

-- b cu 4 elemente si c cu 2 elemente('{"A04"}','{9,7,9,9,9,9}');

-- b cu un element si c cu 6 elemente

Page 41: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

O altă variantă de populare cu date este:

Pentru selecţie se poate utiliza:

Dacă elementul vectorului nu există, celula aceasta va fi reprezentată prin NULL.

8.2. Tablouri multidimensionale

Tablorile multidimensionale (dim.>=2) trebuie să aibă dimensiunea stabilită în momentul declarării acestora. De exemplu:

Pentru popularea cu date recomand utilizarea celei de a două variante:

Pentru selecţie, se pot extrage doar datele aflate în anumite zone ale tablourilor.

8.3. Căutarea în tablouri

Pentru a utiliza elemente dintr-o dată de tip tablou, se

40

INSERT INTO pic.t15(b,c) VALUES (ARRAY['B01','B02','B03'], ARRAY[17,20,5,4]), (ARRAY['B02','B05'], ARRAY[7]), (ARRAY['B03'], ARRAY[1,2,3,4,5]);

INSERT INTO pic.t15(b,c) VALUES (ARRAY['B01','B02','B03'], ARRAY[17,20,5,4]), (ARRAY['B02','B05'], ARRAY[7]), (ARRAY['B03'], ARRAY[1,2,3,4,5]);

SELECT * FROM pic.t15;--este selectat primul element din vect.b şi primul element din vect. cselect b[1],c[1] FROM pic.t15; SELECT b[2],c[1] from pic.t15; /* selecteaza toate inreg. din t1 ptr. care elementul al doilea al vectorului b are caracterele 2 si 3 egale cu 0, respectiv 2 */select * from pic.t15 where b[2] like '_02';

SELECT * FROM pic.t15;--este selectat primul element din vect.b şi primul element din vect. cselect b[1],c[1] FROM pic.t15; SELECT b[2],c[1] from pic.t15; /* selecteaza toate inreg. din t1 ptr. care elementul al doilea al vectorului b are caracterele 2 si 3 egale cu 0, respectiv 2 */select * from pic.t15 where b[2] like '_02';

--matrice 3 linii x 4 coloanecreate table pic.t16(a serial primary key, b varchar(10)[3][4], c int[3][4]);

--matrice 3 linii x 4 coloanecreate table pic.t16(a serial primary key, b varchar(10)[3][4], c int[3][4]);

INSERT INTO pic.t16(b,c) VALUES(ARRAY[['A11','A12','A13','A14'],['A21','A22','A23','A24'], ['A31','A32','A33','A34']], --b (din prima înregistrare)ARRAY[[11,12,13,14],[21,22,23,24],[31,32,33,34]]),--c(prima înreg.)(ARRAY[['B11','B12','B13','B14'],['B21','B22','B23','B24'], ['B31','B32','B33','B34']],-- b (din a doua înregistrare)ARRAY[[11,12,13,14],[21,22,23,24],[31,32,33,34]]);--c(a doua înreg.)

INSERT INTO pic.t16(b,c) VALUES(ARRAY[['A11','A12','A13','A14'],['A21','A22','A23','A24'], ['A31','A32','A33','A34']], --b (din prima înregistrare)ARRAY[[11,12,13,14],[21,22,23,24],[31,32,33,34]]),--c(prima înreg.)(ARRAY[['B11','B12','B13','B14'],['B21','B22','B23','B24'], ['B31','B32','B33','B34']],-- b (din a doua înregistrare)ARRAY[[11,12,13,14],[21,22,23,24],[31,32,33,34]]);--c(a doua înreg.)

select * from pic.t16; SELECT b[1][1],b[2][3],c[2][1] FROM pic.t16;/* extrage valorile ce se află pe primul rând şi între coloanele 2 şi 3 ale tabloului b */ SELECT b[1][2:3] FROM pic.t16; /* extrage valorile ce se afla între rândurile 1 şi 2 (inclusiv) şi între coloanele 2 şi 3 (inclusiv) ale tabolului b */ SELECT b[1:2][2:3] FROM pic.t16;

select * from pic.t16; SELECT b[1][1],b[2][3],c[2][1] FROM pic.t16;/* extrage valorile ce se află pe primul rând şi între coloanele 2 şi 3 ale tabloului b */ SELECT b[1][2:3] FROM pic.t16; /* extrage valorile ce se afla între rândurile 1 şi 2 (inclusiv) şi între coloanele 2 şi 3 (inclusiv) ale tabolului b */ SELECT b[1:2][2:3] FROM pic.t16;

Page 42: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

8.Operaţii cu tablouri de date

utilizează funcţia generate_subscripts, funcţie ce expandează tabloul, în sensul că fiecare nouă înregistrare va conţine câte o celulă. Funcţia are forma:

Pentru exemplificare, considerăm tabelul de mai jos, populat cu date de tip tablou:

Selectează toate celulele care au valoarea 30:

Un alt exemplu ar fi atunci când sunt căutate corespondenţe între celulele tabloului. Considerăm un tabel cu coduri şi descrieri asociate, ambele câmpuri fiind de tip tablou. Tipul câmpului cod este un vector ce conţine şiruri cu maxim 30 de caractere, iar tipul câmpului descriere (descr) este tot vector cu elemente şiruri de caractere de maxim 50 de caractere.

Ex.:Să se afişeze toate descrierile pentru codurile care se termină cu cifra 3:

9. Operaţii cu date de tip XML

Tipul de dată XML permite stocarea informaţiei aferente unui fişier de tip XML (întreaga structură arborescentă) într-o singură celulă (un câmp al unei înregistrări). PostgreSQL oferă funcţii unice de căutare atât la nivelul arborelui de tip XML, cât şi la nivelul tuturor înregistrărilor din tabel. Aceste funcţii de

41

generate_subscripts(tablou anyarray, dimensiune_tablou int)generate_subscripts(tablou anyarray, dimensiune_tablou int)

drop table if exists t1; create temp table t1(a serial primary key, b int[]); insert into t1(b) values (array[10]),(array[10,20]),(array[20,30,40]),(array[10,20,30]); select * from t1;

drop table if exists t1; create temp table t1(a serial primary key, b int[]); insert into t1(b) values (array[10]),(array[10,20]),(array[20,30,40]),(array[10,20,30]); select * from t1;

select b, s, b[s] as "celula b[s]" FROM (select b, generate_subscripts(b,1) as s from t1)par WHERE b[s]=30;

select b, s, b[s] as "celula b[s]" FROM (select b, generate_subscripts(b,1) as s from t1)par WHERE b[s]=30;

DROP TABLE IF EXISTS t2;CREATE TEMP TABLE t2(a serial PRIMARY KEY, cod varchar(30)[], descr varchar(50)[]);INSERT INTO t2(cod,descr) VALUES (array['A1','A2','A3'], array['descrA1','descrA2','descrA3']), (array['B1','B2','B3','B4'], array['descrB1','descrB2','descrB3']), (array['C1','C2'], array['descrC1','descriereC2']);SELECT * FROM t2;

DROP TABLE IF EXISTS t2;CREATE TEMP TABLE t2(a serial PRIMARY KEY, cod varchar(30)[], descr varchar(50)[]);INSERT INTO t2(cod,descr) VALUES (array['A1','A2','A3'], array['descrA1','descrA2','descrA3']), (array['B1','B2','B3','B4'], array['descrB1','descrB2','descrB3']), (array['C1','C2'], array['descrC1','descriereC2']);SELECT * FROM t2;

select cod[s] as cod_s, descr[s] as descriere_s FROM (select cod,descr, generate_subscripts(cod,1) as s from t2)par WHERE cod[s] ILIKE '%3';

select cod[s] as cod_s, descr[s] as descriere_s FROM (select cod,descr, generate_subscripts(cod,1) as s from t2)par WHERE cod[s] ILIKE '%3';

Page 43: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

căutare sunt lente şi recomand o primă căutare doar ca text, apoi rafinarea căutării, pe rezultatul obţinut, prin utilizarea acestor funcţii.

Căutarea se realizează cu funcţia xpath

10. Funcţii PostgreSQL

Pe lângă operatorii SQL standard, PostgreSQL oferă o serie de funcţii pentru completarea acestora.

10.1. Operaţii cu data calendaristică

Din data calendaristică se poate extrage anul, ziua, luna, ziua săptămânii etc. De asemenea se pot utiliza operatorii aritmetici “+” şi ”-”.

42

CREATE TABLE pic.t17(a serial PRIMARY KEY, b xml);-- adauga un xml cu un singur nod INSERT INTO pic.t17(b) VALUES ('<A0> UN NOD </A0>');-- adauga un xml cu un nod si doua atribute INSERT INTO pic.t17(b) VALUES ('<A0 m="123" n="76"> UN TEST </A0>');-- adauga un xml cu un nod parinte si noduri copil INSERT INTO pic.t17(b) VALUES ('<A0> <A11/> <A12>Al doilea rand</A12> </A0>');--<A11/> este echivalent cu a scrie <A11></A11> select * from pic.t17;

CREATE TABLE pic.t17(a serial PRIMARY KEY, b xml);-- adauga un xml cu un singur nod INSERT INTO pic.t17(b) VALUES ('<A0> UN NOD </A0>');-- adauga un xml cu un nod si doua atribute INSERT INTO pic.t17(b) VALUES ('<A0 m="123" n="76"> UN TEST </A0>');-- adauga un xml cu un nod parinte si noduri copil INSERT INTO pic.t17(b) VALUES ('<A0> <A11/> <A12>Al doilea rand</A12> </A0>');--<A11/> este echivalent cu a scrie <A11></A11> select * from pic.t17;

xpath(val_căutată,câmp_XML)xpath(val_căutată,câmp_XML)

--afşează valoarea din nodurile A0 SELECT xpath('//A0/text()',b) FROM pic.t17; -- afiseaza nodurile XML de sub A0 SELECT xpath('//A0',b) FROM pic.t17;

--afşează valoarea din nodurile A0 SELECT xpath('//A0/text()',b) FROM pic.t17; -- afiseaza nodurile XML de sub A0 SELECT xpath('//A0',b) FROM pic.t17;

--afişează valoarea din nodurile A12 SELECT xpath('//A12/text()',b) FROM pic.t17;--afişare XML cu o anumită valoare a nodurilor; afişare XML ca şir de caractere; valoarea din cadrul nodului A12 conţine şirul "ra" SELECT xpath('//A12/text()',b) FROM pic.t17

WHERE CAST(xpath('//A12/text()',b) as text) ILIKE '%ra%';-- valoarea din cadrul nodului A12 sa conţină şirul "ra"-- afişare XML simplă (noduri XML) SELECT xpath('//A12',b) FROM pic.t17

WHERE CAST(xpath('//A12/text()',b) as text) ILIKE '%ra%';

--afişează valoarea din nodurile A12 SELECT xpath('//A12/text()',b) FROM pic.t17;--afişare XML cu o anumită valoare a nodurilor; afişare XML ca şir de caractere; valoarea din cadrul nodului A12 conţine şirul "ra" SELECT xpath('//A12/text()',b) FROM pic.t17

WHERE CAST(xpath('//A12/text()',b) as text) ILIKE '%ra%';-- valoarea din cadrul nodului A12 sa conţină şirul "ra"-- afişare XML simplă (noduri XML) SELECT xpath('//A12',b) FROM pic.t17

WHERE CAST(xpath('//A12/text()',b) as text) ILIKE '%ra%';

Page 44: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

10.Funcţii PostgreSQL

Ex.:Să se afişeze în clar numele zilei curente din săptămână (luni, marţi etc.), apoi pentru ziua de joi să se extindă pentru AM, PM:

Ex.:Pentru exemplul cu biblioteca: Să se calculeze câte zile a fost împrumutată fiecare carte (tabel generat în ultimul exemplu):

sau:

10.2. Operaţii cu dată de tip oră, minut, secundă şi miimi de secundă

Cu datele de tip time se pot realiza operaţii de tipul:

43

select CASE WHEN extract(DOW from current_date) = 1 THEN 'Luni' WHEN extract(DOW from current_date) = 2 THEN 'Marţi' WHEN extract(DOW from current_date) = 3 THEN 'Miercuri' WHEN extract(DOW from current_date) = 4 AND

current_time < '12:00:00.0' THEN 'JoiAM' WHEN extract(DOW from current_date) = 4 AND

current_time >= '09:00:00.0' THEN 'JoiPM' WHEN extract(DOW from current_date) = 5 THEN 'Vineri' WHEN extract(DOW from current_date) = 6 THEN 'Sambata' WHEN extract(DOW from current_date) = 7 THEN 'Duminica' ELSE 'Incorect' END AS Ziua;

select CASE WHEN extract(DOW from current_date) = 1 THEN 'Luni' WHEN extract(DOW from current_date) = 2 THEN 'Marţi' WHEN extract(DOW from current_date) = 3 THEN 'Miercuri' WHEN extract(DOW from current_date) = 4 AND

current_time < '12:00:00.0' THEN 'JoiAM' WHEN extract(DOW from current_date) = 4 AND

current_time >= '09:00:00.0' THEN 'JoiPM' WHEN extract(DOW from current_date) = 5 THEN 'Vineri' WHEN extract(DOW from current_date) = 6 THEN 'Sambata' WHEN extract(DOW from current_date) = 7 THEN 'Duminica' ELSE 'Incorect' END AS Ziua;

SELECT cota, SUM( CASE WHEN data_rest IS NOT NULL THEN data_rest-data_impr WHEN data_rest IS NULL THEN CURRENT_DATE - data_impr END ) as nr_zile FROM biblio.oper GROUP BY cota;

SELECT cota, SUM( CASE WHEN data_rest IS NOT NULL THEN data_rest-data_impr WHEN data_rest IS NULL THEN CURRENT_DATE - data_impr END ) as nr_zile FROM biblio.oper GROUP BY cota;

SELECT cota,SUM(CASE WHEN data_rest IS NULL THEN CURRENT_DATE-data_impr ELSE data_rest - data_impr END ) as nr_zile FROM biblio.oper GROUP BY cota;

SELECT cota,SUM(CASE WHEN data_rest IS NULL THEN CURRENT_DATE-data_impr ELSE data_rest - data_impr END ) as nr_zile FROM biblio.oper GROUP BY cota;

select CURRENT_DATE; -- data curentă-- extrage numărul zilei din săptămână select extract(DOW from current_date); select extract(YEAR from current_date);--extrage anul -- extrage luna calendaristică select extract(MONTH from current_date); select extract(DAY from current_date);-- extrage ziua select current_date - 22; -- scade din data curentă 22 de zile select current_date + 1000; --adună la data curentă 1000 de zile

select CURRENT_DATE; -- data curentă-- extrage numărul zilei din săptămână select extract(DOW from current_date); select extract(YEAR from current_date);--extrage anul -- extrage luna calendaristică select extract(MONTH from current_date); select extract(DAY from current_date);-- extrage ziua select current_date - 22; -- scade din data curentă 22 de zile select current_date + 1000; --adună la data curentă 1000 de zile

Page 45: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

10.3. Date de tip UUID / GUID

Datele de tip UUID (în postgreSQL) sau GUID în alte SGBD-uri sunt reprezentate pe 128 de biţi (32 simboluri în baza 16). Acestea sunt generate aleator şi se consideră că sunt practic unice. De obicei este utilizat pentru identificarea unică a unor resurse hardware sau software. Înainte de primul apel al acestei funcţii, este necesară lansarea comenzii SQL:

deoarece această funcţie se regăseşte ca extensie. De exemplu:

Exemplu de dată de tip uuid: "0c6f0514-9204-11e2-81ec-83bcce9043a7"

10.4. Funcţii pentru înlocuirea caracterelor. Căutarea cu şi fără diacritice

Presupunem următorul exemplu:

Actualizare tabel:

sau:

Funcţia translate(câmp, şir iniţial de caractere, şir final de caractere) înlocuieşte caracterele din argumentul al doilea cu cele din argumentul al treilea, corespunzător funcţiei (translate). Practic, primul caracter din argumentul al doilea este înlocuit cu primul caracter din argumentul al treilea, la fel şi pentru următoarele caractere.

44

select current_time;-- afiş. ora,min.,sec. şi fracţiunea de sec. select cast('05:20:20.0' as time);-- transformă: char[] -> time select current_time as timp1, current_time + cast('05:20:20.0' as time) as timp2; select current_date + current_time as a;-- date + time => timestamp select '2009-03-11'::date + '12:20'::time as a; select to_date('20.05.1984','dd.mm.yyyy');-- util ptr. preluare format ro/fr/ge select to_date('05/20/1984','mm/dd/yyyy');-- en

select current_time;-- afiş. ora,min.,sec. şi fracţiunea de sec. select cast('05:20:20.0' as time);-- transformă: char[] -> time select current_time as timp1, current_time + cast('05:20:20.0' as time) as timp2; select current_date + current_time as a;-- date + time => timestamp select '2009-03-11'::date + '12:20'::time as a; select to_date('20.05.1984','dd.mm.yyyy');-- util ptr. preluare format ro/fr/ge select to_date('05/20/1984','mm/dd/yyyy');-- en

CREATE EXTENSION "uuid-ossp";CREATE EXTENSION "uuid-ossp";

CREATE TABLE pic.t18(a serial, b uuid); SELECT * FROM pic.t18;-- datele de tip uuid sunt generate aleator--SELECT * FROM pic.t18 INSERT INTO pic.t18(b) SELECT uuid_generate_v1(); ;

CREATE TABLE pic.t18(a serial, b uuid); SELECT * FROM pic.t18;-- datele de tip uuid sunt generate aleator--SELECT * FROM pic.t18 INSERT INTO pic.t18(b) SELECT uuid_generate_v1(); ;

CREATE TABLE pic.t19 ( a int PRIMARY KEY, b int, c varchar(50)); INSERT INTO pic.t19 VALUES (1, 10, 'usa'), (2, 15, 'uşa'), (3, 20, 'uşă'), (4, 30, 'Uşa'), (5, 35, 'uŞa'), (6, 40, 'uŞĂ'), (7, 50, 'UŞĂ'), (8, 60, 'USA'), (9, 70, 'Xsa'); select * from pic.t19;

CREATE TABLE pic.t19 ( a int PRIMARY KEY, b int, c varchar(50)); INSERT INTO pic.t19 VALUES (1, 10, 'usa'), (2, 15, 'uşa'), (3, 20, 'uşă'), (4, 30, 'Uşa'), (5, 35, 'uŞa'), (6, 40, 'uŞĂ'), (7, 50, 'UŞĂ'), (8, 60, 'USA'), (9, 70, 'Xsa'); select * from pic.t19;

UPDATE pic.t19 SET c='Xsă' WHERE b=70; UPDATE pic.t19 SET c='Xsă' WHERE b=70;

SELECT * FROM pic.t19 WHERE c = 'usa'; -- o înregistrare SELECT * FROM pic.t19 WHERE c = 'usa'; -- o înregistrare

Page 46: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

10.Funcţii PostgreSQL

Dacă se caută cu şi fără diacritice:

În acest caz, convertim ambii termeni în expresii independente de diacritice:

Dar tot nu sunt luate în considerare şi literele mari. Pentru a rezolva aceasta:

Pentru a avea o căutare parţială, avem:

Termenul de comparaţie este şirul fără diacritice, cu litere mici.Pentru:

Termenul de comparaţie este şirul cu diacritice – litere mici şi fără diacritice – litere mari.Iar dacă avem:

comparaţia ţine cont de litera mare sau litera mică şi nu de diacritice.Cazul general:

comparaţia NU ţine cont de literă mare sau literă mică ŞI NICI de

45

SELECT * FROM pic.t19 WHERE translate(c,'ăîşţâ','aista') ='usa'; -- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(c,'ăîşţâ','aista') ='usa'; -- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(c,'ăîşţâ','aista') ='uşa'; -- 0 înregistrări

SELECT * FROM pic.t19 WHERE translate(c,'ăîşţâ','aista') ='uşa'; -- 0 înregistrări

SELECT * FROM pic.t19 WHERE translate(c,'ăîşţâ','aista') = translate('uşa','ăîşţâ','aista');

-- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(c,'ăîşţâ','aista') = translate('uşa','ăîşţâ','aista');

-- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâĂÎŞŢÂ','aistaAISTA') = translate('usa','ăîşţâĂÎŞŢÂ','aistaAISTA'); -- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâĂÎŞŢÂ','aistaAISTA') = translate('usa','ăîşţâĂÎŞŢÂ','aistaAISTA'); -- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâ','aista') LIKE translate('uşa','ăîşţâ','aista'); -- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâ','aista') LIKE translate('uşa','ăîşţâ','aista'); -- 3 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâ','aista') ILIKE translate('uşa','ăîşţâ','aista'); --5 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâ','aista') ILIKE translate('uşa','ăîşţâ','aista'); --5 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâĂÎŞŢÂ','aistaAISTA') LIKE translate('uşa','ăîşţâĂÎŞŢÂ','aistaAISTA');--3 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâĂÎŞŢÂ','aistaAISTA') LIKE translate('uşa','ăîşţâĂÎŞŢÂ','aistaAISTA');--3 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâĂÎŞŢÂ','aistaAISTA') ILIKE translate('uşa','ăîşţâĂÎŞŢÂ','aistaAISTA');--8 înregistrări

SELECT * FROM pic.t19 WHERE translate(t19.c,'ăîşţâĂÎŞŢÂ','aistaAISTA') ILIKE translate('uşa','ăîşţâĂÎŞŢÂ','aistaAISTA');--8 înregistrări

Page 47: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

diacritice.

11. Tranzacţii. Interogări multiserver

Prin gestiunea tranzacţiilor poate fi controlată validarea/salvarea unui grup de comenzi SQL. De exemplu, într-o aplicaţie de gestiune a stocurilor, în momentul în care adăugăm o linie în tabelul cu ieşirile de materiale şi o ştergem din stoc, este important ca ambele comenzi să fie finalizate cu succes, altfel pot apărea surplusuri în stoc.

Implicit, execuţia unui bloc de comenzi (separate prin semicolon „;”) presupune execuţia tuturor comenzilor din cadrul blocului într-o singură tranzacţie. Considerăm exemplul:

Instrucţiunea COMMIT validează şi închide actuala tranzacţie:

Instrucţiunea ROLLBACK fără etichetă/punct salvare are acelaşi efect ca şi instrucţiunea COMMIT.

Se pot defini puncte/etichete în care să revină în caz de eşec al unei anumite comenzi:

Instrucţiunea ROLLBACK, pe lângă anularea tranzacţiei până

46

DROP TABLE IF EXISTS pic.t20; CREATE table pic.t20(datam date, ora int, val numeric,

CONSTRAINT k_d1 PRIMARY KEY(datam,ora)); INSERT INTO pic.t20 VALUES ('2000-01-01',6,8),('2000-01-01',14,12), ('2000-01-01',22,16), ('2000-01-02',6,24), ('2000-01-02',14,26), ('2000-01-02',22,32), ('2000-01-03',6,44), ('2000-01-03',14,90), ('2000-01-03',22,120), ('2000-01-04',6,122), ('2000-01-04',14,129), ('2000-01-04',22,135); select * from pic.t20;

DROP TABLE IF EXISTS pic.t20; CREATE table pic.t20(datam date, ora int, val numeric,

CONSTRAINT k_d1 PRIMARY KEY(datam,ora)); INSERT INTO pic.t20 VALUES ('2000-01-01',6,8),('2000-01-01',14,12), ('2000-01-01',22,16), ('2000-01-02',6,24), ('2000-01-02',14,26), ('2000-01-02',22,32), ('2000-01-03',6,44), ('2000-01-03',14,90), ('2000-01-03',22,120), ('2000-01-04',6,122), ('2000-01-04',14,129), ('2000-01-04',22,135); select * from pic.t20;

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK;-- ne intoarce in punctul BEGIN TRANSACTION; -- NU SUNT modificate inregistrarile

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK;-- ne intoarce in punctul BEGIN TRANSACTION; -- NU SUNT modificate inregistrarile

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; SAVEPOINT x1; UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK TO SAVEPOINT x1;--ne întoarce in punctul x1 ROLLBACK;-- ne intoarce în punctul BEGIN TRANSACTION;

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; SAVEPOINT x1; UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK TO SAVEPOINT x1;--ne întoarce in punctul x1 ROLLBACK;-- ne intoarce în punctul BEGIN TRANSACTION;

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; COMMIT;--închide tranzacţia UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK;-- nu are ce să închidă; rămân modificate

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; COMMIT;--închide tranzacţia UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK;-- nu are ce să închidă; rămân modificate

Page 48: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

11.Tranzacţii. Interogări multiserver

în punctul specificat, are şi efect de validare a restului de comenzi, situate în afara zonei de anulare.

Reapelarea instrucţiunii “BEGIN TRANSACTION” fără ca tranzacţia anterioară să fie închisă nu are efect.

Pentru preluarea datelor situate pe un alt server de baze de date, se utilizează funcţia dblink. Prima comandă lansată în acest

sens va fi din interfaţa pgAdmin3 şi va fi:deoarece această funcţie este o extensie a PostgreSQL. Sintaxa este:

Pentru exemplificare, constituim un tabel pic.t21 pe server-ul ce furnizează datele.

Pe celălalt server vom lansa comanda:

Se poate realiza un view pentru a vizualiza modificările tabelul pic.t21 în timp real:

Există funcţii asemănătoare pentru interfaţare şi cu alte servere de baze de date, cum ar fi cel de Oracle.

47

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; ROLLBACK; -- închide tranzacţia UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK;--nu are efect

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; ROLLBACK; -- închide tranzacţia UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK;--nu are efect

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; SAVEPOINT x1; BEGIN TRANSACTION;-- acest apel este ignorat UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK TO SAVEPOINT x1;-- ne intoarce in punctul x1 ROLLBACK;-- ne intoarce in punctul BEGIN TRANSACTION;

BEGIN TRANSACTION; UPDATE pic.t20 SET val = val + 1000 WHERE ora = 22; SAVEPOINT x1; BEGIN TRANSACTION;-- acest apel este ignorat UPDATE pic.t20 SET val = val - 1000 WHERE ora = 14; ROLLBACK TO SAVEPOINT x1;-- ne intoarce in punctul x1 ROLLBACK;-- ne intoarce in punctul BEGIN TRANSACTION;

create table pic.t21 (a int PRIMARY KEY, b varchar(20)); insert into pic.t21 (a,b) values (1, 'alb'); select * from pic.t21;

create table pic.t21 (a int PRIMARY KEY, b varchar(20)); insert into pic.t21 (a,b) values (1, 'alb'); select * from pic.t21;

dblink(şir_conectare,bloc_comenzi_sql )dblink(şir_conectare,bloc_comenzi_sql )

CREATE OR REPLACE VIEW pic.z1 AS SELECT a FROM dblink('dbname = picdb password = abcd port = 5435', 'select a from pic.t21') as t(a int) WHERE a NOT IN (SELECT a FROM pic.t22); SELECT * FROM pic.z1;

CREATE OR REPLACE VIEW pic.z1 AS SELECT a FROM dblink('dbname = picdb password = abcd port = 5435', 'select a from pic.t21') as t(a int) WHERE a NOT IN (SELECT a FROM pic.t22); SELECT * FROM pic.z1;

CREATE EXTENSION dblinkCREATE EXTENSION dblink

DROP TABLE IF EXISTS pic.t22 CASCADE; CREATE TABLE pic.t22 AS SELECT a FROM dblink('dbname = picdb password = abcd port = 5435', 'select a from pic.t21') AS t(a int); SELECT * FROM pic.t22;

DROP TABLE IF EXISTS pic.t22 CASCADE; CREATE TABLE pic.t22 AS SELECT a FROM dblink('dbname = picdb password = abcd port = 5435', 'select a from pic.t21') AS t(a int); SELECT * FROM pic.t22;

Page 49: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

12. Teste rezolvate – gestiune bibliotecă

Se consideră o arhitectură simplă pentru o aplicaţie ce gestionează operaţiile de împrumut şi restituire dintr-o bibliotecă. Astfel avem:

☑ un tabel cu utilizatorii, având structura: utiliz(cnp, nume, prenume adresa, tel, email, data_inscrierii);

☑ un tabel ce conţine cărţile din bibliotecă, având structura: inv(cota, titlu, editura, an_ap, nr_pag,autori, nr_vol, limba);

☑ un tabel cu operaţiile de împrumumut şi restituire, cu structura: oper(data_impr, ora_impr, cnp, cota, data_rest, ora_rest, nr_zile_termen, operator_impr, oper_rest),

unde câmpul nr_zile_termen reprezintă numărul de zile pentru care a fost împrumutată cartea şi se completează în momentul împrumutului, iar câmurile operator_impr şi oper_rest conţin numele bibliotecarului ce a împrumutat cartea respectiv a celui care a primit cartea.

1. Să se scrie codul SQL pentru constituirea celor trei tabele.

Notă: Cheile externe (FOREIGN KEY) au următoarele efecte: ● NU putem avea în tabelul oper o cota care NU se regăseşte şi în

tabelul inv;● NU putem avea în tabelul oper un cnp care să nu existe şi în

tabelul utiliz.2. Să se scrie codul pentru popularea tabelelor cu câteva înregistrări.

48

DROP SCHEMA IF EXISTS biblio; CREATE SCHEMA biblio;CREATE TABLE biblio.utiliz(cnp char(13) PRIMARY KEY, nume varchar(50),prenume varchar(50), adresa varchar(250), tel varchar(50),email varchar(50), data_inscrierii date DEFAULT CURRENT_DATE, data_n date);

DROP SCHEMA IF EXISTS biblio; CREATE SCHEMA biblio;CREATE TABLE biblio.utiliz(cnp char(13) PRIMARY KEY, nume varchar(50),prenume varchar(50), adresa varchar(250), tel varchar(50),email varchar(50), data_inscrierii date DEFAULT CURRENT_DATE, data_n date);

CREATE TABLE biblio.inv(cota varchar(50) PRIMARY KEY,titlu varchar(100),ditura varchar(50), an_ap int, nr_pag int, autori varchar(200), nr_vol int, limba varchar(30), imprumutata boolean DEFAULT false);

CREATE TABLE biblio.inv(cota varchar(50) PRIMARY KEY,titlu varchar(100),ditura varchar(50), an_ap int, nr_pag int, autori varchar(200), nr_vol int, limba varchar(30), imprumutata boolean DEFAULT false);

CREATE TABLE biblio.oper(data_impr date DEFAULT CURRENT_DATE, ora_impr time DEFAULT CURRENT_TIME, cnp char(13),cota varchar(50),data_rest date, ora_rest time, nr_zile_termen int DEFAULT 30,oper_impr varchar(50), oper_rest varchar(50), CONSTRAINT k_oper PRIMARY KEY(data_impr,ora_impr,cnp,cota), CONSTRAINT f1_oper FOREIGN KEY(cota) REFERENCES biblio.inv (cota), CONSTRAINT f2_oper FOREIGN KEY(cnp) REFERENCES biblio.utiliz(cnp));

CREATE TABLE biblio.oper(data_impr date DEFAULT CURRENT_DATE, ora_impr time DEFAULT CURRENT_TIME, cnp char(13),cota varchar(50),data_rest date, ora_rest time, nr_zile_termen int DEFAULT 30,oper_impr varchar(50), oper_rest varchar(50), CONSTRAINT k_oper PRIMARY KEY(data_impr,ora_impr,cnp,cota), CONSTRAINT f1_oper FOREIGN KEY(cota) REFERENCES biblio.inv (cota), CONSTRAINT f2_oper FOREIGN KEY(cnp) REFERENCES biblio.utiliz(cnp));

Page 50: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

12.Teste rezolvate – gestiune bibliotecă

Notă : Sunt populate cu date mai întâi tabelele de tip master (sau părinte), altfel cheia din tabelul slave (sau copil) nu se va regăsi şi în tabelul părinte.3 Să se afişeze cotele, titlurile, cnp-urile şi numele persoanelor pentru toate cărţile împrumutate (au fost sau sunt imprumutate).

sau

4. Să se afişeze toate cărţile (cota,titlu,data_impr) împrumutate de către utilizatorii al căror nume conţine secvenţa 'ion':

49

INSERT INTO biblio.utiliz(cnp,nume,data_n) VALUES ('cnp0000000001','Ion','1992-05-21'), ('cnp0000000002','Vasile', '1991-04-21'), ('cnp0000000003','Ion','1996-05-21'),('cnp0000000004','Grigore','1982-05-21'), ('cnp0000000005','Ion', '1972-09-21'),('cnp0000000006','Geo','1993-09-21'),('cnp0000000007','Ionescu','1992-05-21'), ('cnp0000000008','Vlad','1999-05-21'), ('cnp0000000009','Alin','1992-08-21');

INSERT INTO biblio.utiliz(cnp,nume,data_n) VALUES ('cnp0000000001','Ion','1992-05-21'), ('cnp0000000002','Vasile', '1991-04-21'), ('cnp0000000003','Ion','1996-05-21'),('cnp0000000004','Grigore','1982-05-21'), ('cnp0000000005','Ion', '1972-09-21'),('cnp0000000006','Geo','1993-09-21'),('cnp0000000007','Ionescu','1992-05-21'), ('cnp0000000008','Vlad','1999-05-21'), ('cnp0000000009','Alin','1992-08-21');

INSERT INTO biblio.inv(cota, titlu, editura, an_ap, nr_pag ) VALUES ('001','T1','ALL',1977,150),('002','T21','Nemira',1977,190), ('003','T1','Tehnica',1977,250),('004','T54','Albatros',1977,220), ('005','T97','Nemira',1977,80),('006','T1','ALL',1977,50), ('007','T77','Tehnica',1977,120),('008','T21','Albatros',1987,100);

INSERT INTO biblio.inv(cota, titlu, editura, an_ap, nr_pag ) VALUES ('001','T1','ALL',1977,150),('002','T21','Nemira',1977,190), ('003','T1','Tehnica',1977,250),('004','T54','Albatros',1977,220), ('005','T97','Nemira',1977,80),('006','T1','ALL',1977,50), ('007','T77','Tehnica',1977,120),('008','T21','Albatros',1987,100);

INSERT INTO biblio.oper(data_impr,cnp,cota,nr_zile_termen,oper_impr) VALUES ('2013-03-22','cnp0000000002','006',17,'X1'), ('2012-05-22','cnp0000000002','006',127,'X1'), ('2013-05-22','cnp0000000002','001', 27,'X1'),('2013-01-21','cnp0000000001','005',117,'X1'),('2012-05-22', 'cnp0000000007','002',71,'X2'), ('2009-05-22','cnp0000000002','006', 577,'X2'),('2013-05-22','cnp0000000005', '006',7,'X1'),('2012-05-22', 'cnp0000000005','006',17,'X1'), ('2012-11-22','cnp0000000002','006', 57,'X1'), ('2013-03-01','cnp0000000002','005',19,'X1');

INSERT INTO biblio.oper(data_impr,cnp,cota,nr_zile_termen,oper_impr) VALUES ('2013-03-22','cnp0000000002','006',17,'X1'), ('2012-05-22','cnp0000000002','006',127,'X1'), ('2013-05-22','cnp0000000002','001', 27,'X1'),('2013-01-21','cnp0000000001','005',117,'X1'),('2012-05-22', 'cnp0000000007','002',71,'X2'), ('2009-05-22','cnp0000000002','006', 577,'X2'),('2013-05-22','cnp0000000005', '006',7,'X1'),('2012-05-22', 'cnp0000000005','006',17,'X1'), ('2012-11-22','cnp0000000002','006', 57,'X1'), ('2013-03-01','cnp0000000002','005',19,'X1');

SELECT oper.cota,inv.titlu,oper.cnp,utiliz.nume FROM biblio.oper, biblio.utiliz, biblio.inv WHERE oper.cota = inv.cota AND oper.cnp = utiliz.cnp;

SELECT oper.cota,inv.titlu,oper.cnp,utiliz.nume FROM biblio.oper, biblio.utiliz, biblio.inv WHERE oper.cota = inv.cota AND oper.cnp = utiliz.cnp;

SELECT inv.cota,inv.titlu,utiliz.cnp,utiliz.nume FROM biblio.oper, biblio.utiliz, biblio.inv WHERE oper.cota = inv.cota AND oper.cnp = utiliz.cnp;

SELECT inv.cota,inv.titlu,utiliz.cnp,utiliz.nume FROM biblio.oper, biblio.utiliz, biblio.inv WHERE oper.cota = inv.cota AND oper.cnp = utiliz.cnp;

INSERT INTO biblio.oper(data_impr, cnp, cota, data_rest, nr_zile_termen, oper_impr, oper_rest) VALUES ('2013-01-22','cnp0000000002','001','2013-02-22',55,'X1','X1'), ('2012-12-22','cnp0000000003','003','2013-02-22',17,'X1','X2'), ('2013-01-22','cnp0000000002','002','2013-02-25',55,'X1','X1'), ('2013-01-22','cnp0000000004','001','2013-02-24',5,'X1','X1');

INSERT INTO biblio.oper(data_impr, cnp, cota, data_rest, nr_zile_termen, oper_impr, oper_rest) VALUES ('2013-01-22','cnp0000000002','001','2013-02-22',55,'X1','X1'), ('2012-12-22','cnp0000000003','003','2013-02-22',17,'X1','X2'), ('2013-01-22','cnp0000000002','002','2013-02-25',55,'X1','X1'), ('2013-01-22','cnp0000000004','001','2013-02-24',5,'X1','X1');

Page 51: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

II.Limbajul SQL

5. Să se afişeze toate cărţile (cota, titlu) care se află în bibliotecă în momentul de faţă (ce cărţi mai există pe raft):

sau (toate cărţile din inv mai puţin cele care se află în oper şi nu au completat câmpul data pentru restituire):

sau prin utilizarea subinterogărilor:

6. Să se afişeze toţi restanţierii (nume,cnp,cota,titlu,data_impr, nr_zile_depasire):

7. Să se afişeze numărul total de pagini citite de utilizatori pe fiecare an (afişează anul şi numărul total de pagini). Se preia anul din data împrumutului:

8. Să se afişeze numărul total de pagini citite de fiecare utilizator în fiecare an (afişează anul, nr. total de pagini, nume utilizator, cnp):

50

SELECT oper.cota,inv.titlu,oper.data_impr,utiliz.nume FROM biblio.oper, biblio.inv, biblio.utiliz WHERE oper.cota=inv.cota AND oper.cnp=utiliz.cnp AND utiliz.nume ilike '%ion%';

SELECT oper.cota,inv.titlu,oper.data_impr,utiliz.nume FROM biblio.oper, biblio.inv, biblio.utiliz WHERE oper.cota=inv.cota AND oper.cnp=utiliz.cnp AND utiliz.nume ilike '%ion%';

select inv.cota,inv.titlu from biblio.inv where inv.imprumutata=false;--sauSELECT inv.cota,inv.titlu FROM biblio.inv WHERE NOT inv.imprumutata;

select inv.cota,inv.titlu from biblio.inv where inv.imprumutata=false;--sauSELECT inv.cota,inv.titlu FROM biblio.inv WHERE NOT inv.imprumutata;

select inv.cota,inv.titlu FROM biblio.inv EXCEPTselect distinct inv.cota,inv.titlu from biblio.oper, biblio.inv WHERE oper.cota=inv.cota AND oper.data_rest IS NULL;

select inv.cota,inv.titlu FROM biblio.inv EXCEPTselect distinct inv.cota,inv.titlu from biblio.oper, biblio.inv WHERE oper.cota=inv.cota AND oper.data_rest IS NULL;

SELECT utiliz.nume,oper.cnp,oper.cota,inv.titlu,data_impr, oper.nr_zile_termen,CURRENT_DATE - (oper.data_impr+oper.nr_zile_termen) as nr_zile_depasire FROM biblio.oper, biblio.inv, biblio.utiliz WHERE oper.cnp = utiliz.cnp AND oper.cota = inv.cota AND oper.data_rest IS NULL AND CURRENT_DATE > (oper.data_impr+oper.nr_zile_termen);

SELECT utiliz.nume,oper.cnp,oper.cota,inv.titlu,data_impr, oper.nr_zile_termen,CURRENT_DATE - (oper.data_impr+oper.nr_zile_termen) as nr_zile_depasire FROM biblio.oper, biblio.inv, biblio.utiliz WHERE oper.cnp = utiliz.cnp AND oper.cota = inv.cota AND oper.data_rest IS NULL AND CURRENT_DATE > (oper.data_impr+oper.nr_zile_termen);

SELECT extract(year from oper.data_impr), sum(inv.nr_pag) as nr_t_pag FROM biblio.oper, biblio.inv WHERE oper.cota = inv.cota GROUP BY extract(year from oper.data_impr);

SELECT extract(year from oper.data_impr), sum(inv.nr_pag) as nr_t_pag FROM biblio.oper, biblio.inv WHERE oper.cota = inv.cota GROUP BY extract(year from oper.data_impr);

SELECT par.cota, inv.titlu FROM(select cota from biblio.inv EXCEPT select distinct cota from biblio.oper WHERE oper.data_rest IS NULL)par,biblio.inv WHERE par.cota=inv.cota;

SELECT par.cota, inv.titlu FROM(select cota from biblio.inv EXCEPT select distinct cota from biblio.oper WHERE oper.data_rest IS NULL)par,biblio.inv WHERE par.cota=inv.cota;

Page 52: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

12.Teste rezolvate – gestiune bibliotecă

9. Să se afişeze de câte ori a fost împrumutată fiecare carte (cota, titlu, nr_imprumuturi).

51

SELECT extract(year from oper.data_impr), sum(inv.nr_pag) as nr_t_pag,utiliz.nume,oper.cnp

FROM biblio.oper, biblio.utiliz, biblio.inv WHERE oper.cota = inv.cota AND oper.cnp = utiliz.cnp GROUP BY extract(year from oper.data_impr), utiliz.nume, oper.cnp ORDER BY extract(year from oper.data_impr);

SELECT extract(year from oper.data_impr), sum(inv.nr_pag) as nr_t_pag,utiliz.nume,oper.cnp

FROM biblio.oper, biblio.utiliz, biblio.inv WHERE oper.cota = inv.cota AND oper.cnp = utiliz.cnp GROUP BY extract(year from oper.data_impr), utiliz.nume, oper.cnp ORDER BY extract(year from oper.data_impr);

SELECT oper.cota, inv.titlu,count(oper.*) as nr_impr FROM biblio.oper, biblio.inv WHERE oper.cota = inv.cota GROUP BY oper.cota, inv.titlu;

SELECT oper.cota, inv.titlu,count(oper.*) as nr_impr FROM biblio.oper, biblio.inv WHERE oper.cota = inv.cota GROUP BY oper.cota, inv.titlu;

Page 53: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

III. Programarea la nivel de server – plpgSQLProgramarea la nivel de server (server side) constă în

dezvoltarea unor funcţii ce sunt apelate utilizând comenzi SQL. Aceste funcţii, pot înlocui blocurile de comenzi SQL şi pot fi scrise în diverse limbaje de programare – inclusiv SQL. Aceste funcţii sunt stocate în cadrul server-ului de baze de date, în acest caz PostgreSQL. De asemenea, funcţiile pot realiza operaţii specifice fiecărei înregistrări (chiar diferite la nivel de înregistrare), ceea ce limbajul SQL nu permite. În acest capitol prezint doar limbajul plpgSQL (procedural language postgreSQL). Un alt mare avantaj constă în posibiltatea modificării corpului funcţiei fără a modifica interfaţa software.

1. Funcţii de tipul SQL

Funcţiile sunt la nivel de schemă, se deosebesc între ele prin nume, numărul sau tipul argumentelor. Funcţiile tratate în acest capitol sunt cele de tip SQL şi de tip plpgSQL. Structura simplificată a unei funcţii de tip SQL este:

Corpul funcţiei este încadrat de $$ sau $BODY$ .

1.1. Funcţii de tip SQL ce nu preiau şi nu întorc nimic

În acest caz, lista de parametrii este vidă, iar tipul pentru RETURNS este void. De obicei sunt funcţii ce execută blocuri de comenzi SQL de tipul: CREATE, UPDATE sau DELETE. Funcţia pic.f0() creează un tabel pic.t1.

Funcţia pic.f0() nu preia şi nu întoarce valori. Pentru

52

CREATE [OR REPLACE] function nume_functie -- in loc de DROP ... RETURNS tipul_de_data_intors_de_functie AS$$--- corpul funcţiei---$$LANGUAGE 'sql';

CREATE [OR REPLACE] function nume_functie -- in loc de DROP ... RETURNS tipul_de_data_intors_de_functie AS$$--- corpul funcţiei---$$LANGUAGE 'sql';

--Ex. 1(1): varianta 1 D+A - DEFINIRE + APELCREATE OR REPLACE function pic.f0()RETURNS void AS$$ CREATE TABLE pic.t1(a1 serial PRIMARY KEY, a2 int, a3 int, a4 varchar(20));$$ LANGUAGE 'sql';-- apelul functiei (executia funcţiei)DROP TABLE IF EXISTS c1.t1; select pic.ftest0() as x1;

--Ex. 1(1): varianta 1 D+A - DEFINIRE + APELCREATE OR REPLACE function pic.f0()RETURNS void AS$$ CREATE TABLE pic.t1(a1 serial PRIMARY KEY, a2 int, a3 int, a4 varchar(20));$$ LANGUAGE 'sql';-- apelul functiei (executia funcţiei)DROP TABLE IF EXISTS c1.t1; select pic.ftest0() as x1;

Page 54: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Funcţii de tipul SQL

popularea cu date utilizăm funcţia pic.f1()

Pentru funcţii de tip SQL (language sql) nu putem avea operaţiile pentru crearea tabelului şi pentru inserarea de înregistrări în aceeaşi funcţie. Aceasta este datorată faptului că secvenţa SQL este realizată într-un singur bloc, adică validarea(COMMIT) este realizată la terminarea funcţiei, iar până în acel moment tabelul nu există. Sintaxa pentru funcţii de tip SQL (language SQL) este verificată în momentul definirii funcţiei.

1.2. Funcţii SQL ce nu preiau nimic şi întorc un set de înregistrări

Structura seturilor de înregistrări întoarse poate fi preluată de la un tabel existent sau poate fi constituită în interiorul funcţiei. În acest sens, avem mai multe variante:

☑ Funcţia f1_1() selectează toate câmpurile din tabel şi întoarce înregistrările selectate prin definirea strucurii tabelului selectat. Este valabil doar la funcţii de tip SQL, altfel ar fi trebuit să întoarcă înregistrare cu înregistrare.

Apelul funcţiei poate fi realizat în modurile următoare:

Deşi câmpurile din selecţie au fost specificate (prin denumire), primul apel al funcţiei f1_1() întoarce o singură coloană de tip structură având ca elemente câmpurile din cadrul selecţiei. Al doilea apel al funcţiei f1_1() întoarce separat câmpurile a1, a2, a3 şi a4;

☑ În a doua variantă de selecţie (funcţia f1_2()), în cadrul definiţiei nu mai este specificat tipul datelor din cadrul structurii, ci numai tipul „structură” (SETOF RECORD):

53

/*Ex. 1(2):D+A varianta 2 D+A*/ CREATE OR REPLACE function pic.f1() RETURNS void AS $$INSERT INTO pic.t1(a2,a3,a4) VALUES(7,8,'AA1'),(12,7,'AA2'),(11,5,'AA3');$$ LANGUAGE 'sql'; SELECT pic.f1(); --apel functie varianta 1

/*Ex. 1(2):D+A varianta 2 D+A*/ CREATE OR REPLACE function pic.f1() RETURNS void AS $$INSERT INTO pic.t1(a2,a3,a4) VALUES(7,8,'AA1'),(12,7,'AA2'),(11,5,'AA3');$$ LANGUAGE 'sql'; SELECT pic.f1(); --apel functie varianta 1

--Ex. 1(3A) APEL pic.f1_1() –VARIANTA 1 de selecţieSELECT pic.f1_1(); -- (1,7,...) are semnificatie de structura sauSELECT a1,a2,a3,a4 FROM pic.f2();-- a1,a2,a3,a4 : afişează fiecare coloana (a1,a2 …) din SETOF pic.t1

--Ex. 1(3A) APEL pic.f1_1() –VARIANTA 1 de selecţieSELECT pic.f1_1(); -- (1,7,...) are semnificatie de structura sauSELECT a1,a2,a3,a4 FROM pic.f2();-- a1,a2,a3,a4 : afişează fiecare coloana (a1,a2 …) din SETOF pic.t1

--Ex. 1(3D) DEFINITIE:functie SQL ptr.afisarea înreg.din t1–VARIANTA 1CREATE OR REPLACE function pic.f1_1() RETURNS SETOF pic.t1 AS $$ SELECT * FROM pic.t1 $$ LANGUAGE 'sql';

--Ex. 1(3D) DEFINITIE:functie SQL ptr.afisarea înreg.din t1–VARIANTA 1CREATE OR REPLACE function pic.f1_1() RETURNS SETOF pic.t1 AS $$ SELECT * FROM pic.t1 $$ LANGUAGE 'sql';

Page 55: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

Funcţia f1_2() selectează câmpuri din tabel şi întoarce înregistrările selectate prin definirea structurii tabelului selectat. Dacă apelăm “SELECT a1,a2,a3,a4 FROM pic.f1_2()” nu este cunoscut numele câmpurilor. Apelul funcţiei pic.f1_2() se poate realiza în două moduri:

☑ O altă variantă este dată de definiţia funcţiei pic.f1_3() în care este specificată structura întoarsă ca fiind structura tabelului pic.t1:

şi exemplul de apel:

Câmpurile a1, a2, a3 şi a4 sunt afişate distinct, tipul fiecarui câmp este cunoscut din RETURNS SETOF pic.t1.

1.3. Funcţii SQL cu transfer prin argument şi cu returnare subset de înregistrări

Dacă dorim să punem un filtru asupra datelor din tabelul pic.t1 şi să întoarcem doar un subset al înregistrărilor, vom avea:

şi exemplul de apel:

54

--Ex. 1(4D) -functie SQL ptr. afişarea conţinutului lui t1 –VARIANTA 2CREATE OR REPLACE function pic.f1_2()RETURNS SETOF RECORD AS $$ SELECT a1,a2,a3,a4 FROM pic.t1 $$ LANGUAGE sql;

--Ex. 1(4D) -functie SQL ptr. afişarea conţinutului lui t1 –VARIANTA 2CREATE OR REPLACE function pic.f1_2()RETURNS SETOF RECORD AS $$ SELECT a1,a2,a3,a4 FROM pic.t1 $$ LANGUAGE sql;

--Ex. 1(4A) APEL pic.f1_2() –VARIANTA 2 de selecţieSELECT pic.f1_2(); -- rezultat pe o singura coloană sauSELECT a1,a2,a3,a4 FROM c1.f3() AS (a1 int,a2 int,a3 int,a4 varchar(20)); -- după AS este definita structura RECORD - patru coloane

--Ex. 1(4A) APEL pic.f1_2() –VARIANTA 2 de selecţieSELECT pic.f1_2(); -- rezultat pe o singura coloană sauSELECT a1,a2,a3,a4 FROM c1.f3() AS (a1 int,a2 int,a3 int,a4 varchar(20)); -- după AS este definita structura RECORD - patru coloane

--Ex. 1(5D):functie SQL ptr. afişarea conţinutului t1 –VARIANTA 3CREATE OR REPLACE function pic.f1_3() RETURNS SETOF pic.t1 AS$$ SELECT a1,a2,a3,a4 FROM pic.t1 $$ LANGUAGE 'sql';

--Ex. 1(5D):functie SQL ptr. afişarea conţinutului t1 –VARIANTA 3CREATE OR REPLACE function pic.f1_3() RETURNS SETOF pic.t1 AS$$ SELECT a1,a2,a3,a4 FROM pic.t1 $$ LANGUAGE 'sql';

--Ex. 1(5A) APEL pic.f1_3() –VARIANTA 3 de selecţieSELECT c1.ftest4(); -- afişează un singur câmp de tip structură SAUSELECT * FROM pic.f1_3();--afişeză a1,a2,a3,a4 - sunt deja definiteSELECT a1,a2,a3,a4 FROM c1.ftest4();

--Ex. 1(5A) APEL pic.f1_3() –VARIANTA 3 de selecţieSELECT c1.ftest4(); -- afişează un singur câmp de tip structură SAUSELECT * FROM pic.f1_3();--afişeză a1,a2,a3,a4 - sunt deja definiteSELECT a1,a2,a3,a4 FROM c1.ftest4();

--Ex. 1.1(6D):fcţ. SQL ce preia 2 param. şi întoarce un set de înreg.CREATE OR REPLACE function c1.f3(b2 int, b3 int) RETURNS SETOF RECORD AS$$ SELECT a1,a2,a3,a4 FROM c1.t1 WHERE a2 > $1 AND a3 < $2; $$ LANGUAGE 'sql';

--Ex. 1.1(6D):fcţ. SQL ce preia 2 param. şi întoarce un set de înreg.CREATE OR REPLACE function c1.f3(b2 int, b3 int) RETURNS SETOF RECORD AS$$ SELECT a1,a2,a3,a4 FROM c1.t1 WHERE a2 > $1 AND a3 < $2; $$ LANGUAGE 'sql';

--Ex. 1.1(6A) APEL pic.f3(int,int) SELECT a1,a2,a3,a4 FROM c1.f3(10,15) AS

(a1 int, a2 int, a3 int, a4 varchar(20));

--Ex. 1.1(6A) APEL pic.f3(int,int) SELECT a1,a2,a3,a4 FROM c1.f3(10,15) AS

(a1 int, a2 int, a3 int, a4 varchar(20));

Page 56: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Funcţii de tipul SQL

Tipul variabilei se pune după numele acesteia (invers faţă de limbajul C). Simbolul $1 semnifică primul argument (b2), iar simbolul $2 semnifică al doilea argument (b3).

1.4. Funcţii SQL cu transfer prin argument şi cu returnare de tip boolean

În acest caz funcţia are forma din exemplul următor, unde întoarce valoarea de adevăr TRUE dacă există cel puţin o înregistrare în cadrul celui de al doilea SELECT, altfel întoarce FALSE:

iar apelul are forma:

2. Funcţii de tipul plpgSQL

Funcţiile (procedurile) de tipul plpgSQL sunt de câteva ori mai lente decat funcţiile SQL însă sunt mult mai flexibile, acestea permiţând operaţii variate pentru fiecare înregistrare în parte. Structura simplificată a unei funcţii de tip plpgSQL este:

Un exemplu de funcţie plpgSQL ce nu preia şi nu întoarce date:

iar exemplul de apel:

55

--Ex. 1.1(7D):funcţie SQL ce preia 1 param. şi întoarce val. bool.CREATE OR REPLACE function pic.f4(b2 int) RETURNS BOOLEAN AS$$ SELECT EXISTS(SELECT * FROM c1.t1 WHERE a2>$1); $$ LANGUAGE 'sql';

--Ex. 1.1(7D):funcţie SQL ce preia 1 param. şi întoarce val. bool.CREATE OR REPLACE function pic.f4(b2 int) RETURNS BOOLEAN AS$$ SELECT EXISTS(SELECT * FROM c1.t1 WHERE a2>$1); $$ LANGUAGE 'sql';

/*Ex. 1.1(7A) APEL pic.f4() */ SELECT pic.f4(2) as f1;/*Ex. 1.1(7A) APEL pic.f4() */ SELECT pic.f4(2) as f1;

CREATE [OR REPLACE] function nume_functie -- în loc de DROP ... RETURNS tipul_de_data_intors_de_functie AS$$DECLARE –- urmează declaraţii variabile localeBEGIN --- corpul funcţiei---END$$ LANGUAGE 'sql';

CREATE [OR REPLACE] function nume_functie -- în loc de DROP ... RETURNS tipul_de_data_intors_de_functie AS$$DECLARE –- urmează declaraţii variabile localeBEGIN --- corpul funcţiei---END$$ LANGUAGE 'sql';

--Ex. 2.1(1D):funcţie SQL ce nu preia param. şi nu întoarce date.CREATE OR REPLACE FUNCTION pic.f2_1() RETURNS void AS$$ BEGIN DROP TABLE IF EXISTS pic.t2; CREATE TABLE pic.t2(a1 serial PRIMARY KEY,a2 int,a3 int,a4 varchar(20)); INSERT INTO c1.t2(a2,a3,a4) VALUES (17,18,'AA11'),(112,17,'AA12'),(111,15,'AA13');END $$ LANGUAGE 'plpgsql';

--Ex. 2.1(1D):funcţie SQL ce nu preia param. şi nu întoarce date.CREATE OR REPLACE FUNCTION pic.f2_1() RETURNS void AS$$ BEGIN DROP TABLE IF EXISTS pic.t2; CREATE TABLE pic.t2(a1 serial PRIMARY KEY,a2 int,a3 int,a4 varchar(20)); INSERT INTO c1.t2(a2,a3,a4) VALUES (17,18,'AA11'),(112,17,'AA12'),(111,15,'AA13');END $$ LANGUAGE 'plpgsql';

/*Ex. 2.1(1A) APEL pic.f2_1() */ SELECT pic.f2_1();/*Ex. 2.1(1A) APEL pic.f2_1() */ SELECT pic.f2_1();

Page 57: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

O funcţie de tip SQL nu ar fi permis crearea tabelului şi popularea acestuia în cadrul aceluiaşi bloc de instrucţiuni. În continuare ne vom referi doar la plpgSQL.

3. Declararea variabilelor. Secvenţe de decizie

În plpgSQL se pot declara variabile de tipul celor întâlnite în limbajul SQL. Aceste variabile se pot declara în secţiunile precedate de cuvântul cheie DECLARE ce apare înaintea blocului de date delimitat de BEGIN şi END. Cuvintele cheie din plpgSQL, în mod asemănător cu cele din SQL, sunt case insensitive (nu ţin cont de literă mare sau mică).

În plpgSQL este recunoscută instrucţiunea de decizie IF iar principalele forme sunt prezentate în cele ce urmează:

În următorul exemplu este creată o funcţie care adaugă o înregistrare dacă numărul acestora (înainte de adăugare) este impar şi două înregistrări dacă numărul acestora este par.

iar apelul are forma:

Comanda SQL:“SELECT count(*) FROM pic.t1 INTO nr_inreg;” are ca efect determinarea numărului total de înregistrări cu ajutorul funcţiei de agregare COUNT(*) şi transferarea valorii rezultate în variabila nr_inreg.

4. Parametri de intrare şi ieşire

Parametrii de ieşire (variabilele ce conţin valorile returnate de funcţie) pot fi specificaţi şi prin lista de argumente a funcţiei, prin utilizarea cuvântului cheie OUT în faţa acestora.

Parametrii de intrare (preluaţi de către funcţie) au cuvântul cheie IN în faţa acestora sau nu au nimic (în mod implicit parametrii din lista de argumente sunt parametri de intrare).

În exemplul următor, valorile date prin variabilele a şi b

56

IF <expresie> THEN < BLOC INSTRUCŢIUNI > END IF –- sauIF <expresie> THEN < BLOC INSTRUCŢIUNI_1 > ELSE

< BLOC INSTRUCŢIUNI_2 > END IF

IF <expresie> THEN < BLOC INSTRUCŢIUNI > END IF –- sauIF <expresie> THEN < BLOC INSTRUCŢIUNI_1 > ELSE

< BLOC INSTRUCŢIUNI_2 > END IF

/*Ex. 3(1D):*/ CREATE OR REPLACE FUNCTION pic.f3_1() RETURNS void AS$$ DECLARE nr_inreg int;-- deschide blocul pentru declaratiiBEGIN SELECT count(*) FROM pic.t1 INTO nr_inreg;IF NOT (nr_inreg % 2) = 0 THEN -- daca este impar INSERT INTO pic.t1(a2,a3,a4) VALUES (1001,0,'---');ELSE INSERT INTO pic.t1(a2,a3,a4) VALUES (1002,0,'M'),(1003,17,'N');END IF; END $$ LANGUAGE plpgsql;

/*Ex. 3(1D):*/ CREATE OR REPLACE FUNCTION pic.f3_1() RETURNS void AS$$ DECLARE nr_inreg int;-- deschide blocul pentru declaratiiBEGIN SELECT count(*) FROM pic.t1 INTO nr_inreg;IF NOT (nr_inreg % 2) = 0 THEN -- daca este impar INSERT INTO pic.t1(a2,a3,a4) VALUES (1001,0,'---');ELSE INSERT INTO pic.t1(a2,a3,a4) VALUES (1002,0,'M'),(1003,17,'N');END IF; END $$ LANGUAGE plpgsql;

/*Ex. 3(1A) APEL pic.f3_1() */ select pic.f3_1();/*Ex. 3(1A) APEL pic.f3_1() */ select pic.f3_1();

Page 58: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Parametri de intrare şi ieşire

sunt transmise funcţiei, iar aceasta întoarce valoarea c, valoare ce conţine suma celor două variabile.

Notă: Expresia c:=a+b; înseamnă asignarea rezultatului adunării în variabila c (operatorul de asignare).

Nu este necesară scrierea instrucţiunii return c; deoarece există OUT c.

Pentru apelul funcţiei se transmit doar parametrii de intrare, în acest caz câmpul rezultat va avea numele funcţiei.

Dacă apelul are forma de mai jos, câmpul rezultat are numele variabilei de ieşire.

În continuare este prezentat un alt exemplu cu doi parametri de intrare şi trei parametri de ieşire. În prima variantă a definirii funcţiei nu a fost necesară specificaţia RETURNS, iar denumirile variabilelor de ieşire sunt recunoscute (precum şi cele de intrare) şi pot fi utilizate în corpul funcţiei:

Apelul funcţiei se realizează fie prin menţionarea parametrilor de ieşire:

,

fie prin selecţia tuturor câmpurilor existente:

În exemplul de mai sus se poate adăuga RETURNS RECORD fără a avea vreun efect asupra execuţiei funcţiei.

Cuvântul cheie IN (INPUT) este opţional, acesta fiind sensul implicit pentru argumente.

57

/*Ex. 4(1D):*/ create or replace function pic.f4_1(IN a int, IN b int, OUT c int) returns int as$$ BEGIN c:=a+b; END $$ language plpgsql;.

/*Ex. 4(1D):*/ create or replace function pic.f4_1(IN a int, IN b int, OUT c int) returns int as$$ BEGIN c:=a+b; END $$ language plpgsql;.

/*Ex. 4(1A-1) APEL pic.f4_1() */ SELECT pic.f1(5,7);/*Ex. 4(1A-1) APEL pic.f4_1() */ SELECT pic.f1(5,7);

/*Ex 4(1A-2) APEL pic.f4_1() */ SELECT * FROM pic.f1(4,9);/*Ex 4(1A-2) APEL pic.f4_1() */ SELECT * FROM pic.f1(4,9);

/* Ex. 4(2D-1): */ CREATE OR REPLACE FUNCTION pic.f4_2(IN a int, IN b int, OUT suma int, OUT produs int, OUT impartire numeric) AS$$ BEGIN suma:=a+b; produs:=a*b; impartire:=a/(b*1.0);END $$ language plpgsql;

/* Ex. 4(2D-1): */ CREATE OR REPLACE FUNCTION pic.f4_2(IN a int, IN b int, OUT suma int, OUT produs int, OUT impartire numeric) AS$$ BEGIN suma:=a+b; produs:=a*b; impartire:=a/(b*1.0);END $$ language plpgsql;

/*Ex. 4(2A-1) APEL pic.f4_2() */ SELECT suma, produs, impartire FROM pic.f2(5,7);

/*Ex. 4(2A-1) APEL pic.f4_2() */ SELECT suma, produs, impartire FROM pic.f2(5,7);

/*Ex. 4(2A-2) APEL pic.f4_2() */ SELECT * FROM pic.f2(5,7);

/*Ex. 4(2A-2) APEL pic.f4_2() */ SELECT * FROM pic.f2(5,7);

/* Ex. 4(2D-2): */ CREATE OR REPLACE FUNCTION pic.f4_2(a int, IN b int, OUT suma int, OUT produs int, OUT impartire numeric) RETURNS RECORD AS$$ BEGIN suma:=a+b; produs:=a*b; impartire:=a/(b*1.0); END $$ LANGUAGE plpgsql;

/* Ex. 4(2D-2): */ CREATE OR REPLACE FUNCTION pic.f4_2(a int, IN b int, OUT suma int, OUT produs int, OUT impartire numeric) RETURNS RECORD AS$$ BEGIN suma:=a+b; produs:=a*b; impartire:=a/(b*1.0); END $$ LANGUAGE plpgsql;

Page 59: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

5. Implementarea notificărilor

Uneori sunt necesare informaţii despre valorile variabilelor în diverse puncte sau sunt necesare informaţii despre anumite stări din cadrul funcţiei (de exemplu, numărul de înregistrări afectate de o operaţie SQL de tipul UPDATE sau DELETE), iar aceste informaţii sunt necesare fără a ieşi din funcţie. În aceste condiţii sunt utilizate notificările, acestea se transmit de la server către client.

În exemplul următor sunt adăugate câteva înregistrări într-un tabel t1, apoi sunt realizate operaţii de adăugare înregistrări şi actualizare. Se construiesc notificări pentru a transmite către client numărul de înregistrări adăugate şi numărul de înregistrări afectate de comanda UPDATE. De asemenea se testează o expresie şi se transmite o notificare către client.

Prin instrucţiunea GET DIAGNOSTICS este preluat conţinutul variabilei ROW_COUNT din cadrul server-ului, variabilă ce conţine numărul de înregistrări afectate de ultima comandă SQL.

Instrucţiunea RAISE NOTICE transmite notificarea către client. În şirul ce urmează este specificat textul transmis către client, iar în locul simbolurilor “%” din cadrul şirului se vor transmite valorile variabilelor din finalul instrucţiunii. De exemplu, dacă avem: “RAISE NOTICE 'A= % ...B=% ...C=%',a,b,c;”, iar dacă a=10, b='TEST' şi c=15.7, atunci textul afişat va fi: “NOTICE: A=10 … B=TEST ...C=15.7”.

Notificările pot să apară (în funcţie de configurarea serverului de baze de date) în fişierele cu istoricul operaţiilor la nivel de server de baze de date şi pot fi utile pentru interpretarea anumitor situaţii apărute.

După apelul funcţiei pic.f5_1() în fereastra SQL din

58

/* Ex. 5(1D): */ CREATE OR REPLACE FUNCTION pic.f5_1() RETURNS TEXT AS$$ DECLARE nr_ins int; nr_up int; achR text; total int;BEGIN achR:='OK'; DROP TABLE IF EXISTS pic.t1;CREATE TABLE pic.t1(a serial PRIMARY KEY, b int, c varchar(10));INSERT INTO pic.t1(b,c) VALUES (11,'A1'),(21,'B2'),(31,'B3'),(41,'C3');

GET DIAGNOSTICS nr_ins = ROW_COUNT; RAISE NOTICE 'Au fost adaugate: % inregistrari',nr_ins; UPDATE pic.t1 SET b=b+2 WHERE c LIKE 'B%';

GET DIAGNOSTICS nr_up = ROW_COUNT; RAISE NOTICE 'Au fost actualizate: % inregistrari',nr_up; SELECT SUM(b) FROM pic.t1 INTO total;IF total < 60 THEN achR:='NOK'; END IF; RETURN achR; END $$ LANGUAGE plpgsql;

/* Ex. 5(1D): */ CREATE OR REPLACE FUNCTION pic.f5_1() RETURNS TEXT AS$$ DECLARE nr_ins int; nr_up int; achR text; total int;BEGIN achR:='OK'; DROP TABLE IF EXISTS pic.t1;CREATE TABLE pic.t1(a serial PRIMARY KEY, b int, c varchar(10));INSERT INTO pic.t1(b,c) VALUES (11,'A1'),(21,'B2'),(31,'B3'),(41,'C3');

GET DIAGNOSTICS nr_ins = ROW_COUNT; RAISE NOTICE 'Au fost adaugate: % inregistrari',nr_ins; UPDATE pic.t1 SET b=b+2 WHERE c LIKE 'B%';

GET DIAGNOSTICS nr_up = ROW_COUNT; RAISE NOTICE 'Au fost actualizate: % inregistrari',nr_up; SELECT SUM(b) FROM pic.t1 INTO total;IF total < 60 THEN achR:='NOK'; END IF; RETURN achR; END $$ LANGUAGE plpgsql;

/*Ex. 5(1A) APEL pic.f5_1() */ SELECT pic.f5_1();/*Ex. 5(1A) APEL pic.f5_1() */ SELECT pic.f5_1();

Page 60: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Implementarea notificărilor

pgAdmin3 în tab-ul Messages se pot urmări notificările apărute. Există metode de preluare a notificărilor în cadrul interfeţei client.

6. Structuri repetitive

O buclă cu instrucţiuni, în plpgSQL are forma:

Ieşirea din buclă se realizează cu instrucţiunea EXIT (echivalent cu instrucţiunea break din limbajul C), iar revenirea la începutul buclei (fară executarea restului de instrucţiuni) se realizează cu instrucţiunea CONTINUE (idem în limbajul C), utilizarea acestora fiind exemplificată în cele ce urmează.

Bucla de tip WHILE va avea forma:

iar bucla de tip FOR va avea forma:

Pentru bucla de tip FOR putem avea formele:

sau:

59

LOOP-- bloc instructiuniEND LOOP;

LOOP-- bloc instructiuniEND LOOP;

i:=0; –- iniţializare variabilă LOOP –- începutul buclei-- instrucţiuniIF i<10 THEN CONTINUE; END IF;IF i>100 THEN EXIT; END IF;-- instrucţiuni în care varibila i are valori între 10 şi 100END LOOP; –- sfârşitul buclei

i:=0; –- iniţializare variabilă LOOP –- începutul buclei-- instrucţiuniIF i<10 THEN CONTINUE; END IF;IF i>100 THEN EXIT; END IF;-- instrucţiuni în care varibila i are valori între 10 şi 100END LOOP; –- sfârşitul buclei

WHILE -- condiţie (expresie evaluată la TRUE --- adică diferită de 0)LOOP –- începutul buclei--instrucţiuniEND LOOP;–- sfârşitul buclei

WHILE -- condiţie (expresie evaluată la TRUE --- adică diferită de 0)LOOP –- începutul buclei--instrucţiuniEND LOOP;–- sfârşitul buclei

FOR nume IN expresieDomeniuLOOP--instructiuniEND LOOP;

FOR nume IN expresieDomeniuLOOP--instructiuniEND LOOP;

FOR i IN 1..100LOOP-- i are valori de la 1 la 100END LOOP;

FOR i IN 1..100LOOP-- i are valori de la 1 la 100END LOOP;

Page 61: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

În continuare este prezentat un exemplu de citire dintr-un tabel. În acest sens, este contruit un tabel t1 în care sunt adăugate câteva înregistrări.

Funcţia pentru citirea din tabel va fi:

Bucla se opreşte în momentul în care variabila r devine NULL, adică atunci când nu mai sunt înregistrări de parcurs. Fără secvenţa RETURN NEXT r; funcţia nu adaugă în tabelul întors înregistrarea curentă, practic pentru fiecare apel al instrucţiunii next este adăugată o înregistrare la tabelul întors. Pentru a apela funcţia este necesară specificarea structurii câmpurilor rezultate:

În cadrul buclei prin care sunt întoarse înregistrările, se pot efectua diverse operaţii. În acest sens, este prezentat un exemplu de funcţie care afişează numai înregistrările pentru care valoarea câmpului b este mai mică decât valoarea anterioară pentru acelaşi câmp:

Tabelul parcurs este dat de :"SELECT a,b,c FROM pic.t1".

60

FOR r IN DENUMIRE_TABEL --aici „expresieDomeniu” este alcatuit din mulţimea liniilor tabeluluiLOOP -- r este variabila ce conţine o înregistrare (linie din tabel)-- r parcurge tot tabelul (la fiecare ciclu preia altă inregistrare)–- r este de tip RECORDEND LOOP;

FOR r IN DENUMIRE_TABEL --aici „expresieDomeniu” este alcatuit din mulţimea liniilor tabeluluiLOOP -- r este variabila ce conţine o înregistrare (linie din tabel)-- r parcurge tot tabelul (la fiecare ciclu preia altă inregistrare)–- r este de tip RECORDEND LOOP;

/* Ex. 6(1D): */ DROP TABLE IF EXISTS pic.t1;create table pic.t1(a serial PRIMARY KEY, b int, c varchar(10));INSERT INTO pic.t1(b,c) VALUES(10,'A10'),(17,'A17'),(14,'A14'),(13,'A13'),(11,'A11'); select * from pic.t1;

/* Ex. 6(1D): */ DROP TABLE IF EXISTS pic.t1;create table pic.t1(a serial PRIMARY KEY, b int, c varchar(10));INSERT INTO pic.t1(b,c) VALUES(10,'A10'),(17,'A17'),(14,'A14'),(13,'A13'),(11,'A11'); select * from pic.t1;

/* Ex. 6(1D): */CREATE OR REPLACE FUNCTION pic.f1() RETURNS SETOF RECORD AS$$ DECLARE r record;-- r este de tip înregistrare (RECORD)BEGIN FOR r IN SELECT a,b,c FROM pic.t1 -- r este variabila de parcurgere

LOOP -- inceput buclă RETURN NEXT r; -- întoarce înregistrare cu înregistrareEND LOOP;--sfârşit buclă

END $$ LANGUAGE plpgsql;

/* Ex. 6(1D): */CREATE OR REPLACE FUNCTION pic.f1() RETURNS SETOF RECORD AS$$ DECLARE r record;-- r este de tip înregistrare (RECORD)BEGIN FOR r IN SELECT a,b,c FROM pic.t1 -- r este variabila de parcurgere

LOOP -- inceput buclă RETURN NEXT r; -- întoarce înregistrare cu înregistrareEND LOOP;--sfârşit buclă

END $$ LANGUAGE plpgsql;

/*Ex. 6(1A) APEL pic.f6_1() */ select a,b,c FROM pic.f6_1() AS (a int, b int, c varchar(10));

/*Ex. 6(1A) APEL pic.f6_1() */ select a,b,c FROM pic.f6_1() AS (a int, b int, c varchar(10));

/*Ex. 6(2D):*/CREATE OR REPLACE FUNCTION pic.f6_2() RETURNS SETOF RECORD AS $$DECLARE r record; b1 int; –- b1 memoreaza valoarea anterioara BEGIN b1:=0; FOR r IN SELECT a,b,c FROM pic.t1

LOOP IF r.b < b1 THEN b1:=r.b; RETURN NEXT r; ELSE b1:=r.b; END IF; END LOOP;

END $$ LANGUAGE plpgsql;

/*Ex. 6(2D):*/CREATE OR REPLACE FUNCTION pic.f6_2() RETURNS SETOF RECORD AS $$DECLARE r record; b1 int; –- b1 memoreaza valoarea anterioara BEGIN b1:=0; FOR r IN SELECT a,b,c FROM pic.t1

LOOP IF r.b < b1 THEN b1:=r.b; RETURN NEXT r; ELSE b1:=r.b; END IF; END LOOP;

END $$ LANGUAGE plpgsql;

Page 62: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Structuri repetitive

Apelul funcţiei:

În continuare este prezentat un exemplu prin care sunt înlocuite funcţiile SQL de agregare MIN şi MAX:

iar apelul:

Funcţia f6_3 este echivalentă cu următoarea comandă SQL:

7. Construcţia dinamică a interogărilor

Uneori structura unei interogări poate să depindă de anumiţi parametri din lista de argumente a funcţiei sau de un anumit context. De exemplu, iniţial punem un filtru pentru un anumit câmp (denumire_camp=<parametru>) prin înlocuirea efectivă a valorii parametrului, apoi vrem să afişăm înregistrările care nu conţin valori (denumire_camp IS NULL). Se observă necesitatea schimbării structurii interogării. În acest caz se construieşte un şir de caractere ce reprezintă interogarea, apoi aceasta se execută prin utilizarea instrucţiunii EXECUTE. În acest mod, comenzile vor fi reprezentate prin şiruri de caractere ce se formează în momentul apelării funcţiei.

În continuare este prezentat un exemplu de interogare formată din mai multe şiruri de caractere:

61

/*Ex. 6(2A) APEL pic.f6_2() */ SELECT a,b,c FROM pic.f6_2() AS (a int, b int, c varchar(10));

/*Ex. 6(2A) APEL pic.f6_2() */ SELECT a,b,c FROM pic.f6_2() AS (a int, b int, c varchar(10));

/* Ex. 6(3D): */ CREATE OR REPLACE FUNCTION pic.f6_3() RETURNS SETOF RECORD AS$$ DECLARE r record; b_min int; b_max int;--memorează val.min şi max.BEGIN b_min:=1000; b_max:=-1000; FOR r IN SELECT a,b,c FROM pic.t1

LOOP if r.b < b_min THEN b_min:=r.b; end if; if r.b >= b_max THEN b_max:=r.b; end if;END LOOP;

FOR r IN SELECT a,b,c FROM pic.t1LOOP IF r.b = b_min OR r.b = b_max THEN return next r; END IF;END LOOP;

END $$ LANGUAGE plpgsql;

/* Ex. 6(3D): */ CREATE OR REPLACE FUNCTION pic.f6_3() RETURNS SETOF RECORD AS$$ DECLARE r record; b_min int; b_max int;--memorează val.min şi max.BEGIN b_min:=1000; b_max:=-1000; FOR r IN SELECT a,b,c FROM pic.t1

LOOP if r.b < b_min THEN b_min:=r.b; end if; if r.b >= b_max THEN b_max:=r.b; end if;END LOOP;

FOR r IN SELECT a,b,c FROM pic.t1LOOP IF r.b = b_min OR r.b = b_max THEN return next r; END IF;END LOOP;

END $$ LANGUAGE plpgsql;

/*Ex. 6(3A) APEL pic.f6_3() */ SELECT a,b,c FROM pic.f6_3() AS (a int, b int, c varchar(10));

/*Ex. 6(3A) APEL pic.f6_3() */ SELECT a,b,c FROM pic.f6_3() AS (a int, b int, c varchar(10));

select t1.a,t1.b,t1.c FROM (SELECT min(b) as b_min, max(b) as b_max FROM pic.t1) par, pic.t1 WHERE t1.b=par.b_min OR t1.b=par.b_max;

select t1.a,t1.b,t1.c FROM (SELECT min(b) as b_min, max(b) as b_max FROM pic.t1) par, pic.t1 WHERE t1.b=par.b_min OR t1.b=par.b_max;

Page 63: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

Instrucţiunea “EXECUTE achQ INTO rez;” execută comanda SQL din şirul achQ, iar rezultatul este memorat în variabila rez (aici interogarea întoarce o singură valoare). Exemplu de apel:

Un alt exemplu de funcţie cu interogare dinamică şi cu doi parametri de intrare:

iar apelul:

Un alt exemplu, preia un vector cu şiruri (ultimul element este NULL) şi întoarce un şir rezultat prin concatenarea elementelor din cadrul vectorului cu şiruri:

iar apelul:

În continuare este prezentat un exemplu de funcţie ce preia un şir, îl concatenează cu şirul “test” apoi întoarce şirul rezultat în urma concatenării:

Funcţia quote_literal(b) întoarce valoarea lui b ca şir de caractere şi nu mai este necesară specificarea acestuia ca şir de

62

/*Ex. 7(1D):*/CREATE OR REPLACE FUNCTION pic.f7_1(a text) RETURNS int as $$ DECLARE rez int; achQ text;BEGIN achQ='select '||a; EXECUTE achQ INTO rez; return rez;END $$ language plpgsql;

/*Ex. 7(1D):*/CREATE OR REPLACE FUNCTION pic.f7_1(a text) RETURNS int as $$ DECLARE rez int; achQ text;BEGIN achQ='select '||a; EXECUTE achQ INTO rez; return rez;END $$ language plpgsql;

/*Ex. 7(1A) APEL pic.f7_1() */ SELECT pic.f7_1('5+9');/*Ex. 7(1A) APEL pic.f7_1() */ SELECT pic.f7_1('5+9');

/*Ex. 7(2D):*/CREATE OR REPLACE FUNCTION pic.f7_2(a text, b text) RETURNS int AS $$ DECLARE rez int; achQ text;BEGIN achQ = 'select ' || a || '+' || b; EXECUTE achQ INTO rez;return rez; END $$ language plpgsql;

/*Ex. 7(2D):*/CREATE OR REPLACE FUNCTION pic.f7_2(a text, b text) RETURNS int AS $$ DECLARE rez int; achQ text;BEGIN achQ = 'select ' || a || '+' || b; EXECUTE achQ INTO rez;return rez; END $$ language plpgsql;

/*Ex. 7(2A) APEL pic.f7_2() */ SELECT pic.f7_2('5','9');/*Ex. 7(2A) APEL pic.f7_2() */ SELECT pic.f7_2('5','9');

/*Ex. 7(3D):*/CREATE OR REPLACE FUNCTIOn pic.f7_3(_sir_ text[]) RETURNS text AS $$ DECLARE i int; rez text;BEGIN rez:=''; i:=1;LOOP IF _sir_[i] IS NULL THEN RETURN rez; END IF; rez := rez || _sir_[i] || ';'; i:=i+1;END LOOP; END $$ LANGUAGE 'plpgsql';

/*Ex. 7(3D):*/CREATE OR REPLACE FUNCTIOn pic.f7_3(_sir_ text[]) RETURNS text AS $$ DECLARE i int; rez text;BEGIN rez:=''; i:=1;LOOP IF _sir_[i] IS NULL THEN RETURN rez; END IF; rez := rez || _sir_[i] || ';'; i:=i+1;END LOOP; END $$ LANGUAGE 'plpgsql';

/*Ex 7(3A) APEL pic.f7_3() */ select pic.f7_3(ARRAY['UNU','DOI','TREI',NULL]) as rez;

/*Ex 7(3A) APEL pic.f7_3() */ select pic.f7_3(ARRAY['UNU','DOI','TREI',NULL]) as rez;

/*Ex 7(4D):*/CREATE OR REPLACE FUNCTION pic.f7_4(b text) RETURNS text AS$$ DECLARE achQ text; rez text;BEGIN achQ ='SELECT '||quote_literal(b)||'||'||quote_literal(' test');EXECUTE achQ INTO rez; RETURN rez;END $$ LANGUAGE 'plpgsql';

/*Ex 7(4D):*/CREATE OR REPLACE FUNCTION pic.f7_4(b text) RETURNS text AS$$ DECLARE achQ text; rez text;BEGIN achQ ='SELECT '||quote_literal(b)||'||'||quote_literal(' test');EXECUTE achQ INTO rez; RETURN rez;END $$ LANGUAGE 'plpgsql';

Page 64: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Construcţia dinamică a interogărilor

caractere prin introducerea simbolurilor apostrof. Apelul are forma:

Un alt exemplu îl constuie o funcţie ce preia un tablou cu şiruri de caractere ce reprezintă filtre. Funcţia preia date din tabelul t1 şi creează un tabel t2 cu rezultatul selecţiei:

Afişează doar liniile ce cuprind valorile A222 sau A333:

8. Funcţii de tip trigger

În scopul captării evenimentelor de editare specifice unui tabel (INSERT, UPDATE, DELETE), pot fi utilizate funcţii/proceduri speciale ce pot fi apelate automat de către sistemul de gestiune a bazelor de date în momentul apariţiei unui eveniment de editare asupra unui tabel. Aceste funcţii pot apărea imediat înainte de validarea evenimentului de editare sau după validarea acestuia (ex.: BEFORE UPDATE sau AFTER UPDATE).

De asemenea, în cazul unui eveniment de tip UPDATE aceste funcţii speciale au acces atât la vechile valori, cât şi la noile valori din cadrul câmpurilor înregistrării care se modifică.

De exemplu, construim un tabel care conţine un câmp cu data calendaristică datac şi altul cu anul din cadrul datei calendaristice an. Dacă modificăm câmpul cu data calenaristică datac dorim să se actualizeze automat câmpul cu anul an corespunzător câmpului datac, fară a apela explicit vreo funcţie. În acest sens construim tabelul:

63

/*Ex. 7(4A) APEL pic.f7_4() */ select pic.f7_4('trei');/*Ex. 7(4A) APEL pic.f7_4() */ select pic.f7_4('trei');

drop table if exists t1;create temporary table t1(idx serial, val varchar(20));insert into t1(val) values ('A111'),('A222'),('A333'),('A222'),('B111'); select * from t1;

drop table if exists t1;create temporary table t1(idx serial, val varchar(20));insert into t1(val) values ('A111'),('A222'),('A333'),('A222'),('B111'); select * from t1;

/*Ex. 7(5D):*/ CREATE OR REPLACE FUNCTION pic.f7_5(_filtru_ text[]) RETURNS void AS$$ DECLARE achQ text; i int;BEGIN achQ:='CREATE TEMP TABLE t2 as SELECT * FROM t1 WHERE '; i:=1;LOOP IF _filtru_[i] IS NULL THEN achQ := achQ || ';'; EXECUTE achQ; RETURN; END IF;IF i>1 THEN achQ := achQ || ' OR '; END IF; achQ := achQ || ' val=' || quote_literal(_filtru_[i]); i:=i+1;END LOOP; END $$ LANGUAGE 'plpgsql';

/*Ex. 7(5D):*/ CREATE OR REPLACE FUNCTION pic.f7_5(_filtru_ text[]) RETURNS void AS$$ DECLARE achQ text; i int;BEGIN achQ:='CREATE TEMP TABLE t2 as SELECT * FROM t1 WHERE '; i:=1;LOOP IF _filtru_[i] IS NULL THEN achQ := achQ || ';'; EXECUTE achQ; RETURN; END IF;IF i>1 THEN achQ := achQ || ' OR '; END IF; achQ := achQ || ' val=' || quote_literal(_filtru_[i]); i:=i+1;END LOOP; END $$ LANGUAGE 'plpgsql';

/*Ex. 7(4A) APEL pic.f7_5() */ select * from t1;SELECT pic.f7_5(ARRAY['A222','A333',NULL]); SELECT * FROM t2;

/*Ex. 7(4A) APEL pic.f7_5() */ select * from t1;SELECT pic.f7_5(ARRAY['A222','A333',NULL]); SELECT * FROM t2;

Page 65: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

Crearea funcţiei de tip trigger:

În funcţia de tip triger variabilele NEW şi OLD sunt predefinite, sunt de tip înregistrare RECORD şi memorează noua, respectiv vechea valoare a înregistrării afectate. Funcţia triger poate întoarce şi înregistrarea OLD (vechile valori).

O funcţie de tip triger poate fi ataşată unuia sau mai multor tabele. Ataşarea funcţiei f8_1() la tabelul t1 pentru operaţia de UPDATE se realizează prin:

Condiţia “WHEN ((OLD.* IS DISTINCT FROM NEW.*))” are ca efect limitarea apelului funcţiei triger doar atunci când se modifică un câmp (noile valori sunt diferite de vechile valori).

În vederea testării se adaugă înregistrări şi apoi se execută o comandă UPDATE în vederea modificării valorii câmpului datac dintr-o înregistrare.

În urma comenzii UPDATE funcţia triger f8_1() a fost apelată automat.

Extindem exemplul anterior prin construcţia unui tabel pic.t2, care pe lângă câmpul datac (data calendaristică) conţine câmpul cu valoarea veche a anului (înainte de modificare) anul_v şi câmpul anul_n cu valoarea nouă a anului, după modificare. În momentul modificării câmpului datac, celelalte două câmpuri anul_v şi anul_c trebuie să se actualizeze automat. În acest sens, construim tabelul:

Funcţia triger va fi:

64

DROP TABLE IF EXISTS pic.t1; CREATE TABLE pic.t1(datac date, an smallint,idx serial PRIMARY KEY);

DROP TABLE IF EXISTS pic.t1; CREATE TABLE pic.t1(datac date, an smallint,idx serial PRIMARY KEY);

/*Ex. 8(1D):*/ CREATE OR REPLACE FUNCTION pic.f8_1() RETURNS trigger AS $$ BEGIN SELECT EXTRACT( YEAR FROM NEW.datac) INTO NEW.an; return NEW; END $$ LANGUAGE 'plpgsql';

/*Ex. 8(1D):*/ CREATE OR REPLACE FUNCTION pic.f8_1() RETURNS trigger AS $$ BEGIN SELECT EXTRACT( YEAR FROM NEW.datac) INTO NEW.an; return NEW; END $$ LANGUAGE 'plpgsql';

/*Ex. 8(1T):*/ CREATE TRIGGER t8_1_trg BEFORE UPDATE ON pic.t1 FOR EACH ROW WHEN ((OLD.* IS DISTINCT FROM NEW.*)) EXECUTE PROCEDURE pic.f8_1();

/*Ex. 8(1T):*/ CREATE TRIGGER t8_1_trg BEFORE UPDATE ON pic.t1 FOR EACH ROW WHEN ((OLD.* IS DISTINCT FROM NEW.*)) EXECUTE PROCEDURE pic.f8_1();

/*Ex. 8(1A) TESTARE pic.f8_1() pentru pic.t1 */ INSERT INTO pic.t1(datac) VALUES('2013-03-15'),('2013-03-17'),('2013-03-19'); UPDATE pic.t1 SET datac=datac+2 WHERE datac='2013-03-17';select * from pic.t1;

/*Ex. 8(1A) TESTARE pic.f8_1() pentru pic.t1 */ INSERT INTO pic.t1(datac) VALUES('2013-03-15'),('2013-03-17'),('2013-03-19'); UPDATE pic.t1 SET datac=datac+2 WHERE datac='2013-03-17';select * from pic.t1;

DROP TABLE IF EXISTS pic.t2; CREATE TABLE pic.t2(datac date, an_v smallint, an_n smallint,idx serial PRIMARY KEY);

DROP TABLE IF EXISTS pic.t2; CREATE TABLE pic.t2(datac date, an_v smallint, an_n smallint,idx serial PRIMARY KEY);

Page 66: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

8.Funcţii de tip trigger

Codul pentru ataşarea funcţiei triger f8_2() de tabelul pic.t2 este:

iar pentru testare:

Un alt exemplu presupune un tabel pic.t3, cu următoarele câmpuri: numărul zilei din săptamână nz, denumirea zilei denzi şi un câmp idx de tip serial. În momentul introducerii numărului zilei, dacă acesta este între 1 şi 7, se va afişa denumirea acesteia, altfel numărul zilei rămâne nemodificat:

Funcţia triger pic.f8_3() va avea forma:

iar comenzile de asociere între funcţia triger şi tabel:

În vederea testării, executăm comenzile:

65

/*Ex. 8(2D):*/CREATE OR REPLACE FUNCTION pic.f8_2() RETURNS trigger AS $$ BEGIN SELECT EXTRACT( YEAR FROM OLD.datac) INTO NEW.an_v; SELECT EXTRACT( YEAR FROM NEW.datac) INTO NEW.an_n; return NEW; END $$ LANGUAGE 'plpgsql';

/*Ex. 8(2D):*/CREATE OR REPLACE FUNCTION pic.f8_2() RETURNS trigger AS $$ BEGIN SELECT EXTRACT( YEAR FROM OLD.datac) INTO NEW.an_v; SELECT EXTRACT( YEAR FROM NEW.datac) INTO NEW.an_n; return NEW; END $$ LANGUAGE 'plpgsql';

/*Ex. 8(2T):*/ CREATE TRIGGER t2_trg BEFORE UPDATE ON pic.t2 FOR EACH ROW WHEN ((old.* IS DISTINCT FROM new.*)) EXECUTE PROCEDURE pic.f8_2();

/*Ex. 8(2T):*/ CREATE TRIGGER t2_trg BEFORE UPDATE ON pic.t2 FOR EACH ROW WHEN ((old.* IS DISTINCT FROM new.*)) EXECUTE PROCEDURE pic.f8_2();

/*Ex. 8(2A) TESTARE pic.f8_2() pentru pic.t2 */ INSERT INTO pic.t2(datac) VALUES('2013-03-15'),('2013-03-17'),('2013-03-19'); UPDATE pic.t1 SET datac=datac+5 WHERE datac='2013-03-17';select * from pic.t1 ;select * from pic.t2;

/*Ex. 8(2A) TESTARE pic.f8_2() pentru pic.t2 */ INSERT INTO pic.t2(datac) VALUES('2013-03-15'),('2013-03-17'),('2013-03-19'); UPDATE pic.t1 SET datac=datac+5 WHERE datac='2013-03-17';select * from pic.t1 ;select * from pic.t2;

DROP TABLE IF EXISTS pic.t3; CREATE TABLE pic.t3(nz smallint,denzi varchar(15),idx serial PRIMARY KEY);

DROP TABLE IF EXISTS pic.t3; CREATE TABLE pic.t3(nz smallint,denzi varchar(15),idx serial PRIMARY KEY);

/*Ex 8(3D):*/ CREATE OR REPLACE FUNCTION pic.f8_3() RETURNS trigger AS $$ BEGIN IF NEW.nz=1 THEN NEW.denzi='Luni'; END IF; IF NEW.nz=2 THEN NEW.denzi='Marti'; END IF; IF NEW.nz=3 THEN NEW.denzi='Miercuri'; END IF; IF NEW.nz=4 THEN NEW.denzi='Joi'; END IF; IF NEW.nz=5 THEN NEW.denzi='Vineri'; END IF; IF NEW.nz=6 THEN NEW.denzi='Sambata'; END IF; IF NEW.nz=7 THEN NEW.denzi='Duminica'; END IF; IF NEW.nz<1 OR NEW.nz>7 THEN OLD.denzi=NULL; return OLD; ELSE return NEW; END IF; END $$ LANGUAGE 'plpgsql';

/*Ex 8(3D):*/ CREATE OR REPLACE FUNCTION pic.f8_3() RETURNS trigger AS $$ BEGIN IF NEW.nz=1 THEN NEW.denzi='Luni'; END IF; IF NEW.nz=2 THEN NEW.denzi='Marti'; END IF; IF NEW.nz=3 THEN NEW.denzi='Miercuri'; END IF; IF NEW.nz=4 THEN NEW.denzi='Joi'; END IF; IF NEW.nz=5 THEN NEW.denzi='Vineri'; END IF; IF NEW.nz=6 THEN NEW.denzi='Sambata'; END IF; IF NEW.nz=7 THEN NEW.denzi='Duminica'; END IF; IF NEW.nz<1 OR NEW.nz>7 THEN OLD.denzi=NULL; return OLD; ELSE return NEW; END IF; END $$ LANGUAGE 'plpgsql';

/*Ex. 8(3T-1):*/ CREATE TRIGGER t8_3_1_trg BEFORE UPDATE ON pic.t3 FOR EACH ROW WHEN (old.* IS DISTINCT FROM new.*) EXECUTE PROCEDURE pic.f8_3();

/*Ex. 8(3T-1):*/ CREATE TRIGGER t8_3_1_trg BEFORE UPDATE ON pic.t3 FOR EACH ROW WHEN (old.* IS DISTINCT FROM new.*) EXECUTE PROCEDURE pic.f8_3();

/*Ex. 8(3A-1) TESTARE pic.f8_3() pentru pic.t3 */ INSERT INTO pic.t3(nz) VALUES(NULL); select * from pic.t3;UPDATE pic.t3 SET nz=2; select * from pic.t3;UPDATE pic.t3 SET nz=8; select * from pic.t3;

/*Ex. 8(3A-1) TESTARE pic.f8_3() pentru pic.t3 */ INSERT INTO pic.t3(nz) VALUES(NULL); select * from pic.t3;UPDATE pic.t3 SET nz=2; select * from pic.t3;UPDATE pic.t3 SET nz=8; select * from pic.t3;

Page 67: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

În momentul inserării nu este apelată funcţia triger deoarece legătura cu tabelul este numai pentru evenimente de tipul UPDATE. În continuare definim şi un triger pentru evenimentele de tip INSERT. Acest triger va apela funcţia triger doar dacă numărul pentru noua zi este mai mare decât 5.

În vederea testării, executăm comenzile:

9. Definirea de noi tipuri de date şi supraîncărcarea operatorilor SQL

Utilizatorul poate să îşi definească propriile tipuri de date, acestea având forma unei structuri, iar odată cu aceasta utilizatorul trebuie să supraîncarce operatorii uzuali pentru a putea utiliza aceste noi tipuri de date.

Pentru exemplificare, presupunem că avem nevoie de un tip de dată care să implementeze o structură de tip adresă.

Recomand ca tipurile de dată să fie definite în schema public în vederea simplificării modulului de utilizare. Aceste tipuri de dată se vor vedea la nivelul întregii baze de date. După definirea noului tip, îl putem utiliza:

Pentru popularea cu date a tabelului pic.pers:

66

/*Ex. 8(3T):*/ DROP TRIGGER IF EXISTS t8_3_2_trg ON pic.t3; CREATE TRIGGER t8_3_2_trg BEFORE INSERT ON pic.t3 FOR EACH ROW WHEN ((old.* IS DISTINCT FROM new.*) AND (new.nz>5)) EXECUTE PROCEDURE pic.f8_3();

/*Ex. 8(3T):*/ DROP TRIGGER IF EXISTS t8_3_2_trg ON pic.t3; CREATE TRIGGER t8_3_2_trg BEFORE INSERT ON pic.t3 FOR EACH ROW WHEN ((old.* IS DISTINCT FROM new.*) AND (new.nz>5)) EXECUTE PROCEDURE pic.f8_3();

/*Ex. 8(3A-2) TESTARE pic.f8_3() pentru pic.t3 */ DELETE FROM pic.t3;INSERT INTO pic.t3(nz) VALUES(NULL);-- nu este apelata fct.:new.nz<5INSERT INTO pic.t3(nz) VALUES(6); -- este apelata fct.:new.nz>5 (6>5)INSERT INTO pic.t3(nz) VALUES(3);--nu este apelată fct.new.nz<5 (3<5)select * from pic.t3;

/*Ex. 8(3A-2) TESTARE pic.f8_3() pentru pic.t3 */ DELETE FROM pic.t3;INSERT INTO pic.t3(nz) VALUES(NULL);-- nu este apelata fct.:new.nz<5INSERT INTO pic.t3(nz) VALUES(6); -- este apelata fct.:new.nz>5 (6>5)INSERT INTO pic.t3(nz) VALUES(3);--nu este apelată fct.new.nz<5 (3<5)select * from pic.t3;

/*Ex. 9(1T):*/ DROP TYPE IF EXISTS adresa01 CASCADE;CREATE TYPE adresa01 AS (tara varchar(30),regiune varchar(30), oras varchar(40), str varchar(50), nr int, cod_postal int, tel varchar(20), e_mail varchar(20));

/*Ex. 9(1T):*/ DROP TYPE IF EXISTS adresa01 CASCADE;CREATE TYPE adresa01 AS (tara varchar(30),regiune varchar(30), oras varchar(40), str varchar(50), nr int, cod_postal int, tel varchar(20), e_mail varchar(20));

/*Ex. 9(2T):*/ DROP TABLE IF EXISTS pic.pers;CREATE TABLE pic.pers(idx serial PRIMARY KEY, nume varchar(40), adresa adresa01 );

/*Ex. 9(2T):*/ DROP TABLE IF EXISTS pic.pers;CREATE TABLE pic.pers(idx serial PRIMARY KEY, nume varchar(40), adresa adresa01 );

/*Ex. 9(1A) TESTARE pentru pic.pers */ INSERT INTO pic.pers(nume,adresa) VALUES('Nume1','(''Ro'',''BV'',''BV'',''Str1'',5,0,''-'',''-'')');SELECT * FROM pic.pers;SELECT nume, (adresa).tara as tara, (adresa).oras FROM pic.pers;

/*Ex. 9(1A) TESTARE pentru pic.pers */ INSERT INTO pic.pers(nume,adresa) VALUES('Nume1','(''Ro'',''BV'',''BV'',''Str1'',5,0,''-'',''-'')');SELECT * FROM pic.pers;SELECT nume, (adresa).tara as tara, (adresa).oras FROM pic.pers;

Page 68: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

9.Definirea de noi tipuri de date şi supraîncărcarea operatorilor SQL

Se observă modul de preluare a informaţiei de tip adresa01. Aceasta este delimitată de apostrof şi paranteze rotunde, iar componentele din cadrul tipului, asemănătoare unei structuri, sunt separate prin virgulă. Dublarea apostrofului pentru componentele tipului de dată este cauzată de primul apostrof ce delimitează tipul de dată.

Pentru accesarea unui element din cadrul tipului definit de utilizator, variabila de tip adresa01 se va trece între paranteze rotunde iar elementul se va referi prin utilizarea simbolului punct (ex.: (adresa).oras)

Accesarea elementelor din cadrul datelor de tip adresa01 este dată şi de exemplul următor:

Implicit, fară a defini un operator de indexare, ordonarea se realizează în ordinea câmpurilor din cadrul structurii de date definite de utilizator (valabil începand cu vers. 9.x PostgreSQL). Elementele structurii pot să apară şi la nivelul evaluării expresiilor precum în exemplul următor:

Fără a avea operatori definiţi explicit, pentru acest tip de dată sunt utilizaţi operatorii standard, ce se aplică pe rând fiecărui tip de dată din cadrul structurii definite de utilizator.

Supraîncărcarea operatorilor SQL lasă utilizatorului posibilitatea de a stabili propriile reguli privind operaţiile. De exemplu, dacă dorim să existe egalitate între două date de tip adresa01 cu informaţii parţial introduse, dar suficiente pentru identificare, este necesar să rescriem/supraîncărcăm operatorul SQL de egalitate. Definim proceduri pentru fiecare operator astfel:

67

/*Ex. 9(2A) TESTARE pentru pic.pers */ INSERT INTO pic.pers(nume,adresa) VALUES('Nume5','(''Tara1'',''Reg3'',''Oras4'',''Str1'',5,5005,''-'',''-'')'),('Nume3','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'),('Nume7','(''Tara2'',''Reg5'',''Oras1'',''Str1'',5,5007,''-'',''-'')'),('Nume9','(''Tara1'',''Reg5'',''Oras9'',''Str1'',5,5009,''-'',''-'')'),('Nume8','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5008,''-'',''-'')'),('Nume8','(''Tara1'',''Reg3'',''Oras2'',''Str1'',5,5003,''-'',''-'')');

/*Ex. 9(2A) TESTARE pentru pic.pers */ INSERT INTO pic.pers(nume,adresa) VALUES('Nume5','(''Tara1'',''Reg3'',''Oras4'',''Str1'',5,5005,''-'',''-'')'),('Nume3','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'),('Nume7','(''Tara2'',''Reg5'',''Oras1'',''Str1'',5,5007,''-'',''-'')'),('Nume9','(''Tara1'',''Reg5'',''Oras9'',''Str1'',5,5009,''-'',''-'')'),('Nume8','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5008,''-'',''-'')'),('Nume8','(''Tara1'',''Reg3'',''Oras2'',''Str1'',5,5003,''-'',''-'')');

/*Ex. 9(3A) TESTARE pentru pic.pers */ SELECT * FROM pic.pers;SELECT * FROM pic.pers ORDER BY adresa;--echivalent cuSELECT * FROM pic.pers ORDER BY (adresa).tara,(adresa).regiune,(adresa).oras,(adresa).str,(adresa).nr,(adresa).tel,(adresa).e_mail;

/*Ex. 9(3A) TESTARE pentru pic.pers */ SELECT * FROM pic.pers;SELECT * FROM pic.pers ORDER BY adresa;--echivalent cuSELECT * FROM pic.pers ORDER BY (adresa).tara,(adresa).regiune,(adresa).oras,(adresa).str,(adresa).nr,(adresa).tel,(adresa).e_mail;

/*Ex. 9(4A) TESTARE pentru pic.pers */ SELECT * FROM pic.pers WHERE (adresa).oras ILIKE '%bv%'; --sauSELECT * FROM pic.pers WHERE adresa = '(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'::adresa01;SELECT * FROM pic.pers WHERE adresa < '(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'::adresa01;

/*Ex. 9(4A) TESTARE pentru pic.pers */ SELECT * FROM pic.pers WHERE (adresa).oras ILIKE '%bv%'; --sauSELECT * FROM pic.pers WHERE adresa = '(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'::adresa01;SELECT * FROM pic.pers WHERE adresa < '(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'::adresa01;

Page 69: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

a) întoarce valoarea de adevăr TRUE dacă cele două adrese sunt din aceeaşi ţară:

b) întoarce valoarea de adevăr TRUE dacă cele două adrese sunt din acelaşi oraş:

c) întoarce valoarea de adevăr TRUE dacă cele două adrese sunt pe aceeaşi stradă:

d) întoarce valoarea de adevăr TRUE dacă cele două adrese sunt identice:

e) este definit operatorul „mai mic” între două date de tip adresa01 în scopul ordonării alfanumerice:

f) este definit operatorul „mai mare” între două date de tip adresa01 în scopul ordonării alfanumerice:

68

/*Ex. 9(1D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_niv_tara(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara = $2.tara OR $1.cod_postal=$2.cod_postal THEN RETURN TRUE; END IF; RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex. 9(1D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_niv_tara(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara = $2.tara OR $1.cod_postal=$2.cod_postal THEN RETURN TRUE; END IF; RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex. 9(2D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_niv_oras(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF ($1.tara = $2.tara AND $1.oras=$2.oras) OR $1.cod_postal=$2.cod_postal THEN RETURN TRUE; END IF;RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex. 9(2D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_niv_oras(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF ($1.tara = $2.tara AND $1.oras=$2.oras) OR $1.cod_postal=$2.cod_postal THEN RETURN TRUE; END IF;RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex. 9(3D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_niv_str(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF ($1.tara = $2.tara AND $1.oras=$2.oras AND $1.str=$2.str) OR $1.cod_postal=$2.cod_postal THEN RETURN TRUE;END IF;RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex. 9(3D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_niv_str(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF ($1.tara = $2.tara AND $1.oras=$2.oras AND $1.str=$2.str) OR $1.cod_postal=$2.cod_postal THEN RETURN TRUE;END IF;RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex. 9(4D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_identice(_a_ adresa01, _b_ adresa01) RETURNS boolean AS $BODY$ BEGIN IF ($1.tara = $2.tara AND $1.oras=$2.oras AND $1.str=$2.str AND $1.nr=$2.nr) OR ($1.cod_postal=$2.cod_postal AND $1.nr=$2.nr) THEN RETURN TRUE; END IF; RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex. 9(4D):*/ CREATE OR REPLACE FUNCTION pic.op_egal_identice(_a_ adresa01, _b_ adresa01) RETURNS boolean AS $BODY$ BEGIN IF ($1.tara = $2.tara AND $1.oras=$2.oras AND $1.str=$2.str AND $1.nr=$2.nr) OR ($1.cod_postal=$2.cod_postal AND $1.nr=$2.nr) THEN RETURN TRUE; END IF; RETURN FALSE; END $BODY$ LANGUAGE 'plpgsql';

/*Ex 9(5D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mic(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara < $2.tara THEN RETURN TRUE; END IF;IF $1.tara=$2.tara THEN if $1.oras<$2.oras then return TRUE;end if; END IF;IF $1.tara = $2.tara and $1.oras=$2.oras THEN if $1.str < $2.str then return TRUE; end if; END IF;IF $1.tara = $2.tara and $1.oras=$2.oras and $1.str=$2.str THEN if $1.nr < $2.nr then return TRUE; end if; END IF;RETURN FALSE;END $BODY$ LANGUAGE plpgsql;

/*Ex 9(5D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mic(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara < $2.tara THEN RETURN TRUE; END IF;IF $1.tara=$2.tara THEN if $1.oras<$2.oras then return TRUE;end if; END IF;IF $1.tara = $2.tara and $1.oras=$2.oras THEN if $1.str < $2.str then return TRUE; end if; END IF;IF $1.tara = $2.tara and $1.oras=$2.oras and $1.str=$2.str THEN if $1.nr < $2.nr then return TRUE; end if; END IF;RETURN FALSE;END $BODY$ LANGUAGE plpgsql;

Page 70: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

9.Definirea de noi tipuri de date şi supraîncărcarea operatorilor SQL

g) este definit operatorul “mai mic sau egal” între două date de tip adresa01 în scopul ordonării alfanumerice:

h) este definit operatorul “mai mare sau egal” între două date de tip adresa01 în scopul ordonării alfanumerice:

i) operatorul de indexare (implicit, pentru indexare, SGBD-ul utilizează o tehnică ce utililizează arbori binari – btree)

69

/*Ex. 9(7D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mic_egal(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara <= $2.tara THEN RETURN TRUE; END IF;IF $1.tara=$2.tara THEN if $1.oras<=$2.oras then RETURN TRUE;end if;END IF;IF $1.tara = $2.tara and $1.oras = $2.oras THEN IF $1.str <= $2.str THEN RETURN TRUE; END IF; END IF;IF $1.tara = $2.tara and $1.oras=$2.oras and $1.str=$2.str THEN IF $1.nr <= $2.nr THEN RETURN TRUE; END IF; END IF;RETURN FALSE; END $BODY$ LANGUAGE plpgsql;

/*Ex. 9(7D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mic_egal(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara <= $2.tara THEN RETURN TRUE; END IF;IF $1.tara=$2.tara THEN if $1.oras<=$2.oras then RETURN TRUE;end if;END IF;IF $1.tara = $2.tara and $1.oras = $2.oras THEN IF $1.str <= $2.str THEN RETURN TRUE; END IF; END IF;IF $1.tara = $2.tara and $1.oras=$2.oras and $1.str=$2.str THEN IF $1.nr <= $2.nr THEN RETURN TRUE; END IF; END IF;RETURN FALSE; END $BODY$ LANGUAGE plpgsql;

/*Ex 9(8D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mare_egal(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara >= $2.tara THEN RETURN TRUE; END IF;IF $1.tara=$2.tara THEN if $1.oras>=$2.oras then RETURN TRUE;end if; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras THEN IF $1.str >= $2.str THEN RETURN TRUE; END IF; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras and $1.str = $2.str THEN IF $1.nr >= $2.nr THEN RETURN TRUE; END IF; END IF;RETURN FALSE; END $BODY$ LANGUAGE plpgsql;

/*Ex 9(8D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mare_egal(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara >= $2.tara THEN RETURN TRUE; END IF;IF $1.tara=$2.tara THEN if $1.oras>=$2.oras then RETURN TRUE;end if; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras THEN IF $1.str >= $2.str THEN RETURN TRUE; END IF; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras and $1.str = $2.str THEN IF $1.nr >= $2.nr THEN RETURN TRUE; END IF; END IF;RETURN FALSE; END $BODY$ LANGUAGE plpgsql;

/*Ex. 9(6D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mare(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara > $2.tara THEN RETURN TRUE;END IF;IF $1.tara=$2.tara THEN if $1.oras>$2.oras then return TRUE;end if; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras THEN IF $1.str > $2.str THEN RETURN TRUE; END IF; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras and $1.st r= $2.str THEN IF $1.nr > $2.nr THEN RETURN TRUE; END IF; END IF;RETURN FALSE;END $BODY$ LANGUAGE plpgsql;

/*Ex. 9(6D):*/ CREATE OR REPLACE FUNCTION pic.op_mai_mare(_a_ adresa01, _b_ adresa01) RETURNS boolean AS$BODY$ BEGIN IF $1.tara > $2.tara THEN RETURN TRUE;END IF;IF $1.tara=$2.tara THEN if $1.oras>$2.oras then return TRUE;end if; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras THEN IF $1.str > $2.str THEN RETURN TRUE; END IF; END IF;IF $1.tara = $2.tara and $1.oras = $2.oras and $1.st r= $2.str THEN IF $1.nr > $2.nr THEN RETURN TRUE; END IF; END IF;RETURN FALSE;END $BODY$ LANGUAGE plpgsql;

Page 71: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

Funcţia operator de indexare întoarce valorile -1, +1 sau 0, în funcţie de egalitate. Urmează etapa în care asignăm simboluri de operatori SQL cu funcţiile operator definite mai sus. Astfel sunt definiţi operatorii:

Următoarea etapă constă în crearea clasei de operatori pentru funcţia de indexare.

Urmează etapa de testare:

70

/*Ex. 9(9D): */ CREATE OR REPLACE FUNCTION pic.op_btree(_a_ adresa01, _b_ adresa01) RETURNS integer AS $BODY$ BEGINIF $1.tara < $2.tara OR ($1.tara = $2.tara and $1.oras < $2.oras) OR ($1.tara=$2.tara and $1.oras=$2.oras and $1.str<$2.str) OR ($1.tara=$2.tara and $1.oras=$2.oras and $1.str=$2.str and $1.nr<$2.nr) THEN RETURN -1; END IF; IF $1.tara > $2.tara OR ($1.tara = $2.tara and $1.oras > $2.oras) OR ($1.tara = $2.tara and $1.oras = $2.oras and $1.str > $2.str) OR ($1.tara=$2.tara and $1.oras=$2.oras and $1.str=$2.str AND $1.nr>$2.nr) THEN RETURN 1; END IF; RETURN 0; END; $BODY$ LANGUAGE plpgsql ;

/*Ex. 9(9D): */ CREATE OR REPLACE FUNCTION pic.op_btree(_a_ adresa01, _b_ adresa01) RETURNS integer AS $BODY$ BEGINIF $1.tara < $2.tara OR ($1.tara = $2.tara and $1.oras < $2.oras) OR ($1.tara=$2.tara and $1.oras=$2.oras and $1.str<$2.str) OR ($1.tara=$2.tara and $1.oras=$2.oras and $1.str=$2.str and $1.nr<$2.nr) THEN RETURN -1; END IF; IF $1.tara > $2.tara OR ($1.tara = $2.tara and $1.oras > $2.oras) OR ($1.tara = $2.tara and $1.oras = $2.oras and $1.str > $2.str) OR ($1.tara=$2.tara and $1.oras=$2.oras and $1.str=$2.str AND $1.nr>$2.nr) THEN RETURN 1; END IF; RETURN 0; END; $BODY$ LANGUAGE plpgsql ;

/*Ex. 9(3L):*/ CREATE OPERATOR ====( PROCEDURE = pic.op_egal_niv_str, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(3L):*/ CREATE OPERATOR ====( PROCEDURE = pic.op_egal_niv_str, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(4L):*/ CREATE OPERATOR ===*(PROCEDURE = pic.op_egal_identice, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(4L):*/ CREATE OPERATOR ===*(PROCEDURE = pic.op_egal_identice, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(5L):*/ CREATE OPERATOR <(PROCEDURE = pic.op_mai_mic, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(5L):*/ CREATE OPERATOR <(PROCEDURE = pic.op_mai_mic, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(6L):*/ CREATE OPERATOR <=( PROCEDURE = pic.op_mai_mic_egal, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(6L):*/ CREATE OPERATOR <=( PROCEDURE = pic.op_mai_mic_egal, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(7L):*/ CREATE OPERATOR >( PROCEDURE = pic.op_mai_mare, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(7L):*/ CREATE OPERATOR >( PROCEDURE = pic.op_mai_mare, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(8L):*/ CREATE OPERATOR >=( PROCEDURE = pic.op_mai_mare_egal, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(8L):*/ CREATE OPERATOR >=( PROCEDURE = pic.op_mai_mare_egal, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(9L):*/ CREATE OPERATOR CLASS adresa01_operatii DEFAULT FOR TYPE adresa01 USING btree AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 ===*, OPERATOR 4 >=, OPERATOR 5 >, FUNCTION 1 pic.op_btree(adresa01, adresa01);

/*Ex. 9(9L):*/ CREATE OPERATOR CLASS adresa01_operatii DEFAULT FOR TYPE adresa01 USING btree AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 ===*, OPERATOR 4 >=, OPERATOR 5 >, FUNCTION 1 pic.op_btree(adresa01, adresa01);

/*Ex. 7(10L)*/CREATE OPERATOR FAMILY adresa01_operatii USING btree;/*Ex. 7(10L)*/CREATE OPERATOR FAMILY adresa01_operatii USING btree;

/*Ex. 9(1L):*/ CREATE OPERATOR ==( PROCEDURE = pic.op_egal_niv_tara, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(1L):*/ CREATE OPERATOR ==( PROCEDURE = pic.op_egal_niv_tara, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(2L):*/ CREATE OPERATOR ===( PROCEDURE = pic.op_egal_niv_oras, LEFTARG = adresa01, RIGHTARG = adresa01);

/*Ex. 9(2L):*/ CREATE OPERATOR ===( PROCEDURE = pic.op_egal_niv_oras, LEFTARG = adresa01, RIGHTARG = adresa01);

Page 72: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

9.Definirea de noi tipuri de date şi supraîncărcarea operatorilor SQL

În exemplul de mai sus, în prima interogare s-a testat operatorul == (egalitate la nivel de ţară), interogarea trebuie să întoarcă toate înregistrările pentru 'Tara2'. În a doua interogare este testat operatorul de indexare prin utilizarea ordonării.

Pentru a testa intrarea în funcţia de indexare, se poate introduce o notificare sau se poate simula o eroare în această funcţie. De asemenea, se poate testa operatorul de indexare prin utilizarea câmpului de tip adresa01 în construcţia pentru PRIMARY KEY.

Înregistrările 2 şi 3 sunt identice, ceea ce va genera o eroare în funcţia btree().

10. Teste rezolvate

10.1. Funcţie pentru contorizarea timpilor de parcare

Se dă un tabel cu structura: “data de intrare”, ”ora de intrare (tip time)”, “nr. înmatriculare”, “data de ieşire”, “ora de ieşire”. Să se scrie o funcţie care adaugă o înregistrare în momentul unei intrări în parcare şi care în momentul ieşirii întoarce timpul de staţionare.

Verificăm dacă maşina cu numărul de înmatriculare transmis prin argument există în parcare. Dacă nu există, adăugăm o înregistrare în tabel, altfel actualizăm înregistrarea cu acel număr de înmatriculare cu data şi ora curentă. Calculăm diferenţa între cele două momente şi întoarcem valoarea de tip interval.

71

/*Ex. 9(5A) TESTARE pentru tipul adresa01 */ SELECT * FROM pic.pers WHERE adresa == '(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'::adresa01; –- pentru verificarea operatorului de indexare realizăm o ordonareSELECT * FROM pic.pers ORDER BY adresa;

/*Ex. 9(5A) TESTARE pentru tipul adresa01 */ SELECT * FROM pic.pers WHERE adresa == '(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'::adresa01; –- pentru verificarea operatorului de indexare realizăm o ordonareSELECT * FROM pic.pers ORDER BY adresa;

/*Ex. 9(7A)TESTARE pentru adresa01 */ INSERT INTO pic.pers2(nume,adresa) VALUES('Nume5','(''Tara1'',''Reg3'',''Oras4'',''Str1'',5,5005,''-'',''-'')'),('Nume3','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'),('Nume3','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'),('Nume8','(''Tara1'',''Reg3'',''Oras2'',''Str1'',5,5003,''-'',''-'')');

/*Ex. 9(7A)TESTARE pentru adresa01 */ INSERT INTO pic.pers2(nume,adresa) VALUES('Nume5','(''Tara1'',''Reg3'',''Oras4'',''Str1'',5,5005,''-'',''-'')'),('Nume3','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'),('Nume3','(''Tara2'',''Reg4'',''Oras3'',''Str1'',5,5006,''-'',''-'')'),('Nume8','(''Tara1'',''Reg3'',''Oras2'',''Str1'',5,5003,''-'',''-'')');

/*Ex. 9(6A)TESTARE pentru adresa01 */ DROP TABLE IF EXISTS pic.pers2; CREATE TABLE pic.pers2(nume varchar(40),adresa adresa01 PRIMARY KEY);

/*Ex. 9(6A)TESTARE pentru adresa01 */ DROP TABLE IF EXISTS pic.pers2; CREATE TABLE pic.pers2(nume varchar(40),adresa adresa01 PRIMARY KEY);

DROP TABLE IF EXISTS pic.parc; CREATE TABLE pic.parc(datain date,orain time, nr_inmatr varchar(20), dataout date, oraout time);

DROP TABLE IF EXISTS pic.parc; CREATE TABLE pic.parc(datain date,orain time, nr_inmatr varchar(20), dataout date, oraout time);

Page 73: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

III.Programarea la nivel de server – plpgSQL

Întodeauna trecem argumentele implicite (cu DEFAULT) după cele obligatorii.

10.2. Calculul debitelor medii zilnice

Se realizează citiri ale unui contor de fluid la intervale aleatoare. Se notează valoarea contorului şi momentul citirii. Să se scrie o funcţie ce calculează debitele medii zilnice (de la ora 6:00 ziua curentă până a doua zi la ora 6:00).

Variabila de tip înregistrare r1 reprezintă ultima înregistrare cu data de ieri, iar q reprezintă debitul mediu orar la nivelul unei zile:

72

CREATE OR REPLACE FUNCTION pic.parcare(_nr_inmatr_ text,_data_ date DEFAULT CURRENT_DATE, _ora_ time DEFAULT CURRENT_TIME)RETURNS interval AS $$ DECLARE f boolean; dif interval;BEGIN --verificăm dacă există deja maşina în parcareSELECT EXISTS(SELECT * FROM pic.parc WHERE nr_inmatr = _nr_inmatr_ AND dataout IS NULL) INTO f;IF NOT f THEN INSERT INTO pic.parc(datain,orain,nr_inmatr) VALUES (_data_,_ora_,_nr_inmatr_);RETURN '0'::interval; END IF;--intrare nouăUPDATE pic.parc SET dataout = _data_, oraout = _ora_ WHERE nr_inmatr = _nr_inmatr_ AND dataout IS NULL;SELECT dataout + oraout - datain - orain FROM pic.parc WHERE nr_inmatr = _nr_inmatr_ AND dataout = _data_ AND oraout = _ora_ INTO dif; RETURN dif; END; $$ LANGUAGE 'plpgsql';

CREATE OR REPLACE FUNCTION pic.parcare(_nr_inmatr_ text,_data_ date DEFAULT CURRENT_DATE, _ora_ time DEFAULT CURRENT_TIME)RETURNS interval AS $$ DECLARE f boolean; dif interval;BEGIN --verificăm dacă există deja maşina în parcareSELECT EXISTS(SELECT * FROM pic.parc WHERE nr_inmatr = _nr_inmatr_ AND dataout IS NULL) INTO f;IF NOT f THEN INSERT INTO pic.parc(datain,orain,nr_inmatr) VALUES (_data_,_ora_,_nr_inmatr_);RETURN '0'::interval; END IF;--intrare nouăUPDATE pic.parc SET dataout = _data_, oraout = _ora_ WHERE nr_inmatr = _nr_inmatr_ AND dataout IS NULL;SELECT dataout + oraout - datain - orain FROM pic.parc WHERE nr_inmatr = _nr_inmatr_ AND dataout = _data_ AND oraout = _ora_ INTO dif; RETURN dif; END; $$ LANGUAGE 'plpgsql';

SELECT pic.parcare('BC-45-AAA'); SELECT * from pic.parc; SELECT pic.parcare('BC-45-AAA'); SELECT * from pic.parc;

SELECT pic.parcare('BC-45-AAA'); SELECT * from pic.parc; SELECT pic.parcare('BC-45-AAA'); SELECT * from pic.parc;

DROP TABLE IF EXISTS pic.d1; CREATE table pic.d1(datam date, ora int, val_contor numeric, CONSTRAINT k_d1 PRIMARY KEY(datam, ora)); INSERT INTO pic.d1 VALUES ('2000-01-01',6,8), ('2000-01-01',14,12),('2000-01-01',22,16), ('2000-01-02',6,24), ('2000-01-02',14,26),('2000-01-02',22,32), ('2000-01-03',6,44), ('2000-01-03',14,90),('2000-01-03',22,120), ('2000-01-04',6,122), ('2000-01-04',14,129),('2000-01-04',22,135); select * from pic.d1;

DROP TABLE IF EXISTS pic.d1; CREATE table pic.d1(datam date, ora int, val_contor numeric, CONSTRAINT k_d1 PRIMARY KEY(datam, ora)); INSERT INTO pic.d1 VALUES ('2000-01-01',6,8), ('2000-01-01',14,12),('2000-01-01',22,16), ('2000-01-02',6,24), ('2000-01-02',14,26),('2000-01-02',22,32), ('2000-01-03',6,44), ('2000-01-03',14,90),('2000-01-03',22,120), ('2000-01-04',6,122), ('2000-01-04',14,129),('2000-01-04',22,135); select * from pic.d1;

CREATE OR REPLACE FUNCTION pic.debit_m() RETURNS SETOF RECORD AS$$ DECLARE r RECORD;r1 RECORD; k int;BEGIN k:=0;FOR r IN SELECT datam, ora, val ,0.001 as q FROM pic.d1 LOOP IF r.ora=6 and k>1 THEN k:=k+1;r.q:=(r.val-r1.val)/24.0; r1:=r; return next r; END IF; IF r.ora = 6 and k = 1 THEN k:=k+1; r1.q:=r1.val/24.0; r.q:=(r.val-r1.val)/24.0; return next r1; r1:=r; return next r; END IF; IF r.ora=6 and k=0 THEN k:=k+1; r1:=r; END IF; END LOOP; END $$ language plpgsql;

CREATE OR REPLACE FUNCTION pic.debit_m() RETURNS SETOF RECORD AS$$ DECLARE r RECORD;r1 RECORD; k int;BEGIN k:=0;FOR r IN SELECT datam, ora, val ,0.001 as q FROM pic.d1 LOOP IF r.ora=6 and k>1 THEN k:=k+1;r.q:=(r.val-r1.val)/24.0; r1:=r; return next r; END IF; IF r.ora = 6 and k = 1 THEN k:=k+1; r1.q:=r1.val/24.0; r.q:=(r.val-r1.val)/24.0; return next r1; r1:=r; return next r; END IF; IF r.ora=6 and k=0 THEN k:=k+1; r1:=r; END IF; END LOOP; END $$ language plpgsql;

SELECT datam, ora, val, q FROM pic.debit_m() AS (datam date, ora int, val numeric,q numeric);

SELECT datam, ora, val, q FROM pic.debit_m() AS (datam date, ora int, val numeric,q numeric);

Page 74: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

IV. Introducere în limbajul CNotă: Pentru o mai bună înţelegere, recomand testarea exemplelor din dreptunghiurile cu linie continuă şi colţuri rotunjite. După testare se vor modifica valorile variabilelor şi se va urmări rezultatul. În final se va încerca rescrierea liniilor pentru a obţine acelaşi rezultat sau rezultate asemănătoare pentru alte condiţii sau alte valori ale variabilelor. Se va crea iniţial un workspace, apoi se va crea câte un proiect (de exemplu, în codeLite) cu opţiunea de lucru în consolă. Codul din fişierul iniţial creat pe post de şablon va fi înlocuit cu codul din dreptunghi. Fiecare proiect se va compila şi rula (Ctrl+F9). Recomand studierea individuală a lucrului cu debuger-ul pentru o înţelegere mai aprofundată. În loc de /*\n*/ se va adăuga linie nouă.

1. Organizarea programelor

La baza oricărei aplicaţii software sau pentru cazurile simple stă un algoritm (metodă de rezolvare). Acesta preia date din memoria dinamică a calculatorului (RAM) sau de pe suporturi de stocare şi le prelucrează. Rezultatul prelucrării (a execuţiei algoritmilor) este stocat în memoria dinamică şi apoi poate fi afişat, memorat pe suporturi de stocare a datelor, sau transmis către alte aplicaţii software.

Codul sursă se scrie cu ajutorul unui editor de texte, acest editor poate fi unul simplu gen notepad, notepad++, getit sau unul specializat, înglobat într-un mediu integrat de dezvoltare pentru software-uri (ex.: TuboC++, BorlandC++, C++Builder, VisualC++, SymantecC++, DevC++, CodeLite, NetBean, EclipseC++, gt++, gtk++ etc.).Compilatorul transformă codul sursă în cod obiect, altfel spus: transformă textul literar în cod maşină – reprezentat de comenzi la nivel de microprocesor).

Figura IV-1: Etapele pentru obţinerea unei aplicaţii software

În cadrul codului sursă se pot utiliza rutine (proceduri/funcţii) definite în cadrul unor biblioteci statice

73

Cod sursă(*.c,*.cpp)

Cod obiect(*.obj/*.o)

Executabil / bibliotecă(*.exe,aplicaţie,*.dll,*.lib,*.so,*.a,…)

Compilator

Editor de text

Compilare

Editare

Programator

Linkeditare

Link-editor

Biblioteci statice(*.lib/*.a)

Linkeditare

Page 75: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

(*.lib – library sau *.a – archive), caz în care codul utilizat din bibliotecile statice este încorporat în executabil.

Codul bibliotecilor dinamice (*.dll – dynamic link library sau *.so – shared objects) este doar apelat în momentul execuţiei sau al lansării aplicaţiei (diferenţele apar pentru Linux), acesta nefiind inclus în fişierul executabil sau în biblioteca rezultată.

1.1. Structura unui program în limbajul C/C++

Un program C/C++ cuprinde următoarele elemente pricipale:✗ operatori (aritmetici, logici etc.);✗ instrucţiuni (de decizie, de parcurgere a unei bucle etc.);✗ funcţii (apelate din cadrul bibliotecilor sau definite de

utilizator);✗ variabile şi constante;✗ funcţia main().

Textul unui program poate fi scris într-un fişier sau în mai multe fişiere. Un program va avea o singură funcţie main(), indiferent dacă este scris într-un singur fişier sau în mai multe fişiere. Programul compilat şi linkeditat va începe întodeauna prin lansarea în execuţie a instrucţiunilor şi funcţiilor din cadrul lui main(). Prin ieşirea din funcţia main() se încheie şi execuţia programului.

Comentariile sunt reprezentate prin simbolurile: /*comentariu la nivel de bloc*/ iar //comentariu la nivel de linie.

2. Variabile, alocări, tipuri de date, operatori C/C++

2.1. Noţiunile de variabilă şi constantă

Datele din cadrul unui program sunt stocate în memoria dinamică (RAM), ele vor fi marcate ca fiind şterse fie la un anumit moment în timpul execuţiei programului, fie la sfârşitul acestuia. VARIABILE pot fi reprezentate prin date ce urmează a se modifica în cadrul programului în urma execuţiei unor operaţii asupra acestora. Există şi date care rămân constante în urma execuţiei programului – denumite CONSTANTE.

Pentru ca aceste date să poată fi accesate, este necesară declararea acestora în cadrul programului. O variabilă va avea o denumire, pe care o va pune utilizatorul în momentul declarării acestora. De regulă, dimensiunea maximă a denumirii unei variabile este de 32 de caractere, poate conţine atât litere cât şi cifre (denumirea începe cu o literă sau cu simbolul underline, adică “_”)

Operaţiile din cadrul unui program se realizează asupra variabilelor. Fiecare variabilă va avea o anumită structură în ceea ce priveşte reprezentarea sa în memorie (aceasta dă tipul de

74

Page 76: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Variabile, alocări, tipuri de date, operatori C/C++

variabilă). În funcţie de reprezentarea în cadrul memoriei, variabilele pot fi de mai multe tipuri. Acestea trebuie declarate înainte de compilarea programului astfel încât compilatorul să le rezerve memorie în momentul încărcării executabilului în memorie.

Variabilele la nivelul unui bloc de instrucţiuni trebuie să aibă nume diferite.

2.2. Tipuri de alocare a variabilelor

Variabilele pot fi locale (declarate în cadrul funcţiilor) sau globale (declarate în afara funcţiilor). La nivelul unui bloc de instrucţiuni, o variabilă poate fi declarată în orice punct al acestuia (facilitatea provine din C++), dar aceasta poate fi utilizată doar în instrucţiunile situate după declararea acesteia. Mulţi programatori declară variabilele la începutul blocului de instrucţiuni sau a funcţiei (C standard).

2.2.1. Alocarea de tip automatic

Memoria RAM necesară datelor este rezervată în momentul întâlnirii declaraţiei. De exemplu, declaraţia long a; rezervă pentru variabila a 32 de biţi (4 octeţi). Memoria este eliberată automat în momentul în care se închide blocul în care a fost declarată variabila (adică se închide acolada “}”).

2.2.2. Alocarea de tip static

Alocarea de tip static presupune că variabila este alocată de program în momentul declarării acesteia şi nu va fi ştearsă din memorie decât în momentul terminării programului. Acestea sunt tratate detaliat în capitolul despre vizibilitatea variabilelor.

2.2.3. Alocarea de tip dinamic

Alocarea dinamică presupune că variabila respectivă este declarată de tip pointer în punctul respectiv al programului. În acest caz, în momentul în care programul ajunge cu execuţia în acel punct rezervă memorie doar pentru adresa unde se găsesc datele şi NU pentru date. Pentru date se va aloca memorie printr-o funcţie din biblioteca C (ex. funcţia malloc). Memoria astfel alocată va necesita dealocare (eliberare) printr-o altă funcţie specializată (ex.: free) în momentul în care aceste date nu mai sunt necesare.

2.3. Tipuri de variabile

Principalele tipuri de variabile sunt prezentate în anexă. În momentul compilării programului, este cunoscut tipul

variabilelor. În acest mod programul „știe” cât ocupă în memorie fiecare variabilă și cum să „utilizeze” variabila respectivă.

75

Page 77: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Consider că înţelegerea corectă a variabilelor reprezintă jumătate din efortul de înţelegere a programării.

2.4. Operatorii C/C++

Operatorii sunt descrişi în anexă. În continuare este prezentat un exemplu de interschimbare a două variabile fără utilizarea unei variabile auxiliare. În acest sens, s-a utilizat operatorul ^ (sau exclusiv / XOR) la nivel de bit.

Un alt exemplu de lucru cu operatori binari constă în extragerea informaţiei reprezentate pe biţii 16,15,14 (numerotaţi de la dreapta la stânga începând cu 1) dintr-un număr reprezentat pe 32 de biţi.

Cei trei biţi din variabila masca reprezintă biţii a căror informaţie (dacă sunt 0 sau 1) este extrasă. Se realizează o operaţie şi/AND (&) la nivel de bit între mască şi numărul de analizat. După această operaţie se execută o deplasare (şiftare) la dreapta cu 13 biţi astfel încât bit-ul 14 să devină primul bit din stânga apoi se citeşte numărul rezultat. Notă: Informaţia din număr se completează la stânga cu zero până la reprezentarea numărului.

76

/*Ex.3.1(1) utilizare “SAU EXCLUSIV” (XOR)*/#include <stdio.h> int main() { short a = 5, b = 10; printf("Inainte --- a:%d b:%d \n”,a,b); a=a^b; //(1111)

2=(0101)

2^(1010)

2, adica 7=5^10;

b=a^b; //(0101)2=(1111)

2^(1010)

2, adica 5=15^10;

a=a^b; //(1010)2=(1111)

2^(0101)

2, adica 10=15^5;

printf("Dupa --- a:%d b:%d \n”,a,b); }

/*Ex.3.1(1) utilizare “SAU EXCLUSIV” (XOR)*/#include <stdio.h> int main() { short a = 5, b = 10; printf("Inainte --- a:%d b:%d \n”,a,b); a=a^b; //(1111)

2=(0101)

2^(1010)

2, adica 7=5^10;

b=a^b; //(0101)2=(1111)

2^(1010)

2, adica 5=15^10;

a=a^b; //(1010)2=(1111)

2^(0101)

2, adica 10=15^5;

printf("Dupa --- a:%d b:%d \n”,a,b); }

/*Ex.3.1(2) extragere informaţii dintr-un număr*/#include <stdio.h>int main(){ unsigned long a = 0x5B5F0;//declarare urmată de atribuire // a=(1001 1011 1001 1111 0000)

2

unsigned long masca = 0xE000;// masca=(1110 0000 0000 0000)2

unsigned long s; s = a & masca; //s=(0000 1010 0000 0000 0000)

2 Ξ s=0xA000

s >>= 13; //deplasare la dreapta cu 13 biţi urmată de atribuire printf(“X=%x\n”,s); //s=(0000 0000 0000 0000 0101)

2 adică s=0x0005

return 0; }

/*Ex.3.1(2) extragere informaţii dintr-un număr*/#include <stdio.h>int main(){ unsigned long a = 0x5B5F0;//declarare urmată de atribuire // a=(1001 1011 1001 1111 0000)

2

unsigned long masca = 0xE000;// masca=(1110 0000 0000 0000)2

unsigned long s; s = a & masca; //s=(0000 1010 0000 0000 0000)

2 Ξ s=0xA000

s >>= 13; //deplasare la dreapta cu 13 biţi urmată de atribuire printf(“X=%x\n”,s); //s=(0000 0000 0000 0000 0101)

2 adică s=0x0005

return 0; }

Page 78: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Variabile, alocări, tipuri de date, operatori C/C++

2.5. Teste

Scrieţi ce se afişează în urma execuţiei următoarelor instrucţiuni (liniile sunt independente), iar în cazul existenţei unor erori să se semnalezeze erorile apărute în urma execuţiei şi sursa acestora:1. int a = 19; (a %= +3)++; printf(“a=%d”,a);2. int a = 19; (a%= -3)--; printf(“a=%d”,a);3. int a = 33; a>>=2;printf(“%d”,a);4. int a = 10,b; b = (a | 15) & (a ^ 12); printf(“%d”,b); 5. int a = 11, b, c, d; b = (a ^ 11) & (a | 22); c= a ^ 11; d=a | 22;

printf(“b=%d c=%d d=%d”,b,c,d);6. int a,b = 13; a=(--b)++; printf(“a=%d”,a); 7. int a = 15,b=2;if((a>1)&&(b>=3)) a <<= b; else a >>= b; printf(“a=%d”,a); 8. int a = 13,b; b = (a ^ 5) & (a | 2); printf(“b=%d”,b);9 int a = 10; a >>= 2; printf(“a=%d”,a); 10.int a = 10, b, c, d; b=(a^10)&(a|11); c= a^10; d=a|2;

printf(“b=%d c=%d d=%d”,b,c,d);

3. Implementarea structurilor de control

Algoritmul proiectat pentru rezolvarea unei anumite probleme trebuie implementat în limbajul de programare, iar prelucrarea datelor se realizează cu ajutorul instrucţiunilor. Instrucţiunea este transformată de compilator într-o secvenţă cod maşină, pe care o execută microprocesorul cu scopul implementării instrucţiunii respective. O instrucţiune este o construcţie validă (care respectă sintaxa limbajului) urmată de „ ; ” (semicolon).

Un algoritm poate fi realizat prin combinarea a trei structuri fundamentale:

➔ structura secvenţială;➔ structura alternativă (de decizie, de selecţie);➔ structura repetitivă (ciclică).

3.1. Implementarea structurii secvenţiale

Structura secvenţială este o înşiruire de instrucţiuni, plasate una după alta, în ordinea execuţiei acestora.

Pseudocodul:

Implementarea structurii secvenţiale se realizează cu ajutorul instrucţiunilor:

3.1.1. Instrucţiunea vidă

Sintaxa: ;

77

I 1 I 2 I n

instr1; instr2;........; instr n;instr1; instr2;........; instr n;

Page 79: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Descriere: Instrucţiunea vidă nu are niciun efect. Se utilizează în construcţii în care se cere prezenţa unei instrucţiuni, dar nu se execută nimic.

3.1.2. Instrucţiunea expresie

Sintaxa: expresie;sau: apel_funcţie;Ex.: sqrt() este o funcţie definită

în biblioteca matematică

3.1.3. Instrucţiunea compusă (instrucţiunea bloc)

Sintaxa:

Într-un bloc de instrucţiuni se pot declara variabile care pot fi accesate doar în corpul blocului. Instrucţiunea bloc este utilizată în locurile în care este necesară prezenţa unei singure instrucţiuni, însă procesul de calcul implică executarea mai multor instrucţiuni.

3.2. Implementarea structurii de decizie (alternative, de selecţie)

3.2.1. Instrucţiunea if

Sintaxa:

unde [ ...] semnifică faptul că este opţional. Ramura else este opţională.

La întâlnirea instrucţiunii if, se evaluează <expresie>. Dacă valoarea expresiei are valoarea de adevăr TRUE (≠0), se execută instrucţiunea #1 (instr#1); dacă valoarea expresiei este FALSE (=0), se execută instrucţiunea #2 (instr#2). Se execută doar una dintre cele două instrucţiuni: fie instr#1, fie instr#2. După execuţia instrucţiunii if, se trece la execuţia instrucţiunii care urmează acesteia.

Instrucţiunile instr#1 şi instr#2 pot fi instrucţiuni compuse (blocuri), sau chiar alte instrucţiuni if (if-uri imbricate).

78

int a=3,b=4, c;double d;c=a+b;d=sqrt(b);

int a=3,b=4, c;double d;c=a+b;d=sqrt(b);

{ declaraţii variabile; instr1; instr2;........; instr n;}

{ declaraţii variabile; instr1; instr2;........; instr n;}

if(<expresie>) instr1; [else instr2;]

if(<expresie>) instr1; [else instr2;]

Figura IV-2: Instrucţiunea if

if (<expresie>)TRUE FALSE

instr.1 instr.2

Page 80: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Implementarea structurilor de control

Variabilele a şi b se citesc de la tastatură cu ajutorul funcţiei scanf, unde %d specifică formatul datei de tip întreg, iar operatorul & semnifică adresa variabilei.

3.2.2. Instrucţiunea switch

În unele cazuri este necesară o decizie multiplă specială. Instrucţiunea switch permite acest lucru.

Se testează dacă valoarea pentru expresie este una dintre constantele specificate (expresie_const_1, expresie_const_2, etc.) şi se execută instrucţiunea de pe ramura corespunzătoare. În schema logică test_expresie este una din condiţiile:expresie=expresie_const_1, expresie=expresie_const_2 etc. Este evaluată <expresie> (expresie aritmetică), iar valoarea ei este comparată cu valoarea expresiilor constante 1, 2, n etc. (expresii constante = expresii care nu conţin variabile). Se execută instrucţiunea corespunzătoare acelei ramuri (instrucţiune_ k), unde expresie_const_k este egală cu rezultatul evaluării <expresie>.

Dacă se întâlneşte in-strucţiunea break, parcurgerea este întreruptă şi se va ieşi din blocul dat de switch. Dacă nu este întâlnită instrucţiunea break, se parcurge şi instrucţiunea următoare. În cazul în care valoarea expresiei nu este găsită printre valorile expresiilor constante, se execută cazul marcat cu eticheta default (opţională). Expresia <expresie>, trebuie să aibă ca rezultat o valoare de tip întreg. În cazul în care sunt de alt tip este necesară convertirea acestora la tipul întreg.

79

int a,b,c;scanf(“%d”,&a); scanf(“%d”,&b),if(a<(b+1)) c++; else {a--; c=a+b; if(c) a++; }

int a,b,c;scanf(“%d”,&a); scanf(“%d”,&b),if(a<(b+1)) c++; else {a--; c=a+b; if(c) a++; }

Figura IV-3: Diagramainstrucţiunii. switch

test expresie

instrucţiune 1

instrucţiune n

instrucţiune 2

break

break

instrucţiune m

defaultcase

Dacă expresie=expresie_const_1 instrucţiune1; [ieşire;]Dacă expresie=expresie_const_2 instrucţiune2; [ieşire;]........................Dacă expresie=expresie_const_n instrucţiune_n;Altfel instrucţiune_m;

Dacă expresie=expresie_const_1 instrucţiune1; [ieşire;]Dacă expresie=expresie_const_2 instrucţiune2; [ieşire;]........................Dacă expresie=expresie_const_n instrucţiune_n;Altfel instrucţiune_m;

Page 81: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Ex.:• pentru luna=1 obţinem a=4, b=4• pentru luna=2 obţinem a=2, b=5• pentru luna=3 obţinem a=1, b=3• pentru luna=4 obţinem a=2, b=4• pentru luna>4 obţinem a=0, b=0

3.3. Implementarea structurilor repetitive (ciclice)

Există două categorii de instrucţiuni ciclice: cu test iniţial şi cu test final. Structura ciclică cu test iniţial este implementată prin instrucţiunile for şi while, iar cea cu test final este implementată prin instrucţiunea do while.

3.3.1. Implementarea structurilor ciclice cu test iniţial – Instrucţiunea for

Limbajul C are o instrucţiune for deosebit de flexibilă. Instrucţiunea for implementează structura ciclică cu număr cunoscut de paşi. Sintaxa:

În continuare este pre-zentat pseudocodul şi un exemplu.

80

for(EXPRESIE_1;EXPRESIE_2;EXPRESIE_3)BLOC INSTRUCŢIUNI;

for(EXPRESIE_1;EXPRESIE_2;EXPRESIE_3)BLOC INSTRUCŢIUNI;

switch (<expresie>)//Sintaxa:{case expresie_const_1: instr_1;[break;]case expresie_const_2: instr_2;[break;]. . . . . . . . . . . . . . . . . . . . case expresie_const_n: instr_n;[ default:instrucţiune_m; ]}

switch (<expresie>)//Sintaxa:{case expresie_const_1: instr_1;[break;]case expresie_const_2: instr_2;[break;]. . . . . . . . . . . . . . . . . . . . case expresie_const_n: instr_n;[ default:instrucţiune_m; ]}

int a=3,b=4; cin>>luna;switch(luna){ case 1:a++; break; case 2:{a--;b++;} break; case 3:{a--;b--;} case 4:a--; default:{a=0; b=0;} } cout<<”a=”<<a<<”b”<<b;

int a=3,b=4; cin>>luna;switch(luna){ case 1:a++; break; case 2:{a--;b++;} break; case 3:{a--;b--;} case 4:a--; default:{a=0; b=0;} } cout<<”a=”<<a<<”b”<<b;

int a = 0;for(int i=0;i<100;i++) a++;

int a = 0;for(int i=0;i<100;i++) a++;

Figura IV-4: Diagramainstrucţiunii for

< EXPRESIE_1 >(de obicei iniţializare

contori)

Evaluare < EXPRESIE_2 >

BLOC_INSTRUCŢIUNI(blocul instr. for)

< EXPRESIE_3 >(de obicei

incrementare contori)

FALSE

TRUE

Page 82: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Implementarea structurilor de control

Nu este obligatorie prezenţa expresiilor, ci doar a instruc-ţiunilor vide. În exemplul de mai sus (dreapta) instrucţiunea for implementează o buclă infinită, iar în exemplul de mai sus (stânga) sunt implementate mai multe bucle for imbricate.

3.3.2. Instrucţiunea while

Sintaxa:

La întâlnirea instrucţiunii while, se evaluează <EXPRESIE>. Dacă aceasta are valoarea TRUE (diferită de ZERO), se execută BLOC_INSTRUCŢIUNI. Se reevaluează valoarea expresiei. Dacă aceasta are valoarea de adevăr TRUE, se repetă instrucţiunea etc. Astfel, blocul cu instrucţiuni (corpul ciclului) se repetă atât timp cât <EXPRESIE> are valoarea de adevăr TRUE. În momentul în care <EXPRESIE> are valoarea de adevăr FALSE (sau egal cu ZERO), se iese din ciclu şi se trece la următoarea instrucţiune din afara buclei while.

În cazul în care la prima evaluare a expresiei, aceasta are valoarea de adevăr FALSE, corpul instrucţiunii while nu va fi executat niciodată. Instrucţiunile din corpul ciclului while trebuie să modifice valoarea expresiei, altfel va fi un ciclu infinit.

Blocul cu instrucţiuni din corpul ciclului while poate fi constituit dintr-o singură instrucţiune, caz în care nu mai sunt necesare acoladele.

81

while(<expresie>) instr1;

while(<expresie>) instr1;

Evaluare EXPRESIE_1ATÂT TIMP cât EXPRESIE_2 este TRUE REPETĂ

beginBLOC_INSTRUCŢIUNIEvaluare EXPRESIE_3end

Evaluare EXPRESIE_1ATÂT TIMP cât EXPRESIE_2 este TRUE REPETĂ

beginBLOC_INSTRUCŢIUNIEvaluare EXPRESIE_3end

int i,j,m,n,a,b;for(i=0;i<n;i++) for(j=0;j<m;j++) {a+=i*j; if(i<j) b=a; else b=-a; }

int i,j,m,n,a,b;for(i=0;i<n;i++) for(j=0;j<m;j++) {a+=i*j; if(i<j) b=a; else b=-a; }

int a=9; for(;;) {a--; if(a<5) break;}

int a=9; for(;;) {a--; if(a<5) break;}

Figura IV-5: Diagrama instrucţiunii while

Evaluare <EXPRESIE>

BLOC_INSTRUCŢIUNI

TRUE FALSE

Page 83: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

3.3.3. Instrucţiunea “do while”

Sintaxa:

Se execută blocul de instrucţiuni. Se evaluează apoi <EXPRESIE>. Dacă aceasta are valoarea de adevăr TRUE, se execută din nou blocul de instrucţiuni, altfel se iese din buclă. Se testează din nou valoarea expresiei. Se repetă execuţia blocului de instrucţiuni atât timp cât valoarea de adevăr a expresiei este TRUE. În cazul instrucţiunii do while, corpul ciclului se execută cel puţin o dată.

3.3.4. Instrucţiunea “break”

Aceasta forţează ieşirea din interiorul unei bucle fără a se mai ţine seama de condiţia de menţinere în buclă. Instrucţiunile situate în corpul buclei, după instrucţiunea break, nu vor mai fi executate.

3.3.5. Intrucţiunea “continue”

Aceasta duce la ignorarea instrucţiunilor din buclă, situate după aceasta, şi testarea din nou a expresiei de menţinere în buclă. În cazul buclelor for se realizează şi evaluarea celei de a treia expresii responsabilă cu incrementarea contorilor.

În continuare este prezentat un exemplu de implementare a instrucţiunii for. Exemplul constă în calcularea valorii unei integrale definite între două puncte a şi b. Aceasta se rezumă la calculul ariei de sub grafic. În acest sens, intervalul ab este împărţit într-un număr de segmente transmis ca şi parametrul funcţiei (a se vedea capitolul funcţii). Fiecare segment obţinut constituie înălţimea unui trapez, iar valorile funcţiei în cele două capete ale segmentului se constituie în baza mare pentru trapez, respectiv baza mică pentru trapez. Suma ariilor tuturor trapezelor (pentru fiecare segment din intervalul ab) aproximează valoarea integralei.

82

do BLOC_INSTRUCŢIUNI while(<EXPRESIE>)

do BLOC_INSTRUCŢIUNI while(<EXPRESIE>)

Figura IV-6: Diagrama instrucţiunii do while

Evaluare <EXPRESIE>

BLOC_INSTRUCŢIUNI

TRUE FALSE

Page 84: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Implementarea structurilor de control

4. Tablouri şi pointeri. Aritmetica pointerilor.

4.1. Alocarea dinamică. Noţiunea de pointer

4.1.1. Când se utilizează alocarea dinamică?

Variabilele conţin datele ce se modifică în cadrul execuţiei programului. Fiecare dintre acestea se află la o anumită adresă de memorie şi este referită printr-o etichetă (nume). În cazul în care dimensiunea acestor date este mare (raportată la memoria RAM a calculatorului) sau nu este cunoscută la începutul programului, se utilizează alocarea dinamică. De asemenea se mai utilizează şi în alte cazuri, tratate la capitolul despre funcţii.

4.1.2. Noţiunea de pointer

Pointerul este o variabilă ce conţine adresa unui obiect. Obiectul a cărui adresă este conţinută de pointer poate fi variabilă sau funcţie.

În exemplul de mai jos (declararea a două variabile), este echivalent cu a scrie sau

.Variabila a este de tip întreg, iar variabila b este de tip pointer, aceasta din urmă conţine adresa unei variabile de tip întreg (adresa la care se află o valoare de tip întreg).

Adresele au lungimea tipului de dată int (întreg) şi coincid cu dimensiunea magistralei de adresare pentru calculatoare (iniţial 8 biţi – microprocesoare Z80, 16 biţi microprocesoare 286,386,486, 32 biţi – mai recente, iar cele actuale sunt de 64 biţi. De exemplu, memoria maximă adresabilă pentru microprocesoarele pe 32 de biţi va fi de 232 octeţi, adică aproximativ 4 Gb memorie RAM. Memoria RAM în care sunt încărcate programele şi datele ne-o putem imagina ca o riglă având 232 adrese, la fiecare adresă se va regăsi

83

int a; int *b; int a,*b;

int *b,a;

/*Ex.3.3(1): calculul valorii unei integrale definite de la a la b*/#include <stdio.h>double f1(int x) {return x*x-5*x+2;} //f1 este un ex. de functiedouble integr(double a, double b, int n) // fct.ce întoarce val.integr.{ //pas – inaltimea unui trapez, sum-suma partiala si cea finala // a b sunt cele doua valori intre care se calc. integrala double q, sum, pas = (b - a) / (n * 1.0); for(sum = 0, q = a + pas; q <= b; q += pas) sum += ( f1(q) + f1(q-pas) ) * pas / 2.0; return sum; }int main(){double h = integr(2,8,10000); printf("Integrala: %f\n",h); return 0;}

/*Ex.3.3(1): calculul valorii unei integrale definite de la a la b*/#include <stdio.h>double f1(int x) {return x*x-5*x+2;} //f1 este un ex. de functiedouble integr(double a, double b, int n) // fct.ce întoarce val.integr.{ //pas – inaltimea unui trapez, sum-suma partiala si cea finala // a b sunt cele doua valori intre care se calc. integrala double q, sum, pas = (b - a) / (n * 1.0); for(sum = 0, q = a + pas; q <= b; q += pas) sum += ( f1(q) + f1(q-pas) ) * pas / 2.0; return sum; }int main(){double h = integr(2,8,10000); printf("Integrala: %f\n",h); return 0;}

Page 85: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

o locaţie de memorie ce conţine 8 biţi (1 octet în franceză sau 1 byte în engleză). Din acest motiv, tipul de date boolean ce conţine doar valorile de adevăr TRUE sau FALSE (codificabile doar cu un bit) este reprezentat în memorie pe un octet. Nu pot fi reprezentate date în memorie sub un octet.

În cazul declarării variabilei de tip pointer, semnul * din stânga acesteia semnifică faptul ca acesta conţine o adresă (variabila este de tip pointer) şi nu o valoare. În momentul utilizării variabilei, semnul * din stânga acesteia are altă semnificaţie, acesta semnifică faptul că se preia valoarea variabilei de tip pointer. De exemplu, în instrucţiunea: variabila a preia valoarea de la adresa lui b (valoarea la care pointează b).

Operatorul unar & este utilizat pentru obţinerea adresei. De exemplu, variabila pointer b preia adresa lui a, iar a nu este de tip pointer .

Variabilele din declaraţiile sunt de asemenea pointeri.

4.2. Noţiunea de tablou

Tablourile au acelaşi tip de dată ca şi variabilele simple şi pot avea una sau mai multe dimensiuni (ex.: tablori cu o dimensiune = vectori, tablouri cu două dimensiuni = matrici). Declarea tablourilor se realizează prin utilizarea operatorului [].

Ex.: , unde b este un tablou unidimensional cu 10 elemente de tip double, c este un tablou bidimensional cu 10x5 elemente de tip double, d este un tablou cu patru dimensiuni având 5x6x3x4 elemente de tip double.

În cazul variabilelor de tip tablou, este alocată automat memorie pentru întregul tablou. Elementele acestuia nu sunt iniţializate (la fel ca la variabilele simple), acestea având valori aleatorii. Referirea la un element din cadrul tabloului se

Indecşii încep cu valoarea 0. În memoria RAM tablourile sunt repezentate prin secvenţe continue. Practic, d va conţine adresa tabloului (un bloc compact de 5x6x3x4 elemente, ocupând în memorie 5x6x3x4x8 octeţi – double este reprezentat pe 8 octeţi).

În cazul alocării dinamice a tabloului d (double ****d), primii 3 vectori din imagine conţin adrese şi doar ultimul vector conţine valorile de tip double.

84

a =* b;

b =& a;

int *b,****c,**d;

double b[10],c[10][5],d[5][6][3][4],a;

a = d[1][2][0][3];// a preia valoarea unei celule din cadrul tabloului d

a = d[1][2][0][3];// a preia valoarea unei celule din cadrul tabloului d

Page 86: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Tablouri şi pointeri. Aritmetica pointerilor.

Figura IV-7: Referirea la celula d[3][2[0][3] într-un tablou cu 4 dimensiuni alocat dinamic

Variabila d conţine adresa celulei d[0]. Celula d[3] conţine adresa vectorului desenat în dreapta acesteia. Celula d[3][2] conţine adresa vectorului desenat sub această celulă. Celula d[3][2][0] conţine adresa vectorului desenat în dreapta acesteia. Ultimul vector din dreapta conţine doar valori de tipul double. În continuare este prezentat un exemplu de declaraţii de variabile, inclusiv de tip tablou.

În acest exemplu, a este o variabilă de tip întreg (conţine o valoare de tip întreg), a1 este o variabilă pointer la tip întreg (conţine adresa unde este memorată variabila de tip întreg), a2 este un tablou unidimensional (vector) cu 4 elemente de tip întreg, b1 este un tablou bidimensional (matrice) cu 3x4 elemente de tip întreg, b2 este un vector cu 5 elemente de tip pointer la întreg, b3 este un pointer la o matrice cu elemente de tip întreg, c1 este un tablou tridimensional cu elemente de tip întreg şi cu dimensiunea 4x7x2, c2 este o matrice 14x6 cu elementele de tip pointer la tip întreg, c3 este un vector cu 7 elemente de tip pointer la matrice de tip întreg, iar c4 este un pointer la tablou tridimensional cu elemente de tip întreg. În continuare este prezentat şi un exemplu de atribuiri cu elemente din cadrul tablourilor.

În urma execuţiei instrucţiunii a=a1[1];, variabila a va avea aceeaşi valoare ca şi în cazul execuţiei instrucţiunii a=a2[1];.

4.3. Alocarea dinamică a memoriei

Variabilele de tip pointer presupun utilizarea alocării dinamice pentru memorie, cu excepţia cazurilor când acestea copiază adresa altor zone de memorie deja alocate. Utilizatorul

85

int a, *a1, a2[4], b1[3][4], *b2[5], **b3;int c1[4][7][2], *c2[14][6], **c3[7], ***c4;

int a, *a1, a2[4], b1[3][4], *b2[5], **b3;int c1[4][7][2], *c2[14][6], **c3[7], ***c4;

a = a2[1]; a = b1[0][0]; a = c1[1][0][1]; a1 = a2; a1 = b1[1]; a1 = b2[3]; a1 = c1[1][2]; a1 = c2[1][0];b3 = c2[3]; b3 = c3[1];a = *a1; a = a1[0]; a = b2[2][0]; a = c2[1][0][0];c3[2][0][0] = a; a1 = &a; b3[1] = a1; c4[0] = c3[1];

a = a2[1]; a = b1[0][0]; a = c1[1][0][1]; a1 = a2; a1 = b1[1]; a1 = b2[3]; a1 = c1[1][2]; a1 = c2[1][0];b3 = c2[3]; b3 = c3[1];a = *a1; a = a1[0]; a = b2[2][0]; a = c2[1][0][0];c3[2][0][0] = a; a1 = &a; b3[1] = a1; c4[0] = c3[1];

d[4]

d[3]

d[2]

d[1]

d[0]

d[3][0] d[3][1] d[3][2] d[3][3] d[3][4]d[3][5]

d[3][2][0]

d[3][2][1]

d[3][2][2]

d[3][2][0][0] d[3][2][0][1] d[3][2][0][2] d[3][2][0][3]

Page 87: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

poate solicita în timpul execuţiei programului alocarea unei zone de memorie. Această zonă de memorie poate fi eliberată în momentul în care nu mai este necesară.

Alocarea memoriei se poate realiza cu funcţiile din bibliotecă având prototipul (declaraţiile) în <alloc.h> sau prin utilizarea operatorului new. O primă funcţie pentru alocare este:void *malloc(unsigned n);. Funcţia alocă un bloc de memorie de n octeţi şi întoarce un pointer la începutul zonei de memorie alocată. În cazul în care nu este posibilă alocarea unei zone compacte de n octeţi funcţia returnează NULL (valoarea 0x0000). Memoria alocată nu este iniţializată. La sfârşitul operaţiilor, memoria trebuie eliberată. În cazul alocării cu funcţia malloc, dealocarea memoriei se face cu funcţia void free(void *p);. Funcţia eliberează o zonă de memorie de la adresa stocată în variabila p, zonă alocată în prealabil prin funcţia malloc.

Funcţiile de alocare întorc pointeri generici (void*) la zone de memorie, în timp ce utilizatorul alocă memorie pentru un anumit tip de dată. Pentru a putea accesa memoria alocată, indirect, prin intermediul pointerului, acesta va trebui să fie un pointer cu tip, ceea ce impune conversia explicită (prin operatorul cast) a pointerului întors de funcţia de alocare într-un pointer cu tip.

sau

Notă: Operatorul delete se utilizează urmat de [] doar atunci când variabila a cărei memorie rezervată urmează a fi eliberată este de tip vector.

În continuare este prezentată o funcţie de alocarea dinamică a unei matrice cu elemente de tipul double. Funcţia aloca2double preia numărul de linii şi coloane a matricei ce urmează a fi alocate dinamic şi întoarce adresa primului vector (echivalentul adresei celulei d[0] din exemplul de mai sus):

86

int *p; p = (int*) malloc ( n*sizeof(int) );if(p == NULL) { printf(„Memorie insuficienta!”);}//......if( p ) free( p ); // identic cu if(p!=NULL)

int *p; p = (int*) malloc ( n*sizeof(int) );if(p == NULL) { printf(„Memorie insuficienta!”);}//......if( p ) free( p ); // identic cu if(p!=NULL)

int *p; p = new int[ n ];if( p == NULL ) { printf(„Memorie insuficienta!”);}//......if( p ) delete[] p;

int *p; p = new int[ n ];if( p == NULL ) { printf(„Memorie insuficienta!”);}//......if( p ) delete[] p;

Page 88: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Tablouri şi pointeri. Aritmetica pointerilor.

Funcţia de dealocare pentru matricea alocată dinamic va avea forma:

Funcţia preia adresa matricei şi numărul de linii. În cadrul contorului k sunt dealocaţi vectorii care au reuşit să fie alocaţi dinamic. Utilizarea celor două funcţii este redată în exemplul următor:

Notă: Fie declaraţia int *a;. Alocarea a=new int; este echivalentă cu alocarea a=new int[1];, adică dacă nu este vector putem considera că alocăm memorie pentru un vector cu un singur element. Astfel, aritmetica pointerilor prezentată în cele ce urmează devine mai simplă.

87

/*Ex.[4.1]*/ double **aloca2double(int m,int n){double **A; int k,i; A = (double**) malloc( m * sizeof(double*) ); if( !A ) return NULL; for( k = 0; k < m; k++ ) { A[k] = (double*) malloc( n * sizeof(double) ); if( !A ) //alocare esuata, elibereaza memoria deja alocată { for( i = 0; i < k; i++ ) free( A[i] ); free( A ); return NULL; }//endif }//endfor for( k = 0; k < m; k++ ) for( i = 0; i < n; i++ ) A[k][i] = 0; return A;}

/*Ex.[4.1]*/ double **aloca2double(int m,int n){double **A; int k,i; A = (double**) malloc( m * sizeof(double*) ); if( !A ) return NULL; for( k = 0; k < m; k++ ) { A[k] = (double*) malloc( n * sizeof(double) ); if( !A ) //alocare esuata, elibereaza memoria deja alocată { for( i = 0; i < k; i++ ) free( A[i] ); free( A ); return NULL; }//endif }//endfor for( k = 0; k < m; k++ ) for( i = 0; i < n; i++ ) A[k][i] = 0; return A;}

/*Ex.[4.2]:*/ void elib2double( double**A, int m ){int k; for( k = 0; k < m; k++ ) if( A[k] ) free( A[k] ); if( A ) free( A ); }

/*Ex.[4.2]:*/ void elib2double( double**A, int m ){int k; for( k = 0; k < m; k++ ) if( A[k] ) free( A[k] ); if( A ) free( A ); }

/* Ex #4.3: */ #include <stdio.h>#include <stdlib.h>/*\n*/ #include <time.h>/*\n*/ #include <bfd.h>//declarare şi explicitare funcţie alocare dinamică -- aloca2double//elibereaza zona de memorie alocata -- elib2double double **x; int m1 = 3, n1 = 4; srand( time(NULL) ); //inţializare generare numere aleatoare x = aloca2double( m1, n1 ); //apel functie alocare dinamica //iniţializarea variabilei alocate dinamic cu valori aleatoare for( int i = 0; i < m1; i++ ) for( int j = 0; j < n1; j++ ) x[i][j] = rand() % 100;//rand() generează nr.aleatoare: 1÷2^16 for( int i = 0; i < m1; i++ ) { for( int j = 0; j < n1; j++ ) printf(" %f ",x[i][j]); printf("\n"); } elib2double( x, m1 ); return 0;}

/* Ex #4.3: */ #include <stdio.h>#include <stdlib.h>/*\n*/ #include <time.h>/*\n*/ #include <bfd.h>//declarare şi explicitare funcţie alocare dinamică -- aloca2double//elibereaza zona de memorie alocata -- elib2double double **x; int m1 = 3, n1 = 4; srand( time(NULL) ); //inţializare generare numere aleatoare x = aloca2double( m1, n1 ); //apel functie alocare dinamica //iniţializarea variabilei alocate dinamic cu valori aleatoare for( int i = 0; i < m1; i++ ) for( int j = 0; j < n1; j++ ) x[i][j] = rand() % 100;//rand() generează nr.aleatoare: 1÷2^16 for( int i = 0; i < m1; i++ ) { for( int j = 0; j < n1; j++ ) printf(" %f ",x[i][j]); printf("\n"); } elib2double( x, m1 ); return 0;}

Page 89: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

4.4. Aritmetica pointerilor

Datorită faptului că adresele de memorie a elementelor dintr-un vector sunt consecutive, se pot efectua operaţii cu aceste adrese în cadrul tabloului. La incrementarea unei variabile pointer, C/C++ incrementează automat adresa cu o valoare adecvată (1 octet dacă tipul variabilei la care punctează este char, 2 octeţi pentru tipul de date short, patru octeţi pentru long sau float etc.), astfel încât pointerul să indice următoarea valoare pe care o are tipul pointerului (tipul datei la care punctează). Pentru tipuri de date complexe (structuri, clase) se incrementează cu dimensiunea structurii sau clasei la care punctează.

Pentru o înţelegere mai bună privind aritmetica pointerilor sunt redate în continuare câteva exemple comentate.

4.5. Teste

Scrieţi ce se afişează în urma execuţiei următoarelor instrucţiuni (liniile sunt independente), iar în cazul existenţei unor erori, să se semnaleze erorile apărute în urma execuţiei şi sursa acestora. Executaţi codul şi confruntaţi rezultatele afişate cu cele scrise.1. int a[2],b[7]={12,23,34,45,56,67,78}; a[0] = *(&b[2] + 1); a[1] = *b; printf(“a[0]=%d a[1]=%d”,a[0], a[1]); 2. int a[3],c[4][3]={{10,23,34},{11,22,13},{31,42,33},{14,21,31}};a[0] = 1 + *(&c[0][1] + 1); a[1] = **(&c[1] + 1); a[2]=**c; printf(“a[0]=%d a[1]=%d a[2]=%d”,a[0],a[1],a[2]); 3. char *str = "ABCDEF"; str[1] = str[1]+1-'C'; str[3]=str[4]-(str[3]+1); printf(“%s”,str); 4. int a,b[7]={11,13,15,17,19,21,23}; a = *(&b[6] - 6); printf(“a=%d”,a); 5. int a,c[4][3]={{11,13,15},{21,23,25},{31,33,35},{41,43,45}};a = *(c[3] - 1) + *(&c[0][1] - 1); printf(“a=%d”,a); 6. int a[2][3][2]={{{10,12},{13,15},{14,16}},{{50,52},{51,53},{54, 56}}},b; b = ***a + *(a[1][2] - 1) + **(a[0] + 1); printf(“b=%d”, b);7. char *str="ABCDEFG"; str[3]='G'-!(str[3]-str[1]); str[4]=!str[3]

88

/*Ex.[4.4]*/ #include <stdio.h> //biblioteca pentru funcţia printfvoid main(void){ int t[4] = {0, 1, 2, 3};//declaraţie + iniţializare ptr.vector 4 el. int *p; p = &t[2]; // p preia adresa celui de al treilea element din vect.t p -= 2; printf("%d\n", *p); /* afisează valoarea lui t[0] */ p += 1; printf("%d\n", *p); /* afişeazîă valoarea lui t[1] */ p++; printf("%d\n", *p); /* afişează valoarea lui t[2] */ (*p) += 5; printf("%d\n", *p); /* afisează valoarea lui t[2]+5 */}

/*Ex.[4.4]*/ #include <stdio.h> //biblioteca pentru funcţia printfvoid main(void){ int t[4] = {0, 1, 2, 3};//declaraţie + iniţializare ptr.vector 4 el. int *p; p = &t[2]; // p preia adresa celui de al treilea element din vect.t p -= 2; printf("%d\n", *p); /* afisează valoarea lui t[0] */ p += 1; printf("%d\n", *p); /* afişeazîă valoarea lui t[1] */ p++; printf("%d\n", *p); /* afişează valoarea lui t[2] */ (*p) += 5; printf("%d\n", *p); /* afisează valoarea lui t[2]+5 */}

Page 90: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Tablouri şi pointeri. Aritmetica pointerilor.

; printf(“%s”,str); 8. int a,b[7]={11,13,15,17,19,21,23}; a = *(&b[7] - 4); printf(“a=%d”,a);9. int a,c[4][3]={{11,13,15},{21,23,25},{31,33,35},{41,43,45}};a = *(&c[0][0] + 2); printf(“a=%d”,a); 10. int a[2][3][2]={{{10,12},{13,15},{14,16}},{{50,52},{51,53},{54,56}}}, b; b=***(a+1)+*(a[1][0]+1);printf(“b=%d”,b);11. int a,c[4][3]={{11,13,15},{21,23,25},{31,33,35},{41,43,45}}; a = **(&c[1] - 1) + *(&c[1][2] - 1); cout<<a; 12. int a[2][3][2]={{{10,12},{13,15},{14,16}},{{50,52},{51,53},{54,56}}}, b; b=*(**a+1)+*(a[1][2]-1)-**a[0]; printf(“b=%d”,b);13. char *str="ABCDEFG"; str[0]='D'-str[3]+str[1];str[4]=!str[4]; printf(“%s”,str); 14. int a[2][3][2]={{{10,12},{13,15},{14,16}},{{50,52},{51,53},54,56}}},b; b = *(**(a + 1) + 1) + *a[1][2] - **a[1]; printf(“b=%d”,b); 15. int a,c[4][3]={{11,13,15},{21,23,25},{31,33,35},{41,43,45}}; a=*(&c[3][2]-2)+**(&c[1]+1);printf(“a=%d”,a);16. int a[2][3][2]={{{10,12},{13,15},{14,16}},{{50,52},{51,53},54,56}}},b; b = ***a + **(*a + 1); printf(“b=%d”,b);

5. Funcţii. Aria de vizibilitate a variabilelor

5.1. Noţiunea de funcţie

Orice program C/C++ este structurat pe funcţii, astfel nu vom avea instrucţiuni decât în cadrul funcţiilor. Orice program C/C++ începe prin execuţia funcţiei main() sau similară. Un program va avea o singură funcţie main(), indiferent de numărul de fişiere în care este scris codul. Ieşirea din funcţia main() echivalează cu ieşirea din program.

Funcţia int main(int argc, char **argv) preia numărul de argumente (argc) şi lista de argumente (argv). Argumentele pot să reprezinte lista de opţiuni specifică lansării în execuţie a unei aplicaţii. Iesirea normală din aplicaţie corespunde cu return 0;.

Din punct de vedere conceptual, funcţia reprezintă o aplicaţie definită pe o mulţime D (D = mulţimea, domeniul de definiţie), cu valori în mulţimea C (C = mulţimea de valori, codomeniul), care îndeplineşte condiţia că oricărui element din D îi corespunde un unic element din C.

Funcţiile comunică prin lista de argumente. Ele primesc ca parametri (argumente) datele de intrare, efectuează prelucrările descrise în corpul funcţiei asupra acestora şi pot returna rezultatul într-o singură variabilă, care poate fi şi de tip pointer. În cazul în care funcţia trebuie să întoarcă mai multe valori, se va utiliza transferul prin referinţă sau va întoarce adresa unui obiect de tip structură sau clasă ce va conţine toate

89

Page 91: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

datele. Execuţia programului începe cu funcţia principală, numită main().

5.2. Structura unei funcţii

O funcţie este formată din antet şi corp:

Detaliat, structura unei funcţii este:

Prima linie reprezintă antetul funcţiei, în care se indică: tipul funcţiei, numele acesteia şi lista declaraţiilor parametri-lor formali. Dacă funcţia nu întoarce nicio valoare, în locul tip_vali_return se specifică void.

Lista_declaraţiilor_param_formali (încadrată între paranteze rotunde) constă într-o listă (enumerare), care conţine tipul şi identificatorul fiecărui parametru de intrare, despărţite prin virgulă. Tipul unui parametru poate fi oricare, chiar şi tipul pointer. Dacă lista parametrilor formali este vidă, în antet, după numele funcţiei, apar doar parantezele (), sau (void).

Corpul funcţiei este un bloc, care implementează algoritmul de calcul folosit de către funcţie. În corpul funcţiei apar (în orice ordine) declaraţii pentru variabilele locale şi instrucţiuni. Dacă funcţia întoarce o valoare, se foloseşte instrucţiunea return valoare. La execuţie, la întâlnirea acestei instrucţiuni, se revine în funcţia apelantă. Într-o funcţie putem avea mai multe intrucţiuni return, însă doar una din acestea va putea fi executată.

5.3. Declararea, explicitarea şi apelul funcţiilor

Declaraţia unei funcţii conţine antetul funcţiei şi informează compilatorul asupra tipului, numelui funcţiei şi a listei parametrilor formali (în care se poate indica doar tipul parametrilor formali, nu şi numele acestora). Declaraţiile de funcţii se numesc prototipuri, şi sunt constituite din antetul funcţiei, din care pot lipsi numele parametrilor formali (altfel spus, în cadrul declaraţiilor, opţional, se pot scrie şi denumiri de variabile, dar acestea sunt ignorate de compilator).

Explicitarea unei funcţii conţine antetul funcţiei şi corpul acesteia. Nu este admisă definirea/explicitarea unei funcţii în corpul altei funcţii.

90

antet_funcţie{corpul_funcţiei}

antet_funcţie{corpul_funcţiei}

tip_val_return nume_func(lista_declaraţiilor_param_formali){ declaraţii_variabile_locale;

instrucţiuni;return valoare/pointer;}

tip_val_return nume_func(lista_declaraţiilor_param_formali){ declaraţii_variabile_locale;

instrucţiuni;return valoare/pointer;}

Page 92: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Funcţii. Aria de vizibilitate a variabilelor

O funcţie poate fi declarată şi explicitată în cadrul aceluiaşi fişier (dacă este explicitată/definită la începutul fişierului, nu mai este necesară şi declararea acesteia), sau în fişiere diferite. O funcţie nu poate fi spartă în mai multe fişiere.

5.4. Domeniul de vizibilitate al variabilelor

Variabilele pot fi globale - declarate în afara unui bloc de date (practic, în afara funcţiilor) sau locale – declarate în cadrul blocurilor de date (blocuri ce se regăsesc în cadrul funcţiilor). O variabilă globală poate fi vazută în orice funcţie din fişierul respectiv dacă variabila este declarată înainte de explicitarea funcţiei.

Variabilele declarate în interiorul unei funcţii, cât şi parametrii formali ai acesteia nu pot fi accesaţi decât în interiorul acesteia. Aceste variabile sunt numite variabile locale şi nu pot fi accesate din alte funcţii. Domeniul de vizibilitate a unei variabile este porţiunea (zona) de cod la a cărei execuţie variabila respectivă este accesibilă. Deci, pentru variabilele locale declarate la începutul funcţiei, domeniul de vizibilitate este funcţia în care ea a fost definită sau zona de instrucţiuni din cadrul funcţiei situată după declaraţia acesteia.

Dacă în interiorul unei funcţii există instrucţiuni compuse (blocuri) care conţin declaraţii de variabile, aceste variabile nu sunt vizibile în afara blocului.

Dacă înainte de apelul funcţiilor folosite, acestea au fost definite (explicitate), acestea nu mai trebuiesc declarate la începutul fişierului sau în fişierele de tip «header». De regulă prototipurile (declaraţiile) funcţiilor se scriu în fişierele de tip header, aceste fişiere au de regulă extensia “*.h”. Utilizarea unei astfel de funcţii impune doar includerea în program a header-ului asociat, cu ajutorul directivei preprocesor #include.

Domeniul de vizibilitate a unei variabile sau a unei funcţii este:

● întregul fişier sursă, dacă declaraţia este în fişier header inclus prin directiva #include;

● fişierul sursă, după punctul de declaraţie sau explicitare dacă declaraţia funcţiei sau variabilei apare în afara oricărei funcţii (la nivel global);

● funcţia sau blocul în care apare declaraţia, după întâlnirea declaraţiei.

O variabilă globală declarată într-un fişier va putea fi văzută în alt fişier din cadrul aceluiaşi program numai dacă este redeclarată tot la începutul noului fişier, dar având cuvântul cheie extern în faţă.

91

Page 93: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

În continuare considerăm un exemplu în care avem trei fişiere cu diverse declaraţii de variabile şi funcţii.

Prin declararea static, variabila globală se vede doar în fisierul respectiv şi nu poatre fi declarată prin cuvântul cheie extern în alt fişier. Valoarea variabilei de tip static declarată local la nivelul unei funcţii îşi va menţine valoarea chiar şi după ieşirea din funcţia respectivă, la o nouă intrare în funcţie ea va avea ultima valoare.

În cazul variabilelor locale, compilatorul alocă memorie în momentul întâlnirii declaraţiei din cadrul blocului sau funcţiei în care acestea sunt declarate. Când execuţia funcţiei sau blocului se termină, se eliberează memoria pentru acestea (alocare de tip automatic) şi valorile pentru variabilele locale se pierd.

Dacă variabila este de tip pointer şi a fost alocată dinamic în interiorul funcţiei, ea va trebui dealocată cu funcţia cores-punzătoare, altfel ea va ocupa în continuare spaţiul din memorie chiar şi după ieşirea din funcţie.

6. Transferul parametrilor în cadrul funcţiilor

Funcţiile comunică între ele prin argumente (parametri). Există următoarele moduri de transfer (transmitere) a parametrilor către funcţiile apelate:

● Transfer prin valoare;● Transfer prin adresă;● Transfer prin referinţă.

6.1. Transferul parametrilor prin valoare

De la programul apelant către funcţia apelată, prin apel, se transmit valorile parametrilor. Aceste valori vor fi atribuite, la apel, parametrilor funcţiei. Procedeul de transmitere a para-

92

/* fişier temp2.h */int f5(int);

/* fişier temp2.h */int f5(int);

/*fişier temp1.cpp*/#include “temp2.h”static int a1;int q1,q2;int f2(int);int f1(int a, int b){ int m,n; /*...*/ }void main(){int x,y,z1,z2; //....z1 = f1(3, 4);z2 = f2(a1) - f5(q1); }int f2(int d){ return d++; }

/*fişier temp1.cpp*/#include “temp2.h”static int a1;int q1,q2;int f2(int);int f1(int a, int b){ int m,n; /*...*/ }void main(){int x,y,z1,z2; //....z1 = f1(3, 4);z2 = f2(a1) - f5(q1); }int f2(int d){ return d++; }

//fişier temp2.cppextern int q2;int d;//variabila globalăint f3(int a, int b){ int m,n;//............}int f4(void){int x,y,d;//........ x = f3(q2,y); y = f5(q2);//..}int f5(int d){int a; a = ::d-d; return a--;}//prin ::d se preia valoarea //din variabila globală

//fişier temp2.cppextern int q2;int d;//variabila globalăint f3(int a, int b){ int m,n;//............}int f4(void){int x,y,d;//........ x = f3(q2,y); y = f5(q2);//..}int f5(int d){int a; a = ::d-d; return a--;}//prin ::d se preia valoarea //din variabila globală

Page 94: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Transferul parametrilor în cadrul funcţiilor

metrilor prin valoare constă în încărcarea valorii parametrilor efectivi în zona de memorie a parametrilor funcţiei (în stivă). La apelul unei funcţii, parametrii reali trebuie să corespundă ca ordine şi tip cu cei din declaraţie.

O modificare a valorii parametrului de intrare, în interiorul funcţiei (printr-o operaţie din corpul funcţiei), nu va modifica valoarea parametrului din afara funcţiei, ci doar a copiei locale a parametrului din cadrul stivei.

6.2. Transferul parametrilor prin adresă

Parametrii transmişi unei funcţii pot fi pointeri (variabile care conţin adrese). În aceste cazuri, parametrii funcţiei apelate vor fi iniţializaţi cu valorile parametrilor efectivi, deci cu valorile unor adrese. Astfel, funcţia apelată poate modifica conţinutul locaţiilor spre care pointează argumentele (pointerii).

6.3. Transferul parametrilor prin referinţă

Este asemănătoare cu transferul prin adresă/pointer cu deo-sebirea că parametrului funcţiei i se poate asocia (atribui) chiar obiectul (valoarea variabilei) parametrului transmis. Astfel, parametrul transmis poate fi modificat direct prin operaţiile din corpul funcţiei apelate.

Prin referinţă se creează un alias pentru variabila sursă, alias ce este transmis prin lista de argumente.

93

/*Ex.6.1(1):transfer prin valoare*/ #include <stdio.h> int f1(int a, int b) {a++; b -= 5; return a + b;} void main() { int x,y,z; printf("x=\n"); scanf(“%d”,&x);/*ex:3*/ printf("y=\n"); scanf(“%d”,&y);//ex:4 z = f1(x, y); printf("z=%d\n",z);//ex:z=7 printf("Dupa iesire din f1:x=%d";y=%d,x,y); //ex:x=3,y=4 }

/*Ex.6.1(1):transfer prin valoare*/ #include <stdio.h> int f1(int a, int b) {a++; b -= 5; return a + b;} void main() { int x,y,z; printf("x=\n"); scanf(“%d”,&x);/*ex:3*/ printf("y=\n"); scanf(“%d”,&y);//ex:4 z = f1(x, y); printf("z=%d\n",z);//ex:z=7 printf("Dupa iesire din f1:x=%d";y=%d,x,y); //ex:x=3,y=4 }

/*Ex.6.2(1):transfer prin adresă */ #include <stdio.h> int f2(int *a, int *b) { (*a) ++; (*b) -= 5; return *a + *b; } void main() { int x,y,z; printf("x=\n"); scanf(“%d”, &x); //ex:3 printf("y=\n"); scanf(“%d”, &y); //ex:4 z = f2(&x, &y); printf("z=%d\n", z); //ex:z=3 printf("Dupa iesire din f1:x=%d";y=%d, x, y); //ex:x=4;y=-1 }

/*Ex.6.2(1):transfer prin adresă */ #include <stdio.h> int f2(int *a, int *b) { (*a) ++; (*b) -= 5; return *a + *b; } void main() { int x,y,z; printf("x=\n"); scanf(“%d”, &x); //ex:3 printf("y=\n"); scanf(“%d”, &y); //ex:4 z = f2(&x, &y); printf("z=%d\n", z); //ex:z=3 printf("Dupa iesire din f1:x=%d";y=%d, x, y); //ex:x=4;y=-1 }

Page 95: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Comparând cele trei moduri de transmitere a parametrilor către o funcţie, se poate observa:

● La apelul prin valoare, transferul datelor este unidirecţional, adică valorile se transferă numai de la funcţia apelantă către cea apelată;

● La apelurile prin adresă şi referinţă, transferul datelor este bidirecţional, deoarece o modificare a parametrilor funcţiei determină modificarea parametrilor efectivi (au nume diferite, dar referă aceleaşi locaţii de memorie);

● La transmiterea parametrilor prin valoare, ca parametri efec-tivi pot apărea expresii sau nume de variabile;

● La transmiterea parametrilor prin referinţă, ca parametri efec-tivi nu pot apărea expresii, ci doar nume de variabile;

● La transmiterea parametrilor prin pointeri, ca parametri efec-tivi pot apărea expresii de pointeri.

În următorul exemplu avem transferul simultan prin cele trei moduri.

În cazul în care funcţia trebuie să întoarcă mai multe valori, iar acestea nu pot fi grupate sub o variabilă de tip pointer (tablouri sau structuri), se poate utiliza transferul prin referinţă.

94

/*Ex.6.3(1)://transfer prin referinţă */ #include <iostream.h> int f3(int &a, int &b) {a++; b -= 5; return a + b; } void main() { int x,y,z; printf("x=\n"); scanf(“%d” ,&x); //ex:3 printf("y=\n"); scanf(“%d”,&y); //ex:4 z = f3(x,y); printf("z=%d\n",z); //ex:z=3 printf("Dupa iesire din f1:x=%d";y=%d,x,y); //ex:x=4;y=-1 }

/*Ex.6.3(1)://transfer prin referinţă */ #include <iostream.h> int f3(int &a, int &b) {a++; b -= 5; return a + b; } void main() { int x,y,z; printf("x=\n"); scanf(“%d” ,&x); //ex:3 printf("y=\n"); scanf(“%d”,&y); //ex:4 z = f3(x,y); printf("z=%d\n",z); //ex:z=3 printf("Dupa iesire din f1:x=%d";y=%d,x,y); //ex:x=4;y=-1 }

/*Ex.6.3(2):Transfer mixt */ #include <stdio.h>#include <malloc.h>short f1(short a, short *b, short &c, short d[][2], short **e){ d[0][0]++; d[1][1]++; e[0][0]++; e[1][1]++; //a++; (*b)++; c++; return a + (*b) + c;}int main(){short x[3][2] = {{10,20},{30,40},{50,60}}, r, **y; y = (short**) malloc( 3 * sizeof(short*) ); for(int i = 0;i < 3;i++) y[i]=(short*) malloc( 2 * sizeof(short) ); for(int i = 0; i < 3; i++ ) for( int j = 0; j < 2; j++ ) y[i][j] = x[i][j]; //cele 2 tablouri(x,y) au aceleasi valori r = f1( x[0][0], &x[0][0], x[0][0], x, y );printf("r=%d x[0][0]=%d x[1][1]=%d x[2][1]=%d\n",r,x[0][0],x[1][1],x[2][1]);printf("y[0][0]=%d y[1][1]=%d y[2][1]=%d\n", y[0][0], y[1][1], y[2][1]);return 0;}

/*Ex.6.3(2):Transfer mixt */ #include <stdio.h>#include <malloc.h>short f1(short a, short *b, short &c, short d[][2], short **e){ d[0][0]++; d[1][1]++; e[0][0]++; e[1][1]++; //a++; (*b)++; c++; return a + (*b) + c;}int main(){short x[3][2] = {{10,20},{30,40},{50,60}}, r, **y; y = (short**) malloc( 3 * sizeof(short*) ); for(int i = 0;i < 3;i++) y[i]=(short*) malloc( 2 * sizeof(short) ); for(int i = 0; i < 3; i++ ) for( int j = 0; j < 2; j++ ) y[i][j] = x[i][j]; //cele 2 tablouri(x,y) au aceleasi valori r = f1( x[0][0], &x[0][0], x[0][0], x, y );printf("r=%d x[0][0]=%d x[1][1]=%d x[2][1]=%d\n",r,x[0][0],x[1][1],x[2][1]);printf("y[0][0]=%d y[1][1]=%d y[2][1]=%d\n", y[0][0], y[1][1], y[2][1]);return 0;}

Page 96: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Transferul parametrilor în cadrul funcţiilor

6.4. Funcţii cu număr variabil de argumente

În limbajul C sunt o serie de funcţii din bibliotecile standard care au un număr variabil de argumente; din acestea cele mai cunoscute sunt printf şi scanf, acestea având sintaxa:

La început vor fi puse argumentele fixe, apoi vor fi trecute argumentele, ce pot fi în număr variabil. Funcţiile cu număr variabil de argumente implică utilizarea unui tip de dată va_list şi a trei macroinstrucţiuni: va_start, va_arg şi va_end. Acestea au următoarea semnificaţie:

☑ va_list − gestionează tipul de dată din lista de argumente (de obicei int sau char*);

☑ void va_start(va_list ap, lastfix); − lastfix este ultimul argument fix din lista de parametri. Această macroinstruc-ţiune stabileşte de unde începe citirea argumentelor;

☑ type va_arg(va_list ap, type); − întoace valoarea argumentului curent, la fiecare citire v_arg va avansa (va puncta) la argumentul următor din lista de argumente a funcţiei;

☑ void va_end(va_list ap); − va elibera resursele alocate acestor citiri.Exemplul următor adună numerele transmise prin argumente şi

le afişează. Citirea se opreşte în momentul în care argumentul are valoarea zero.

Funcţia sprintf converteşte o variabilă dintr-un anumit tip de dată (în acest caz tipul int) în şir de caractere (char*). Funcţia strlen întoarce numărul de caractere din şir, iar funcţia strcat(char* destinaţie, char* sursă) concatenează (adaugă) şirul sursă în şirul destinaţie.

Acest mecanism se poate utiliza cu succes pentru trans-miterea adreselor unor obiecte grafice.

95

int printf(const char *format[, argument, ...]);int scanf(const char *format[, address, ...]);

int printf(const char *format[, argument, ...]);int scanf(const char *format[, address, ...]);

/*Ex.6.4: Funcţie cu număr variabil de argumente */#include <stdio.h>/*\n*/#include <stdarg.h>/*\n*/#include <string.h>void sum(char *msg, ...){int total = 0; va_list ap; int arg; char sir[100], ch[50]; va_start(ap, msg); strcpy(sir,msg); while ((arg = va_arg(ap,int)) != 0) { sprintf(ch,"%d",arg);

if(strlen(sir)>strlen("Suma :")) strcat(sir," + "); strcat(sir,ch); total += arg; }

printf(" %s = %d\n", sir, total); va_end(ap);}int main(void) { sum("Suma :",1,2,3,4,0); return 0; }

/*Ex.6.4: Funcţie cu număr variabil de argumente */#include <stdio.h>/*\n*/#include <stdarg.h>/*\n*/#include <string.h>void sum(char *msg, ...){int total = 0; va_list ap; int arg; char sir[100], ch[50]; va_start(ap, msg); strcpy(sir,msg); while ((arg = va_arg(ap,int)) != 0) { sprintf(ch,"%d",arg);

if(strlen(sir)>strlen("Suma :")) strcat(sir," + "); strcat(sir,ch); total += arg; }

printf(" %s = %d\n", sir, total); va_end(ap);}int main(void) { sum("Suma :",1,2,3,4,0); return 0; }

Page 97: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

7. Structuri de date. Liste

7.1. Noţiunea de structură

Structurile grupează date de tipuri diferite, constituind definiţii ale unor noi tipuri de date. Componentele unei structuri se numesc membrii (câmpurile) structurii. La declararea unei structuri se pot preciza tipurile, identificatorii elementelor componente şi numele structurii.

Forma generală de declarare a unei structuri este

în care:● struct este un cuvânt cheie (obligatoriu);● identificator_tip_structura reprezintă numele noului tip (poate

lipsi);● lista_de_declaratii_membri este o listă în care apar tipurile

şi identificatorii membrilor structurii.Membrii unei structuri pot fi de orice tip, cu excepţia

tipului structură (struct), care se declară.

7.2. Declaraţii de tip

Limbajul C permite atribuirea unui nume pentru un tip (predefinit sau utilizator) de date. Pentru aceasta se folosesc declaraţiile de tip. Forma generală a acestora este:

Nume_tip poate fi folosit la declararea datelor în mod similar cuvintelor cheie pentru tipurile predefinite .

Uneori este necesar ca în inte-riorul unei structuri să avem variabile de acelaşi tip cu structura (de exemplu, nodurile unei liste). În acest caz, identificator_tip_structura se va repeta după închiderea corpului/blocului structurii ca în exemplul din dreapta.

96

typedef tip nume_tip;typedef tip nume_tip;

struct identificator_tip_structura {lista_de_declaratii_membrii;};

struct identificator_tip_structura {lista_de_declaratii_membrii;};

struct data_c {int zi; char luna[12]; int an;};//..............struct data_c d1,*d2; d1.zi=4;d1->zi = 5;d1.an = 1968;d2->an = 1969;strcpy(d1.luna,”aprilie”); strcpy(d2->luna,”mai”);

struct data_c {int zi; char luna[12]; int an;};//..............struct data_c d1,*d2; d1.zi=4;d1->zi = 5;d1.an = 1968;d2->an = 1969;strcpy(d1.luna,”aprilie”); strcpy(d2->luna,”mai”);

typedef struct{ double parte_reală; double parte_imaginară; } COMPLEX;COMPLEX x, y;

typedef struct{ double parte_reală; double parte_imaginară; } COMPLEX;COMPLEX x, y;

typedef struct NOD{//.............NOD *urm,*ant;

} NOD;NOD *cap, *p;

typedef struct NOD{//.............NOD *urm,*ant;

} NOD;NOD *cap, *p;

typedef int INTREG;INTREG x, y;

typedef int INTREG;INTREG x, y;

Page 98: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Structuri de date. Liste

7.3. Liste

Lista este o colecţie de elemente (celule) înlănţuite ce formează o structură dinamică, situată în memoria dinamică, în care toate elementele sunt de acelaşi tip; numărul de elemente este variabil, chiar nul (listă vidă, pointează la NULL – adică adresa primei celule din listă este NULL, adică nu există).

Altfel spus, lista este o secvenţă de zero sau mai multe elemente, numite noduri, toate fiind de acelaşi tip. Spre deo-sebire, tabloul este o structură statică, situată în memoria dinamică.

Un nod al listei apare ca o structură recursivă, având o componentă de tip pointer la structura, reprezentând legătura (înlănţuirea) spre nodul următor. Fiecare element (celulă/nod) din cadrul listei înlănţuite are o structură de tipul:

Dacă în cadrul elementului/celulei/nodului se face referire doar la elementul/celula/nodul următor atunci avem liste simplu înlănţuite. Dacă se face şi referire la nodul anterior atunci avem liste dublu înlănţuite.

Structura unui element/celulă/nod este:

Figura IV-8: Structura unui nod

Înlănţuirea celulelor este prezentată în diagrama:

Figura IV-9: Listă dublu înlănţuită

Pentru lucrul cu liste simplu înlănţuite este suficient să se cunoască adresa capului listei, iar pentru listele dublu înlănţuite se poate ajunge la orice nod dacă se cunoaşte adresa unui singur nod din listă, oricare ar fi acesta.

7.3.1. Crearea unei liste dublu înlănţuite

Este necesară alocarea dinamică de memorie pentru orice nod nou creat. Alocarea se poate face atât cu funcţia malloc, cât şi cu operatorul new. Ştergerea elementelor din listă trebuie să asigure şi dealocarea (eliberarea) memoriei corespunzătoare. Aceasta se realizează cu funcţiia free, respectiv operatorul delete.

97

ADRESANODULUIANTERIOR

DATENOD

ADRESANODULUIURMĂTOR

CAPLISTĂ

→ Informaţie utilă; → Informaţie de înlănţuire către elementul (celula) următor;

//pentru listele dublu înlănţuite → Informaţie de înlănţuire către elementul (celula) anterior;

→ Informaţie utilă; → Informaţie de înlănţuire către elementul (celula) următor;

//pentru listele dublu înlănţuite → Informaţie de înlănţuire către elementul (celula) anterior;

Page 99: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Este obligatoriu ca la cele două capete cap->ante şi p->urm să aibă valoarea NULL (p fiind ultimul nod din listă).

Dacă p->urm == cap şi cap->ante == p, atunci avem listă circulară.

7.3.2. Parcurgerea unei liste

Presupunem că în acest caz variabila p este un pointer de tip NOD folosit la parcurgerea listei.

.

Bucla for execută o instrucţiune vidă, identificată prin semicolon (;). Avansul se opreşte pe ultimul nod;

De exemplu, presupunem că avem o listă ale cărei noduri au structura:

Funcţia pentru crearea unei liste cu n noduri şi care întoarce primul element al listei va fi:

Dacă dorim să obţinem adresa ultimei celule/nod a/al listei, utilizăm funcţia următoare:

98

cap = new NOD; //crearea capului listei sau // (cap=(NOD*) malloc(sizeof(NOD));) memset( cap, 0, sizeof(NOD) ); /* asigură iniţializarea cu val.0 respectiv val. NULL pentru pointeri */ //........................ //presupunem: p ultimul nod al listei p1 = new NOD; memset(cap, 0, sizeof(NOD) ); p->urm = p1; p1->ant = p; p = p1;

cap = new NOD; //crearea capului listei sau // (cap=(NOD*) malloc(sizeof(NOD));) memset( cap, 0, sizeof(NOD) ); /* asigură iniţializarea cu val.0 respectiv val. NULL pentru pointeri */ //........................ //presupunem: p ultimul nod al listei p1 = new NOD; memset(cap, 0, sizeof(NOD) ); p->urm = p1; p1->ant = p; p = p1;

//.......................for( p = cap; p->urm; p = p->urm );

//.......................for( p = cap; p->urm; p = p->urm );

/*Ex.7.3.2(1)*/typedef struct NOD2{ int id; NOD2 *urm,*ant; }NOD2;

/*Ex.7.3.2(1)*/typedef struct NOD2{ int id; NOD2 *urm,*ant; }NOD2;

/*Ex.7.3.2(3):parcurgerea listei cu poziţionare pe ultimul nod (întoarce adresa ultimului nod din cadrul listei)*/NOD2* fp1( NOD2 *caplista ){ NOD2 *p; for( p = caplista; p->urm; p = p->urm );//p->urm sau p->urm==NULL return p;}

/*Ex.7.3.2(3):parcurgerea listei cu poziţionare pe ultimul nod (întoarce adresa ultimului nod din cadrul listei)*/NOD2* fp1( NOD2 *caplista ){ NOD2 *p; for( p = caplista; p->urm; p = p->urm );//p->urm sau p->urm==NULL return p;}

/*Ex.7.3.2(2): crearea unei liste cu n noduri, întoarce adresa capului listei*/ NOD2* fc(int n){NOD2 *p, *p1, *caplista; p = NULL; for( int i = 0; i < n; i++ ) { p1 = p; p = (NOD2*) malloc ( sizeof(NOD2) ); if( !p ) return NULL; // eventual se va realiza şi dealocarea memset( p, 0, sizeof(NOD2) ); p->id = i + 1000; // ptr. o viitoare identificare a nodului if( !i ) caplista = p; else { p1->urm = p; p->ant = p1; } } return caplista; }

/*Ex.7.3.2(2): crearea unei liste cu n noduri, întoarce adresa capului listei*/ NOD2* fc(int n){NOD2 *p, *p1, *caplista; p = NULL; for( int i = 0; i < n; i++ ) { p1 = p; p = (NOD2*) malloc ( sizeof(NOD2) ); if( !p ) return NULL; // eventual se va realiza şi dealocarea memset( p, 0, sizeof(NOD2) ); p->id = i + 1000; // ptr. o viitoare identificare a nodului if( !i ) caplista = p; else { p1->urm = p; p->ant = p1; } } return caplista; }

Page 100: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Structuri de date. Liste

Dacă vrem ca pentru fiecare nod să avem anumite prelucrări, utilizăm:

Pentru afişarea listei, avem:

Dacă vrem să eliminăm din listă un nod a cărui adresă de memorie este cunoscută:

Iar dacă nodul ce va fi eliminat din memorie are un identi-ficator cunoscut:

Pentru adăugarea unui nod la sfârşitul listei:

Dacă vrem să adăugăm un nod în listă după un anumit nod, a cărui adresă este cunoscută:

99

/*Ex.7.3.2(4):parcurgerea listei cu prelucrare pentru fiecare nod*/void fp2 (NOD2 *caplista ){ NOD2 *p; for( p = caplista; p; p = p->urm ) { p->id = -p->id; } //ex: id=-id return; }

/*Ex.7.3.2(4):parcurgerea listei cu prelucrare pentru fiecare nod*/void fp2 (NOD2 *caplista ){ NOD2 *p; for( p = caplista; p; p = p->urm ) { p->id = -p->id; } //ex: id=-id return; }

/*Ex.7.3.2(5): afişare listă */void afis( NOD2 *caplista ){ NOD2 *p; int i; printf("\n"); for( p = caplista, i = 0; p; p = p->urm, i++ ) printf(" [%d]:%d",i,p->id); return; }

/*Ex.7.3.2(5): afişare listă */void afis( NOD2 *caplista ){ NOD2 *p; int i; printf("\n"); for( p = caplista, i = 0; p; p = p->urm, i++ ) printf(" [%d]:%d",i,p->id); return; }

/*Ex.7.3.2(6):stergerea unui nod din lista dat prin adresa*/void fd1(NOD2 *d){ if( d->urm ) //nu este ultimul

{ d->ant->urm = d->urm; d->urm->ant = d->ant; } else {d->ant->urm = NULL;} free( d ); }

/*Ex.7.3.2(6):stergerea unui nod din lista dat prin adresa*/void fd1(NOD2 *d){ if( d->urm ) //nu este ultimul

{ d->ant->urm = d->urm; d->urm->ant = d->ant; } else {d->ant->urm = NULL;} free( d ); }

/*Ex.7.3.2(7):stergerea unui nod din lista dat prin id*/ void fd2( int id, NOD2 caplista ) { NOD2 *p; for( p = caplista; p->id != id; p = p->urm ) ; if( p->id == id ) fd1(p); }

/*Ex.7.3.2(7):stergerea unui nod din lista dat prin id*/ void fd2( int id, NOD2 caplista ) { NOD2 *p; for( p = caplista; p->id != id; p = p->urm ) ; if( p->id == id ) fd1(p); }

/*Ex.7.3.2(8):adaugarea unui nod (la sfarsitul listei)*/ void fa1( NOD2 *caplista, NOD2 a ) { NOD2 *p; p = fp1( caplista ); //pozitionare pe ultimul nod p->urm = a; a->ant = p; }

/*Ex.7.3.2(8):adaugarea unui nod (la sfarsitul listei)*/ void fa1( NOD2 *caplista, NOD2 a ) { NOD2 *p; p = fp1( caplista ); //pozitionare pe ultimul nod p->urm = a; a->ant = p; }

/*Ex.7.3.2(9):inserează nod (cu excepţia primei şi ultimei poziţii) se dă nodul anterior*/void fi1( NOD2 *anterior, NOD2 *ins ){ ins->ant = anterior; ins->urm = anterior->urm; anterior->urm->ant = ins; anterior->urm = ins; }

/*Ex.7.3.2(9):inserează nod (cu excepţia primei şi ultimei poziţii) se dă nodul anterior*/void fi1( NOD2 *anterior, NOD2 *ins ){ ins->ant = anterior; ins->urm = anterior->urm; anterior->urm->ant = ins; anterior->urm = ins; }

Page 101: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Iar dacă vrem să adăugăm un nod în listă, după un anumit nod al cărui identificator este cunoscut:

Programul complet este dat de secvenţa următoare (în prealabil se vor înlocui comentariile de tipul /*Ex.:...):

100

/*Ex.7.3.2(10):inserează nod -se dă id-ul nodului anterior*/void fi2( int anterior_id, NOD2 *ins, NOD2 *caplista ){ NOD2 *p; for( p = caplista; p->id != anterior_id; p = p->urm ) ; if( p->id == anterior_id ) fi1(p, ins); }

/*Ex.7.3.2(10):inserează nod -se dă id-ul nodului anterior*/void fi2( int anterior_id, NOD2 *ins, NOD2 *caplista ){ NOD2 *p; for( p = caplista; p->id != anterior_id; p = p->urm ) ; if( p->id == anterior_id ) fi1(p, ins); }

/*Ex.7.3.2(11):Exemplu liste */#include <stdio.h>/*\n*/#include <malloc.h>/*\n*/#include <string.h>/*se copiază codul din exemplele:7.3.2(1),7.3.2(2),7.3.2(3),7.3.2(4), 7.3.2(5),7.3.2(6),7.3.2(7),7.3.2(8),7.3.2(9),7.3.2(10)*/int main(int argc, char **argv)//argc-nr argumente, argv-lista de arg.{NOD2 *c1, *x, *y; c1 = fc(10); x = fp1(c1); printf("\nUltimul nod:%d",x->id);//fp2(c1);//insereaza nod y = (NOD2*) malloc( sizeof(NOD2) ); memset(y ,0 ,sizeof(NOD2) ); y->id = 999; fi2( 1004 ,y ,c1 ); afis(c1); return 0; }

/*Ex.7.3.2(11):Exemplu liste */#include <stdio.h>/*\n*/#include <malloc.h>/*\n*/#include <string.h>/*se copiază codul din exemplele:7.3.2(1),7.3.2(2),7.3.2(3),7.3.2(4), 7.3.2(5),7.3.2(6),7.3.2(7),7.3.2(8),7.3.2(9),7.3.2(10)*/int main(int argc, char **argv)//argc-nr argumente, argv-lista de arg.{NOD2 *c1, *x, *y; c1 = fc(10); x = fp1(c1); printf("\nUltimul nod:%d",x->id);//fp2(c1);//insereaza nod y = (NOD2*) malloc( sizeof(NOD2) ); memset(y ,0 ,sizeof(NOD2) ); y->id = 999; fi2( 1004 ,y ,c1 ); afis(c1); return 0; }

Page 102: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Structuri de date. Liste

8. Funcţii recursive. Parcurgerea arborilor.

O funcţie este numită funcţie recursivă dacă ea se autoapelează, fie direct (în definiţia ei se face apel la ea însăşi), fie indirect (prin apelul altor funcţii). Pentru fiecare apel al funcţiei, parametrii şi variabilele automatice se memorează pe stivă, având valori distincte. Variabilele statice ocupă tot timpul aceeaşi zonă de memorie (figurează într-un singur exemplar) şi îşi păstrează valoarea de la un apel la altul. Orice apel al unei funcţii conduce la o revenire în funcţia respectivă, în punctul următor instrucţiunii de apel. La revenirea dintr-o funcţie, stiva este curăţată (stiva revine la starea dinaintea apelului).

Un exemplu de utilizare a funcţiilor recursive este cel de parcurgere a arborilor binari. În acest sens se dă structura unui

Pentru început este creat un arbore cu şapte noduri. În acest sens se alocă şapte adrese la structuri de tip NOD şi apoi se realizează legăturile între aceste noduri.

Funcţia de parcurgere a arborelui este o funcţie recursivă şi se opreşte în momentul în care ajunge la nodurile frunză (adresele următoare sunt NULL)

101

/*Ex.8(1): structura arbore binar*/typedef struct NOD{ int id; //identificator nod NOD *st,*dr; //adresele nodurilor - stânga, dreapta }NOD;

/*Ex.8(1): structura arbore binar*/typedef struct NOD{ int id; //identificator nod NOD *st,*dr; //adresele nodurilor - stânga, dreapta }NOD;

/*Ex.8(2):creare arbore binar*/ NOD* creare_arbore(void) {NOD *p[7]; //alocare memorie for( int i = 0; i < 7; i++ ) { p[i] = (NOD*) malloc( sizeof(NOD) ); memset( p[i],0,sizeof(NOD) ); p[i]->id = i + 1;} p[0]->st=p[1]; p[0]->dr=p[2]; p[2]->st=p[3]; p[2]->dr=p[4]; p[3]->st=p[5]; p[3]->dr=p[6]; return p[0]; }//întoarce rădăcina arborelui

/*Ex.8(2):creare arbore binar*/ NOD* creare_arbore(void) {NOD *p[7]; //alocare memorie for( int i = 0; i < 7; i++ ) { p[i] = (NOD*) malloc( sizeof(NOD) ); memset( p[i],0,sizeof(NOD) ); p[i]->id = i + 1;} p[0]->st=p[1]; p[0]->dr=p[2]; p[2]->st=p[3]; p[2]->dr=p[4]; p[3]->st=p[5]; p[3]->dr=p[6]; return p[0]; }//întoarce rădăcina arborelui

/*Ex.8(3):parcurge arbore binar*/void parcurge(NOD *p) //preia rădăcina arborelui curent { printf("-%d-", p->id); //if(p->st) parcurge(p->st); //dacă începe din stânga if( p->dr ) parcurge( p->dr ); if( p->st ) parcurge( p->st ); return;}

/*Ex.8(3):parcurge arbore binar*/void parcurge(NOD *p) //preia rădăcina arborelui curent { printf("-%d-", p->id); //if(p->st) parcurge(p->st); //dacă începe din stânga if( p->dr ) parcurge( p->dr ); if( p->st ) parcurge( p->st ); return;}

Page 103: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Căutarea unui anumit nod ce este identificat prin id se face prin funcţia:

Ştergearea întregului arbore este asigurată de funcţia:

Ştergerea legăturii dintre un nod părinte şi un nod fiu este asigurată de funcţia:

Ştergerea unui subarbore din cadrul arborelui este asigurată de funcţia:

Programul principal pentru testare:

Aceste funcţii pot fi extinse asupra arborilor oarecare prin utilizarea unui vector cu pointeri la structuri NOD în locul celor două variabile (st şi dr). Vectorul cu pointeri la tip NOD va avea

102

/*Ex.8(4):întoarce adresa nodului cu id-ul transmis*/NOD* adresa_nod( int id, NOD *p ) { NOD *x = NULL; printf("#%d#",p->id); if( p->id == id ) return p; if(p->st) x = adresa_nod(id, p->st); if(x) return x; if(p->dr) x = adresa_nod(id, p->dr); if(x) return x; return NULL; }

/*Ex.8(4):întoarce adresa nodului cu id-ul transmis*/NOD* adresa_nod( int id, NOD *p ) { NOD *x = NULL; printf("#%d#",p->id); if( p->id == id ) return p; if(p->st) x = adresa_nod(id, p->st); if(x) return x; if(p->dr) x = adresa_nod(id, p->dr); if(x) return x; return NULL; }

/*Ex.8(5):*/ void sterge_arb(NOD *p) { if(p->st) sterge_arb(p->st);//avansează pe ramura din stânga if(p->dr) sterge_arb(p->dr); free(p); } //ştergerea începe doar când a ajuns la nodurile termiale (la nodurile frunză)

/*Ex.8(5):*/ void sterge_arb(NOD *p) { if(p->st) sterge_arb(p->st);//avansează pe ramura din stânga if(p->dr) sterge_arb(p->dr); free(p); } //ştergerea începe doar când a ajuns la nodurile termiale (la nodurile frunză)

/*Ex.8(6): şterge legătura dintre nodul părinte şi nodul pdel */void sterge_legatura(NOD *p,NOD *pdel) { if(p->dr==pdel) p->dr=NULL; else sterge_legatura(p->dr, pdel); if(p->st==pdel) p->st=NULL; else sterge_legatura(p->st, pdel); }

/*Ex.8(6): şterge legătura dintre nodul părinte şi nodul pdel */void sterge_legatura(NOD *p,NOD *pdel) { if(p->dr==pdel) p->dr=NULL; else sterge_legatura(p->dr, pdel); if(p->st==pdel) p->st=NULL; else sterge_legatura(p->st, pdel); }

/*Ex.8(7):ştergerea unui subarbore*/void sterge_subarb(int id, NOD *p) { NOD* x; //în final se va marca cu NULL legătura către subarbore x = adresa_nod(id,p);//identificare adresa nod sterge_arb(x);//şterge legătura de la părinte la nodul x }

/*Ex.8(7):ştergerea unui subarbore*/void sterge_subarb(int id, NOD *p) { NOD* x; //în final se va marca cu NULL legătura către subarbore x = adresa_nod(id,p);//identificare adresa nod sterge_arb(x);//şterge legătura de la părinte la nodul x }

/*Ex.8(8):programul principal pentru testare*/#include <stdio.h>/*\n*/ #include <string.h>/*\n*/#include <malloc.h>/*se copiază codul din exemplele:8(1),8(2),8(3),8(4),8(5),8(6),8(7)*/int main(){ NOD *rad,*x; rad = creare_arbore(); parcurge(rad); x = adresa_nod(4,rad); printf("\n id ptr. id:4 este: %d\n", x->id); sterge_subarb(4,rad); parcurge(rad); return 0;}

/*Ex.8(8):programul principal pentru testare*/#include <stdio.h>/*\n*/ #include <string.h>/*\n*/#include <malloc.h>/*se copiază codul din exemplele:8(1),8(2),8(3),8(4),8(5),8(6),8(7)*/int main(){ NOD *rad,*x; rad = creare_arbore(); parcurge(rad); x = adresa_nod(4,rad); printf("\n id ptr. id:4 este: %d\n", x->id); sterge_subarb(4,rad); parcurge(rad); return 0;}

Page 104: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

8.Funcţii recursive. Parcurgerea arborilor.

ultimul element egal cu NULL pentru a opri căutarea în cadrul vectorului.

9. Funcţii uzuale din bibliotecile C. Lucrul cu fişiere text

9.1. Operaţii cu şiruri de caractere

Vectorii (tablourile unidimensionale) ce conţin date de tipul char au un statut aparte. Spaţiul de memorie asociat variabilelor acestui tip este 1 octet; un caracter se memorează ca un număr întreg, corespunzător codului ASCII al caracterului respectiv. Prin urmare, în C, un caracter poate să apară în operaţii numerice. Valorile acestui tip sunt cuprinse în intervalul [–128...127] în cazul caracterelor cu semn, respectiv [0...255] în cazul celor fără semn (corespunzător setului de caractere ASCII EXTINS).

Orice şir de caractere se termină prin 0 numeric. Altfel spus, un vector de caractere ce conţine pe ultima poziţie caracterul cu codul 0 este un şir de caractere. Dacă într-un şir de caractere setăm sau introducem codul 0, atunci şirul de caractere se va termina în acel punct.

Biblioteca ce conţine funcţiile pentru şiruri de caractere este dată de header-ul <string.h>. În continuare este prezentat un exemplu cu câteva funcţii specifice şirurilor de caractere:

Funcţiile utilizate au sintaxa:● copiază şirul sursă în

destinaţie, dacă şirul destinaţie există acesta este înlocuit;● concatenează la şirul

destinaţie şirul sursă;● adaugă la

şirul destinaţie primele nr_caractere din şirul sursă. Nu adaugă automat la sfârşitul şirului terminatorul de şir (0), altfel atunci când citim şirul există riscul să citim informaţii rămase în memoria RAM până la întâlnirea valorii 0

103

strcpy(char* destinatie, char* sursa); strcpy(char* destinatie, char* sursa);

strcat(char* destinatie,char*sursa)strcat(char* destinatie,char*sursa)

strncat(char* destinatie,char*sursa,int nr_caractere)strncat(char* destinatie,char*sursa,int nr_caractere)

/*Ex.9.1(1):*/ #include <stdio.h>/*\n*/ #include <string.h> void f_siruri() { char b[50], a[50]="Un şir finit!"; printf("şirul a: %s\n",a); strcpy(b, a); //copiază şirul a în şirul b; printf("1.şirul b: %s\n",b); strcpy( b, &b[7] ); b[6]=9; printf("2.şirul b: %s\n",b); strcpy( &a[7],"în"); strncat(a,b,1000);//concatenare } // funcţia strncat nu adaugă terminatorul de şir (codul 0) int main() { f_siruri(); return 0;}

/*Ex.9.1(1):*/ #include <stdio.h>/*\n*/ #include <string.h> void f_siruri() { char b[50], a[50]="Un şir finit!"; printf("şirul a: %s\n",a); strcpy(b, a); //copiază şirul a în şirul b; printf("1.şirul b: %s\n",b); strcpy( b, &b[7] ); b[6]=9; printf("2.şirul b: %s\n",b); strcpy( &a[7],"în"); strncat(a,b,1000);//concatenare } // funcţia strncat nu adaugă terminatorul de şir (codul 0) int main() { f_siruri(); return 0;}

Page 105: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

pentru un octet din memorie.De asemenea există funcţii ce permite conversia din şiruri

de caractere într-un număr de tip int sau double şi invers.

9.2. Operaţii cu funcţii din biblioteca matematică

Biblioteca matematică este adăugată prin directiva #include<math.h> şi utilizează tipul de dată double. În exemplul următor sunt enumerate câteva funcţii din această bibliotecă:

şi un alt exemplu:

Funcţia calculează ab. Pentru

b = 0.5 obţinem funcţia sqrt, iar pentru a = e obţinem funcţia exp.

104

double pow(double a, double b);double pow(double a, double b);

/*Ex.9.2(1):*/ #include <math.h> /*\n*/#include <stdio.h>/*\n*/#include <string.h> main(){ char str[10]; double a = 0.5, b = 3, c; c = pow(a,b); printf(“pow(%f,%f)=%f\n”, a, b, c); c = sqrt(b); printf(“sqrt(%f)=%f\n”, b, c); c = exp(b); printf(“exp(%f)=%f\n”, b, c); c = log( exp(b) );printf(“log(exp(%f))=%f\n”, b, c); strcpy(str,”15.9”); c = atof(c); printf(“atof(%f)=%f\n”, b, c); //ascii to float return 0;}

/*Ex.9.2(1):*/ #include <math.h> /*\n*/#include <stdio.h>/*\n*/#include <string.h> main(){ char str[10]; double a = 0.5, b = 3, c; c = pow(a,b); printf(“pow(%f,%f)=%f\n”, a, b, c); c = sqrt(b); printf(“sqrt(%f)=%f\n”, b, c); c = exp(b); printf(“exp(%f)=%f\n”, b, c); c = log( exp(b) );printf(“log(exp(%f))=%f\n”, b, c); strcpy(str,”15.9”); c = atof(c); printf(“atof(%f)=%f\n”, b, c); //ascii to float return 0;}

/*Ex:9.1(2):*/#include <stdio.h>/*\n*/ #include <stdlib.h>/*\n*/#include <string.h> void f_conversii() { char str[50]; double x; int s; strcpy(str,"55"); s = atoi(str); //ascii to integer printf("s=%d\n",s); strcpy(str,"899.457"); x = atof(str); //ascii to float printf("x=%f\n",x); //invers – din int şi double în şir de caractere sprintf(str,"Un sir double:%f int:%d\n",x,s); printf("Sirul:%s\n",str); } int main() { f_conversii(); return 0;}

/*Ex:9.1(2):*/#include <stdio.h>/*\n*/ #include <stdlib.h>/*\n*/#include <string.h> void f_conversii() { char str[50]; double x; int s; strcpy(str,"55"); s = atoi(str); //ascii to integer printf("s=%d\n",s); strcpy(str,"899.457"); x = atof(str); //ascii to float printf("x=%f\n",x); //invers – din int şi double în şir de caractere sprintf(str,"Un sir double:%f int:%d\n",x,s); printf("Sirul:%s\n",str); } int main() { f_conversii(); return 0;}

/*Ex.9.2(2):*/ #include <math.h>/*\n*/#include <stdio.h> #include <string.h> void functii_biblmath() { double a = 25, b = 0.5, c; c = pow(a,b); printf("pow(%.2f,%.2f)=%.2f\n", a, b, c); c = asin(b); printf("arcsin(%.2f)=%.2f\n", b, c); c = sqrt(a); printf("sqrt(%.2f)=%.2f\n", a, c); } int main() { functii_biblmath(); return 0; }

/*Ex.9.2(2):*/ #include <math.h>/*\n*/#include <stdio.h> #include <string.h> void functii_biblmath() { double a = 25, b = 0.5, c; c = pow(a,b); printf("pow(%.2f,%.2f)=%.2f\n", a, b, c); c = asin(b); printf("arcsin(%.2f)=%.2f\n", b, c); c = sqrt(a); printf("sqrt(%.2f)=%.2f\n", a, c); } int main() { functii_biblmath(); return 0; }

Page 106: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

9.Funcţii uzuale din bibliotecile C. Lucrul cu fişiere text

9.3. Operaţii cu fişiere

Bibliotecile din C oferă funcţii atât pentru lucrul cu fişiere binare, cât şi funcţii pentru lucrul cu fişiere de tip text.

Fişierele de tip binar păstrează informaţiile la nivel de bit exact cum au fost scrise. Funcţii de tipul write scriu în fişier blocuri cu date în format binar, iar datele sunt citite pe blocuri cu funcţii de tipul read.

Fişierele de tip text interpretează caractere precum spaţiu sau linie nouă. Pentru a scrie într-un fişier sau pentru a citi dintr-un fişier, este necesară deschiderea acestuia cu ajutorul unei funcţii. După utilizare, fişierul se închide cu ajutorul unei alte funcţii. Atât operaţiile de citire, cât şi operaţiile de scriere setează o variabilă internă de poziţie în cadrul fişierului (iniţializată în momentul deschiderii fişierului) cu 1L (valoarea unu de tip unsigned long). Pe măsură ce datele sunt scrise sau citite, această variabilă este actualizată automat. Când această variabilă ajunge pe ultima poziţie din cadrul fişierului, este activat un flag (de obicei o variabilă de tip boolean), ce semnifică faptul că s-a ajuns la sfârşitul fişierului.

10. Implementarea unui analizor sintactic pentru expresii matematice

Un alt exemplu sugestiv privind importanţa funcţiilor recursive este reprezentat de analizoarele sintactice. În cele ce urmează este exemplificat un model simplificat al unui analizor pentru expresii matematice.

Ideea constă în împărţinea expresiei în alte expresii, în funcţie de operatorii şi funcţiile matematice identificate. Prima funcţie va genera alte apeluri recursive; fiecare funcţie va

105

/*Ex.9.3(1):*/ #include <stdio.h>/*\n*/ #include <stdlib.h> void fisiere_text() { FILE *fis; int x=0; char s[100]; if( (fis = fopen("un_test.txt","wt") ) == NULL)//wt-scriere+citire { printf("Fisierul nu a putut fi deschis!");return;} fprintf(fis," Un text \n"); fprintf(fis,"Fisierul este de tip text\n Un numar intreg: 35"); fseek(fis,0L,SEEK_SET); int m = ftell(fis); printf("\n pozitia1:%d",m);//poziţie cursor fseek(fis,30L,SEEK_SET); m = ftell(fis); printf("\n pozitia2:%d",m); //fscanf(fis,"%d",&x); fscanf(fis,"%s",s); //printf("x tiparit:%d",x); printf("s tiparit:%s",s); fclose(fis); } int main() { fisiere_text(); return 0; }

/*Ex.9.3(1):*/ #include <stdio.h>/*\n*/ #include <stdlib.h> void fisiere_text() { FILE *fis; int x=0; char s[100]; if( (fis = fopen("un_test.txt","wt") ) == NULL)//wt-scriere+citire { printf("Fisierul nu a putut fi deschis!");return;} fprintf(fis," Un text \n"); fprintf(fis,"Fisierul este de tip text\n Un numar intreg: 35"); fseek(fis,0L,SEEK_SET); int m = ftell(fis); printf("\n pozitia1:%d",m);//poziţie cursor fseek(fis,30L,SEEK_SET); m = ftell(fis); printf("\n pozitia2:%d",m); //fscanf(fis,"%d",&x); fscanf(fis,"%s",s); //printf("x tiparit:%d",x); printf("s tiparit:%s",s); fclose(fis); } int main() { fisiere_text(); return 0; }

Page 107: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

întoarce, în final, fie o valoare de tip double, fie un cod ce va fi ignorat în funcţia care a efectuat apelul. Operatorii şi funcţiile matematice identificate vor fi utilizaţi împreună cu rezultatele funcţiilor de evaluare – analizor1, lansate ca urmare a apelurilor recursive.

Funcţia analizor1 preia un şir de caractere, ce reprezintă o expresie matematică ce conţine operatori aritmetici şi funcţii din biblioteca matematică, şi întoarce valoarea acestei expresii.

În primul rând este necesar să evaluăm dacă expresia nu este chiar un număr. Funcţia double idnr(char* sir) implementează această cerinţă:

În cazul în care nu este un număr, întoarce 123456789L, altfel întoarce numărul convertit din şirul de caractere în tipul double.

O funcţie utilă este cea prin care sunt căutaţi operatorii bool cauta3(char operatorul,char* sir,char* sir1, char* sir2). Această funcţie preia şirul cu expresia în care se caută şi simbolul operatorului care este căutat. Funcţia identifică şirul din stânga operatorului, din dreapta operatorului şi pune cele două şiruri în variabilele sir1 şi sir2. Funcţia întoarce valoarea de adevăr TRUE dacă găseşte operatorul, altfel întoarce FALSE. De asemenea, funcţia contorizează numărul de paranteze închise şi deschise, deoarece altfel nu ar fi posibilă împărţirea în două expresii, fiecare din acestea urmând a fi reevaluate:

Este necesar să verificăm dacă expresia este delimitată de paranteze rotunde (în urma evaluării expresiilor se ajunge şi în

106

/*Ex.10(1): identintifică dacă expresia este un număr*/double idnr(char* sir){int i,cnt;//testeaza daca exista mai multe caractere '.' for(i=0,cnt=0;i<strlen(sir);i++)

{ if(sir[i]=='.') cnt++; if(cnt>1) return 123456789L;} for(i=0;i<strlen(sir);i++) if((sir[i]<'0' || sir[i]>'9')&&(sir[0]!='-')

&&(sir[0]!='+')&&(sir[i]!='.')) return 123456789L; return atof(sir);}

/*Ex.10(1): identintifică dacă expresia este un număr*/double idnr(char* sir){int i,cnt;//testeaza daca exista mai multe caractere '.' for(i=0,cnt=0;i<strlen(sir);i++)

{ if(sir[i]=='.') cnt++; if(cnt>1) return 123456789L;} for(i=0;i<strlen(sir);i++) if((sir[i]<'0' || sir[i]>'9')&&(sir[0]!='-')

&&(sir[0]!='+')&&(sir[i]!='.')) return 123456789L; return atof(sir);}

/*Ex.10(2): identintifică operatorii şi generează subexpresiile */bool cauta3(char operatorul, char* sir, char* sir1, char* sir2){int i,t; for(i=strlen(sir)-1,t=0;i>=0;i--) {if(sir[i]=='(') t++; if(sir[i]==')') t--; if(i && i!=(strlen(sir)-1) && sir[i]==operatorul && !t)

{strncpy(sir1,sir,i); sir1[i]=0; strcpy(sir2,&sir[i+1]); return true;} }return false;}

/*Ex.10(2): identintifică operatorii şi generează subexpresiile */bool cauta3(char operatorul, char* sir, char* sir1, char* sir2){int i,t; for(i=strlen(sir)-1,t=0;i>=0;i--) {if(sir[i]=='(') t++; if(sir[i]==')') t--; if(i && i!=(strlen(sir)-1) && sir[i]==operatorul && !t)

{strncpy(sir1,sir,i); sir1[i]=0; strcpy(sir2,&sir[i+1]); return true;} }return false;}

Page 108: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

10.Implementarea unui analizor sintactic pentru expresii matematice

această situaţie) şi atunci este necesar să eliminăm simbolurile pentru paranteze din cele două capete ale şirului. Acest lucru este asigurat de funcţia bool cautap(char* sir,char* sir1):

Analizorul trebuie să verifice dacă expresia ce urmează a fi evaluată este o funcţie din biblioteca matematică, caz în care întoarce valoarea expresiei. Acest lucru este implementat prin funcţia double cautfnc(char *buff).

Funcţia recursivă double analizor1(char *sir):

Apelul acestora este exemplificat în ceea ce urmează:

107

/*Ex:10(3): identifică dacă expresia este în întregime între paranteze şi le elimină */bool cautap(char* sir, char* sir1){if(sir[0]=='(' && sir[strlen(sir)-1] == ')') { strcpy(sir1, &sir[1]); sir1[strlen(sir)-2] = 0; return true; return false;}

/*Ex:10(3): identifică dacă expresia este în întregime între paranteze şi le elimină */bool cautap(char* sir, char* sir1){if(sir[0]=='(' && sir[strlen(sir)-1] == ')') { strcpy(sir1, &sir[1]); sir1[strlen(sir)-2] = 0; return true; return false;}

/*Ex.10(5): funcţia recursivă de evaluare */double analizor1(char *sir){ double m; char s1[100],s2[100];

if((m=idnr(sir))!=123456789L) return m; if(cautap(sir,s1)) return analizor1(s1);if(cauta3('+',sir,s1,s2)) return analizor1(s1)+analizor1(s2);if(cauta3('-',sir,s1,s2)) return analizor1(s1)-analizor1(s2);if(cauta3('*',sir,s1,s2)) return analizor1(s1)*analizor1(s2);if(cauta3('/',sir,s1,s2)) return analizor1(s1)/analizor1(s2);if((m=cautfnc(sir))!=123456789L) return m; }

/*Ex.10(5): funcţia recursivă de evaluare */double analizor1(char *sir){ double m; char s1[100],s2[100];

if((m=idnr(sir))!=123456789L) return m; if(cautap(sir,s1)) return analizor1(s1);if(cauta3('+',sir,s1,s2)) return analizor1(s1)+analizor1(s2);if(cauta3('-',sir,s1,s2)) return analizor1(s1)-analizor1(s2);if(cauta3('*',sir,s1,s2)) return analizor1(s1)*analizor1(s2);if(cauta3('/',sir,s1,s2)) return analizor1(s1)/analizor1(s2);if((m=cautfnc(sir))!=123456789L) return m; }

/*Ex.10(4): identintifică şi evaluează funcţii din bibl. matematică*/double cautfnc(char *buff){static int i,t,p; double m,m1,m2; char s1[MAX],s2[MAX]; i=0;t=0;p=0;m=0;m1=0;m2=0; if(buff[i]==0) {return -123456789L;} for(i=0;i<MAX;i++) {if(buff[i]==0) break; if(buff[i]==',') p=i;} t=i; i=0; if( (buff[0]=='e') && (buff[1]=='x') && (buff[2]=='p') && (buff[3]=='(') && (buff[strlen(buff)-1]==')') ) return exp(analizor1(&buff[3])); if( (buff[i]=='l') && (buff[i+1]=='o') && (buff[i+2]=='g') ) { strncpy(s1, &buff[i+3],t); s1[t-3]=0; m = log(analizor1(s1)); return(m); } if( (buff[i]=='s') && (buff[i+1]=='i') && (buff[i+2]=='n') ) { strncpy(s1, &buff[i+3],t); s1[t-3]=0; m = sin(analizor1(s1)); return(m); } if( (buff[i]=='c') && (buff[i+1]=='o') && (buff[i+2]=='s') ) { strncpy(s1, &buff[i+3],t); s1[t-3]=0; m = cos(analizor1(s1)); return(m); } if( (buff[i]=='p') && (buff[i+1]=='o') && (buff[i+2]=='w') ) { strncpy(s1,&buff[i+4],p-4); s1[p-4]=0; strncpy(s2,&buff[p+1],t-p); s2[t-p-2]=0; m1=analizor1(s1); m2=analizor1(s2); m = pow(m1,m2); return(m); }return 123456789L;}

/*Ex.10(4): identintifică şi evaluează funcţii din bibl. matematică*/double cautfnc(char *buff){static int i,t,p; double m,m1,m2; char s1[MAX],s2[MAX]; i=0;t=0;p=0;m=0;m1=0;m2=0; if(buff[i]==0) {return -123456789L;} for(i=0;i<MAX;i++) {if(buff[i]==0) break; if(buff[i]==',') p=i;} t=i; i=0; if( (buff[0]=='e') && (buff[1]=='x') && (buff[2]=='p') && (buff[3]=='(') && (buff[strlen(buff)-1]==')') ) return exp(analizor1(&buff[3])); if( (buff[i]=='l') && (buff[i+1]=='o') && (buff[i+2]=='g') ) { strncpy(s1, &buff[i+3],t); s1[t-3]=0; m = log(analizor1(s1)); return(m); } if( (buff[i]=='s') && (buff[i+1]=='i') && (buff[i+2]=='n') ) { strncpy(s1, &buff[i+3],t); s1[t-3]=0; m = sin(analizor1(s1)); return(m); } if( (buff[i]=='c') && (buff[i+1]=='o') && (buff[i+2]=='s') ) { strncpy(s1, &buff[i+3],t); s1[t-3]=0; m = cos(analizor1(s1)); return(m); } if( (buff[i]=='p') && (buff[i+1]=='o') && (buff[i+2]=='w') ) { strncpy(s1,&buff[i+4],p-4); s1[p-4]=0; strncpy(s2,&buff[p+1],t-p); s2[t-p-2]=0; m1=analizor1(s1); m2=analizor1(s2); m = pow(m1,m2); return(m); }return 123456789L;}

Page 109: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

IV.Introducere în limbajul C

Notă: Analizorul poate fi îmbunătăţit prin eliminarea altor excep-ţii sau prin adăugarea de noi funcţii sau operatori.

108

/*Ex:10(6): apelul în vederea testării */#include <stdio.h> /*\n*/#include <stdlib.h>/*\n*/#include <string.h>#include <math.h> /*\n*/ #define MAX 500double analizor1(char*);/* se copiază explicitările pentru funcţiile:idnr(),cauta3(),cautap(),cautfnc(),analizor1() */int main(){double x; char buf[100]="3+5*pow(0.5*4,6.5-4.5)-20*pow(2,2-1.5-1/2)";//scanf("%s",buf);if((x=analizor1(buf))!=123456789L) printf("ŞIR:%s --- D:%f\n",buf,x); else printf("Expresie ERONATA!"); return 0;}

/*Ex:10(6): apelul în vederea testării */#include <stdio.h> /*\n*/#include <stdlib.h>/*\n*/#include <string.h>#include <math.h> /*\n*/ #define MAX 500double analizor1(char*);/* se copiază explicitările pentru funcţiile:idnr(),cauta3(),cautap(),cautfnc(),analizor1() */int main(){double x; char buf[100]="3+5*pow(0.5*4,6.5-4.5)-20*pow(2,2-1.5-1/2)";//scanf("%s",buf);if((x=analizor1(buf))!=123456789L) printf("ŞIR:%s --- D:%f\n",buf,x); else printf("Expresie ERONATA!"); return 0;}

Page 110: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

V. Programarea orientată pe obiecteLimbajul C++

1. Clase şi moşteniri

1.1. Noţiunea de clasă şi obiect

Ideea de bază de la care pleacă programarea orientată pe obiecte este de a grupa structurile de date cu operaţiile care prelucrează respectivele date. Un asemenea ansamblu poartă denumirea de clasă. Clasa reprezintă tipul datei, iar obiectul reprezintă variabila după ce a fost alocată în memorie. Obiectul reprezintă instanţierea unei clase. Proiectarea de programe utilizând clase se numeşte programare orientată pe obiecte (OOP- Object Oriented Programming).

O clasă poate să conţină date (membri/atribute) şi funcţii (membre/metode/operatori). Datele sunt reprezentate prin decla-rațiile variabilelor din cadrul clasei. În cadrul unei clase pot fi declarate inclusiv variabile de tip structură sau de tip clasă. Date + Metode = Clasă (tipul datei)

Principiul încapsulării (ascunderea informaţiei ce stă la baza realizării clasei): accesul la datele membre se poate face numai prin intermediul setului de metode asociat. Obiectul este caracterizat complet prin metodele asociate. O parte din metode vor fi utilizate de cel ce utilizează clasa în cadrul aplicațiilor, iar altă parte va fi invizibilă pentru utlizatorul final (atât codul, cât și apelul acestora). Conform principiului încapsulării, utilizatorul nu are acces la date, ci numai la metodele pe care dezvoltatorul clasei le-a lăsat pentru a putea fi apelate.

1.2. Operatori specifici C++

Operator Simbol Forma Operaţia realizată

rezoluţie / indicator acces

:: ::a ::f()

• accesează variabilele globale chiar dacă au acelaşi nume cu cele locale;

• accesează membrii/membrele din cadrul claselor.

valoare .* OB.*a întoarce valoarea (OB valoare) valoare ->* OB->*a întoarce valoarea (OB pointer)

new new new tip

alocă memorie; ex ptr. un vector de 10 întregi: new int[10] întoarce NULL în caz de eşec, altfel întoarce adresa alocată

109

Page 111: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

Operator Simbol Forma Operaţia realizată

delete deletedelete adelete a[]

• eliberează zona de memorie;• Operatorul [] se utilizează

pentru tablouri.

this this this/ *this

arată adresa obiectului curent (în care ne aflăm), iar *this este valoarea obiectului curent (obiectul).

Adresa obiectului curent este dată de operatorul this.

1.3. Noţiunea de moştenire

Procedeul de derivare permite definirea unei clase noi, numită clasă derivată, care moşteneşte proprietăţile (membri + membre) unei clase deja definite, numită clasă de bază, pe care le completează cu proprietăţi (membri + membre) noi.

Prin procedeul de derivare/moştenire, clasa de bază nu este afectată şi nu trebuie recompilată, declaraţia (fişierul header) şi codul obiect ale clasei de bază (librăria) sunt suficiente pentru crearea unei clase derivate.

Dintr-o clasă (numită clasă de bază) pot fi derivate mai multe clase, iar fiecare clasă derivată poate servi ca bază pentru alte clase derivate. Astfel se realizează o ierarhie de clase. Pornind de la clase simple şi generale, fiecare nivel al ierarhiei acumulează caracteristicile (membri + membre) claselor părinte (bază) şi le adaugă un anumit grad de specializare. În cazul în care o clasă moşteneşte proprietăţile mai multor clase, avem moştenire multiplă, aceasta fiind specifică POO doar în câteva limbaje. Sintaxa declaraţia clasei derivate în cazul unei singure clase de bază:

class nume_clasa_derivata : modificator_acces nume_clasă_baza iar în cazul mai multor clase de bază (moştenire multiplă):

class nume_clasa_derivata : modificator_acces nume_clasă_baza_1 [<, modificator_acces nume_clasă_baza_n >]

2. Constructori şi destructori

2.1. Constructori

Constructorul este o funcţie care are acelaşi nume cu al clasei (inclusiv case sensitive) – specific C++;

Constructorul se apelează automat la crearea fiecărui obiect al clasei – creare de tip static, automatic sau dinamic;

O clasă poate avea mai mulţi constructuri, ei se deosebesc prin numărul şi tipul argumentelor;

110

Page 112: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Constructori şi destructori

În cazul în care nu se scrie niciun constructor, se va apela automat un constructor, fără argumente şi de tip public. Dacă utilizatorul declară cel puţin un constructor, atunci compilatorul nu mai generează acest constructor implicit;

Există şi un constructor implicit de copiere ce iniţializează obiectul curent cu datele (membrii) din alt obiect de acelaşi tip (aparţinând aceleiaşi clase). Acesta este de forma: nume_clasă(nume_clasa &) şi poate fi redefinit;

Constructorii nu întorc valori;

2.2. Destructori

Destructorul are acelaşi nume cu al clasei şi se declară cu operatorul ~ (tilda) înainte – specific C++;

Destructorul este apelat automat atunci când obiectul respectiv îşi încetează existenţa în memorie;

Utilizatorul nu va putea apela explicit destructorul unei clase;

Destructorul nu preia şi nu întoarce valori; O clasă are un singur destructor; În cazul în care nu este declarat niciun destructor se va

apela unul implicit;Explicitarea funcţiilor membre (inclusiv a constructorilor

şi destructorilor) se poate face fie în interiorul declaraţiei clasei, fie în exteriorul clasei prin utilizarea operatorului rezoluţie " :: ".

Funcţiile din cadrul unei clase se pot clasifica în:✗ constructori;✗ destructori;✗ funcţii normale de acces;✗ funcţii de tip prieten (friend);✗ funcţii virtuale;✗ funcţii statice;✗ funcţii de tipul operator.

2.3. Exemple

În continuare sunt prezentate câteva exemple în care apar noţiunile de constructor, destructor şi moştenire.

2.3.1. Exemplu privind moştenirea

Constructorul A(short a1_=5, short a2_=7) { a1=a1_;a2=a2_;}

111

/*Ex. 2.3(1.1):definire clasa A*/ class A{ public: short a1,a2; A(short a1_=5, short a2_=7) { a1=a1_; a2=a2_;} void afis() {std::cout<<"\n a1="<<a1<<" a2="<<a2;} };

/*Ex. 2.3(1.1):definire clasa A*/ class A{ public: short a1,a2; A(short a1_=5, short a2_=7) { a1=a1_; a2=a2_;} void afis() {std::cout<<"\n a1="<<a1<<" a2="<<a2;} };

Page 113: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

înlocuieşte mai mulţi constructori, în acest caz trei constructori şi anume:

☑ A(short a1_, short a2_); ☑ A(short a1_,) echivalent cu A(short a1_, 7);☑ A() echivalent cu A(5, 7).

Parametrii din cadrul constructorului B pot fi pasaţi constructorului A. În acest sens este necesar ca denumirea parametrilor din declaraţia constructorului B să fie aceeaşi cu denumirea parametrilor constructorului A din momentul explicitării constructorului B. Chiar dacă în “B(short b1_,short b2_):A(b2_)” parametrul b2_ este al doilea parametru, acesta va fi preluat corect.

2.3.2. Exemplu - apel constructori şi destructori într-o ierarhie de clase

Este prezentat un exemplu cu două clase având mai mulţi constructori, cu scopul de a pune în evidenţă ordinea de apel a constructorilor şi destructorilor. Clasa A este clasa de bază, iar B este clasa derivată.

Cuvântul cheie public este detaliat în capitolele următoare şi semnifică posibilitatea de acces a datelor şi funcţiilor atât din cadrul clasei, cât şi din exteriorul acesteia.

Constructorul clasei derivate va avea specificat construc-

112

/* Ex 2.3(2.1):definire clasa A */ class A {int a1,a2; A(){ a1 = 0; a2 = 0; cout<<"\n in constr. A() ";} A(int a1_) { a1 = a1_; a2 = 0; cout<<"\n in constr. A(int) "; } A(int a1_,int a2_) {a1 = a1_; a2 = a2_;cout<<"\n in A(int,int) ";} ~A() {cout<<"\n in DESTRUCTOR ~A() ";} };

/* Ex 2.3(2.1):definire clasa A */ class A {int a1,a2; A(){ a1 = 0; a2 = 0; cout<<"\n in constr. A() ";} A(int a1_) { a1 = a1_; a2 = 0; cout<<"\n in constr. A(int) "; } A(int a1_,int a2_) {a1 = a1_; a2 = a2_;cout<<"\n in A(int,int) ";} ~A() {cout<<"\n in DESTRUCTOR ~A() ";} };

/*Ex 2.3(2.2):definirea clasă B*/ class B:public A{ public: int b1, b2; B():A() { b1=0;b2=0;cout<<"\n in constr. B() ";} B(int b1_):A(b1_-5) {b1 = b1_; b2 = 0; cout<<"\n in constr.B(int)";} B(int b1_,int b2_) : A(b1_+b2_, 15) {b1 = b1_;b2 = b2_; cout<<"\n în constructorul B(int,int) ";} ~B() {cout<<"\n in DESTRUCTOR ~B() ";} };

/*Ex 2.3(2.2):definirea clasă B*/ class B:public A{ public: int b1, b2; B():A() { b1=0;b2=0;cout<<"\n in constr. B() ";} B(int b1_):A(b1_-5) {b1 = b1_; b2 = 0; cout<<"\n in constr.B(int)";} B(int b1_,int b2_) : A(b1_+b2_, 15) {b1 = b1_;b2 = b2_; cout<<"\n în constructorul B(int,int) ";} ~B() {cout<<"\n in DESTRUCTOR ~B() ";} };

/*Ex. 2.3(1.3):*/ #include<iostream>/*Se copiază Ex2.3(1.1),(1.2)(1.3)*/ int main() { B x,y(11), z(100,200); x.afis(); y.afis(); z.afis(); return 0;}

/*Ex. 2.3(1.3):*/ #include<iostream>/*Se copiază Ex2.3(1.1),(1.2)(1.3)*/ int main() { B x,y(11), z(100,200); x.afis(); y.afis(); z.afis(); return 0;}

/*Ex. 2.3(1.2):definirea clasei B*/ class B : public A{ public: short b1,b2;B():A() {b1 = -1; b2 = -1;} B(short b1_):A(b1_) {b1 = b1_; b2 = 20;}B(short b1_, short b2_) : A(b2_) { b1 = b1_; b2 = b2_;}void afis(){std::cout<<"a1="<<a1<<" a2="<<a2<<" b1="<<b1<<" b2="<<b2;} };

/*Ex. 2.3(1.2):definirea clasei B*/ class B : public A{ public: short b1,b2;B():A() {b1 = -1; b2 = -1;} B(short b1_):A(b1_) {b1 = b1_; b2 = 20;}B(short b1_, short b2_) : A(b2_) { b1 = b1_; b2 = b2_;}void afis(){std::cout<<"a1="<<a1<<" a2="<<a2<<" b1="<<b1<<" b2="<<b2;} };

Page 114: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Constructori şi destructori

torul clasei de bază pe care îl apelează deoarece o clasă poate avea mai mulţi constructori (funcţii de tip constructor). Mai întâi, se apelează în mod automat constructorul clasei de bază, iar apoi se apelează în mod automat constructorul clasei derivate. Apelul destructorilor se realizează automat în momentul distru-gerii obiectului şi se realizează în ordine inversă, mai întâi se apelează destructorul clasei derivate, iar apoi se apelează destructorul clasei de bază.

În momentul declaraţiei variabilei (de tip automatic), ce reprezintă obiectul, este apelat automat un constructor al clasei, iar în momentul închiderii blocului în care este declarat obiectul (cu excepţia obiectelor alocate dinamic), este apelat automat destructorul. Dacă obiectul este alocat dinamic, atunci constructorul va fi apelat în momentul alocării dinamice a memoriei pentru acel obiect, iar destructorul va fi apelat automat în momentul eliberării zonei de memorie ce conţine obiectul.

În acest exemplu, x este obiectul (variabila), iar B este clasa (tipul de dată). Secvenţa de declarare “B x;” este echivalentă cu “B x()” unde x() este constructorul fără parametri.Notă:➢ Pot exista cazuri în care nu avem constructori, situaţie în care

este apelat automat un constructor fără argumente şi fără conţinut, de ex.: A() {} denumit şi constructor implicit;

➢ Se apelează în primul rând constructorul clasei de bază, iar apoi constructorul clasei derivate;

➢ Pentru fiecare obiect din tablou se apelează constructorul fără argumente sau după caz constructorul implicit;

➢ La încetarea vizibilităţii unui tablou cu obiecte, se apelează destructorul pentru fiecare obiect din tablou.

2.4. Exemple privind ordinea de apel a constructorilor şi destructorilor

2.4.1. Exemplul nr.1

Ce se afişează în urma execuţiei funcţiei int main() ?#include <iostream>#include <string.h>using namespace std;class A { protected: char nob[30]; //nob=nume obiect public:

113

/*Ex 2.3(2.3):*/ #include <iostream> using namespace std; /*Se copiază Ex 2.3(2.1),(2.2),(2.3)*/ int main() {cout<<"\n X"<<endl; B x; cout<<"\n S[3]"<<endl; B s[3]; cout<<"\n Y"<<endl; B y(4,5); return 0; }

/*Ex 2.3(2.3):*/ #include <iostream> using namespace std; /*Se copiază Ex 2.3(2.1),(2.2),(2.3)*/ int main() {cout<<"\n X"<<endl; B x; cout<<"\n S[3]"<<endl; B s[3]; cout<<"\n Y"<<endl; B y(4,5); return 0; }

Page 115: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

int a; A() { a = 15; strcpy(nob,"N/A"); afis("A-Constr."); } A(int a1) { a = a1; strcpy(nob,"N/A"); afis("A-Constr."); } ~A() { afis("A-Destr."); } virtual void print() = 0; virtual void afis(char* clasa) { cout<<"CLASA:"<<clasa<<" Variabila:"<<nob<<endl; } };class B : protected virtual A{protected: int b; public: B(int a1) : A(a1) { b = 0; afis("B-Constr_0"); } B(char *nob1,int b1):A() { b = b1; strcpy(nob,nob1); afis("B-Constr_2");} ~B() { afis("B-Destructor"); } void print() {cout<<"B::a:"<<a<<endl;} }; class C : public virtual A{ int c; public: C() : A() { c = 0; afis("C-Constr_0"); } C(char *nob1, int c1) : A()

{ strcpy(nob, nob1); afis("C-Constr_2"); } ~C() { afis("C-Destructor"); } }; class D : public B, private C{ int d; public: D() : B(1), C() { afis("D-Constr_0"); } D(char *nob1 ,int d1) : B(d1-4), C() { strcpy(A::nob,nob1); afis("D-Constr_2"); } ~D() { afis("D-Destructor"); } }; int main() { D y("y",5);/* verificare posibilitate asignari*/ return 0;}

2.4.2. Exemplul nr.2

Ce se afişează în urma execuţiei codului următor?#include <iostream>#include <stdio.h>#include <string.h>using namespace std;class A1{ int x, ta; char nvar[30]; protected: int ya; public: A1() { strcpy(nvar,"N/A"); x = 0; ya = 0; afis("CONSTR_0"); } A1(char *nvar1)

{ strcpy(nvar,nvar1); x = 0; ya=0; afis("CONSTR_1"); }

114

Page 116: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Constructori şi destructori

A1(char *nvar1,int x1, int ya1){ strcpy(nvar,nvar1); x = x1; ya = ya1; afis("CONSTR_2"); }

~A1() { afis("DESTRUCTOR"); } virtual void afis(char *sir); };

void A1::afis(char *sir) { cout<<"A1#numevar:"<<nvar<<"-"<<sir<<endl; }

class B2 : protected A1{int x; char nvar[30]; protected:int yb; public:int t2; B2() : A1() { strcpy(nvar,"N/A"); x = 0; yb = 0; afis("CONSTR_0"); } B2(char *nvar1) : A1(nvar1,2,5) { strcpy(nvar,nvar1); x = 0; yb = 0; afis("CONSTR_1"); } B2(char *nvar1,int x1,int yb1):A1(nvar1) { strcpy(nvar,nvar1); x = x1; yb = yb1; afis("CONSTR_2"); } ~B2() {afis("DESTRUCTOR");} void afis(char *sir); };

void B2::afis(char *sir){ cout<<"B2#numevar:"<<nvar<<"-"<<sir<<endl; }

int main(){ A1 *ax[2]; B2 bx; { A1 az("az"); { B2 by("by",0,0); ax[0] = new A1("ax",1,1); //asignări ptr. pct. 2 } ax[1] = ax[0]; delete ax[0]; } return 0;}

3. Modificatori şi specificatori de acces. Exemple

3.1. Modificatori şi specificatori de acces

Specificatorii de acces sunt cuvinte cheie care specifică zona de vizibilitate pentru datele şi funcţiile ce urmează cuvântului cheie.

Modificatorii de acces permit modificarea drepturilor de acces asupra unor date sau funcţii în cazul derivării în sensul restrângerii acestora.

Datele (membrii) şi membrele (funcţiile) din interiorul unei clase pot avea următorii specificatori de acces:➢ public: datele/membrele pot fi accesate de oriunde, chiar şi

din afara clasei;

115

Page 117: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

➢ protected: datele/membrele dintr-o clasă de bază pot fi văzute în interiorul claselor derivate, dar nu şi în afara acestora;

➢ private: datele/membrele dintr-o clasă nu sunt văzute decât în interiorul clasei.

Implicit toate datele şi metodele din cadrul unei clase sunt de tip private.

Dacă constructorii nu ar fi declaraţi cu specificatorul de acces public, nu am putea avea obiecte de tipul clasei respective în afara clasei.

Modificatorii de acces

Specificatorul de acces din clasa de

bază

Modificator de acces

Accesul moştenit de

clasa derivată

Accesul din

exterior

privateprotectedpublic

privateprivateprivate

inaccesibilprivateprivate

inaccesibilinaccesibilinaccesibil

privateprotectedpublic

protectedprotectedprotected

inaccesibilprotectedprotected

inaccesibilinaccesibilinaccesibil

privateprotectedpublic

publicpublicpublic

inaccesibilprotectedpublic

inaccesibilinaccesibilaccesibil

3.2. Exemplu privind accesul

În continuare este prezentat un exemplu de utilizare a modificatorilor şi specificatorilor de acces. Este definită o ierarhie de clase pe trei nivele: 1-clasa de baza A, 2- clasele B1, B2, B3 cu modificatorii de acces public, protected şi private, 3- clasele C1, C2, C3 cu modificatorii de acces de tip public. În vederea testării se va elimina treptat câte un comentariu corespunzător intrucţiunilor de atribuire din funcţia int main ().

Într-o clasă, dacă nu este scris un specificator de acces înainte de declaraţia unei date (variabile/membru) sau a unei funcţii (metode/membre); acesta va fi private, altfel spus aceasta va putea fi utilizată doar în cadrul clasei respective, cu excepţia funcţiilor de tip friend, funcţii detaliate în alt subcapitol (de exemplu, variabila a1 din cadrul clasei A).

116

/*Ex. 3.2(1.1):definire clasă A*/ class A{ short a1; protected: short a2; public: short a3;A(short a1_=0,short a2_=0,short a3_= 0) {a1 = a1_; a2=a2_; a3=a3_;}~A() {} };

/*Ex. 3.2(1.1):definire clasă A*/ class A{ short a1; protected: short a2; public: short a3;A(short a1_=0,short a2_=0,short a3_= 0) {a1 = a1_; a2=a2_; a3=a3_;}~A() {} };

Page 118: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Modificatori şi specificatori de acces. Exemple

Prin modificatorul de acces public, tot ce este public sau protected în clasa A va rămâne la fel şi în clasele derivate, iar datele de tip private din A nu sunt accesibile şi în clasele derivate.

Prin utilizarea modificatorului de acces protected, tot ce este de tip public sau protected în clasa A devine de tip protected în clasa derivată B2.

În acest caz, când modificatorul de acces este de tip private, tot ce este de tip public sau protected în clasa A devine de tip private în clasa derivată B3.

În acest caz, variabilele a2 şi a3 sunt accesibile în cadrul clasei C1.

De asemenea variabilele a2 şi a3 sunt accesibile în cadrul clasei C2.

Datorită modificatorului de acces al clasei B3 (private),

117

/*Ex. 3.2(1.2):definirea clasei B1*/ class B1 : public A { short bx1; protected: short by1; public: short bz1; B1( short bx1_, short by1_, short bz1_, short a1_, short a2_, short a3_ ) : A( a1_, a2_, a3_) { bx1 = bx1_; by1 = by1_; bz1 = bz1_; } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.2):definirea clasei B1*/ class B1 : public A { short bx1; protected: short by1; public: short bz1; B1( short bx1_, short by1_, short bz1_, short a1_, short a2_, short a3_ ) : A( a1_, a2_, a3_) { bx1 = bx1_; by1 = by1_; bz1 = bz1_; } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.3):definire clasă B2*/class B2: protected A {short bx1;protected:short by1;public:short bz1;B2( short bx1_, short by1_, short bz1_, short a1_, short a2_, short a3_ ) : A( a1_, a2_, a3_) { bx1 = bx1_; by1 = by1_; bz1 = bz1_; } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.3):definire clasă B2*/class B2: protected A {short bx1;protected:short by1;public:short bz1;B2( short bx1_, short by1_, short bz1_, short a1_, short a2_, short a3_ ) : A( a1_, a2_, a3_) { bx1 = bx1_; by1 = by1_; bz1 = bz1_; } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.4):definire clasă B3*/class B3: private A {short bx1;protected:short by1;public:short bz1;B3( short bx1_, short by1_, short bz1_, short a1_, short a2_, short a3_ ) : A( a1_, a2_, a3_ ) { bx1 = bx1_; by1 = by1_; bz1 = bz1_; } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.4):definire clasă B3*/class B3: private A {short bx1;protected:short by1;public:short bz1;B3( short bx1_, short by1_, short bz1_, short a1_, short a2_, short a3_ ) : A( a1_, a2_, a3_ ) { bx1 = bx1_; by1 = by1_; bz1 = bz1_; } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.5):definire clasă C1*/class C1 : public B1 { C1( short bx1_,short by1_,short bz1_,short a1_,short a2_, short a3_ ) : B1( bx1_, by1_, bz1_, a1_, a2_, a3_ ) { } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.5):definire clasă C1*/class C1 : public B1 { C1( short bx1_,short by1_,short bz1_,short a1_,short a2_, short a3_ ) : B1( bx1_, by1_, bz1_, a1_, a2_, a3_ ) { } short sum() { return a2 + a3; } };

/*Ex. 3.2(1.6):definirea clasei C2*/class C2: public B2 { C2(short bx1_,short by1_,short bz1_, short a1_,short a2_,short a3_) : B2( bx1_, by1_, bz1_, a1_, a2_, a3_) {}short sum() { return a2 + a3; } };

/*Ex. 3.2(1.6):definirea clasei C2*/class C2: public B2 { C2(short bx1_,short by1_,short bz1_, short a1_,short a2_,short a3_) : B2( bx1_, by1_, bz1_, a1_, a2_, a3_) {}short sum() { return a2 + a3; } };

/*Ex. 3.2(1.7):definire clasă C3*/class C3: public B3 { C3( short bx1_,short by1_,short bz1_,short a1_,short a2_,short a3_) : B3( bx1_, by1_, bz1_, a1_, a2_, a3_ ) {}/*short sum(){return a2+a3;}//a2 si a3 sunt INACCESIBILE in C3 !*/ };

/*Ex. 3.2(1.7):definire clasă C3*/class C3: public B3 { C3( short bx1_,short by1_,short bz1_,short a1_,short a2_,short a3_) : B3( bx1_, by1_, bz1_, a1_, a2_, a3_ ) {}/*short sum(){return a2+a3;}//a2 si a3 sunt INACCESIBILE in C3 !*/ };

Page 119: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

variabilele a2 şi a3 rămân inaccesbile şi pentru clasa derivată C3.

Rezultatele testării sunt date în tabelul următor:

Atribuirea Acce-sibilă

SA - A MA - B SA - B MA - C SA - C

q = x.a1; NU private public inaccesibil public inaccesibil

q = x.a2; NU protected public protected public protected

q = x.a3 DA public public public public public

q = y.a1; NU private protected inaccesibil public inaccesibil

q = y.a2; NU protected protected protected public protected

q = y.a3; NU public protected protected public protected

q = z.a1; NU private private inaccesibil public inaccesibil

q = z.a2; NU protected private private public private

q = z.a3; NU public private private public privateÎn acest tabel “MA -” reprezintă modificatorul de acces

pentru clasa derivată ce are în denumire prima literă ce apare după “MA -”, iar “SA -” reprezintă specificatorul de acces în cadul clasei ce are în denumire prima literă ce apare după “SA -”

4. Funcţii de tip friend şi de tip static

4.1. Funcţii de tipul friend

O funcţie de tip friend (prieten) este o funcţie care nu este membră a clasei şi are acces la toţi membrii clasei. În interiorul clasei, ea se declară prin scrierea cuvântului cheie friend înaintea declaraţiei propiu-zise a funcţiei. O clasă ale cărei funcţii sunt, în totalitate, friend pentru altă clasă se numeşte clasă prietenă a acelei clase.

4.2. Exemplu cu funcţie de tip friend

Scopul exemplului este de a arăta când este necesară definirea unei funcţii de tip friend. În acest sens, se defineşte o clasă ce conţine o funcţie friend pentru clasa PCT. Dacă

118

/*Ex 3.2(1.8):implementare Se copiază Ex 3.2(1.1),(1.2),(1.3),(1.4),(1.5),(1.6),(1.7)*/ int main(){ B1 x(3,7,8,1,2,3); B2 y(3,7,8,1,2,3); B3 z(3,7,8,1,2,3); short q;// Notă:Pentru test se vor şterge, pe rând, comentariile/*q=x.a1;*/ /*q=x.a2;*/ /*q=x.a3;*/ /*q=y.a1;*/ /*q=y.a2;*/ /*q=y.a3;*/ /*q=z.a1;*/ /*q=z.a2;*/ /*q=z.a3;*/ return 0;}

/*Ex 3.2(1.8):implementare Se copiază Ex 3.2(1.1),(1.2),(1.3),(1.4),(1.5),(1.6),(1.7)*/ int main(){ B1 x(3,7,8,1,2,3); B2 y(3,7,8,1,2,3); B3 z(3,7,8,1,2,3); short q;// Notă:Pentru test se vor şterge, pe rând, comentariile/*q=x.a1;*/ /*q=x.a2;*/ /*q=x.a3;*/ /*q=y.a1;*/ /*q=y.a2;*/ /*q=y.a3;*/ /*q=z.a1;*/ /*q=z.a2;*/ /*q=z.a3;*/ return 0;}

Page 120: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Funcţii de tip friend şi de tip static

coordonatele x, y ar fi fost de tip public, nu ar fi fost necesară declarea funcţiei double distanta(PCT &a, PCT &b) de tip friend pentru clasa PCT.

Funcţia double distanta(PCT &a, PCT &b) este definită ca una obişnuită, externă clasei PCT, preia referinţele a două obiecte de tip PCT şi întoarce valoarea distanţei dintre cele două puncte.

În acest exemplu funcţia accesează date de tip private ale clasei PCT, din acest motiv este declarată de tip friend, astfel poate accesa datele de tip private şi protected.

Dacă declarăm coordonatele x şi y de tip public, nu mai este necesară declaraţia de tip friend pentru funcţie. Nu se recomandă utilizarea funcţiilor de tip friend deoarece reduc avantajul con-ceptului de programare orientată pe obiecte, de exemplu această funcţie nu apare în clasa curentă şi implicit nu apare nici în clasele derivate.

4.3. Membrii statici

Un tip aparte de membri ai unei clase sunt membrii statici. Atât funcţiile membru, cât şi datele membru (atributele) unei clase pot fi declarate static.

Dacă declaraţia unei variabile membru este precedată de cuvantul-cheie static, atunci va exista o copie unică a acelei variabile, care va fi folosită în comun de către toate obiectele instanţiate din clasa respectivă. Spre deosebire de variabilele membru obişnuite, pentru variabilele statice nu sunt create copii individuale ale acestora pentru fiecare obiect în parte; practic, toate obiectele vor accesa aceeaşi variabilă. Accesarea unei variabile statice se face folosind numele clasei şi operatorul de specificare a domeniului ("::").

Când se declară o dată membru ca fiind de tip static într-o clasă, ea nu este încă alocată. Prin declarare nu se alocă memorie,

119

/*Ex. 4.2(1.1):definirea clasei A*/class PCT{ double x,y; public: friend double distanta( PCT &a, PCT &b );PCT() {x = 0; y = 0;} PCT( double x1, double y1 ) { x = x1; y = y1;} };

/*Ex. 4.2(1.1):definirea clasei A*/class PCT{ double x,y; public: friend double distanta( PCT &a, PCT &b );PCT() {x = 0; y = 0;} PCT( double x1, double y1 ) { x = x1; y = y1;} };

/*Ex. 4.2(1.2):definirea funcţiei externe clasei A*/double distanta( PCT &a, PCT &b ){return sqrt(( a.x - b.x )*(a.x - b.x)+(a.y - b.y)*(a.y - b.y) );}

/*Ex. 4.2(1.2):definirea funcţiei externe clasei A*/double distanta( PCT &a, PCT &b ){return sqrt(( a.x - b.x )*(a.x - b.x)+(a.y - b.y)*(a.y - b.y) );}

/*Ex. 4.2(1.3):implementare apel funcţie frend */#include <iostream> #include <math.h> // pentru funcţia sqrt using namespace std; /*Se copiază pe linie nouă Ex 4.2(1.1),(1.2)*/ int main() { PCT p1(5,8), p2(7,10); double dist = distanta(p1,p2); cout<<"distanta= "<<dist; return 0; }

/*Ex. 4.2(1.3):implementare apel funcţie frend */#include <iostream> #include <math.h> // pentru funcţia sqrt using namespace std; /*Se copiază pe linie nouă Ex 4.2(1.1),(1.2)*/ int main() { PCT p1(5,8), p2(7,10); double dist = distanta(p1,p2); cout<<"distanta= "<<dist; return 0; }

Page 121: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

acest lucru se realizează în exteriorul clasei. Pentru a defini o variabilă membru statică, aceasta trebuie prevazută cu o definire globală, undeva în afara clasei.

Variabilele statice (ca şi funcţiile membru statice de altfel) pot fi utilizate indiferent dacă există sau nu instanţe ale clasei respective. De aceea, iniţializarea unei variabile statice NU poate cădea în sarcina constructorilor clasei (constructorii, se execută doar la momentul generării unei instanţe). Constructorii pot, însă, să modifice valorile variabilelor statice (de exemplu, pentru a contoriza numărul instanţelor unei clase, create la execuţia unui program).

Variabilele membru statice sunt folosite cel mai adesea pentru a asigura controlul accesului la o resursă comună. Acest tip de variabile se mai folosesc şi pentru a stoca informaţii comune unei întregi clase de obiecte.

Funcţiile membru pot fi declarate statice. În C++ o funcţie membru statică se comportă asemănător cu o funcţie globală al cărei domeniu este delimitat de clasa în care este definită.

4.4. Exemplu cu date de tip static şi funcţii de tip static

Scopul exemplului este de a arăta utilitatea datelor de tip static şi a funcţiilor de tip static.

Clasa A conţine o variabilă de tip static s, variabilă ce este incrementată în cadrul constructorului şi decrementată în cadrul destructorului. De asemenea, este definită o funcţie, membră a clasei A, ce permite afişarea valorii variabilei de tip static s. Funcţia trebuie să fie de tip static deoarece iniţial nu avem niciun fel de obiect şi nu ar putea fi apelată.

Pentru linia 1: s = 0 deoarece nu există niciun obiect, adică nu s-a apelat niciun constructor. Pentru linia 2: s = 6 ca urmare a apelului de tip automatic pentru vectorul ce conţine 6 obiecte în urma instanţierii clasei A. Pentru linia 3: s = 8 datorită apariţiei a încă două obiecte de tipul A. După închiderea

120

/*Ex. 4.4(1.1):definirea clasei A*/ class A { public: static int s; int x; A() {x = 0; s++; } A(int x1) {x = x1; s++;} ~A() {s--;} static void afis() { cout<<"s="<<s<<endl; } };

/*Ex. 4.4(1.1):definirea clasei A*/ class A { public: static int s; int x; A() {x = 0; s++; } A(int x1) {x = x1; s++;} ~A() {s--;} static void afis() { cout<<"s="<<s<<endl; } };

/*Ex. 4.4(1.2):implementare */ #include <iostream>using namespace std;/*Se copiază pe linie nouă 4.4(1.1)*/int A::s = 0;int main() { cout<<"\n 1: Nr: obiecte: "; A::afis(); {A v[6]; cout<<"\n 2: Nr: obiecte: "; A::afis(); {A m(3),u; cout<<"\n 3: Nr: obiecte: "; A::afis();

} cout<<"\n 4: Nr: obiecte: "; A::afis(); } cout<<"\n 5: Nr: obiecte: "; A::afis(); return 0;}

/*Ex. 4.4(1.2):implementare */ #include <iostream>using namespace std;/*Se copiază pe linie nouă 4.4(1.1)*/int A::s = 0;int main() { cout<<"\n 1: Nr: obiecte: "; A::afis(); {A v[6]; cout<<"\n 2: Nr: obiecte: "; A::afis(); {A m(3),u; cout<<"\n 3: Nr: obiecte: "; A::afis();

} cout<<"\n 4: Nr: obiecte: "; A::afis(); } cout<<"\n 5: Nr: obiecte: "; A::afis(); return 0;}

Page 122: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Funcţii de tip friend şi de tip static

ultimului bloc de instrucţiuni, este apelat automat destructorul pentru ultimele două obiecte adăugate, astfel pentru linia 4: avem s = 6. După închiderea blocului următor este apelat destructorul pentru obiectele din cadrul vectorului, astfel pentru linia 5: avem s = 0.

Variabila s este comună tuturor obiector de tipul clasei A, aceasta este independentă de existenţa obiectelor de tipul clasei respective, variabila s fiind memorată separat de celelalte obiecte.

5. Polimorfism, funcţii virtuale

Funcţiile virtuale sunt utilizate pentru implementarea obiectelor polimorfice.

5.1. Obiecte polimorfice

Obiectele polimorfice se careacterizează prin faptul că folosind aceeaşi formă de apel pentru funcţiile membre realizăm operaţii diferite. Funcţiile virtuale implementează filozofia "o singură interfaţă, mai multe metode", care pune în evidenţă polimorfism-ul.

5.2. Variabile de tip pointer care punctează la clasele derivate

Presupunem două clase, denumite BAZA şi DERIVATA, unde clasa DERIVATA moşteneşte clasa BAZA. În aceste condiţii, următoarele instrucţiuni sunt valabile:

☑ BAZA *p;//pointer-ul care punctează la clasa BAZA☑ BAZA OB_TIP_BAZA;//un obiect de tip BAZA☑ DERIVATA OB_TIP_DER;//un obiect de tip DERIVATA, pointer-ul p

poate puncta(prelua adresa) la obiecte de tip BAZA☑ p=&OB_TIP_BAZA;//p preia adresa lui OB_TIP_BAZA, p poate puncta la

obiecte derivate☑ p=&OB_TIP_DER;//p preia adresa lui OB_TIP_DER

Un pointer al clasei de bază poate puncta la un obiect din clasa derivată, fără a genera vreo eroare, invers nu este valabil. Prin acest pointer putem avea acces doar la membrii clasei derivate care au fost moşteniţi de la clasa de bază.

5.3. Funcţii virtuale

O funcţie virtuală este o funcţie membră a unei clase, care se declară în interiorul unei clase de bază şi se redefineşte (modifică) în clasele derivate.

Pentru a crea o funcţie virtuală, trebuie să utilizăm

121

Page 123: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

cuvântul cheie virtual, înainte de declaraţia funcţiei. La nivelul fiecărei clase, funcţiile virtuale implementează cod specific clasei respective, însă ele au acelaşi nume, aceeaşi listă de parametrii şi întorc aceelaşi tip de dată. Când un pointer al clasei de bază punctează la o funcţie virtuală din clasa derivată, şi aceasta este apelată prin intermediul acestui pointer, compilatorul determină care versiune (care din codurile/ care explicitare) a funcţiei trebuie apelată, ţinând cont de tipul obiectului (identifică clasa din ierarhie) la care punctează acel pointer. Altfel spus, tipul obiectului (clasa) la care punctează determină versiunea funcţiei virtuale care va fi executată.

O funcţie virtuală poate fi declarată şi numai formal, ea nerealizând nimic concret, aceasta fiind declarată doar pentru ca în clasele derivate să fie declarată şi explicitată. O astfel de funcţie virtuală, fără cod/explicitare se numeşte funcţie virtuală pură. Sintaxa pentru o funcţie virtuală pură este: virtual tip nume_funcţie(listă_de_parametri) = 0 ;

O clasă ce conţine o funcţie virtuală pură se numeşte clasă abstractă. Clasele abstracte sunt utilizate doar pentru a fi moştenite. Nu se pot exista instanţe ale claselor abstracte.

5.4. Exemple – polimorfism şi clase abstracte

5.4.1. Implementare polimorfism pentru afişare simplă

Primul exemplu conţine trei clase A, B şi C, ce conţin funcţia void afis(), declarată de tip virtual. Această funcţie este apelată utilizând polimorfismul.

Dacă nu se specifică constructorul pentru clasa de bază, se preia automat constructorul implicit.

În funcţia int main() se declară un vector cu adrese de tipul clasei de bază.

122

/*Ex. 5.4(1.1):definirea clasei A */class A {protected: int x; public: A(){ x = 0;} A(int x1){ x = x1;}virtual void afis() { cout<<"A: x="<<x<<endl; } };

/*Ex. 5.4(1.1):definirea clasei A */class A {protected: int x; public: A(){ x = 0;} A(int x1){ x = x1;}virtual void afis() { cout<<"A: x="<<x<<endl; } };

/*Ex. 5.4(1.2):definirea clasei B */class B: public A { protected: int y; public: B() : A(){ y = 0; }B(int x1,int y1) : A(x1){ y = y1;} void afis() { cout<<"B: x="<<x<<" y="<<y<<endl; } };

/*Ex. 5.4(1.2):definirea clasei B */class B: public A { protected: int y; public: B() : A(){ y = 0; }B(int x1,int y1) : A(x1){ y = y1;} void afis() { cout<<"B: x="<<x<<" y="<<y<<endl; } };

/*Ex. 5.4(1.3):definirea clasei C */class C: public B { protected: int z; public: C() : B(){ z = 0; }C(int x1, int y1,int z1):B(x1,y1) {z=z1;}void afis() { cout<<"C: x="<<x<<" y="<<y<<" z="<<z<<endl; } };

/*Ex. 5.4(1.3):definirea clasei C */class C: public B { protected: int z; public: C() : B(){ z = 0; }C(int x1, int y1,int z1):B(x1,y1) {z=z1;}void afis() { cout<<"C: x="<<x<<" y="<<y<<" z="<<z<<endl; } };

Page 124: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Polimorfism, funcţii virtuale

La adresa unui obiect de tipul clasei de bază a fost pusă o adresă a unui obiect de tipul unei clase derivate. Pentru w[0] şi w[1] apelează funcţia void afis() din cadrul clasei B, pentru w[2] apelează funcţia void afis() din cadrul clasei A, iar pentru w[3] şi w[4] apelează funcţia void afis() din cadrul clasei C.

Pentru controalele dintr-o interfaţă grafică, considerăm o clasă de bază generică TControl, din care sunt derivate clase generice precum: TEDit, TComboBox, TRadioButtons, TLabel etc. Fiecare din aceste clase are o metodă/funcţie specifică pentru desenarea fundalului. Pentru a schimba rapid culoarea de fond, se defineşte un vector w[] cu adrese la tip TControl. Adresa fiecărui control se copiază în acest vector, apoi se apelează într-o buclă o funcţie generică de forma void w[i]―>afisare_fundal(), ce va avea ca efect apelul fiecărei funcţii specifice (ex.: pentru un obiect de tip TRadioButtons, se apelează funcţia de afişare fundal speci-fică clasei TRadioButtons).

5.4.2. Implementare polimorfism pentru afişarea datei calendaristice

Un alt exemplu, permite afişarea datei calendaristice în funcţie de setările pentru ţară. Clasa de bază permite afişarea datei calendaristice în formatul general, specific bazelor de date an-lună-zi.

Clasa derivată pentru reprezentarea datei calendaristice în format românesc:

Clasa derivată pentru reprezentarea datei calendaristice în

123

/*Ex. 5.4(1.4):implementare polimorfism */ #include <iostream>using namespace std;/*Se copiază pe linie nouă 5.4(1.1),(1.2),(1.3)*/int main() { cout<<"Din A"<<endl; A t(1); t.afis(); cout<<"Din B"<<endl; B m(5,7); m.afis();cout<<"Din C"<<endl; C s(1,2,3); s.afis();cout<<"Vector cu 5 adrese de tipul A"<<endl; A* w[5]; cout<<"B()"; w[0] = new B(); //(idem w[1],w[3],w[4])cout<<"B(10,11) ";w[1]=new B(10,11); cout<<"A(30) ";w[2] = new A(30); cout<<"C() ";w[3]=new C();cout<<"C(21,22,23)\n";w[4]=new C(21,22,23); for(int i=0; i<5; i++) { cout<<" i:"<<i<<"--"; w[i]->afis(); }return 0; }

/*Ex. 5.4(1.4):implementare polimorfism */ #include <iostream>using namespace std;/*Se copiază pe linie nouă 5.4(1.1),(1.2),(1.3)*/int main() { cout<<"Din A"<<endl; A t(1); t.afis(); cout<<"Din B"<<endl; B m(5,7); m.afis();cout<<"Din C"<<endl; C s(1,2,3); s.afis();cout<<"Vector cu 5 adrese de tipul A"<<endl; A* w[5]; cout<<"B()"; w[0] = new B(); //(idem w[1],w[3],w[4])cout<<"B(10,11) ";w[1]=new B(10,11); cout<<"A(30) ";w[2] = new A(30); cout<<"C() ";w[3]=new C();cout<<"C(21,22,23)\n";w[4]=new C(21,22,23); for(int i=0; i<5; i++) { cout<<" i:"<<i<<"--"; w[i]->afis(); }return 0; }

/* Ex. 5.4(2.1):definirea clasei de bază DataC */class DataC { protected: unsigned short zi, luna, an; public: DataC( unsigned short an1, unsigned short luna1, unsigned short zi1) { an = an1; zi = zi1; luna = luna1; } virtual void afis() {cout<<"Format general:"<<an<<"-"<<luna<<"-"<<zi<<endl;}};

/* Ex. 5.4(2.1):definirea clasei de bază DataC */class DataC { protected: unsigned short zi, luna, an; public: DataC( unsigned short an1, unsigned short luna1, unsigned short zi1) { an = an1; zi = zi1; luna = luna1; } virtual void afis() {cout<<"Format general:"<<an<<"-"<<luna<<"-"<<zi<<endl;}};

/*Ex. 5.4(2.2):definirea clasei DataCro*/class DataCro: public DataC { public:DataCro( unsigned short an1, unsigned short luna1, unsigned short zi1 ) : DataC( an1, luna1, zi1 ) {}void afis() { cout<<"Format ro:"<<zi<<"."<<luna<<"."<<an<<endl; } };

/*Ex. 5.4(2.2):definirea clasei DataCro*/class DataCro: public DataC { public:DataCro( unsigned short an1, unsigned short luna1, unsigned short zi1 ) : DataC( an1, luna1, zi1 ) {}void afis() { cout<<"Format ro:"<<zi<<"."<<luna<<"."<<an<<endl; } };

Page 125: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

format englez:

Funcţia int main() ce implementează polimorfismul:

5.4.3. Implementare clase abstracte

Clasă abstractă:

Clasă derivată:

Funcţia int main() ce implementează clasa abstractă:

Se observă faptul că este posibil apelul funcţiei void afis2() (funcţie ce aparţine clasei A) din cadrul obiectelor x şi y: x.afis2() şi y.afis2() .

6. Moştenirea multiplă

În cazul în care o clasă moşteneşte proprietăţile mai multor clase, avem moştenire multiplă, o clasă derivă din mai multe clase de bază. Sintaxa:

Constructorul clasei derivate apelează constructorii ambelor clase de bază în ordinea dată.

124

/*Ex. 5.4(2.3):definirea clasei DataCen*/class DataCen: public DataC { public:DataCen( unsigned short an1, unsigned short luna1, unsigned short zi1 ) : DataC( an1, luna1, zi1 ) { }void afis() { cout<<"Format en:"<<luna<<"/"<<zi<<"/"<<an<<endl; } };

/*Ex. 5.4(2.3):definirea clasei DataCen*/class DataCen: public DataC { public:DataCen( unsigned short an1, unsigned short luna1, unsigned short zi1 ) : DataC( an1, luna1, zi1 ) { }void afis() { cout<<"Format en:"<<luna<<"/"<<zi<<"/"<<an<<endl; } };

/*Ex. 5.4(2.4):implementare polimorfism*/ #include <iostream>using namespace std;/*Se copiază pe linie nouă 5.4(2.1),(2.2),(2.3)*/int main() { DataC *x[3], *c; DataCro *a; DataCen *b; a = new DataCro(2013,03,11); b = new DataCen(2011,5,25); c = new DataC(2012,1,21); x[0] = a; x[1] = b; x[2] = c; for(int i=0;i<3;i++) x[i]->afis(); delete a;delete b;delete c;return 0; }

/*Ex. 5.4(2.4):implementare polimorfism*/ #include <iostream>using namespace std;/*Se copiază pe linie nouă 5.4(2.1),(2.2),(2.3)*/int main() { DataC *x[3], *c; DataCro *a; DataCen *b; a = new DataCro(2013,03,11); b = new DataCen(2011,5,25); c = new DataC(2012,1,21); x[0] = a; x[1] = b; x[2] = c; for(int i=0;i<3;i++) x[i]->afis(); delete a;delete b;delete c;return 0; }

/*Ex. 5.4(3.1):implementare clasă abstractă*/ class A{ public: int i;A(int i1){ i = i1; } A(){i=0;} //sau unul singur:A(int i1=0) {i=i1;} virtual void afis1() = 0; //functie virtuala pura --- nu are corp virtual void afis2() { cout<<"A---i2: "<<i<<endl; } };

/*Ex. 5.4(3.1):implementare clasă abstractă*/ class A{ public: int i;A(int i1){ i = i1; } A(){i=0;} //sau unul singur:A(int i1=0) {i=i1;} virtual void afis1() = 0; //functie virtuala pura --- nu are corp virtual void afis2() { cout<<"A---i2: "<<i<<endl; } };

/* Ex. 5.4(3.2):implementare clasă derivată */ class B: public A { public: B(int i1) : A(i1){ } B() : A(){ }void afis1() { cout<<"B--i1: "<<i<<endl; } };

/* Ex. 5.4(3.2):implementare clasă derivată */ class B: public A { public: B(int i1) : A(i1){ } B() : A(){ }void afis1() { cout<<"B--i1: "<<i<<endl; } };

/*Ex. 5.4(3.3):implementare clasă abstractă*/ #include <iostream>using namespace std; /*Se copiază pe linie nouă Ex 5.4(3.1),(3.2)*/int main() { /*A x(5); dă eroare */ B x(5),y; x.afis1(); x.afis2(); y.afis1(); y.afis2(); return 0;}

/*Ex. 5.4(3.3):implementare clasă abstractă*/ #include <iostream>using namespace std; /*Se copiază pe linie nouă Ex 5.4(3.1),(3.2)*/int main() { /*A x(5); dă eroare */ B x(5),y; x.afis1(); x.afis2(); y.afis1(); y.afis2(); return 0;}

/*Sintaxă moştenire multiplă*/ class nume_clasa_derivata : modificator_acces nume_clasă_baza_1 [<, modificator_acces nume_clasă_baza_n >]

/*Sintaxă moştenire multiplă*/ class nume_clasa_derivata : modificator_acces nume_clasă_baza_1 [<, modificator_acces nume_clasă_baza_n >]

Page 126: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Moştenirea multiplă

Moştenirea de tip diamant apare atunci când o clasă moşteneşte două sau mai multe clase, iar cel puţin două din acestea provin prin moştenire de la aceeaşi clasă.

6.1. Exemplu pentru moştenire multiplă simplă

Exemplul pune în evidenţă ordinea de apel a construc-torilor. Sunt date două clase de bază A şi B din care se derivează clasa C.

Este apelat mai întâi constructorul A(), apoi este apelat constructorul B() şi apoi se execută codul specific constructorului C(). Apelul constructorului C(int x1,int y1,int z1) duce la apelul constructorului A(y1), apoi la apelul constructorului B(y1), urmat de execuţia codului din constructorul C(int x1,int y1,int z1).

6.2. Exemplu privind moştenirea de tip diamant

În acest exemplu este prezentat un exemplu de clasă (D) ce moşteneşte două clase (B şi C), care la rândul lor au moştenit o clasă comună (A).

Exemplul pune în evidenţă forţarea apelului constructorului împlicit pentru clasa D, în care apare moştenirea de tip diamant.

125

/*Ex. 6.1.(1.1):implementare clasă bază A */ class A{ protected: int x; public: A(){x = 0; cout<<"\n in A() ";}A(int x1) { x = x1; cout<<"\n in A(int) "; }virtual void afis(){cout<<"x="<<x<<endl;} ~A(){cout<<"\n ~A() ";} };

/*Ex. 6.1.(1.1):implementare clasă bază A */ class A{ protected: int x; public: A(){x = 0; cout<<"\n in A() ";}A(int x1) { x = x1; cout<<"\n in A(int) "; }virtual void afis(){cout<<"x="<<x<<endl;} ~A(){cout<<"\n ~A() ";} };

/*Ex. 6.1.(1.3):implementare clasă derivată C */class C: public A, public B {int z; public:C() : A(), B(){ z = 0; cout<<"\n in C() "; }C(int x1,int y1,int z1):A(y1),B(y1) {z=z1; cout<<"\n C(int,int,int)";}virtual void afis(){ cout<<"\n X="<<x<<" Y="<<y<<" Z="<<z<<endl;} ~C() {cout<<"\n in ~C() ";} };

/*Ex. 6.1.(1.3):implementare clasă derivată C */class C: public A, public B {int z; public:C() : A(), B(){ z = 0; cout<<"\n in C() "; }C(int x1,int y1,int z1):A(y1),B(y1) {z=z1; cout<<"\n C(int,int,int)";}virtual void afis(){ cout<<"\n X="<<x<<" Y="<<y<<" Z="<<z<<endl;} ~C() {cout<<"\n in ~C() ";} };

/*Ex. 6.1(1.4):Creare obiecte*/ #include <iostream> using namespace std;/*Se copiază pe linie nouă 6.1(1.1),(1.2),(1.3)*/ int main() { C w1, r1(2,3,4); w1.afis(); r1.afis(); return 0;}

/*Ex. 6.1(1.4):Creare obiecte*/ #include <iostream> using namespace std;/*Se copiază pe linie nouă 6.1(1.1),(1.2),(1.3)*/ int main() { C w1, r1(2,3,4); w1.afis(); r1.afis(); return 0;}

/*Ex. 6.2.(1.1):implementare clasă bază A*/ class A{ protected: int x; public: A(){ x = -100; } A(int x1) {x=x1;}virtual void afis() { cout<<"A: x="<<x<<endl; } };

/*Ex. 6.2.(1.1):implementare clasă bază A*/ class A{ protected: int x; public: A(){ x = -100; } A(int x1) {x=x1;}virtual void afis() { cout<<"A: x="<<x<<endl; } };

/*Ex. 6.1.(1.2):implementare clasă de bază B */ class B { protected: int y; public: B() { y = 0;cout<<"\n in B() ";}B(int y1) { y = y1; cout<<"\n in B(int) ";}virtual void afis(){cout<<"\n y="<<y<<endl;} ~B(){cout<<"\n ~B()";} };

/*Ex. 6.1.(1.2):implementare clasă de bază B */ class B { protected: int y; public: B() { y = 0;cout<<"\n in B() ";}B(int y1) { y = y1; cout<<"\n in B(int) ";}virtual void afis(){cout<<"\n y="<<y<<endl;} ~B(){cout<<"\n ~B()";} };

Page 127: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

Prin utilizarea în momentul derivării a opţiunii virtual A, ne asigurăm că vom avea o singură copie a clasei A pentru obiectele ce sunt rezultatul instanţierii unei clase ce utilizează moştenirea multiplă.

Apelul clasei D:

Se observă faptul că valoarea 2 transmisă ca şi parametru pentru membrul x din cadrul clasei A nu se afişează, în schimb se afişează valoarea -100, corespunzătoare iniţializării membrului x prin constructorul fără parametrii A().

7. Supraîncărcarea operatorilor

Supraîncărcarea operatorilor (overloading-ul) presupune re-definirea operatorilor cu ajutorul funcţiei de tipul operator.

7.1. Restricţii privind supraîncărcarea operatorilor

➢ nu pot fi supraîncărcaţi decât operatorii existenţi;➢ operatorii: " . "," .* "," :: " , " ?: " şi " sizeof " nu pot fi

supraîncărcaţi;➢ operatorii binari vor fi supraîncărcaţi doar ca operatori binari;➢ operatorii unari vor fi supraîncărcaţi doar ca operatori unari;➢ se păstrează precedenţa operatorilor operator (nu există posibi-

litatea de a determina, de exemplu, ca "+" să fie prioritar faţă de "/");

➢ nu este posibilă definirea unui operator care să ia ca parametri exclusiv pointeri (exceptând operatorii: = & ,);

➢ nu se poate modifica numărul operanzilor preluaţi de un operator

126

/*Ex. 6.2.(1.2):implementare clasă derivată B*/ class B: public virtual A {protected: int y; public: B():A(){ y = 0;} B(int x1, int y1) : A(x1) { y = y1;} virtual void afis() { cout<<"B: x="<<x<<" y="<<y<<endl;} };

/*Ex. 6.2.(1.2):implementare clasă derivată B*/ class B: public virtual A {protected: int y; public: B():A(){ y = 0;} B(int x1, int y1) : A(x1) { y = y1;} virtual void afis() { cout<<"B: x="<<x<<" y="<<y<<endl;} };

/*Ex. 6.2.(1.3):implementare clasă derivată C */ class C: public virtual A {protected:int z; public:C(): A(){ z = 0; }C(int x1, int z1) : A(x1) { z = z1;}virtual void afis() { cout<<"C: x="<<x<<" z="<<z<<endl; } };

/*Ex. 6.2.(1.3):implementare clasă derivată C */ class C: public virtual A {protected:int z; public:C(): A(){ z = 0; }C(int x1, int z1) : A(x1) { z = z1;}virtual void afis() { cout<<"C: x="<<x<<" z="<<z<<endl; } };

/*Ex. 6.2.(1.4):implementare clasă moştenire multiplă D */class D: public B, public C {int t; public: D() : B(), C() { t = 0; }D(int x1, int y1, int z1, int t1) : B(x1,y1), C(x1,z1) { t=t1; }virtual void afis() {cout<<"D:x="<<x<<" y="<<y<<" z="<<z<<" t="<<t<<endl;}};

/*Ex. 6.2.(1.4):implementare clasă moştenire multiplă D */class D: public B, public C {int t; public: D() : B(), C() { t = 0; }D(int x1, int y1, int z1, int t1) : B(x1,y1), C(x1,z1) { t=t1; }virtual void afis() {cout<<"D:x="<<x<<" y="<<y<<" z="<<z<<" t="<<t<<endl;}};

/*Ex. 6.1(1.5):Creare obiecte*/ #include <iostream>using namespace std;/*Se copiază \n Ex 6.1(1.1),(1.2),(1.3),(1.4)*/int main() { D w1(2,3,4,5); w1.afis(); return 0;}

/*Ex. 6.1(1.5):Creare obiecte*/ #include <iostream>using namespace std;/*Se copiază \n Ex 6.1(1.1),(1.2),(1.3),(1.4)*/int main() { D w1(2,3,4,5); w1.afis(); return 0;}

Page 128: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Supraîncărcarea operatorilor

(însă se poate ignora unul din parametri);➢ un operator trebuie să fie ori membru al unei clase, ori să aibă

cel puţin un parametru de tip clasă. De la această regulă fac excepţie doar operatorii new şi delete;

➢ pentru operatorii : " = "," [] ", " () "," -> " funcţia operator trebuie să fie membră nestatică a clasei.

7.2. Sintaxa formei de apel

7.2.1. Operatori binari

Pentru un operator binar "op" avem: (op poate fi unul din operatorii din lista cu operatori C++):

Funcţia Sintaxa formei de apel externe

Sintaxa formei interne (canonice) de apel

membră a clasei obiect1 op obiect2 obiect1.operator op (obiect 2)nemembră obiect1 op obiect2 operator op (obiect1, obiect2)

7.2.2. Operatori unari

Pentru operatorul unar "op" avem:Funcţia Sintaxa formei de

apel externeSintaxa formei interne

(canonice) de apel

membră a claseiop obiect1obiect1 op

obiect1.operator op ()obiect1.operator op ()

nemembrăop obiect1obiect1 op

operator op (obiect1)operator op (obiect1)

7.3. Exemple privind supraîncărcarea operatorilor

7.3.1. Clasă ce conţine coordonatele carteziene ale unui punct

Este prezentat un exemplu de supraîncărcare a operatorilor pentru o clasă ce conţine coordonatele carteziene ale unui punct.

Supraîncărcarea operatorului ^ se realizează utilizând o funcţie membră a clasei iar a operatorului + prin utilizarea unei

127

/*Ex.7.3.1(1.1):definirea clasei Loc2D ce utilizează supraînc. op*/class Loc2D{ int x,y; public: Loc2D() { x = 0; y = 0; } Loc2D(int x1, int y1) { x = x1; y = y1; } friend Loc2D operator +( Loc2D &a, Loc2D &b); Loc2D operator ^(Loc2D d); Loc2D operator -(Loc2D d) {Loc2D s; s.x=x+d.x; s.y=y+d.y; return s;} Loc2D operator %(Loc2D d) { Loc2D s; s.x = x + (d.x-x)/2; s.y = this->y + (d.y-y)/2;return s;} void afis(char* str) {cout<<"x="<<x<<" y="<<y<<" ;"<<str<<endl;} };

/*Ex.7.3.1(1.1):definirea clasei Loc2D ce utilizează supraînc. op*/class Loc2D{ int x,y; public: Loc2D() { x = 0; y = 0; } Loc2D(int x1, int y1) { x = x1; y = y1; } friend Loc2D operator +( Loc2D &a, Loc2D &b); Loc2D operator ^(Loc2D d); Loc2D operator -(Loc2D d) {Loc2D s; s.x=x+d.x; s.y=y+d.y; return s;} Loc2D operator %(Loc2D d) { Loc2D s; s.x = x + (d.x-x)/2; s.y = this->y + (d.y-y)/2;return s;} void afis(char* str) {cout<<"x="<<x<<" y="<<y<<" ;"<<str<<endl;} };

Page 129: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

funcţii externă clasei (funcţie de tip friend). Cei doi operatori execută aceleaşi operaţii. Funcţia ce supraîncarcă operatorul % întoarce un punct situat la jumătatea distanţei (dintre coordonatele date de obiectul curent-this şi cele din obiectul din argument).

Funcţia operator^ se apelează din cadrul unui obiect, fiind în obiectul din stânga se preia ca argument obiectul din dreapta şi este întors un nou obiect cu rezultatul execuţiei.

Sunt prezentate ambele forme de utilizare a funcţiilor operator: prin operatori sau apel “în clar” a funcţiei operator. Alţi operatori supraîncărcaţi sunt prezentaţi în exemplul următor:

Funcţia operator+= este externă clasei. Funcţia operator/= întoarce obiectul în care ne aflăm, ca şi valoare.

128

/*Ex.7.3.1(1.2):definirea operatorilor ^ + */Loc2D Loc2D::operator ^(Loc2D d) { Loc2D s; s.x = x + d.x; s.y = y + d.y; return s;}Loc2D operator +(Loc2D &a, Loc2D &b) { Loc2D c(a.x+b.x, a.y+b.y); return c;}

/*Ex.7.3.1(1.2):definirea operatorilor ^ + */Loc2D Loc2D::operator ^(Loc2D d) { Loc2D s; s.x = x + d.x; s.y = y + d.y; return s;}Loc2D operator +(Loc2D &a, Loc2D &b) { Loc2D c(a.x+b.x, a.y+b.y); return c;}

/*Ex. 7.3.1(1.3):definirea operatorilor ^ + */#include <iostream>using namespace std;/*se copiază :Ex6.3.1(1.1),(1.2)*/int main(int argc, char **argv){ Loc2D f(3,4), g(5,6), m, h, k; m = f+g; m.afis("adunare m=f+g;"); m = operator+(f,g); m.afis("apel în clar : m=operator+(f,g);"); m = f-g; m.afis("apel cu fct. membra a clasei m=f-g;"); m = f.operator-(g); m.afis("apel în clar m=f.operator-(g);"); h = f^g; h.afis("adunare cu functie membra a clasei h=f^g;"); h = f.operator ^(g); h.afis("apel functie in clar h=f.operator ^(g);"); k = f%g; k.afis("jumatatea distantei intre 2 pcte k=f%g "); k = f.operator%(g); k.afis("apel functie în clar h=f.operator ^(g);"); return 0; }

/*Ex. 7.3.1(1.3):definirea operatorilor ^ + */#include <iostream>using namespace std;/*se copiază :Ex6.3.1(1.1),(1.2)*/int main(int argc, char **argv){ Loc2D f(3,4), g(5,6), m, h, k; m = f+g; m.afis("adunare m=f+g;"); m = operator+(f,g); m.afis("apel în clar : m=operator+(f,g);"); m = f-g; m.afis("apel cu fct. membra a clasei m=f-g;"); m = f.operator-(g); m.afis("apel în clar m=f.operator-(g);"); h = f^g; h.afis("adunare cu functie membra a clasei h=f^g;"); h = f.operator ^(g); h.afis("apel functie in clar h=f.operator ^(g);"); k = f%g; k.afis("jumatatea distantei intre 2 pcte k=f%g "); k = f.operator%(g); k.afis("apel functie în clar h=f.operator ^(g);"); return 0; }

/*Ex.7.3.1(2.1):definirea operatorilor ^ + */class Loc2D{int x,y;public: Loc2D() {x=0;y=0;} Loc2D(int x1, int y1) {x=x1;y=y1;}void afis(char* str1, char *str2) {cout<<str1<<".x="<<x<<" ; "<<str1<<".y="<<y<<" ; "<<str2<<endl;}friend Loc2D operator +=(Loc2D &c, Loc2D &b);Loc2D operator /=(Loc2D &b){x+=b.x; y+=b.y; return *this;}};//end_classLoc2D operator +=(Loc2D &c, Loc2D &b) { c.x+=b.x; c.y+=b.y; return c;}

/*Ex.7.3.1(2.1):definirea operatorilor ^ + */class Loc2D{int x,y;public: Loc2D() {x=0;y=0;} Loc2D(int x1, int y1) {x=x1;y=y1;}void afis(char* str1, char *str2) {cout<<str1<<".x="<<x<<" ; "<<str1<<".y="<<y<<" ; "<<str2<<endl;}friend Loc2D operator +=(Loc2D &c, Loc2D &b);Loc2D operator /=(Loc2D &b){x+=b.x; y+=b.y; return *this;}};//end_classLoc2D operator +=(Loc2D &c, Loc2D &b) { c.x+=b.x; c.y+=b.y; return c;}

Page 130: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Supraîncărcarea operatorilor

În continuare este prezentat un exemplu cu operatorul de asignare/atribuire.

Nu este o simplă copiere a obiectelor, operatorul = este supraîncărcat pentru a efectua alte operaţii. În lipsa supraîncărcării operatorul de asignare va copia obiectul din dreapta în partea stângă.

În continuare, este prezentat un alt exemplu ce supraîncarcă operatori de egalitate şi diferit - fiecare întoarce o valoare de adevăr:

Operatorul == întoarce valoarea TRUE dacă cele două obiecte sunt egale.

129

/*Ex.7.3.1(2.2):apelul operatorilor */ #include <iostream>using namespace std; /*copiere Ex7.3.1(2.1)*/int main() { Loc2D s(5,6), t(7,8); s += t;t.afis("t","t:apel normal"); s.afis("s","s:apel normal");

Loc2D m(5,6), n(7,8); m = operator +=(m,n);n.afis("n",":apel explicit"); m.afis("m",":apel explicit");

Loc2D a(1,2), b(3,4); b /= a;a.afis("a",":a-apel normal"); b.afis("b",":b-apel normal");

Loc2D c(1,2), d(3,4); d = d.operator /=(c);c.afis("c",":c-apel explicit"); d.afis("d",":d-apel explicit");return 0;}

/*Ex.7.3.1(2.2):apelul operatorilor */ #include <iostream>using namespace std; /*copiere Ex7.3.1(2.1)*/int main() { Loc2D s(5,6), t(7,8); s += t;t.afis("t","t:apel normal"); s.afis("s","s:apel normal");

Loc2D m(5,6), n(7,8); m = operator +=(m,n);n.afis("n",":apel explicit"); m.afis("m",":apel explicit");

Loc2D a(1,2), b(3,4); b /= a;a.afis("a",":a-apel normal"); b.afis("b",":b-apel normal");

Loc2D c(1,2), d(3,4); d = d.operator /=(c);c.afis("c",":c-apel explicit"); d.afis("d",":d-apel explicit");return 0;}

/*Ex.7.3.1(3.1):apelul operatorilor */ class Loc2D{ int x,y; public: Loc2D() { x=0; y=0; } Loc2D(int x1, int y1) { x=x1; y=y1; } void afis(char* str1, char *str2) { cout<<str1<<".x="<<x<<" ; "<<str1<<".y="<<y<<" ; "<<str2<<endl; }Loc2D operator=(Loc2D t) { x = t.x+10; y = t.y+10; return *this; } };

/*Ex.7.3.1(3.1):apelul operatorilor */ class Loc2D{ int x,y; public: Loc2D() { x=0; y=0; } Loc2D(int x1, int y1) { x=x1; y=y1; } void afis(char* str1, char *str2) { cout<<str1<<".x="<<x<<" ; "<<str1<<".y="<<y<<" ; "<<str2<<endl; }Loc2D operator=(Loc2D t) { x = t.x+10; y = t.y+10; return *this; } };

/*Ex.7.3.1(3.2):apelul operatorilor */ #include <iostream>using namespace std;/*copiere Ex7.3.1(3.1)*/ int main() {Loc2D a(4,5), b; a.afis("a","initial"); b.afis("b","initial"); b = a; b.afis("b","dupa atribuire - functie membra a clasei"); return 0; }

/*Ex.7.3.1(3.2):apelul operatorilor */ #include <iostream>using namespace std;/*copiere Ex7.3.1(3.1)*/ int main() {Loc2D a(4,5), b; a.afis("a","initial"); b.afis("b","initial"); b = a; b.afis("b","dupa atribuire - functie membra a clasei"); return 0; }

/*Ex.7.3.1(4.1):declararea operatorilor == şi != */class Loc2D{ int x,y; public:Loc2D() {x=0;y=0;} Loc2D(int x1, int y1) {x=x1;y=y1;} void afis(char* str1, char *str2) {cout<<str1<<".x="<<x<<" ; "<<str1<<".y="<<y<<" ; "<<str2<<endl;}bool friend operator !=(Loc2D a,Loc2D b); bool operator ==(Loc2D b);};bool operator !=(Loc2D a,Loc2D b) {return ((a.x==b.x)&&(a.y==b.y));}bool Loc2D::operator ==(Loc2D b) {return ((x==b.x) && (y==b.y));}

/*Ex.7.3.1(4.1):declararea operatorilor == şi != */class Loc2D{ int x,y; public:Loc2D() {x=0;y=0;} Loc2D(int x1, int y1) {x=x1;y=y1;} void afis(char* str1, char *str2) {cout<<str1<<".x="<<x<<" ; "<<str1<<".y="<<y<<" ; "<<str2<<endl;}bool friend operator !=(Loc2D a,Loc2D b); bool operator ==(Loc2D b);};bool operator !=(Loc2D a,Loc2D b) {return ((a.x==b.x)&&(a.y==b.y));}bool Loc2D::operator ==(Loc2D b) {return ((x==b.x) && (y==b.y));}

Page 131: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

De asemenea, se poate supraîncărca operatorul de indexare. Pentru aceasta considerăm o clasă VECT ce conţine un vector cu 5 elemente.

Accesarea indexului 3 va întoarce un rezultat mai mare decât valoarea iniţială cu 1000, iar pentru indecşii strict mai mici decât 2 va întoarce un rezultat mai mic cu 1000:

Instrucţiunea s3=s[1]; este echivalentă cu instrucţiunea s3=s.operator[](1); Accesarea e[4][1] este echivalentă cu apelul e[4].operator[](1) ( indexul 1 – al doilea index din cadrul celui de-al cincilea obiect).

7.3.2. Clasă ce conţine o matrice

În continuare este prezentat un exemplu de supraîncărcare a operatorilor pentru operaţiile cu matrice. În acest sens, declarăm o clasă Matrice:

130

/*Ex.7(1.1):definirea clasei Matrice ce foloseşte supraîncărcarea op*/class Matrice{ double **a;int m,n; // dimensiunea matricei: nr.linii x nr.coloanedouble** aloca(int m2, int n2);public: Matrice(int m1, int n1); //preluare dimensiuneMatrice(int m1, int n1, double **a1); //preluare dim. matrice+dateMatrice operator%(Matrice B);friend Matrice operator^(Matrice &A,Matrice &B);void set(int i,int j, double val);double get(int i,int j); //preia valoarea de la poziţia (i,j);void afis(); };

/*Ex.7(1.1):definirea clasei Matrice ce foloseşte supraîncărcarea op*/class Matrice{ double **a;int m,n; // dimensiunea matricei: nr.linii x nr.coloanedouble** aloca(int m2, int n2);public: Matrice(int m1, int n1); //preluare dimensiuneMatrice(int m1, int n1, double **a1); //preluare dim. matrice+dateMatrice operator%(Matrice B);friend Matrice operator^(Matrice &A,Matrice &B);void set(int i,int j, double val);double get(int i,int j); //preia valoarea de la poziţia (i,j);void afis(); };

/*Ex.7.3.1(4.2):apelul operatorilor */ #include <iostream>using namespace std;/*copiere Ex7.3.1(4.1)*/int main() {Loc2D s(6,8),t(6,8),m(6,9);if(s==t) cout<<"1. s == t"<<endl; else cout<<"1. s != t"<<endl;if(s==m) cout<<"2. s == m"<<endl; else cout<<"2. s != m"<<endl;if(s!=t) cout<<"3. s != t"<<endl; else cout<<"3. s == t"<<endl;if(s!=m) cout<<"4. s != m"<<endl; else cout<<"4. s == m"<<endl;return 0; }

/*Ex.7.3.1(4.2):apelul operatorilor */ #include <iostream>using namespace std;/*copiere Ex7.3.1(4.1)*/int main() {Loc2D s(6,8),t(6,8),m(6,9);if(s==t) cout<<"1. s == t"<<endl; else cout<<"1. s != t"<<endl;if(s==m) cout<<"2. s == m"<<endl; else cout<<"2. s != m"<<endl;if(s!=t) cout<<"3. s != t"<<endl; else cout<<"3. s == t"<<endl;if(s!=m) cout<<"4. s != m"<<endl; else cout<<"4. s == m"<<endl;return 0; }

/*Ex.7.3.1(5.1): operatorul de indexare */class VECT {double a[5];public:VECT() { for(int i=0;i<5;i++) a[i]=0;}VECT(double *a1) { for(int i=0;i<5;i++) a[i]=a1[i]; }~VECT(){ } double operator[](int i){if(i==3) return a[i]+1000; if(i<2) return a[i]-1000; return a[i];}};

/*Ex.7.3.1(5.1): operatorul de indexare */class VECT {double a[5];public:VECT() { for(int i=0;i<5;i++) a[i]=0;}VECT(double *a1) { for(int i=0;i<5;i++) a[i]=a1[i]; }~VECT(){ } double operator[](int i){if(i==3) return a[i]+1000; if(i<2) return a[i]-1000; return a[i];}};

/*Ex.7.3.1(5.2):apelul operatorului de indexare */ #include <iostream>using namespace std;/*copiere Ex7.3.1(5.1)*/int main(){double q[5]={10,20,30,40,50}; VECT s(q),e[7]; double s1,s2,s3; s1=s[3]; s2=s[4]; s3=s[1]; cout<<"s1="<<s1<<" ; s2="<<s2<<"; s3="<<s3<<endl; e[4]=s; cout<<"Din vector cu obiecte e[4][1]: "<<e[4][1]; return 0;}

/*Ex.7.3.1(5.2):apelul operatorului de indexare */ #include <iostream>using namespace std;/*copiere Ex7.3.1(5.1)*/int main(){double q[5]={10,20,30,40,50}; VECT s(q),e[7]; double s1,s2,s3; s1=s[3]; s2=s[4]; s3=s[1]; cout<<"s1="<<s1<<" ; s2="<<s2<<"; s3="<<s3<<endl; e[4]=s; cout<<"Din vector cu obiecte e[4][1]: "<<e[4][1]; return 0;}

Page 132: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

7.Supraîncărcarea operatorilor

Metoda operator^ este funcţie externă clasei ce are acces la date de tip private (int m,n; double *a) prin declarea acesteia friend.

Funcţiile set şi get asigură implementarea mecanismului de încapsulare a datelor. Datele din cadrul clasei Matrice vor fi accesate şi modificate numai prin aceste funcţii.Funcţia afis asigură afişarea unei matrice pe ecran.

Funcţia aloca asigură alocarea dinamică a memoriei pentru o matrice cu dimensiunea dată prin lista de parametri ai funcţiei aloca (varianta simplificată fără testele privind alocarea dinamică).

Sau varianta completă:

Clasa Matrice are un constructor cu doi parametri ce alocă memorie pentru o matrice şi iniţializează elementele matricii cu valoarea zero

şi un constructor cu trei parametri ce preia matricea prin argument:

131

/*Ex.7(1.2):definirea clasei Matrice ce foloseşte supraîncărcarea op*/void Matrice::afis() {for(int i=0;i<m;i++) { for(int j=0; j<n; j++) cout<<" "<<a[i][j]; cout<<"\n";} }

/*Ex.7(1.2):definirea clasei Matrice ce foloseşte supraîncărcarea op*/void Matrice::afis() {for(int i=0;i<m;i++) { for(int j=0; j<n; j++) cout<<" "<<a[i][j]; cout<<"\n";} }

/*Ex.7(1.3):alocare dinamică memorie matrice - fără teste de alocare*/double** Matrice::aloca(int m2, int n2){double **a; a = (double**)new double[m2]; for( int i=0;i<m2;i++) a[i] = new double[n2]; return a; }

/*Ex.7(1.3):alocare dinamică memorie matrice - fără teste de alocare*/double** Matrice::aloca(int m2, int n2){double **a; a = (double**)new double[m2]; for( int i=0;i<m2;i++) a[i] = new double[n2]; return a; }

/*Ex7(1.3):alocare dinamică memorie matrice - cu teste de alocare*/double** Matrice::aloca(int m2, int n2){double **a;if(!(a = (double**)new double[m2])) {cout<<”alocare esuată”;return NULL;} for(int i=0;i<m2;i++) if(!(a[i]=new double[n2])) { for(int k=0;k<i;k++) delete[] a[k]; delete[] a;cout<<”alocare esuată”;return NULL; } return a;}

/*Ex7(1.3):alocare dinamică memorie matrice - cu teste de alocare*/double** Matrice::aloca(int m2, int n2){double **a;if(!(a = (double**)new double[m2])) {cout<<”alocare esuată”;return NULL;} for(int i=0;i<m2;i++) if(!(a[i]=new double[n2])) { for(int k=0;k<i;k++) delete[] a[k]; delete[] a;cout<<”alocare esuată”;return NULL; } return a;}

/*Ex.7(1.4):constructor cu 2 parametri*/Matrice::Matrice(int m1, int n1){ m = m1; n = n1; a = aloca(m,n); for( int i=0; i<m; i++)

for( int j=0; j<n; j++) a[i][j] = 0; }

/*Ex.7(1.4):constructor cu 2 parametri*/Matrice::Matrice(int m1, int n1){ m = m1; n = n1; a = aloca(m,n); for( int i=0; i<m; i++)

for( int j=0; j<n; j++) a[i][j] = 0; }

Page 133: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

Sunt definite funcţiile ce asigură încapsularea datelor:

Este definită funcţia operator% ce asigură supraîncărcarea operaţiei de adunare a două matrice:

Se presupune că matricea B este de dimensiune m x n.

Exemplul complet este:

132

/*Ex.7(1.5):constructor cu 3 parametri*/Matrice::Matrice(int m1, int n1, double **a1) { m = m1; n = n1; a = aloca(m,n); for( int i=0; i<m; i++)

for(int j=0;j<n;j++) a[i][j]=a1[i][j]; }

/*Ex.7(1.5):constructor cu 3 parametri*/Matrice::Matrice(int m1, int n1, double **a1) { m = m1; n = n1; a = aloca(m,n); for( int i=0; i<m; i++)

for(int j=0;j<n;j++) a[i][j]=a1[i][j]; }

/*Ex.7(1.6):funcţii ptr.încapsularea datelor*/ void Matrice::set(int i, int j, double val) { a[i][j] = val; } double Matrice::get(int i, int j) { return a[i][j]; }

/*Ex.7(1.6):funcţii ptr.încapsularea datelor*/ void Matrice::set(int i, int j, double val) { a[i][j] = val; } double Matrice::get(int i, int j) { return a[i][j]; }

/*Ex.7(1.7):supraîncărcarea operatorului % pentru adunare*/Matrice Matrice::operator%(Matrice B){ Matrice C(m,n); for(int i=0;i<m;i++) for(int j=0;j<n;j++) C.a[i][j]=this->a[i][j]+B.a[i][j]

//sau C.set(i,j,this->get(i,j)+B.get(i,j)); return C; }

/*Ex.7(1.7):supraîncărcarea operatorului % pentru adunare*/Matrice Matrice::operator%(Matrice B){ Matrice C(m,n); for(int i=0;i<m;i++) for(int j=0;j<n;j++) C.a[i][j]=this->a[i][j]+B.a[i][j]

//sau C.set(i,j,this->get(i,j)+B.get(i,j)); return C; }

/*Ex.7(1.8):supraîncărcarea ptr. adunare – funcţie externă*/Matrice operator^(Matrice &A, Matrice &B) { Matrice C( A.m, A.n ); for( int i=0; i<A.m; i++ ) for( int j=0; j<A.n; j++ ) C.set(i, j, A.get(i,j)+B.get(i,j) ); return C; }

/*Ex.7(1.8):supraîncărcarea ptr. adunare – funcţie externă*/Matrice operator^(Matrice &A, Matrice &B) { Matrice C( A.m, A.n ); for( int i=0; i<A.m; i++ ) for( int j=0; j<A.n; j++ ) C.set(i, j, A.get(i,j)+B.get(i,j) ); return C; }

/*Ex.7(1.9):supraîncărcarea ptr. adunare – funcţie externă*/#include <iostream>using namespace std;/*Se copiază:Ex7(1.1),(1.2),(1.3),(1.4),(1.5),(1.6),(1.7),(1.8)*/int main() //ex. de utilizare ptr. o matrice 3x2{ double **c; c = (double**)new double[3]; for(int i=0; i<3; i++) c[i] = new double[2]; c[0][0]=5;c[0][1]=4;c[1][0]=25;c[1][1]=24; c[2][0]=15; c[2][1]=14; Matrice X(3,2,c), Y(3,2,c), Z(3,2); //Z=X+Y; Z=X%Y; cout<<"X"<<endl; X.afis(); cout<<"Y"<<endl; Y.afis(); cout<<"Z=X%Y"<<endl; Z.afis(); return 0; }

/*Ex.7(1.9):supraîncărcarea ptr. adunare – funcţie externă*/#include <iostream>using namespace std;/*Se copiază:Ex7(1.1),(1.2),(1.3),(1.4),(1.5),(1.6),(1.7),(1.8)*/int main() //ex. de utilizare ptr. o matrice 3x2{ double **c; c = (double**)new double[3]; for(int i=0; i<3; i++) c[i] = new double[2]; c[0][0]=5;c[0][1]=4;c[1][0]=25;c[1][1]=24; c[2][0]=15; c[2][1]=14; Matrice X(3,2,c), Y(3,2,c), Z(3,2); //Z=X+Y; Z=X%Y; cout<<"X"<<endl; X.afis(); cout<<"Y"<<endl; Y.afis(); cout<<"Z=X%Y"<<endl; Z.afis(); return 0; }

Page 134: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

8.Fluxuri de intrare/ieşire

8. Fluxuri de intrare/ieşire

8.1. Fluxuri de intrare/ieşire şi obiecte standard

Stream-urile au în principal rolul de a abstractiza operaţiile de intrare-ieşire. Acestea oferă metode de scriere şi citire a datelor, independente de dispozitivul I/O şi chiar independente de platformă. Aceste stream-uri tratează într-un mod unitar lucrul cu diverse periferice atât standard (tastatură, display), cât şi nestandard (plotere, controllere etc.). Stream-urile încapsulează (ascund) problemele specifice dispo-zitivului cu care se lucrează, sub librăria standard iostream. În C++ stream-urile au fost implementate utilizând clase, după cum urmează:➢ clasa streambuf gestionează buffer-ele;➢ clasa ios este clasa de bază pentru clasele de stream-uri de

intrare şi de ieşire. Clasa ios are ca variabilă membru un obiect de tip streambuf;

➢ clasele istream şi ostream sunt derivate din ios;➢ clasa iostream este derivată din istream şi ostream (moştenire

multiplă) şi oferă metode pentru lucrul cu dispozitivul standard de intrare/ieşire;

➢ clasa fstream oferă metode pentru operaţii cu fişiere.Un exemplu de formatare a datelor:

Aceste clase, prin instanţiere, oferă câteva obiecte stan-dard. Astfel, când un program C++, care include biblioteca iostream, este lansat în execuţie, sunt create şi iniţializate automat următoarele obiecte:

✗ cin - gestionează intrarea de la dispozitivul standard de intrare (tastatura);

133

/*Ex. 8.1(1): operaţii de formatare a datelor */ #include <iostream>#include <iomanip>using namespace std;class A { int m,n; double d; public: A( int m1, int n1, double d1 ) { m = m1; n = n1; d = d1;} void afis() {cout<<setfill('*')<<"1.m="<<setw(6)<<m<<endl; cout<<setfill('*')<<"2.m="<<m<<setw(6)<<endl; // nu are efect cout<<"3.m="<<setfill('*')<<setw(6)<<m<<endl; //rămâne tot width 6 cout<<"4.m="<<setfill(' ')<<setw(6)<<m<<endl; //width este tot 6 cout<<"5.m="<<setw(6)<<m<<endl; cout<<"6.d="<<setw(15)<<d<<endl; cout<<"7.d="<<setprecision(6)<<d<<endl; // rotunjire cout<<"8.d="<<setprecision(9)<<d<<endl; // rotunjire cout<<"9.n="<<n<<hex<<" n="<<n<<endl;} };int main() { A x(3,28,7.123456789); x.afis();

int k; cin>>k; cout<<dec<<"k="<<k<<endl;return 0; }

/*Ex. 8.1(1): operaţii de formatare a datelor */ #include <iostream>#include <iomanip>using namespace std;class A { int m,n; double d; public: A( int m1, int n1, double d1 ) { m = m1; n = n1; d = d1;} void afis() {cout<<setfill('*')<<"1.m="<<setw(6)<<m<<endl; cout<<setfill('*')<<"2.m="<<m<<setw(6)<<endl; // nu are efect cout<<"3.m="<<setfill('*')<<setw(6)<<m<<endl; //rămâne tot width 6 cout<<"4.m="<<setfill(' ')<<setw(6)<<m<<endl; //width este tot 6 cout<<"5.m="<<setw(6)<<m<<endl; cout<<"6.d="<<setw(15)<<d<<endl; cout<<"7.d="<<setprecision(6)<<d<<endl; // rotunjire cout<<"8.d="<<setprecision(9)<<d<<endl; // rotunjire cout<<"9.n="<<n<<hex<<" n="<<n<<endl;} };int main() { A x(3,28,7.123456789); x.afis();

int k; cin>>k; cout<<dec<<"k="<<k<<endl;return 0; }

Page 135: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

✗ cout - gestionează ieşirea către dispozitivul standard de ieşire (ecranul);

✗ cerr - gestionează ieşirea către dispozitivul standard de eroare.

Altfel spus:☑ INPUT STREAM (fluxuri de intrare): spre memoria RAM (IN RAM). ☑ OUTPUT STREAM (fluxuri de ieşire): tot ce pleacă din memoria

RAM (OUT RAM).

8.2. Operaţii de intrare/ieşire cu fişiere

Lucrul cu fişiere se realizează prin intermediul clasei ifstream pentru citire, respectiv ofstream pentru scriere. Pentru a le utiliza, aplicaţiile trebuie să includă biblioteca definită în fstream.h. Clasele ofstream şi ifstream sunt derivate din clasa iostream, ca urmare toţi operatorii şi toate funcţiile descrise mai sus sunt moştenite şi de această clasă.

Este prezentat un exemplu de scriere şi citire în fişier:

Instanţiem clasa ofstream pentru scriere în fişier. Obiectul este fis1, iar constructorul preia numele şi calea acestuia. O altă variantă ar fi ofstream fis1(numefis,ios::app); unde ios::app este utilizat pentru adăugarea la sfârşitul fişierului (fără trunchiere). De asemenea, se putea scrie şi ofstream fis1(numefis,ios::app|ios::out); caz în care adaugă la sfârşitul fişierului, dar permite şi operaţia de citire din acesta. Dacă fişierul nu a putut fi deschis, fis1 va avea valoarea NULL.

134

#include <iostream>/*Ex.8.2(1.2): instanţiere clasă pentru scrierea şi citirea din fişier */ #include <iomanip> #include <fstream>using namespace std; /*se copiază Ex 8.2(1.1)*/int main() {A s; s.scrie_in_fisier("C:/a01.txt"); s.citeste_din_fisier("C:/a01.txt"); return 0; }

#include <iostream>/*Ex.8.2(1.2): instanţiere clasă pentru scrierea şi citirea din fişier */ #include <iomanip> #include <fstream>using namespace std; /*se copiază Ex 8.2(1.1)*/int main() {A s; s.scrie_in_fisier("C:/a01.txt"); s.citeste_din_fisier("C:/a01.txt"); return 0; }

/*Ex. 8.2(1.1):declarare clasă A pentru scrierea şi citirea fişier */ class A{ public: void scrie_in_fisier(char* numefis){ ofstream fis1(numefis); if(!fis1) {cout<<"fisierul "<<numefis<<"nu a putut fi deschis pentru scriere"<<endl; return;} fis1<<"ABC"<<" 12 34"<<endl; //au fost scrise două secvenţe fis1<<"a="; int a; cout<<"a="; cin>>a; fis1<<a<<endl; }//prel.tastatură void citeste_din_fisier(char* numefis) {ifstream fis2(numefis);//instanţiem clasa pentru citirea din fişier char m[100]; if(!fis2) {cout<<"fişierul "<<numefis<<" nu a putut fi deschis pentru citire"<<endl; return;} while(!fis2.eof())//cat timp NU s-a ajuns la sfârşitul fişierului { fis2>>m; if(fis2.eof()) break; cout<<m<<endl;} } };

/*Ex. 8.2(1.1):declarare clasă A pentru scrierea şi citirea fişier */ class A{ public: void scrie_in_fisier(char* numefis){ ofstream fis1(numefis); if(!fis1) {cout<<"fisierul "<<numefis<<"nu a putut fi deschis pentru scriere"<<endl; return;} fis1<<"ABC"<<" 12 34"<<endl; //au fost scrise două secvenţe fis1<<"a="; int a; cout<<"a="; cin>>a; fis1<<a<<endl; }//prel.tastatură void citeste_din_fisier(char* numefis) {ifstream fis2(numefis);//instanţiem clasa pentru citirea din fişier char m[100]; if(!fis2) {cout<<"fişierul "<<numefis<<" nu a putut fi deschis pentru citire"<<endl; return;} while(!fis2.eof())//cat timp NU s-a ajuns la sfârşitul fişierului { fis2>>m; if(fis2.eof()) break; cout<<m<<endl;} } };

Page 136: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

8.Fluxuri de intrare/ieşire

În exemplul de mai sus ultimele secvenţe conţin şi carac-terul spaţiu. Separatorul pentru date în cadrul fişierelor text este caracterul spaţiu (cod ASCII:32). În bucla while se realizează citirea datelor din fişier atâta timp cât nu s-a ajuns la sfârşitul fişierului.

9. Introducere în funcţii şi clase template

O funcţie template este o funcţie şablon, având unul sau mai mulţi parametri formali de un tip generic. Funcţiile template sunt utilizate atunci când dorim să utilizăm aceeaşi funcţie pentru tipuri de date diferite, altfel spus acelaşi cod să poată prelucra tipuri diferite de date. Mecanismul template permite definirea o singură dată a şablonului de funcţii, după care se generează automat funcţiile propriu-zise în concordanţă cu necesităţile de utilizare

O definiţie a unei funcţii de tip template poate avea forma: unde T este tipul generic de dată. În

cadrul funcţiilor template nu putem avea conversii de dată (operaţii de tip cast).

Un cod template este compilat în două faze. În prima fază sunt verificate erorile de sintaxă, iar în faza următoare este generat codul corespunzător fiecărui tip de instanţe (pentru fiecare tip de dată din cadrul apelurilor funcţiei).

În continuare este prezentat un exemplu de funcţie template.

#include <iostream> // ex. 8.1using namespace std;template <class T> // T - tip generic de data (denumit, de exemplu: T)T DeterminaMaximul (T a, T b) {T rezultat; rezultat = (a>b)? a : b; //dacă a>b valoarea este a altfel este b return rezultat;}template <class T> T DeterminaSuma (T a, T b) { return a + b;}int main () { int i = -7, j = 6, max_int, suma_int; long l = 10, m = 5, max_long, suma_long; double s = 15.4, t = 7.2, max_double, suma_double; max_int = DeterminaMaximul<int>(i,j); max_long = DeterminaMaximul<long>(l,m); max_double = DeterminaMaximul<double>(s,t); suma_int = DeterminaSuma<int>(i,j); suma_long = DeterminaSuma<long>(l,m);

135

template <class T> void f1(T t1, T t2) { ... }

template <class T> void f1(T t1, T t2) { ... }

Page 137: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

V.Programarea orientată pe obiecte Limbajul C++

suma_double = DeterminaSuma<double>(s,t); cout <<"max_int: "<< max_int <<" suma_int: "<<suma_int<< endl; cout <<"max_long: "<< max_long <<" suma_long: "<<suma_long<< endl; cout <<"max_double: "<< max_double <<" suma_double: "<<suma_double<< endl; return 0;}

O clasă template defineşte un şablon pe baza căruia se pot genera clase propriu-zise. O clasă template se mai numeşte şi clasă generică sau metaclasă (o clasă de clase), reprezentând un nivel de abstractizare ridicat.

Exemplul de mai sus este pus într-o structură de clase:#include <iostream>using namespace std;template <class T> class CALCULEAZA{ public: T maximum(T x, T y); T adunare(T x, T y);};template <class T> T CALCULEAZA<T>::maximum(T x, T y){ return (x > y) ? x : y;}template <class T> T CALCULEAZA<T>::adunare(T x, T y){ return x + y;}int main () { CALCULEAZA<int> cx; CALCULEAZA<double> cy; int i = -7, j = 6, max_int, suma_int; long l = 10, m = 5, max_long, suma_long; double s = 15.4, t = 7.2, max_double, suma_double; max_int = c x.maximum(i,j); max_long = cx.maximum(l,m); max_double = cx.maximum(s,t); suma_int = cx.adunare(i,j); suma_long = cx.adunare(l,m); suma_double = cx.adunare(s,t); cout <<"cx -- max_int: "<< max_int <<" suma_int: "<<suma_int<< endl; cout <<"cx -- max_long: "<< max_long <<" suma_long: "<<suma_long<< endl; cout <<"cx:max_double: "<< max_double <<" suma_double: "<<suma_double<<endl; max_int = cy.maximum(i,j); max_long = cy.maximum(l,m); max_double = cy.maximum(s,t); suma_int = cy.adunare(i,j); suma_long = cy.adunare(l,m); suma_double = cy.adunare(s,t); cout <<"cy -- max_int: "<< max_int <<" suma_int: "<<suma_int<< endl; cout <<"cy -- max_long: "<< max_long <<" suma_long: "<<suma_long<< endl; cout<<"cy:max_double: "<< max_double <<" suma_double: "<<suma_double<<endl; return 0; }

136

Page 138: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

10.Tratarea excepţiilor

10. Tratarea excepţiilor

În timpul executării unui program pot apărea situaţii în care sunt generate erori, datorate de multe ori depăşirii puterii de reprezentare a numerelor, de operaţii nepermise, de depăşiri ale limitelor alocate etc. Ca urmare, este necesară anticiparea unor posibile excepţii, de multe ori provenite de la preluarea incorectă a datelor. Limbajul C++ oferă trei cuvinte cheie pentru a gestiona o excepţie: try, catch şi throw. Cuvântul cheie try este urmat de blocul ce se execută şi care poate genera o eroare în execuţie:

✗ try { bloc ce se execută în mod normal}Acest cuvânt cheie permite aplicaţiei să anticipeze un comportament anormal şi va încerca să trateze posibilele erori;

✗ catch { bloc ce se execută în cazul în care apare o excepţie/eroare }Acest cuvânt cheie este urmat, între acolade, de blocul ce se execută în cazul unei excepţii/erori;

✗ throw transmite excepţia, în vederea tratării acesteia, către sistemul de operare. La întâlnirea lui throw, codul următor nu se mai execută:

În secvenţa dată de catch se intră ca urmare a lui throw din blocul curent sau dintr-o bibliotecă ce corespunde unei funcţii utilizate în acest bloc şi al cărui throw întoarce un tip de dată în concordanţă cu tipul din argumentul lui catch.

137

/*Ex. 9(1): utilizarea excepţiilor */using namespace std;#include<iostream>int main() {char *a; int b=1,c=5,d=0;//ptr.test se va alege val.ptr.dtry{ b = 7; if(!d) throw (char*)"Operatie esuata!"; b = 6; c = b/d; //lăsat singur ==> excepţie primită de la S.O. if (d>-5 && d<0) throw -1; b=5; if(d<=-5) throw 2.14; b=4; }catch(char * str ){cout << "Exceptia 1 primita este: "<< str << '\n';}catch(int a) /*daca arg. este de tip int.*/{cout<<"Exceptia 2"<<endl;}catch(...) { cout<<"Toate exceptiile netratate"<<endl;}cout<<"b="<<b; return 0;}

/*Ex. 9(1): utilizarea excepţiilor */using namespace std;#include<iostream>int main() {char *a; int b=1,c=5,d=0;//ptr.test se va alege val.ptr.dtry{ b = 7; if(!d) throw (char*)"Operatie esuata!"; b = 6; c = b/d; //lăsat singur ==> excepţie primită de la S.O. if (d>-5 && d<0) throw -1; b=5; if(d<=-5) throw 2.14; b=4; }catch(char * str ){cout << "Exceptia 1 primita este: "<< str << '\n';}catch(int a) /*daca arg. este de tip int.*/{cout<<"Exceptia 2"<<endl;}catch(...) { cout<<"Toate exceptiile netratate"<<endl;}cout<<"b="<<b; return 0;}

Page 139: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

VI. Dezvoltarea interfeţei client cu ajutorul bibliotecilor

1. Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

Biblioteca wxWidgets este o bibliotecă cu clase C++ ce permite dezvoltarea interfeţelor grafice. Această bibliotecă este cross-platform şi open sources. În acest capitol vor fi exem-plificate câteva din clasele frecvent utilizate.

1.1. Structura unei aplicaţii

Pentru a observa structura unei aplicaţii ce utilizează clase wxWidgets putem alege următorul template pentru aplicaţie: “Workspace> NewProject> GUI> Executable> Executable (wxWidgets enabled)” (GUI: Graphics User Interface).

La aplicaţiile de tip consolă, punctul de intrare în program era dat de intrarea în funcţia main(), iar aici nu se observă o astfel de funcţie. Observăm o clasă wxApp şi o metodă OnInit(). Lansarea aplicaţiei corespunde cu execuţia metodei OnInit(). Ieşirea din metoda OnInit() cu valoarea de adevăr FALSE (return false) corespunde ieşirii din aplicaţie. Dacă ieşirea din metoda OnInit() se realizează cu valoarea de adevăr TRUE, aplicaţia intră într-o buclă de citire a eve-nimentelor (majoritatea eveni-mentelor sunt de la dispo-zitivele standard, acestea sunt de tipul: apăsarea unei taste, ridicarea unei taste, mişcarea mouse-ului, click sau dublu click pe unul din butoanele mouse-ului etc). Exemplul 1(1) nu afişează nimic, dar constituie structura minimală a unei aplicaţii ce utilizează clase wxWidgets.

În continuare este prezentat un exemplu 2(1-1) ce conţine o fereastră cu două butoane. Prin realizarea unui click cu mouse-ul pe unul din butoane se afişează un mesaj, iar celălat buton deschide o fereastră ce conţine un text.

Clasa primaAplicatie este derivată din clasa wxApp şi conţine metoda OnInit(), cele două funcţii void apasaButon_1 (wxCommandEvent& event) şi void apasaButon_2 (wxCommandEvent& event), ce corespund evenimentului clik pe buton cu mouse-ul. În cadrul primei funcţii este apelată o metodă pentru afişarea unui

138

/*Ex.1(1):intrarea în aplicaţie */ #include <wx/wx.h>class O_aplicatie : public wxApp{ public: virtual bool OnInit(){return true;}};IMPLEMENT_APP(O_aplicatie);

/*Ex.1(1):intrarea în aplicaţie */ #include <wx/wx.h>class O_aplicatie : public wxApp{ public: virtual bool OnInit(){return true;}};IMPLEMENT_APP(O_aplicatie);

Page 140: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

mesaj – wxMessageBox.

În cadrul funcţiei void apasaButon_2 (wxCommandEvent& event) este instanţiată clasa wxFrame, ce realizează construcţia unei ferestre. Primul patrametru pentru constructorul clasei wxFrame este NULL, ceea ce semnifică că această fereastră nu este ataşată unei alte ferestre. Parametrul ID_ANY semnifică faptul că această fereastră nu are ataşat un identificator (raportat la dezvoltator). Şirul “Titlu-2" reprezintă titlul ce va fi afişat în bara feres-trei. Funcţia wxT(“...”) este utilizată pentru conversia şirului de simboluri unicode într-un obiect de tip wxString (clasa wxString gestionează şirurile de simboluri/caractere). Nu a fost stabilită o anumită poziţie a ferestrei şi a fost pusă constanta wxDefaultPosition. Dimensiunea ferestrei a fost stabilită la 150 pixeli pe orizontală şi 200 de pixeli pe verticală. În acest sens dimensiunea ferestrei a fost preluată printr-un constructor al clasei wxSize – wxSize(150,200).

Culoarea pentru fundalul ferestrei a fost stabilită prin utilizarea celor trei canale RGB (RedGreenBlue), fiecare având valori cuprinse între 0 şi 255, 0 semnificând lipsa culorii pe canalul respectiv. Preluarea culorii pentru cele trei canale se realizează prin constructorul wxColour(118, 235, 158). Funcţia SetBackgroundColour(wxColour(118, 235, 158)) setează fundalul ferestrei.

În cadrul metodei void apasaButon_2 (wxCommandEvent& event) a fost instanţiată o clasă wxStaticText, ce construieşte un control de tip text – etichetă. Primul parametru din constructorul clasei identifică ferestra/obiectul căruia îi aparţine, în acest caz fereastra_2. Al doilea parametru, având valoarea wxID_ANY, arată faptul că nu există identificator atribuit acestui control.

Scrierea _("TESTE ANSI") este pentru caractere din setul ASCII, iar wxT("TESTE diacritice:ĂÎŞŢÂ") este pentru codificarea UNICODE.

Metoda OnInit() este explicitată în 2(2-2). Este instanţiată clasa wxFrame pentru prima fereastră din cadrul aplicaţiei, apoi este setată culoarea de fundal pentru fereastră.

În continuare sunt realizate două instanţe ale clasei wxButton. Pentru fiecare din cei doi constructori primul parametru

139

/*Ex.2(1-1):*/ class primaAplicatie : public wxApp{public:virtual bool OnInit();void apasaButon_1(wxCommandEvent& event){wxMessageBox("Mesaj BUTON!");}void apasaButon_2(wxCommandEvent& event) { wxFrame *fereastra_2 = new wxFrame( NULL,ID_ANY,wxT("Titlu-2"), wxDefaultPosition, wxSize(150,200)); fereastra_2->SetBackgroundColour( wxColour( 118, 235, 158 ) ); wxStaticText *L1 = new wxStaticText( fereastra_2, wxID_ANY, _("TESTE")); fereastra_2->Show();} };

/*Ex.2(1-1):*/ class primaAplicatie : public wxApp{public:virtual bool OnInit();void apasaButon_1(wxCommandEvent& event){wxMessageBox("Mesaj BUTON!");}void apasaButon_2(wxCommandEvent& event) { wxFrame *fereastra_2 = new wxFrame( NULL,ID_ANY,wxT("Titlu-2"), wxDefaultPosition, wxSize(150,200)); fereastra_2->SetBackgroundColour( wxColour( 118, 235, 158 ) ); wxStaticText *L1 = new wxStaticText( fereastra_2, wxID_ANY, _("TESTE")); fereastra_2->Show();} };

Page 141: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

este reprezentat de adresa ferestrei în care se construieşte controlul ce implementeză un buton. Al doilea parametru (aici numerele 10, 11) este reprezentat de identificatorul pentru fiecare control. Al treilea parametru din constructor este reprezentat de textul afişat pe buton. Următorii parametrii sunt reprezentaţi de poziţia controlului şi de dimensiunea acestuia.

Legătura între un control şi funcţia ce răspunde la un anumit eveniment este realizată de către funcţiile Connect detaliate în capitolul următor. Aplicaţia comple-tă este dată de exemplul 2(3). În acest exemplu poziţionarea controa-lelor este absolută, poziţia fiecărui control este transmisă ferestrei părinte (fereastra pe care sunt ataşate controalele grafice). Pentru a avea o poziţionare relativă pentru controale, se poate utiliza clasa wxBoxSizer.

Prin instanţierea clasei wxBoxSizer, se definesc “layout”-uri (moduri de afişare) pentru controalele din cadrul ferestrei. În acest sens, fiecare control trebuie adăugat în acel ”container” ce defineşte modul de aranjare a controalelor.Exemplul 2(2-1) devine:

140

/*Ex-2(2-1):*/ bool primaAplicatie::OnInit(){wxFrame *fereastra_1=new wxFrame( NULL, -1, wxT("Un titlu-1"),

wxDefaultPosition, wxSize( 250, 200) );fereastra_1->SetBackgroundColour( wxColour( 218, 235, 158 ) );wxButton *b1,*b2; b1 = new wxButton( fereastra_1,11, wxT("Mesaj nou!"), wxPoint(90,20), wxSize(80,50));b2=new wxButton( fereastra_1, 10, wxT("Fereastră nouă"), wxPoint(10,20), wxSize(100,100) );Connect(11, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (primaAplicatie::apasaButon_1) );Connect(10, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (primaAplicatie::apasaButon_2) );fereastra_1->Show(); return true;}

/*Ex-2(2-1):*/ bool primaAplicatie::OnInit(){wxFrame *fereastra_1=new wxFrame( NULL, -1, wxT("Un titlu-1"),

wxDefaultPosition, wxSize( 250, 200) );fereastra_1->SetBackgroundColour( wxColour( 218, 235, 158 ) );wxButton *b1,*b2; b1 = new wxButton( fereastra_1,11, wxT("Mesaj nou!"), wxPoint(90,20), wxSize(80,50));b2=new wxButton( fereastra_1, 10, wxT("Fereastră nouă"), wxPoint(10,20), wxSize(100,100) );Connect(11, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (primaAplicatie::apasaButon_1) );Connect(10, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (primaAplicatie::apasaButon_2) );fereastra_1->Show(); return true;}

/*Ex-2(3-1):*/#include <wx/wx.h>/*Se copiază Ex-2(1-1):*/IMPLEMENT_APP(primaAplicatie);/*Se copiază Ex-2(2-1):*/

/*Ex-2(3-1):*/#include <wx/wx.h>/*Se copiază Ex-2(1-1):*/IMPLEMENT_APP(primaAplicatie);/*Se copiază Ex-2(2-1):*/

/*Ex.2(1-2):*/ class primaAplicatie : public wxApp{public: virtual bool OnInit();void apasaButon_1(wxCommandEvent& event){wxMessageBox("Mesaj BUTON!");}void apasaButon_2(wxCommandEvent& event) {wxFrame *fereastra_2 = new wxFrame(NULL,wxID_ANY,wxT("titlu-2"),wxDefaultPosition,wxSize(150,200));fereastra_2->SetBackgroundColour( wxColour( 118, 235, 158 )); wxStaticText *L1 = new wxStaticText( fereastra_2, wxID_ANY, _("TESTE"));wxBoxSizer *bSizer_2 = new wxBoxSizer( wxVERTICAL ); fereastra_2->SetSizer( bSizer_2 );bSizer_2->Add( L1, 0, wxALIGN_CENTER|wxALL, 5 );fereastra_2->Show();}};

/*Ex.2(1-2):*/ class primaAplicatie : public wxApp{public: virtual bool OnInit();void apasaButon_1(wxCommandEvent& event){wxMessageBox("Mesaj BUTON!");}void apasaButon_2(wxCommandEvent& event) {wxFrame *fereastra_2 = new wxFrame(NULL,wxID_ANY,wxT("titlu-2"),wxDefaultPosition,wxSize(150,200));fereastra_2->SetBackgroundColour( wxColour( 118, 235, 158 )); wxStaticText *L1 = new wxStaticText( fereastra_2, wxID_ANY, _("TESTE"));wxBoxSizer *bSizer_2 = new wxBoxSizer( wxVERTICAL ); fereastra_2->SetSizer( bSizer_2 );bSizer_2->Add( L1, 0, wxALIGN_CENTER|wxALL, 5 );fereastra_2->Show();}};

Page 142: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

iar exemplul 2(3-1) devine:

Ultima implementare prezintă avantajul posibilităţii de afi-şare completă a controalelor pe o varietate mare de rezoluţii de afişare.

1.2. Gestiunea evenimentelor

În exemplul anterior evenimentul de click al mouse-ului pe un buton era ataşat unei funcţii. Această legătură se poate realiza prin funcţia Connect din cadrul metodei OnInit(). Primul parametru al funcţiei este reprezentat de identificatorul (ales de către noi) pentru controlul căruia îi aparţin evenimentele. Al doilea parametru este reprezentat de o constantă ce reprezintă “codul numeric” al evenimentului, în acest caz wxEVT_COMMAND_BUTTON_CLICKED. Funcţia wxCommandEventHandler preia ca parametru metoda ce prelucrează evenimentul (metoda ce trebuie să fie executată la apariţia evenimentului). Este necesar ca funcţiile ce tratează evenimentul să preia ca parametru o referinţă la o clasă de tip eveniment (wxCommandEvent&). Din aceeaşi categoria fac parte şi clasele wxKeyEvent şi wxMouseEvent, ce sunt specializate pe eveni-mentele de la tastatură, respectiv de la mouse.

Exemplul anterior, în care evenimentele sunt la nivel de aplicaţie, îl vom modifica astfel încât evenimentele să fie la nivel de fereastră. În acest sens avem două variante, una cu funcţii de conectare între evenimente şi metode la nivel de constructor de fereastră şi de deconectare la nivelul destructorului ferestrei şi o altă variantă (nu este singulară) cu tabele de evenimente.

141

/*Ex.2(2-2):*/bool primaAplicatie::OnInit() { wxFrame *fereastra_1;fereastra_1 = new wxFrame( NULL, -1, wxT("Un titlu-1"), wxDefaultPosition, wxSize( 250, 200) );fereastra_1->SetBackgroundColour( wxColour( 218, 235, 158 ) );wxButton *b1,*b2; b1=new wxButton( fereastra_1,11,wxT("Mesaj nou!"));b2 = new wxButton( fereastra_1, 10, wxT("Fereastră nouă") );wxBoxSizer *bSizer_1 = new wxBoxSizer( wxHORIZONTAL ); bSizer_1->Add( b1, 0, wxALIGN_CENTER|wxALL, 5 );bSizer_1->Add( b2, 0, wxALIGN_CENTER|wxALL, 5 );fereastra_1->SetSizer( bSizer_1 ); fereastra_1->Layout();Connect(11, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(primaAplicatie::apasaButon_1) );Connect(10, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(primaAplicatie::apasaButon_2) ); fereastra_1->Show(); return true;}

/*Ex.2(2-2):*/bool primaAplicatie::OnInit() { wxFrame *fereastra_1;fereastra_1 = new wxFrame( NULL, -1, wxT("Un titlu-1"), wxDefaultPosition, wxSize( 250, 200) );fereastra_1->SetBackgroundColour( wxColour( 218, 235, 158 ) );wxButton *b1,*b2; b1=new wxButton( fereastra_1,11,wxT("Mesaj nou!"));b2 = new wxButton( fereastra_1, 10, wxT("Fereastră nouă") );wxBoxSizer *bSizer_1 = new wxBoxSizer( wxHORIZONTAL ); bSizer_1->Add( b1, 0, wxALIGN_CENTER|wxALL, 5 );bSizer_1->Add( b2, 0, wxALIGN_CENTER|wxALL, 5 );fereastra_1->SetSizer( bSizer_1 ); fereastra_1->Layout();Connect(11, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(primaAplicatie::apasaButon_1) );Connect(10, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(primaAplicatie::apasaButon_2) ); fereastra_1->Show(); return true;}

/*Ex.2(3-2):*/ #include <wx/wx.h>/*Se copiază Ex-2(1-1):*/ IMPLEMENT_APP(primaAplicatie);/*Se copiază Ex-2(2-1):*/

/*Ex.2(3-2):*/ #include <wx/wx.h>/*Se copiază Ex-2(1-1):*/ IMPLEMENT_APP(primaAplicatie);/*Se copiază Ex-2(2-1):*/

Page 143: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

În continuare este prezentat exemplul în care avem funcţii de conectare în cadrul constructorului ferestrei şi de deconectare în cadrul destructorului ferestrei.

Iar declaraţia clasei ce conţine fereastra cu evenimente:

În continuare explicităm metodele din cadrul clasei:

Funcţiile de conectare şi deconectare au aceeaşi listă de argumente. Fişierul va avea următoarea structură:

142

/*Ex.2(1-3):*/ class adouaFereastra : public wxFrame{ wxStaticText *L1; public: adouaFereastra() : wxFrame( NULL, wxID_ANY, wxT("Un titlu-2"), wxDefaultPosition, wxSize( 150, 200) ) {this->SetBackgroundColour( wxColour( 118, 235, 158 ) );L1 = new wxStaticText( this, wxID_ANY, _("TESTE"));wxBoxSizer *bSizer_2=new wxBoxSizer(wxVERTICAL);this->SetSizer(bSizer_2); bSizer_2->Add( L1,0,wxALIGN_CENTER|wxALL,5);} };

/*Ex.2(1-3):*/ class adouaFereastra : public wxFrame{ wxStaticText *L1; public: adouaFereastra() : wxFrame( NULL, wxID_ANY, wxT("Un titlu-2"), wxDefaultPosition, wxSize( 150, 200) ) {this->SetBackgroundColour( wxColour( 118, 235, 158 ) );L1 = new wxStaticText( this, wxID_ANY, _("TESTE"));wxBoxSizer *bSizer_2=new wxBoxSizer(wxVERTICAL);this->SetSizer(bSizer_2); bSizer_2->Add( L1,0,wxALIGN_CENTER|wxALL,5);} };

/*Ex.2(2-3):*/ class primaFereastra : public wxFrame{ public: wxButton *b1,*b2; void apasaButon_1(wxCommandEvent& event); void apasaButon_2(wxCommandEvent& event); primaFereastra(); ~primaFereastra(); };

/*Ex.2(2-3):*/ class primaFereastra : public wxFrame{ public: wxButton *b1,*b2; void apasaButon_1(wxCommandEvent& event); void apasaButon_2(wxCommandEvent& event); primaFereastra(); ~primaFereastra(); };

/*Ex.2(3-3):*/ primaFereastra::primaFereastra():wxFrame( NULL, -1, wxT("Un titlu-1"), wxDefaultPosition, wxSize( 250, 200) ) {b1 = new wxButton( this, 11, wxT("Mesaj nou!") ); b2 = new wxButton( this, 10, wxT("Fereastră nouă") ); wxBoxSizer *bSizer_1 = new wxBoxSizer( wxHORIZONTAL ); bSizer_1->Add(b1,0,wxALIGN_CENTER|wxALL,5); bSizer_1->Add(b2,0, wxALIGN_CENTER|wxALL,5); this->SetSizer(bSizer_1); this->Layout(); this->SetBackgroundColour(wxColour( 218, 235, 158 ) ); b1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_1 ), NULL, this ); b2->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_2 ),NULL, this );}

/*Ex.2(3-3):*/ primaFereastra::primaFereastra():wxFrame( NULL, -1, wxT("Un titlu-1"), wxDefaultPosition, wxSize( 250, 200) ) {b1 = new wxButton( this, 11, wxT("Mesaj nou!") ); b2 = new wxButton( this, 10, wxT("Fereastră nouă") ); wxBoxSizer *bSizer_1 = new wxBoxSizer( wxHORIZONTAL ); bSizer_1->Add(b1,0,wxALIGN_CENTER|wxALL,5); bSizer_1->Add(b2,0, wxALIGN_CENTER|wxALL,5); this->SetSizer(bSizer_1); this->Layout(); this->SetBackgroundColour(wxColour( 218, 235, 158 ) ); b1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_1 ), NULL, this ); b2->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_2 ),NULL, this );}

/*Ex.2(4-3):*/ void primaFereastra::apasaButon_1(wxCommandEvent& event) { wxMessageBox("Un mesaj: BUTON APASAT!");} void primaFereastra::apasaButon_2(wxCommandEvent& event) {adouaFereastra *f = new adouaFereastra(); f->Show();}//explicitare DESTRUCTOR primaFereastra::~primaFereastra() { b1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_1 ), NULL, this ); b2->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_2 ), NULL, this );}

/*Ex.2(4-3):*/ void primaFereastra::apasaButon_1(wxCommandEvent& event) { wxMessageBox("Un mesaj: BUTON APASAT!");} void primaFereastra::apasaButon_2(wxCommandEvent& event) {adouaFereastra *f = new adouaFereastra(); f->Show();}//explicitare DESTRUCTOR primaFereastra::~primaFereastra() { b1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_1 ), NULL, this ); b2->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( primaFereastra::apasaButon_2 ), NULL, this );}

Page 144: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

Acelaşi exemplu este refăcut pentru a demonstra utilizarea tabelelor de evenimente. Exemplul 2(1-4) este identic cu exemplul 2(1-3).

Tabela de evenimente:

Există tehnici de gestiune mai eficientă a evenimentelor (ex. metoda Bind()), însă tehnicile expuse acoperă necesităţile pentru construcţia unei interfeţe grafice simple.

1.3. Utilizarea claselor generate de template-uri

În zona open source generatoarele pentru interfeţe grafice sunt limitate, însă consider că fără a utiliza generatoare pentru interfaţă se pot realiza aplicaţii mult mai performante. Singurul

143

/*Ex.2(2-4):*/ class primaFereastra : public wxFrame{ public:wxButton *b1,*b2; primaFereastra() : wxFrame( NULL, -1, wxT("Un titlu-1"), wxDefaultPosition, wxSize( 250, 200) ) {b1 = new wxButton( this, 11, wxT("Mesaj nou!") ); b2 = new wxButton( this, 10, wxT("Fereastră nouă") ); wxBoxSizer *bSizer_1 = new wxBoxSizer( wxHORIZONTAL ); bSizer_1->Add( b1, 0, wxALIGN_CENTER|wxALL,5); bSizer_1->Add( b2, 0, wxALIGN_CENTER|wxALL,5); this->SetSizer( bSizer_1 );this->Layout(); this->SetBackgroundColour (wxColour(218,235,158));} void apasaButon_1(wxCommandEvent& event) {wxMessageBox("Apăsat!");} void apasaButon_2(wxCommandEvent& event) { adouaFereastra *f = new adouaFereastra(); f->Show();} wxDECLARE_EVENT_TABLE(); };

/*Ex.2(2-4):*/ class primaFereastra : public wxFrame{ public:wxButton *b1,*b2; primaFereastra() : wxFrame( NULL, -1, wxT("Un titlu-1"), wxDefaultPosition, wxSize( 250, 200) ) {b1 = new wxButton( this, 11, wxT("Mesaj nou!") ); b2 = new wxButton( this, 10, wxT("Fereastră nouă") ); wxBoxSizer *bSizer_1 = new wxBoxSizer( wxHORIZONTAL ); bSizer_1->Add( b1, 0, wxALIGN_CENTER|wxALL,5); bSizer_1->Add( b2, 0, wxALIGN_CENTER|wxALL,5); this->SetSizer( bSizer_1 );this->Layout(); this->SetBackgroundColour (wxColour(218,235,158));} void apasaButon_1(wxCommandEvent& event) {wxMessageBox("Apăsat!");} void apasaButon_2(wxCommandEvent& event) { adouaFereastra *f = new adouaFereastra(); f->Show();} wxDECLARE_EVENT_TABLE(); };

/*Ex.2(3-4):*/ wxBEGIN_EVENT_TABLE(primaFereastra,wxFrame) EVT_BUTTON(11, primaFereastra::apasaButon_1) EVT_BUTTON(10, primaFereastra::apasaButon_2)wxEND_EVENT_TABLE()

/*Ex.2(3-4):*/ wxBEGIN_EVENT_TABLE(primaFereastra,wxFrame) EVT_BUTTON(11, primaFereastra::apasaButon_1) EVT_BUTTON(10, primaFereastra::apasaButon_2)wxEND_EVENT_TABLE()

/*Ex.2(4):*/ #include <wx/wx.h> class primaAplicatie : public wxApp {public: virtual bool OnInit();};/*Se copiază Ex-2(1-4), Ex-2(2-4), Ex-2(3-4):*/IMPLEMENT_APP(primaAplicatie);bool primaAplicatie::OnInit() { primaFereastra *fereastra_1 = new primaFereastra(); fereastra_1->Show(); return true;}

/*Ex.2(4):*/ #include <wx/wx.h> class primaAplicatie : public wxApp {public: virtual bool OnInit();};/*Se copiază Ex-2(1-4), Ex-2(2-4), Ex-2(3-4):*/IMPLEMENT_APP(primaAplicatie);bool primaAplicatie::OnInit() { primaFereastra *fereastra_1 = new primaFereastra(); fereastra_1->Show(); return true;}

/*Ex.2(3):*/ #include <wx/wx.h>class primaAplicatie : public wxApp {public: virtual bool OnInit();};/*Se copiază Ex-2(1-3), Ex-2(2-3), Ex-2(3-3), Ex-2(4-3),:*/IMPLEMENT_APP(primaAplicatie);bool primaAplicatie::OnInit() { primaFereastra *fereastra_1 = new primaFereastra(); fereastra_1->Show(); return true; }

/*Ex.2(3):*/ #include <wx/wx.h>class primaAplicatie : public wxApp {public: virtual bool OnInit();};/*Se copiază Ex-2(1-3), Ex-2(2-3), Ex-2(3-3), Ex-2(4-3),:*/IMPLEMENT_APP(primaAplicatie);bool primaAplicatie::OnInit() { primaFereastra *fereastra_1 = new primaFereastra(); fereastra_1->Show(); return true; }

Page 145: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

avantaj al generatoarelor pentru interfaţă constă în reducerea timpului iniţial de dezvoltare pentru aplicaţie. Dacă se doreşte personalizarea interfeţei grafice este mai avantajos să lucrăm fără generatoare de interfaţă, inclusiv din punct de vedere al timpilor de dezvoltare.

Pentru clasele wxWidgets există utilitarele wxCraft şi wxFormsBuilder, ce permit construcţia unei interfeţe grafice vizual. Practic, toate proprietăţile adăugate într-o interfaţă sunt stocate într-un fişier de tip XML. Aceste date pot fi transpuse într-o clasă din limbajul C++.

În continuare este prezentat un exemplu de utilizare al unei clase obţinute cu utilitarul wxFormsBuilder (http://sourceforge.net/projects/wxformbuilder/), iar după aceasta este prezen-tat acelaşi modul software (componentă a unei aplicaţii software) fără utilizarea unui constructor pentru interfeţe grafice.

Considerăm că dorim construcţia unui modul software ce afişează aceeaşi informaţie în trei moduri diferite: cutie de editare, bargraf orizonatal, cursor şi de asemenea valoarea acestuia poate fi schimbată prin cutia de editare sau cursor. În acest sens deschidem un proiect nou: Workspace> NewProject> Executable (wxWidgets + wxFB frame). Deschidem “resources> gui.fbp” şi este lansat automat utilitarul wxFormBuilder. Obiectul ale cărui proprietăţi le modificăm îl selectăm în fereastra din stânga “Object Tree”. Denumirile funcţiilor ce vor trata evenimentele vor fi scrise direct în căsuţele corespunzătoare. În momentul finalizării setărilor se va selecta Generate code sau se va apăsa tasta F8.

Utilitarul wxFormBuilder va genera un fişier cu declaraţii gui.h şi unul cu explicitarea metodelor gui.cpp. Structura fişierului gui.h este următoarea:

Clasa FereastraGUI cuprinde declaraţiile celor trei con-troale utilizate pentru afişare: wxTextCtrl (cutia de editare),

144

/* Ex.3(1-1) gui.h */ //adăugare biblioteci wxWidgets …class FereastraGUI : public wxFrame { protected: wxStaticText* L1; wxStaticText* L2; wxTextCtrl* E1; wxSlider* Cursor1; wxGauge* Bar1; virtual void val_modif( wxCommandEvent& event ) { event.Skip(); } virtual void deplaseaza( wxScrollEvent& event ) { event.Skip(); } public:FereastraGUI( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Prima fereastra"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 334,178 ), long style = wxCLOSE_BOX|wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); ~FereastraGUI(); };

/* Ex.3(1-1) gui.h */ //adăugare biblioteci wxWidgets …class FereastraGUI : public wxFrame { protected: wxStaticText* L1; wxStaticText* L2; wxTextCtrl* E1; wxSlider* Cursor1; wxGauge* Bar1; virtual void val_modif( wxCommandEvent& event ) { event.Skip(); } virtual void deplaseaza( wxScrollEvent& event ) { event.Skip(); } public:FereastraGUI( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Prima fereastra"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 334,178 ), long style = wxCLOSE_BOX|wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); ~FereastraGUI(); };

Figura VI-1: Exemplu sincronizare controale

Page 146: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

wxSlider (cursor) şi wxGauge (bargraf). Pe lângă aceste clase, mai sunt declarate şi clase ce implementează controale pentru afişare text (wxStaticText). În clasa de bază FereastraGUI metodele ce răspund la evenimente nu execută nimic (pasează evenimentul mai departe – event.Skip()).

În clasa gui.cpp sunt explicitate metodele declarate în fişierul header. În exemplul 3(2-1) este prezentat codul din constructorul clasei FereastraGUI, responsabil pentru aşezarea controalelor grafice pe suprafaţa ferestrei.

Se observă două instanţieri ale clasei wxBoxSizer ce au ca scop aşezarea tuturor controalelor în acestea. Sunt instanţiate clasele corespunzătoare controalelor şi de asemenea se stabilesc proprietăţile pentru fiecare obiect, ce corespunde câte unui control. După cum se observă toate poziţiile controalelor sunt relative. Clasa FereastraGUI conţine de asemenea legătura între evenimente şi metodele de tratare a acestora.

Funcţiile pentru tratarea evenimentelor corespund

145

/*Ex.3(2-1):*/ this->SetBackgroundColour( wxColour( 218, 235, 158 ) ); wxBoxSizer* bSizer_1; bSizer_1 = new wxBoxSizer( wxVERTICAL ); L1 = new wxStaticText( this, wxID_ANY, _("TESTE"), wxDefaultPosition, wxDefaultSize, 0 ); L1->Wrap( -1 ); L1->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Courier New") ) ); bSizer_1->Add( L1, 0, wxALIGN_CENTER|wxALL, 5 ); wxBoxSizer* bSizer_2; bSizer_2 = new wxBoxSizer( wxHORIZONTAL ); L2 = new wxStaticText(this, wxID_ANY, _("Valoare"), wxDefaultPosition, wxDefaultSize, 0); L2->Wrap( -1 ); bSizer_2->Add( L2, 0, wxALL, 5 ); E1 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); bSizer_2->Add(E1,0,wxALL,5); bSizer_1->Add(bSizer_2,0,wxEXPAND,5); Cursor1 = new wxSlider( this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL); bSizer_1->Add(Cursor1, 0, wxALL|wxEXPAND, 5); Bar1 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL|wxGA_SMOOTH ); bSizer_1->Add( Bar1,0, wxALL|wxEXPAND, 5 ); this->SetSizer( bSizer_1 );this->Layout();this->Centre( wxBOTH );

/*Ex.3(2-1):*/ this->SetBackgroundColour( wxColour( 218, 235, 158 ) ); wxBoxSizer* bSizer_1; bSizer_1 = new wxBoxSizer( wxVERTICAL ); L1 = new wxStaticText( this, wxID_ANY, _("TESTE"), wxDefaultPosition, wxDefaultSize, 0 ); L1->Wrap( -1 ); L1->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Courier New") ) ); bSizer_1->Add( L1, 0, wxALIGN_CENTER|wxALL, 5 ); wxBoxSizer* bSizer_2; bSizer_2 = new wxBoxSizer( wxHORIZONTAL ); L2 = new wxStaticText(this, wxID_ANY, _("Valoare"), wxDefaultPosition, wxDefaultSize, 0); L2->Wrap( -1 ); bSizer_2->Add( L2, 0, wxALL, 5 ); E1 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); bSizer_2->Add(E1,0,wxALL,5); bSizer_1->Add(bSizer_2,0,wxEXPAND,5); Cursor1 = new wxSlider( this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL); bSizer_1->Add(Cursor1, 0, wxALL|wxEXPAND, 5); Bar1 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL|wxGA_SMOOTH ); bSizer_1->Add( Bar1,0, wxALL|wxEXPAND, 5 ); this->SetSizer( bSizer_1 );this->Layout();this->Centre( wxBOTH );

/*Ex-3(3-1):*/ E1->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( FereastraGUI::val_modif ), NULL, this ); Cursor1->Connect( wxEVT_SCROLL_TOP, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this ); Cursor1->Connect( wxEVT_SCROLL_BOTTOM, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this ); Cursor1->Connect( wxEVT_SCROLL_PAGEDOWN, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this );//............................................................. Cursor1->Connect( wxEVT_SCROLL_CHANGED, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this );

/*Ex-3(3-1):*/ E1->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( FereastraGUI::val_modif ), NULL, this ); Cursor1->Connect( wxEVT_SCROLL_TOP, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this ); Cursor1->Connect( wxEVT_SCROLL_BOTTOM, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this ); Cursor1->Connect( wxEVT_SCROLL_PAGEDOWN, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this );//............................................................. Cursor1->Connect( wxEVT_SCROLL_CHANGED, wxScrollEventHandler ( FereastraGUI::deplaseaza ), NULL, this );

Page 147: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

modificării valorii din cutia de editare (FereastraGUI :: val_modif) şi a deplasării cursorului (FereastraGUI :: deplaseaza). Fişierul generat gui.cpp va avea forma:

Pentru a utiliza această clasă se construieşte o nouă clasă derivată din aceasta şi se rescriu metodele definite în clasa de bază ca funcţii virtuale.

Fişierul main.cpp devine:

Metoda FereastraPricipala::deplaseaza preia valoarea cursorului prin utilizarea funcţiei GetValue(), membră a clasei wxSlider şi o afişează în cutia de editare (wxTextCtrl) şi setează bargraf-ul (wxGauge) cu valoarea respectivă. Valoarea întoarsă este de tip întreg şi este transmisă prin intermediul funcţiei SetValue(int) membră a clasei wxGaudge. Pentru afişarea valorii în controlul de editiare este necesară transformarea valorii cursorului din tipul întreg într-un tip clasă wxString. Preluarea valorii în clasa wxString este asigurată de metoda FromDouble(double). Afişarea în cadrul cutiei de editare este

146

/*Ex.3(4-1): gui.cpp */ #include "gui.h"FereastraGUI::FereastraGUI( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ){ /* Ex-3(2-1) + 3(3-1) */ }FereastraGUI::~FereastraGUI() { /* DECONECTARE EVENIMENTE*/}

/*Ex.3(4-1): gui.cpp */ #include "gui.h"FereastraGUI::FereastraGUI( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ){ /* Ex-3(2-1) + 3(3-1) */ }FereastraGUI::~FereastraGUI() { /* DECONECTARE EVENIMENTE*/}

/*Ex.3(5-1): main.h */ #include "gui.h"class PrimaAplicatie : public wxApp { public: virtual bool OnInit();};DECLARE_APP(PrimaAplicatie)class FereastraPricipala : public FereastraGUI {public: FereastraPricipala( wxWindow *parent ); virtual ~FereastraPricipala(); void deplaseaza(wxScrollEvent& event); void val_modif(wxCommandEvent& event ); };

/*Ex.3(5-1): main.h */ #include "gui.h"class PrimaAplicatie : public wxApp { public: virtual bool OnInit();};DECLARE_APP(PrimaAplicatie)class FereastraPricipala : public FereastraGUI {public: FereastraPricipala( wxWindow *parent ); virtual ~FereastraPricipala(); void deplaseaza(wxScrollEvent& event); void val_modif(wxCommandEvent& event ); };

/*Ex.2(2-4): gui.cpp */ #include "main.h"IMPLEMENT_APP(PrimaAplicatie); bool PrimaAplicatie::OnInit(){ SetTopWindow(new FereastraPricipala(NULL)); GetTopWindow()->Show(); return true;} FereastraPricipala::FereastraPricipala(wxWindow *parent) : FereastraGUI( parent ){} FereastraPricipala::~FereastraPricipala(){}void FereastraPricipala::deplaseaza( wxScrollEvent& event ) { int x=Cursor1->GetValue(); Bar1->SetValue(x); wxString a; a = a.FromDouble(x); E1->SetValue(a); } //sau Bar1->SetValue(Cursor1->GetValue());void FereastraPricipala::val_modif( wxCommandEvent& event ) { wxString a; a = E1->GetValue(); double x; a.ToDouble(&x); Bar1->SetValue(x); Cursor1->SetValue(x); }

/*Ex.2(2-4): gui.cpp */ #include "main.h"IMPLEMENT_APP(PrimaAplicatie); bool PrimaAplicatie::OnInit(){ SetTopWindow(new FereastraPricipala(NULL)); GetTopWindow()->Show(); return true;} FereastraPricipala::FereastraPricipala(wxWindow *parent) : FereastraGUI( parent ){} FereastraPricipala::~FereastraPricipala(){}void FereastraPricipala::deplaseaza( wxScrollEvent& event ) { int x=Cursor1->GetValue(); Bar1->SetValue(x); wxString a; a = a.FromDouble(x); E1->SetValue(a); } //sau Bar1->SetValue(Cursor1->GetValue());void FereastraPricipala::val_modif( wxCommandEvent& event ) { wxString a; a = E1->GetValue(); double x; a.ToDouble(&x); Bar1->SetValue(x); Cursor1->SetValue(x); }

Page 148: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

asigurată de metoda SetValue(wxString). Metoda FereastraPricipala::val_modif() preia valoarea din

cutia de editare şi setează atât bargraf-ul (wxGauge), cât şi cursorul (wxSlider) cu valoarea respectivă. Valoarea obţinută prin funcţia GetValue din cutia de editare este de tip wxString. Această valoare este convertită într-o valoare compatibilă cu tipul întreg prin funcţia ToDouble(). Cu ajutorul funcţiilor corespunzătoare SetValue (din fiecare clasă) este transmisă valoarea celor două controale.

Exemplul anterior, refăcut în varianta fără generator de interfaţă este prezentat în cele ce urmează. Declaraţia clasei cuprinde şi datele din vechea clasă:

Constructorul preia şi instrucţiunile din vechiul constructor al clasei de bază:

iar destructorul execută deconectarea evenimentelor:

147

/*Ex.2(1-5):declaraţia clasei*/ class FerPr : public wxFrame{ wxStaticText* L1; wxStaticText* L2;wxTextCtrl* E1; wxSlider* Cursor1; wxGauge* Bar1; public: FerPr(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ); void deplaseaza( wxScrollEvent& event ); void val_modif( wxCommandEvent& event ); ~FerPr(); };

/*Ex.2(1-5):declaraţia clasei*/ class FerPr : public wxFrame{ wxStaticText* L1; wxStaticText* L2;wxTextCtrl* E1; wxSlider* Cursor1; wxGauge* Bar1; public: FerPr(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ); void deplaseaza( wxScrollEvent& event ); void val_modif( wxCommandEvent& event ); ~FerPr(); };

/*Ex.2(2-5):*/ FerPr::FerPr( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) :wxFrame( parent, id, title, pos, size, style ) {this->SetBackgroundColour(wxColour( 218, 235, 158 )); wxBoxSizer* bSizer_1; bSizer_1 = new wxBoxSizer(wxVERTICAL); L1 = new wxStaticText(this, wxID_ANY, _("TESTE"), wxDefaultPosition, wxDefaultSize, 0 ); L1->Wrap(-1); L1->SetFont(wxFont( 14, 74, 90, 92, false, wxT("Courier New") ) ); bSizer_1->Add(L1, 0, wxALIGN_CENTER|wxALL, 5 ); wxBoxSizer* bSizer_2; bSizer_2 = new wxBoxSizer(wxHORIZONTAL); L2 = new wxStaticText(this, wxID_ANY, _("Valoare"), wxDefaultPosition, wxDefaultSize, 0 );L2->Wrap(-1); bSizer_2->Add(L2,0,wxALL,5); E1 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); bSizer_2->Add(E1,0,wxALL,5); bSizer_1->Add(bSizer_2,0,wxEXPAND,5); Cursor1=new wxSlider(this,wxID_ANY,0,0,100, wxDefaultPosition, wxDefaultSize,wxSL_HORIZONTAL ); bSizer_1->Add(Cursor1,0,wxALL|wxEXPAND,5); Bar1 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL|wxGA_SMOOTH ); bSizer_1->Add( Bar1, 0, wxALL|wxEXPAND, 5 ); this->SetSizer( bSizer_1 ); this->Layout(); this->Centre( wxBOTH ); E1->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler (FerPr:: val_modif),NULL,this); Cursor1->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FerPr::deplaseaza),NULL,this);}

/*Ex.2(2-5):*/ FerPr::FerPr( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) :wxFrame( parent, id, title, pos, size, style ) {this->SetBackgroundColour(wxColour( 218, 235, 158 )); wxBoxSizer* bSizer_1; bSizer_1 = new wxBoxSizer(wxVERTICAL); L1 = new wxStaticText(this, wxID_ANY, _("TESTE"), wxDefaultPosition, wxDefaultSize, 0 ); L1->Wrap(-1); L1->SetFont(wxFont( 14, 74, 90, 92, false, wxT("Courier New") ) ); bSizer_1->Add(L1, 0, wxALIGN_CENTER|wxALL, 5 ); wxBoxSizer* bSizer_2; bSizer_2 = new wxBoxSizer(wxHORIZONTAL); L2 = new wxStaticText(this, wxID_ANY, _("Valoare"), wxDefaultPosition, wxDefaultSize, 0 );L2->Wrap(-1); bSizer_2->Add(L2,0,wxALL,5); E1 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); bSizer_2->Add(E1,0,wxALL,5); bSizer_1->Add(bSizer_2,0,wxEXPAND,5); Cursor1=new wxSlider(this,wxID_ANY,0,0,100, wxDefaultPosition, wxDefaultSize,wxSL_HORIZONTAL ); bSizer_1->Add(Cursor1,0,wxALL|wxEXPAND,5); Bar1 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL|wxGA_SMOOTH ); bSizer_1->Add( Bar1, 0, wxALL|wxEXPAND, 5 ); this->SetSizer( bSizer_1 ); this->Layout(); this->Centre( wxBOTH ); E1->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler (FerPr:: val_modif),NULL,this); Cursor1->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FerPr::deplaseaza),NULL,this);}

/*Ex.2(3-5):*/ FerPr::~FerPr() {E1->Disconnect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( FerPr::val_modif ), NULL, this ); Cursor1->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler (FerPr::deplaseaza ), NULL, this ); }

/*Ex.2(3-5):*/ FerPr::~FerPr() {E1->Disconnect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( FerPr::val_modif ), NULL, this ); Cursor1->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler (FerPr::deplaseaza ), NULL, this ); }

Page 149: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

Cele două funcţii pentru tratarea evenimentelor au rămas nemodificate:

Aplicaţia completă va avea structura:

Se observă că nu există niciun fel de diferenţă între rezultatele celor două variante ale aplicaţiei.

1.4. Exemplu cu primitive grafice şi evenimente

În continuare este prezentat un exemplu de aplicaţie ce permite deplasarea unui obiect grafic (în acest caz, un cerc) pe suprafaţa unei ferestre. Deplasarea se poate realiza atât prin tragerea cu mouse-ul, cât şi cu ajutorul tastelor (Alt+săgeţi). De asemnea, este afişată în fereastră poziţia mouse-ului şi pozi-ţia centrului cercului. Prin rotirea rozetei pentru scrol dimensiunea cercului creşte sau scade. Atât cercul, cât şi un dreptunghi, desenat pe conturul interior al ferestrei, îşi schimbă culoarea (roşu, verde sau albastru) la un interval prestabilit de timp. Sursa aplicaţiei conţine două fişiere, unul cu declaraţii (main.h) şi celălalt cu explicitările metodelor (main.cpp)

class PanouDesen : public wxPanel{wxCoord x,y;//pozitie cerc wxCoord x_speed, y_speed; //avans pe cele două direcţii//poziţie actuală mouse şi în momentul reţinerii cercului wxCoord xm,ym,xm1,ym1; int R; //raza cercului bool retine; wxStaticText* L1;

148

/*Ex.2(4-5):*/ void FerPr::deplaseaza( wxScrollEvent& event ) { int x = Cursor1->GetValue(); Bar1->SetValue(x); wxString a; a = a.FromDouble(x); E1->SetValue(a); }void FerPr::val_modif(wxCommandEvent&event) { wxString a; a=E1->GetValue(); double x; a.ToDouble(&x); Bar1->SetValue(x); Cursor1->SetValue(x); }

/*Ex.2(4-5):*/ void FerPr::deplaseaza( wxScrollEvent& event ) { int x = Cursor1->GetValue(); Bar1->SetValue(x); wxString a; a = a.FromDouble(x); E1->SetValue(a); }void FerPr::val_modif(wxCommandEvent&event) { wxString a; a=E1->GetValue(); double x; a.ToDouble(&x); Bar1->SetValue(x); Cursor1->SetValue(x); }

/*Ex.2(5-5):*/ #include <wx/wx.h> class wxMiniApp : public wxApp {public:virtual bool OnInit();};/*Se copiază exemplele: 2(1-5),2(2-5),2(3-5),2(4-5), */ IMPLEMENT_APP(wxMiniApp); bool wxMiniApp::OnInit() { FerPr *f=new FerPr(NULL,wxID_ANY,"Titlu fereastra", wxDefaultPosition, wxSize( 334,178 ), wxCLOSE_BOX|wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL); f->Show(); return true; }

/*Ex.2(5-5):*/ #include <wx/wx.h> class wxMiniApp : public wxApp {public:virtual bool OnInit();};/*Se copiază exemplele: 2(1-5),2(2-5),2(3-5),2(4-5), */ IMPLEMENT_APP(wxMiniApp); bool wxMiniApp::OnInit() { FerPr *f=new FerPr(NULL,wxID_ANY,"Titlu fereastra", wxDefaultPosition, wxSize( 334,178 ), wxCLOSE_BOX|wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL); f->Show(); return true; }

Figura VI-2: Captură ecran

Page 150: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

public: char culoare_cerc; PanouDesen(wxFrame* fereastra_parinte); void evenimentDesenare(wxPaintEvent& evt); void evi_tasta(wxKeyEvent& evt);//apasă o tastă void evi_guzgan_apasaBSt(wxMouseEvent& evt); //apasă buton stâng mouse void evi_guzgan_ridicaBSt(wxMouseEvent& evt);//ridică buton stâng mouse void evi_guzgan_misca(wxMouseEvent& evt); //mişcă mouse void evi_guzgan_scroll(wxMouseEvent& evt);// rotire rozetă scol mouseDECLARE_EVENT_TABLE()};class GestiuneEvenimenteTimp : public wxTimer{ PanouDesen* panou;public: GestiuneEvenimenteTimp(PanouDesen* panou); void Notify(); /*redeclarăm funcţia Notify , aceasta este o funcţie predefinită ce este apelată la un interval de timp [ms] dat de variabila timer din cadrul clasei wxTimer*/ void seteazaContor();};class FereastraPrinc : public wxFrame{ PanouDesen* panou_desenare_1; GestiuneEvenimenteTimp* timp; // clasa ce gestionează evenimentele de timp public: FereastraPrinc(); ~FereastraPrinc(); void inchideFereastra(wxCloseEvent& evt); DECLARE_EVENT_TABLE()};class AplicatiaTEST1: public wxApp{ bool OnInit(); FereastraPrinc* fereastra_1; };

Pentru gestiunea evenimentelor de timp este utilizată o clasă derivată din wxTime. În această clasă este redefinită funcţia Notify() din cadrul clasei wxTime. Această funcţie este executată periodic la un interval de timp prestabilit prin funcţia wmTimer::Start(int).

#include <wx/wx.h>#include <wx/timer.h>#include "main.h"IMPLEMENT_APP(AplicatiaTEST1)//--------------------------------------------------------------------- FereastraPrinc::FereastraPrinc() : wxFrame((wxFrame *)NULL, -1, wxT("Deplasare obiect"), wxPoint(50,50), wxSize(400,200)) { wxBoxSizer* sizer_1 = new wxBoxSizer(wxHORIZONTAL); panou_desenare_1 = new PanouDesen(this); sizer_1->Add(panou_desenare_1, 1, wxEXPAND);SetSizer(sizer_1); timp = new GestiuneEvenimenteTimp(panou_desenare_1); Show();timp->seteazaContor(); }//---------------------------------------------------------------------

149

Page 151: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

FereastraPrinc::~FereastraPrinc() {}//--------------------------------------------------------------------- void FereastraPrinc::inchideFereastra(wxCloseEvent& evt) { timp->Stop(); evt.Skip(); } BEGIN_EVENT_TABLE(FereastraPrinc, wxFrame)

EVT_CLOSE(FereastraPrinc::inchideFereastra)END_EVENT_TABLE()//---------------------------------------------------------------------bool AplicatiaTEST1::OnInit(){ fereastra_1=new FereastraPrinc(); fereastra_1->Show(); return true; } //---------------------------------------------------------------------BEGIN_EVENT_TABLE(PanouDesen, wxPanel)

EVT_PAINT(PanouDesen::evenimentDesenare)EVT_KEY_DOWN(PanouDesen::evi_tasta)EVT_LEFT_DOWN(PanouDesen::evi_guzgan_apasaBSt)EVT_LEFT_UP(PanouDesen::evi_guzgan_ridicaBSt) EVT_MOTION(PanouDesen::evi_guzgan_misca)EVT_MOUSEWHEEL(PanouDesen::evi_guzgan_scroll)

END_EVENT_TABLE()//---------------------------------------------------------------------PanouDesen::PanouDesen(wxFrame* fereastra_parinte) :wxPanel(fereastra_parinte){ x=20; y=40; y_speed=2; x_speed=2; R=20; retine=false; xm1=-1; ym1=-1; culoare_cerc='r'; L1=new wxStaticText(this,wxID_ANY,_("TESTE"),wxDefaultPosition, wxDefaultSize, 0); this->SetCursor(wxCURSOR_CROSS);}//--------------------------------------------------------------------- void PanouDesen::evenimentDesenare(wxPaintEvent& evt){wxPaintDC dc(this); wxString sir_culoare; dc.SetBackground(*wxWHITE_BRUSH); dc.Clear();//sterge fundal if(culoare_cerc=='r') {dc.SetPen(wxPen(wxColour(255,0,0))); sir_culoare="rosu";} if(culoare_cerc=='g') {dc.SetPen(wxPen(wxColour(0,255,0)));sir_culoare="verde";} if(culoare_cerc=='b') {dc.SetPen(wxPen(wxColour(0,0,255)));sir_culoare="albastru";} dc.DrawRectangle(1,1,dc.GetSize().GetWidth()-1,dc.GetSize().GetHeight()-1); dc.DrawText(wxT("Un cerc ")+sir_culoare,x-5, y+R); dc.DrawCircle(wxPoint(x,y),R);}//---------------------------------------------------------------------void PanouDesen::evi_tasta(wxKeyEvent& evt){ wxString ach;

switch (evt.m_keyCode) {case WXK_RIGHT:x+=x_speed;this->Refresh();break;//ALT +SAGEATA case WXK_LEFT: x -= x_speed; this->Refresh();break; case WXK_DOWN: y += y_speed; this->Refresh();break; case WXK_UP: y -= y_speed; this->Refresh();break; } }

//---------------------------------------------------------------------void PanouDesen::evi_guzgan_apasaBSt(wxMouseEvent& evt)

150

Page 152: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Biblioteca wxWidgets şi dezvoltarea interfeţelor grafice în C++

{ wxString ach; xm=evt.GetX(); ym=evt.GetY();if((!retine)&&(xm>=(x-R))&&(xm<=(x+R))&&(ym>=(y-R)) &&(ym<=(y+R))) {xm1=xm; ym1=ym; retine=true; } }//---------------------------------------------------------------------void PanouDesen::evi_guzgan_ridicaBSt(wxMouseEvent& evt){retine=false; xm1=-1;ym1=-1; }//---------------------------------------------------------------------void PanouDesen::evi_guzgan_misca(wxMouseEvent& evt){ xm=evt.GetX();ym=evt.GetY(); if((xm>=(x-R))&&(xm<=(x+R))&&(ym>=(y-R))&&(ym<=(y+R))) this->SetCursor(wxCURSOR_HAND);else this->SetCursor(wxCURSOR_CROSS); wxString sir="x: "+sir.FromDouble(xm)+" --- Y: "+sir.FromDouble(ym); wxString sir1 = " x1: " + sir1.FromDouble(xm1) + " --- Y1: " + sir1.FromDouble(ym1); wxString sir2=" xc: "+sir2.FromDouble(x)+" --- Yc: "+sir2.FromDouble(y); wxString sir3; if(retine) sir3=" MEMO"; else sir3=" Liber"; L1->SetLabel(sir+sir1+sir2+sir3); if(retine) {x+=xm-xm1;y+=ym-ym1;xm1=xm;ym1=ym;this->Refresh();}}//---------------------------------------------------------------------void PanouDesen::evi_guzgan_scroll(wxMouseEvent& evt) { R+=evt.GetWheelRotation()/120.0; this->Refresh();}//---------------------------------------------------------------------GestiuneEvenimenteTimp::GestiuneEvenimenteTimp(PanouDesen* panou):wxTimer() { GestiuneEvenimenteTimp::panou = panou;}//---------------------------------------------------------------------void GestiuneEvenimenteTimp::Notify(){ panou->Refresh();// redesenare+afisareif(panou->culoare_cerc=='r') panou->culoare_cerc='g'; else if(panou->culoare_cerc=='g') panou->culoare_cerc='b'; else if(panou->culoare_cerc=='b') panou->culoare_cerc='r'; }//--------------------------------------------------------------------- void GestiuneEvenimenteTimp::seteazaContor(){ wxTimer::Start(1000);//1000 ms interval apel rutina Notify()}

În aceste exemple avem mai multe categorii de evenimente şi anume:➢ eveniment pentru (re)desenare (clasa wxPaintEvent);➢ evenimente generate de tastatură (clasa wxKeyEvent);➢ evenimente generate de către mouse (clasa wxMouseEvent);➢ evenimente generate de către controalele grafice (clasa

wxCommandEvent);➢ eveniment închidere fereastră (clasa wxCloseEvent).

Evenimenul de tip “TIMP” este tratat într-o manieră diferită, explicată mai sus.

151

Page 153: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

Fiecare funcţie ce tratează evenimente preia o referinţă la o clasă de evenimente, iar în blocul de instrucţiuni corespunzător funcţiei sunt tratate evenimentele cu ajutorul obiectului a cărui referinţă este transmisă prin lista de argumente a funcţiei. De exemplu, pentru un obiect de tip wxMouseEvent, avem funcţia evt.GetX() ce întoarce poziţia pe orizonală a mouse-ului pe ecran, exprimată în număr de pixeli de la originea sistemului de coordo-nate cartezian (originea va fi în colţul din stânga sus) pe axa Ox.

2. Interfaţarea client-server PostgreSQL în limbajul C/C++

2.1. Descrierea bibliotecii libpq

Biblioteca libpq din cadrul PostgreSQL permite interfaţarea server-ului PostgreSQL de către clienţi în limbajul C. În directorul dat de calea “.../PostgreSQL/.../include” se află fişie-rul libpq-fe.h, ce conţine declaraţiile funcţiilor şi structurilor utilizate de biblioteca libpq.

Principalele funcţii din biblioteca libpq permit:✗ conectarea la un server PostgreSQL;✗ obţinerea de informaţii privind starea conexiunii;✗ transmiterea execuţiei pentru comenzile SQL – mod sincron;✗ extragerea rezultatelor în urma unei comenzi SQL.

2.1.1. Conectarea la server

Conectarea la un server PostgreSQL se realizează prin funcţia:

Şirul pentru conexiune transmis ca şi parametru acestei

funcţii cuprinde: ip-ul serverului cu care se conectează (implicit localhost), portul pe care se realizează conexiunea (implicit 5432), numele bazei de date (implicit postgres), numele utilizator (implicit postgres), parola (în mod implicit o preia din fişierul ...\Roaming\postgresql.conf). De asemenea, şirul de conectare poate cuprinde şi opţiuni de conectare. Rezultatul apelului funcţiei de conectare este stocat într-o structură PGconn. Putem să deschidem mai multe conexiuni simultan, fiecare conexiune va corespunde unei variabile de tip PGconn. Fiecare conexiune va putea fi închisă separat prin funcţia ce preia identificatorul conexiunii.

Statusul unei conexiuni îl obţinem cu funcţia:

Acesta poate fi CONNECTION_BAD sau CONNECTION_OK pentru conexiunile sincrone. De asemenea, există o serie de funcţii ce permit obţine-rea de alte informaţii precum: portul, utilizatorul, informaţii

152

void PQfinish(PGconn *conn);void PQfinish(PGconn *conn);

ConnStatusType PQstatus(const PGconn *conn);ConnStatusType PQstatus(const PGconn *conn);

PGconn *PQconnectdb(const char *conninfo);PGconn *PQconnectdb(const char *conninfo);

Page 154: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Interfaţarea client-server PostgreSQL în limbajul C/C++

despre SSL etc.În continuare este prezentat un exemplu de conectare

2.1.2. Transmiterea comenzilor SQL către server

Transmiterea către server a unei comenzi SQL în vederea execuţiei este îndeplinită prin funcţia:

Această funcţie preia identificatorul conexiunii şi şirul ce caractere ce conţine comanda SQL. Rezultatul obţinut, transmis de la server-ul PostgreSQL către client, după execuţia comenzii, este încapsulat într-o structură de date PGresult.

Testarea rezultatului execuţiei se realizează cu funcţia:

Rezultatul poate fi:✗ PGRES_EMPTY_QUERY – comandă vidă (fără conţinut), transmisă

către server;✗ PGRES_COMMAND_OK – comanda a fost corectă, dar clientul nu a

primit date de la server;✗ PGRES_TUPLES_OK – comandă corectă, iar server-ul a răspuns,

este specifică comenzii SQL “SELECT”, dar poate fi utilizată şi la comenzile pentru editare;

✗ PGRES_COPY_OUT – datele sunt în curs de transfer de la server către client;

✗ PGRES_COPY_IN – datele sunt în curs de transfer de la client către server;

✗ PGRES_BAD_RESPONSE – răspunsul de la server nu poate fi interpretat;

✗ PGRES_NONFATAL_ERROR – server-ul a transmis mesaj de avertizare;

✗ PGRES_FATAL_ERROR – server-ul a transmis mesaj de eroare;✗ PGRES_SINGLE_TUPLE – server-ul a transmis către client o

singură înregistrare. Un exemplu de apel a funcţiei de execuţie este redat în

continuare:

153

/*Ex.1(1):*/ const char *sir_conexiune; PGconn *conexiune1;sir_conexiune="dbname=curs_info password=abcd user=postgres port=5435"; conexiune1 = PQconnectdb(sir_conexiune);if (PQstatus(conexiune1) != CONNECTION_OK) { PQfinish(conexiune1); printf("EROARE LA CONECTARE!");} else printf("CONECTAT!!!\n");

/*Ex.1(1):*/ const char *sir_conexiune; PGconn *conexiune1;sir_conexiune="dbname=curs_info password=abcd user=postgres port=5435"; conexiune1 = PQconnectdb(sir_conexiune);if (PQstatus(conexiune1) != CONNECTION_OK) { PQfinish(conexiune1); printf("EROARE LA CONECTARE!");} else printf("CONECTAT!!!\n");

PGresult *PQexec(PGconn *conexiune, const char *commandă);PGresult *PQexec(PGconn *conexiune, const char *commandă);

ExecStatusType PQresultStatus(const PGresult *rezultat);ExecStatusType PQresultStatus(const PGresult *rezultat);

Page 155: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

În caz de eroare este necesară eliberarea memoriei de even-tualele alocări de resurse efectuate până în acel punct. În acest sens este utilizată funcţia PQclear(rezultat1) înainte de închiderea conexiunii.

Se poate trimite o singură comandă SQL sau un bloc cu comenzi SQL.

2.1.3. Extragerea datelor obţinute în urma interogării serverului

În cazul în care rezultatul constă într-un set de înre-gistrări este necesar să ştim numărul de înregistrări returnate. În acest sens utilizăm funcţia:

Aceasta preia adresa variabilei cu rezultatul interogării şi întoarce numărul de înregistrări rezultate în urma interogării şi preluate în variabila de tip PGresult.Notă: Pentru sistemele pe 32 de biţi, numărul de înregistrări nu poate fi mai mare de 232 înregistrări, aceasta se datorează reprezentării tipului “int” pe sistemele pe 32 biţi.

Pentru obţinerea numărului de câmpuri rezultate în urma interogării avem o funcţie asemănătoare:

Este posibilă obţinerea numelui pentru fiecare câmp în parte. Funcţia preia adresa resursei şi numărul de ordine al coloanei şi întoarce numele câmpului.

De asemenea, se poate obţine tipul datei din cadrul fiecărui câmp. Funcţia întoarce OID-ul corespondent tipului datei (acesta este un număr unic şi există în sistemul de cataloage din cadrul PostgreSQL – tabelul pg_type).

Dimensiunea câmpurilor, în octeţi, poate fi obţinută prin funcţia:

Preluarea înregistrărilor se realizează prin preluare celulă cu celulă din tabelul întors. Funcţia prin care se poate realiza

preluarea este:

154

/*Ex.2(1):*/ PGresult *rezultat1;rezultat1 = PQexec(conexiune1,"SELECT cota,titlu,an_ap FROM c8.inv;");if(PQresultStatus(rezultat1) != PGRES_TUPLES_OK) {PQclear(rezultat1);PQfinish(conexiune1);printf("EROARE INTEROGARE!");}

/*Ex.2(1):*/ PGresult *rezultat1;rezultat1 = PQexec(conexiune1,"SELECT cota,titlu,an_ap FROM c8.inv;");if(PQresultStatus(rezultat1) != PGRES_TUPLES_OK) {PQclear(rezultat1);PQfinish(conexiune1);printf("EROARE INTEROGARE!");}

int PQntuples(const PGresult *rezultat);int PQntuples(const PGresult *rezultat);

int PQntuples(const PGresult *rezultat);int PQntuples(const PGresult *rezultat);

char *PQfname(const PGresult *rezultat, int număr_coloană);char *PQfname(const PGresult *rezultat, int număr_coloană);

Oid PQftype(const PGresult *rezultat, int număr_coloană);Oid PQftype(const PGresult *rezultat, int număr_coloană);

int PQfsize(const PGresult *rezultat, int număr_coloană);int PQfsize(const PGresult *rezultat, int număr_coloană);

char *PQgetvalue(const PGresult *rezultat, int număr_rând, int număr_coloană);

char *PQgetvalue(const PGresult *rezultat, int număr_rând, int număr_coloană);

Page 156: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Interfaţarea client-server PostgreSQL în limbajul C/C++

Indiferent de tipul de dată al câmpului/coloanei funcţia întoarce ca valori şiruri de caractere. Secvenţa următoare ilustrează obţinerea acestora.

Întreruperea unei comenzi aflate în execuţie de către server se realizează prin comenzile:

2.2. Exemplu privind apelul funcţiilor libpq în cadrul unui cod C standard

Pentru a putea utiliza biblioteca statică libpq, sunt nece-sare următoarele setări la nivelul unui proiect C/C++:

☑ în setările pentru compilare, pentru “Include Path”, se va adăuga calea pentru fişierele cu declaraţii din cadrul bibliotecii (este localizată: “..... /PostgreSQL /..... /include”);

☑ în setările pentru link-editare, pentru “Libraries Search Path” se va adăuga calea pentru fişierele cu biblioteca libpq: (are forma: “...../PostgreSQL/...../lib”);

☑ în setările pentru link-editare, pentru Linker Options se va adăuga opţiunea “-lpq”;

☑ în fişierele ce apelează funcţii din biblioteca libpq se vor adăuga: “#include <libpq-fe.h>”Pentru testare, în baza de date picdb construim schema c5 şi

un tabel inv în care adăugăm câteva înregistrări:

-- Ex. 1-1CREATE SCHEMA pic; DROP TABLE IF EXISTS pic.inv; CREATE TABLE pic.inv (cota character varying(50) NOT NULL, titlu character varying(100), editura character varying(50), an_ap integer, nr_pag integer, autori character varying(200), nr_vol integer, limba character varying(30), imprumutata boolean DEFAULT false);INSERT INTO pic.inv VALUES ('001', 'T1', 'ALL', 1977, 150, NULL, NULL, NULL, false), ('002', 'T21', 'Nemira', 1977, 190, NULL, NULL, NULL, false), ('003', 'T1', 'Tehnica', 1977, 250, NULL, NULL, NULL, false), ('004', 'T54', 'Albatros', 1977, 220, NULL, NULL, NULL, false), ('005', 'T97', 'Nemira', 1977, 80, NULL, NULL, NULL, false), ('006', 'T1', 'ALL', 1977, 50, NULL, NULL, NULL, false), ('007', 'T77', 'Tehnica', 1977, 120, NULL, NULL, NULL, false), ('008', 'T21', 'Albatros', 1987, 100, NULL, NULL, NULL, false);

155

/*Ex.3(1):*/ int nrCampuri=PQnfields(rezultat1);int nrInregistrari= PQntuples(rezultat1);printf("Nr.Inregistr:%d Nr.Campuri:%d \n",nrInregistrari,nrCampuri);for(int i=0;i<nrInregistrari;i++) { for(int j=0;j<nrCampuri;j++) printf("%s ",PQgetvalue(rezultat1,i,j));printf("\n"); }

/*Ex.3(1):*/ int nrCampuri=PQnfields(rezultat1);int nrInregistrari= PQntuples(rezultat1);printf("Nr.Inregistr:%d Nr.Campuri:%d \n",nrInregistrari,nrCampuri);for(int i=0;i<nrInregistrari;i++) { for(int j=0;j<nrCampuri;j++) printf("%s ",PQgetvalue(rezultat1,i,j));printf("\n"); }

PGcancel *PQgetCancel(PGconn *conn);void PQfreeCancel(PGcancel*cancel);PGcancel *PQgetCancel(PGconn *conn);void PQfreeCancel(PGcancel*cancel);

Page 157: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

Fişierul main.cpp ce permite citirea tabelului va avea structura:

//Ex. 1-2#include <stdio.h>#include <libpq-fe.h>int main(){const char *sir_conexiune;PGconn *conexiune1;//PGconn structura din libpq ce ţine datele conexiuniisir_conexiune = "dbname=picdb password=abcd user=postgres port=5435 host=127.0.0.1";//conectarea la baza de date -- conexiune persistentăconexiune1=PQconnectdb(sir_conexiune);//funcţie ce deschide o conexiune pentru pidbif(PQstatus(conexiune1) != CONNECTION_OK) { PQfinish(conexiune1); printf("EROARE LA CONECTARE!"); }

else printf("CONECTAT!!!\n");//PGresult - structura din libpq ce gestionează rezultatul interogăriiPGresult *rezultat1; //apelează funcţia ce lansează o interogare SQL pentru serverrezultat1 = PQexec(conexiune1, "SELECT cota,titlu,an_ap FROM pic.inv;");//testează rezultatul interogăriiif (PQresultStatus(rezultat1) != PGRES_TUPLES_OK) {PQclear(rezultat1);PQfinish(conexiune1);printf("EROARE LA INTEROGARE!");}//citim nr. de câmpuri şi înregistrări din rezultatul transmisint nrCampuri=PQnfields(rezultat1);//citeşte nr. de câmpuri din rezultatint nrInregistrari=PQntuples(rezultat1); //citeşte nr. de înregistrăriprintf("Nr.Inregistrari:%d Nr.Campuri:%d \n", nrInregistrari, nrCampuri);//citeşte şi afişează rezultatul --//PQgetvalue obţine rezultatul dintr-o celulă sub forma unui şir de caractere for(int i = 0; i < nrInregistrari; i++) { for(int j = 0; j < nrCampuri; j++)

printf("%s ",PQgetvalue(rezultat1, i, j)); printf("\n");

} return 0; }

2.3. Exemplu privind utilizarea bibliotecii libpq în cadrul wxWidgets

Rezultatele interogării bazelor de date sunt reflectate în afişarea controalelor din cadrul ferestrelor. De asemenea, datele din cadrul controalelor se pot reflecta în valorile din cadrul bazelor de date (operaţiile de editare din cadrul aplicaţiilor de baze de date).

Cel mai uzitat control pentru afişarea rezultatelor unei interogări este controlul wxGrid. Considerând rezultatul inte-rogării un tabel, avem o corespondenţă biunivocă între tabelul din cadrul resursei de tip PGresult şi tabelul asociat controlului wxGrid.

156

Page 158: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Interfaţarea client-server PostgreSQL în limbajul C/C++

În tabelul dat de controlul wxGrid datele din celule sunt de tipul wxString, în timp ce datele din cadrul tabelului asociat resursei de tip PGresult sunt de tip şir de caractere (char*). Prin urmare, pentru afişarea datelor în controlul de tip wxGrid, este necesară conversia datelor din şir de caractere în wxString. Această conversie este asigurată prin metoda FromUTF8, funcţie membră a clasei wxString.

Numărul de linii şi coloane al tabelului asociat resursei va fi acelaşi cu cel al tabelului asociat controlului wxGrid. Înaintea execuţiei unei interogări este posibil ca să se cunoască coloanele rezultate (implicit numărul şi ordinea acestora), însă nu se cunoşte numărul de înregistrări. În cazul în care numărul înregistrărilor rezultate în urma interogării este mare (de exemplu de ordinul zecilor de mii), este recomandat ca interogarea să se facă astfel încât să poată fi posibilă paginarea rezultatului prin utilizarea în comanda SQL a instrucţiunilor OFFSET şi LIMIT.

Pentru adăugarea unui set nou de înregistrări vor fi şterse în prealabil toate liniile din grid cu execepţia capului de tabel.

În continuare este prezentat un exemplu de extragere a datelor din tabelul pic.inv (din exemplul anterior) într-un control de tip wxGrid. Numărul de coloane şi înregistrări va fi stabilit dinamic, în funcţie de rezultatul întors. De asemenea se adaugă o înregistrare ce va conţine numărul OID specific fiecărui tip de dată, acesta fiind util în procesarea datelor din tabel.

Figura VI-3: Afişare date

Aplicaţia conţine două fişiere de tip header şi două fişiere sursă cpp : igpg.h, main.h, igpg.cpp, main.cpp. Fişierul igpg.h conţine declaraţia clasei IGPG ce realizează efectiv interfaţarea.

// igpg.h - clasă de interfatare wxwidgests C++ -- PostgreSQL#include <wx/string.h>#include <libpq-fe.h>#include <wx/grid.h>class IGPG { PGconn *conexiuneRx; public: IGPG(wxString dbname, wxString user, wxString pw, wxString

157

Page 159: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

host,wxString port); ~IGPG();//afişare în grid cu structură variabilă de coloane void afisQ(wxGrid *GDx, wxString cdaSQL);};

Un obiect obţinut prin instanţierea clasei IGPG corespunde unei conexiuni. Constructorul clasei IGPG preia parametrii de conectare (numele bazei de date, numele utilizatorului sau aliasul, parola, host-ul reprezentat prin IP-ul calculatorului pe care se află server-ul PostgreSQL - implicit: localhost şi portul pe care rulează server-ul PostgreSQL - implicit: 5432).

igpg.cpp #include <wx/wx.h>#include <wx/grid.h>#include "igpg.h"IGPG::IGPG(wxString dbname, wxString user, wxString pw, wxString host,wxString port){wxString ach; char sir_conexiune[500]; ach = wxT(" dbname=") + dbname + wxT(" user=") + user + wxT(" password=") + pw + wxT(" host=") + host + wxT(" port=") + port; strcpy(sir_conexiune, ach.c_str()); conexiuneRx = PQconnectdb(sir_conexiune); if (PQstatus(conexiuneRx) != CONNECTION_OK) { PQfinish(conexiuneRx); wxMessageBox("EROARE LA CONECTARE!"); } else wxMessageBox("CONECTAT!!!\n");}//----------------------------------------------------------------IGPG::~IGPG() { PQfinish(conexiuneRx);}//----------------------------------------------------------------void IGPG::afisQ(wxGrid *GDx, wxString cdaSQL){ PGresult *rezultatRx; rezultatRx = PQexec(conexiuneRx, cdaSQL); if(PQresultStatus(rezultatRx) != PGRES_TUPLES_OK) return; int nrCampuri = PQnfields(rezultatRx); int nrInregistrari = PQntuples (rezultatRx); GDx->DeleteRows(0, GDx->GetNumberRows()); GDx->DeleteCols(0, GDx->GetNumberCols()); GDx->AppendCols(nrCampuri); GDx->AppendRows(nrInregistrari); wxString ach; int i, j; //preia datele în fiecare celulă for(i = 0; i < nrInregistrari; i++) for(j = 0; j < nrCampuri; j++) { ach = ach.FromUTF8(PQgetvalue(rezultatRx, i, j)); GDx->SetCellValue(i, j, ach); }//afişează denumiri câmpuri for(j = 0; j < nrCampuri; j++) { ach = ach.FromUTF8(PQfname(rezultatRx, j)); GDx->SetColLabelValue(j, ach); }

158

Page 160: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

2.Interfaţarea client-server PostgreSQL în limbajul C/C++

// pe ultima linie afişează OID corespunzător tipulului de câmp int z; GDx->AppendRows(1); GDx->SetRowLabelValue(nrInregistrari, _("OID tip")); for(j = 0; j < nrCampuri; j++) { z = (int)PQftype(rezultatRx, j); ach = ach.FromDouble(z); GDx->SetCellValue(nrInregistrari, j, ach); } if(rezultatRx) PQclear(rezultatRx); //ştergere date buffer}

În cadrul constructorului clasei IGPG este format şirul de conectare, se încearcă realizarea conexiunii şi se testează rezultatul.

Metoda “void IGPG::afisQ(wxGrid *GDx, wxString cdaSQL)” preia comanda ce se transmite server-ului PostgreSQL şi adresa grid-ului în care va fi scris rezultatul. În cadrul acestei metode se execută comanda SQL şi se testează rezultatul. Dacă au fost obţinute rezultate, se citeşte numărul de câmpuri şi numărul de înregistrări obţinute. Se setează controlul de tip wxGrid cu dimensiunea obţinută. Datele sunt copiate celulă cu celulă în controlul wxGrid. Fiecare dată este convertită din şir de caractere în obiect wxString cu ajutorul funcţiei wxString.FromUTF8(char*). Pentru afişarea valorilor de tip OID a fost necesară conversia din tipul integer în obiect wxString cu ajutorul funcţiei wxString.FromDouble(double). După utilizare, zona de memorie ocupată de variabila de tip PGresult este eliberată prin funcţia PQclear.

//main.h#include <wx/wx.h>class MainApp : public wxApp { public: virtual bool OnInit(); };DECLARE_APP(MainApp)class MainFrame : public wxFrame { IGPG *x; protected: wxGrid* GD1; wxButton* B_AFIS; public: MainFrame(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& titlu = _(" Afişare în grid"), const wxPoint& poz = wxDefaultPosition, const wxSize& dim = wxSize(500, 193), long stilfer = wxCLOSE_BOX|wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL); ~MainFrame(); protected: virtual void afiseaza(wxCommandEvent& eveniment);};

În acest fişier, de tip header, sunt declarate clasa ce gestionează aplicaţia (MainApp) şi clasa ce gestionează fereastra principală (unica fereastră). Constructorul ferestrei este setat cu o serie de parametri impliciţi. Stilul ferestrei este construit printr-o operaţie de SAU logic la nivel de bit (operatorul “|”)

159

Page 161: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

între constantele specificate.

//main.cpp#include "igpg.h"#include "main.h"IMPLEMENT_APP(MainApp);bool MainApp::OnInit(){ SetTopWindow(new MainFrame(NULL)); GetTopWindow()->Show(); return true;}MainFrame::MainFrame(wxWindow* parent, wxWindowID id, const wxString& titlu, const wxPoint& poz, const wxSize& dim, long stilfer) : wxFrame(parent, id, titlu, poz, dim, stilfer){wxBoxSizer* mainSizer; mainSizer = new wxBoxSizer(wxVERTICAL); GD1 = new wxGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);GD1->CreateGrid(5,5);GD1->EnableEditing(true);GD1->EnableGridLines(true); GD1->EnableDragGridSize(false);GD1->SetMargins(0, 0); // Coloane GD1->EnableDragColMove(false); GD1->EnableDragColSize(true); GD1->SetColLabelSize(30); GD1->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); // Rânduri GD1->EnableDragRowSize(true); GD1->SetRowLabelSize(80); GD1->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD1->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP); mainSizer->Add(GD1, 0, wxALL, 5); wxBoxSizer* bSizer2; bSizer2 = new wxBoxSizer(wxHORIZONTAL); B_AFIS=new wxButton(this, wxID_ANY, _("AFISEAZA"), wxDefaultPosition, wxDefaultSize, 0); bSizer2->Add(B_AFIS, 0, wxALL, 5); mainSizer->Add(bSizer2, 0, wxEXPAND, 5); this->SetSizer(mainSizer); this->Layout(); this->Centre(wxBOTH); B_AFIS->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MainFrame::afiseaza), NULL, this); x=new IGPG("picdb","postgres","abcd","127.0.0.1","5435");}MainFrame::~MainFrame(){ B_AFIS->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MainFrame::afiseaza), NULL, this);}void MainFrame::afiseaza(wxCommandEvent& eveniment)

{x->afisQ(GD1, "select * from pic.inv"); }

Metodele privind poziţionarea controalelor sunt apelate în constructorul ferestrei. Aceste metode sunt detaliate în docu-mentaţia de pe www.widgets.org, dar pentru acest exemplu nu sunt relevante.

În ultimul capitol este explicat şi modul de legare al altor controale cu server-ul PostgreSQL.

160

Page 162: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Generarea în limbajul C a rapoartelor în fişiere format PDF

3. Generarea în limbajul C a rapoartelor în fişiere format PDF

3.1. Introducere în utilizarea bibliotecii libHARU

Biblioteca libHARU “http://libharu.org/ ” este o colecţie de funcţii C, open source, ce permite crearea fişierelor PDF, indiferent de platformă. Biblioteca se descarcă sub formă de cod sursă. Pentru a putea fi utilizată cu un anumit compilator, este necesară compilarea acesteia cu acelaşi compilator cu care se va lucra. În funcţie de compilator sunt activate sau nu anumite resurse. Din acest motiv este necesar un program de tip makefile pentru compilarea bibliotecii libHARU. În acest sens, pentru un sistem MS Windows şi cu un mediu de dezvoltare CodeLite este necesară parcurgerea următoarelor etape:

☑ În variabila sistem PATH se verifică existenţa directorului care conţine mingw32-make.exe (de ex.: ;D:\MinGW-4.7.1\bin), dacă nu se adaugă în "Local Variable" şi se restartează sistemul de operare;

☑ În MakeFile.mingw se înlocuieşte -mno-cygwin cu NIMIC;☑ Din directorul libharu-versiunea se execută comanda:

mingw32-make -f script/MakeFile.mingw;☑ Pentru testare se deschide un proiect în CodeLite şi se

adaugă opţiunile la nivel de proiect (click dreapta pe proiect) – exemplu:>>Common_settings>>Compiler>>Include_Path:>>

D:/LibHaru/libharu-2.0.8/include;>>Common settings >>Linker>>Library Path:>>

D:/LibHaru/libharu-2.0.8/win32/mingw; D:/LibHaru/libharu-2.0.8>>Common settings >>Linker>>Options:>> -lhpdf -lpng -lz -lm

Fişierele construite cu ajutorul bibliotecii libHARU pot conţine text, linii, imagini, adnotări etc. În module este folosit tipul de dată HPDF_REAL pentru stocarea poziţiei pe una din coordonate.

3.2. Funcţii uzuale oferite de bibliotecă

Modulul HPDF_Doc conţine funcţiile ce gestionează obiectul document (conţine funcţii la nivel de fişier PDF). Dintre aceste funcţii menţionez:

✗ HPDF_Doc HPDF_New (HPDF_Error_Handler user_error_fn, void *user_data) – funcţia instanţiază un obiect PDF;

✗ HPDF_Doc HPDF_Free (HPDF_Doc pdf) – eliberează memoria alocată pentru documentul pdf;

161

Page 163: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

✗ HPDF_STATUS HPDF_Info_SetInfoDateAttr(HPDF_Dict info, HPDF_InfoType type, HPDF_Date value) – funcţie ce setează atributele documentului PDF (autor, titlu, subiect, cuvinte cheie etc.).Modulul HPDF_Page gestionează informaţii specifice fiecărei

pagini din document. Câteva funcţii relevante din acest modul:☑ HPDF_STATUS HPDF_Page_SetWidth (HPDF_Page page, HPDF_REAL

value) – setează lăţimea paginii;☑ HPDF_STATUS HPDF_Page_SetHeight(HPDF_Page page, HPDF_REAL

value); – setează înălţimea paginii;☑ HPDF_STATUS HPDF_Page_SetSize(HPDF_Page page, HPDF_PageSizes

size, HPDF_PageDirection direction); – setare pagină (ex.: HPDF_Page_SetSize(pag1, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT);

☑ HPDF_REAL HPDF_Page_TextWidth (HPDF_Page page, const char *text) – obţine lungimea, în unităţi grafice pentru textul transmis prin argument.Modulul HPDF_Font gestionează informaţiile specifice

fonturilor utilizate. Câteva funcţii relevante pentru acest modul:✗ const char * HPDF_Font_GetFontName (HPDF_Font font) – obţine

numele fontului din cadrul unei resurse de tip font;✗ const char * HPDF_Font_GetEncodingName(HPDF_Font font) –

obţine numele encoding-ul ataşat unei resurse font.Pot fi utilizate mai multe tipuri de fonturi:

☑ Base 14 Font – sunt fonturi create în cadrul fişierelor PDF, nu necesită o încărcare a acestora din fişiere.

☑ TrueType Font – cele mai răspândite, fonturi bazate pe funcţiile de desenare ale conturului (TrueType este un format vectorial care folosește curbe B-spline pătratice);

☑ CID Font – fonturi multicaracter dezvoltate de Adobe.Punctul de origine pentru desenarea unui font este

considerat a fi stâga jos. Modulul HPDF_Image permite încărcarea imaginilor format JPG

sau PNG. Dintre funcţiile acestui modul fac parte:✗ HPDF_LoadPngImageFromFile() – încarcă un fişier format PNG;✗ HPDF_LoadJpgImageFromFile() – încarcă un fişier format JPG;✗ HPDF_LoadRawImageFromMem() – încarcă direct din memorie o

imagine binară;✗ HPDF_Point HPDF_Image_GetSize (HPDF_Image image);✗ HPDF_UINT HPDF_Image_GetWidth (HPDF_Image image);✗ HPDF_UINT HPDF_Image_GetHeight (HPDF_Image image).

Modulul HPDF_Annotations permite adăugarea de adnotări şi conţine funcţii precum:

☑ HPDF_STATUS HPDF_TextAnnot_SetOpened(HPDF_Annotation annot, HPDF_BOOL opened) – setează adnotarea pentru a se afişa automat la deschiderea fişierului PDF;

☑ HPDF_TextAnnot_SetIcon(HPDF_Annotation annot, HPDF_AnnotIcon

162

Page 164: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Generarea în limbajul C a rapoartelor în fişiere format PDF

icon) – setează imaginea ataşată adnotării (HPDF_ANNOT_ICON_COMMENT, HPDF_ANNOT_ICON_NOTE, HPDF_ANNOT_ICON_HELP, HPDF_ANNOT_ICON_INSERT etc.).

Centrul coordonatelor paginii (0,0) este în punctul stânga-jos. Rezoluţia implicită este de 72 dpi, deci pentru o pagină format A4 vom avea 210 × 297 (mm) sau 8.27 x 11.69 inches, adică aproximativ 595 x 841 pixeli. Reprezentarea pentru numărul de pixeli este dată de tipul HPDF_REAL.

O resursă pagină (HPDF_Page) se poate afla în următoarele moduri: HPDF_GMODE_PAGE_DESCRIPTION, HPDF_GMODE_PATH_OBJECT şi HPDF_GMODE_TEXT_OBJECT. Trecerea dintr-un mod în altul se realizează în funcţie de metodele apelate şi este detaliată în diagrama următoare:

Figura VI-4: Diagrama de trecere dintr-un mod grafic în altul

Pentru a putea scrie, este necesară trecerea în modul HPDF_GMODE_TEXT_OBJECT. În acest mod este asigurat avansul pe orizontală conform dimensiunii fontului. Pentru a continua pe linia următoare, se poate utiliza funcţia HPDF_Page_MoveToNextLine(). La încheierea sesiunii de scriere se va ieşi din acest mod grafic.

163

HPDF_GMODE_PAGE_DESCRIPTION(implicit)

Operaţii permise: Setări pagină, font, culoare etc.

HPDF_GMODE_PATH_OBJECTOperaţii permise; Funcţiile de mai sus. Poziţionarea va fi relativă,se raportează la ultima poziţie.

HPDF_Page_MoveToNextLine()HPDF_Page_MoveTo() etc. sau primitive grafice: HPDF_Page_Rectangle() HPDF_Page_Circle() etc.

HPDF_GMODE_TEXT_OBJECTOperaţii permise;

Afişare textSetări pagină, font, culoare etc.

Funcţii de validare a operaţiilor de desenare:HPDF_Page_Stroke()HPDF_Page_FillStroke HPDF_Page_EndPath etc.

HPDF_Page_BeginText()HPDF_Page_BeginText()

Page 165: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

3.3. Exemplu de construcţie a unui fişier PDF

În continuare este prezentat un exemplu comentat pentru crearea a unui fişier format PDF.

Figura VI-5: Exemplu afişare raport

#include <stdlib.h>#include <stdio.h>#include <string.h>#include <exception>#include "hpdf.h"

#ifdef HPDF_DLLvoid __stdcall#elsevoid#endif//definirea funcţiei pentru afişarea erorilorerror_handler (HPDF_STATUS error_no, HPDF_STATUS detail_no, void *user_data){ printf ("ERROR: error_no=%04X, detail_no=%u\n",

(HPDF_UINT)error_no, (HPDF_UINT)detail_no); // A SE VERIFICA http://libharu.sourceforge.net/error_handling.html

throw std::exception ();}

164

Page 166: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Generarea în limbajul C a rapoartelor în fişiere format PDF

int main (int argc, char **argv){ const char *page_titlu = "TITLUL RAPORTULUI";

HPDF_Doc pdf; //Documentul PDFHPDF_Page page1, page2; // două pagini din cadrul documentului HPDF_Font def_font; HPDF_REAL tw, height, width;

pdf = HPDF_New (error_handler, NULL); if(!pdf) {printf("eroare: Nu poate fi creat obiectul PdfDoc !\n"); return 1; }

//setare informatii fişier PDFHPDF_SetInfoAttr (pdf,HPDF_INFO_AUTHOR,"Autor Nume");HPDF_SetInfoAttr (pdf,HPDF_INFO_TITLE,"TEST");

try {page1 = HPDF_AddPage (pdf);

// adăugarea primei pagini din cadrul documentului PDFHPDF_Page_SetSize (page1, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT);

// setarea paginii A4 portret height=HPDF_Page_GetHeight(page1); width=HPDF_Page_GetWidth(page1); //preluarea dimensiuni paginii

HPDF_Page_SetRGBFill(page1, 1, 0, 0);//setare culoare de scriere rosu HPDF_Page_SetLineWidth(page1, 1); //grosime limie de scriereHPDF_Page_Rectangle(page1,50,50,width-100,height-110);

//desenare dreptunghiHPDF_Page_Stroke(page1); // definitivare imagini desenaredef_font = HPDF_GetFont(pdf, "Helvetica", NULL); HPDF_Page_SetFontAndSize(page1, def_font, 24);

// setare font scriere pentru prima paginătw = HPDF_Page_TextWidth(page1, page_titlu);// dimensiunea pe orizontală pentru textul din page_titluHPDF_Page_BeginText(page1); //începe secvenţa de scriereHPDF_Page_MoveTextPos(page1,(width-tw)/2,height-50);//poziţionare cursor pentru începerea scrieriiHPDF_Page_ShowText(page1, page_titlu); //afişare textHPDF_Page_EndText(page1);//sfârşitul secţiunii de scriere

HPDF_Page_BeginText(page1);//o nouă secţiune de scriereHPDF_Page_MoveTextPos(page1,60,height-80);//o noua repoziţionare absolutăHPDF_Page_SetFontAndSize(page1, def_font, 16); //setare font scriereHPDF_Page_SetRGBFill(page1, 0.8, 0.521, 0.2);//setare culoare de scriereHPDF_Page_ShowText(page1, "UN TEST CU FONTURI"); //afişare textHPDF_Page_EndText(page1); //sfârşit secţiune de scriere//desenarea unui dreptunghi linie cu linieconst HPDF_UINT16 DASH_MODE2[] = {3, 9};HPDF_Page_SetLineWidth(page1, 2.0); HPDF_Page_SetDash(page1,DASH_MODE2,2,2); HPDF_Page_MoveTo(page1, 210, 370);

165

Page 167: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VI.Dezvoltarea interfeţei client cu ajutorul bibliotecilor

HPDF_Page_LineTo(page1,390,370); HPDF_Page_LineTo(page1,390,410); HPDF_Page_LineTo(page1,210,410); HPDF_Page_LineTo(page1,210,370);HPDF_Page_Stroke(page1);

//un alt text în prima paginăHPDF_Page_BeginText(page1);HPDF_Font font=HPDF_GetFont(pdf,"Courier-BoldOblique","CP1250");HPDF_Page_SetFontAndSize (page1, font, 29);HPDF_Page_SetRGBFill (page1, 0.3, 0.121, 0.7);HPDF_Page_MoveTextPos (page1, 220, 380);HPDF_Page_ShowText (page1, "UN CHENAR");HPDF_Page_EndText (page1);

page2 = HPDF_AddPage(pdf); //adăugarea celei de-a doua paginiHPDF_Image image;image = HPDF_LoadPngImageFromFile(pdf, "stoky.png");double iw, ih;iw=HPDF_Image_GetWidth(image);ih=HPDF_Image_GetHeight(image);//preluarea dimensiunii imaginiiHPDF_Page_DrawImage(page1,image,10,height-ih-10,iw,ih);HPDF_Page_DrawImage(page2,image,10,height-ih-10,iw,ih);//ataşarea imaginii în a doua paginăHPDF_Rect rect1 = {50, 350, 70, 330};HPDF_Rect rect2 = {210, 350, 230, 330};HPDF_Rect rect3 = {50, 250, 70, 230};HPDF_Annotation adnotare;//adăugarea celor trei adnotări

adnotare=HPDF_Page_CreateTextAnnot(page1,rect1,"COMENTARIU...",NULL);HPDF_TextAnnot_SetIcon(adnotare, HPDF_ANNOT_ICON_COMMENT);HPDF_TextAnnot_SetOpened(adnotare, HPDF_TRUE);adnotare=HPDF_Page_CreateTextAnnot(page1,rect2,"Adnotare ...",

NULL); HPDF_TextAnnot_SetIcon(adnotare, HPDF_ANNOT_ICON_NOTE);adnotare=HPDF_Page_CreateTextAnnot(page1, rect3,"Help ....",

NULL); HPDF_TextAnnot_SetIcon(adnotare, HPDF_ANNOT_ICON_HELP);

//scriere text în a doua paginăHPDF_Page_BeginText(page2);def_font = HPDF_GetFont(pdf, "Times-BoldItalic", NULL);HPDF_Page_SetFontAndSize(page2, def_font, 36);HPDF_Page_MoveTextPos(page2, (width - tw) / 2, height - 50);HPDF_Page_ShowText(page2, "TITLUL DIN PAGINA 2");def_font = HPDF_GetFont (pdf, "Times-Roman", NULL);HPDF_Page_SetFontAndSize (page2, def_font, 24);HPDF_Page_MoveTextPos (page2, 0, 0 - 136); // deplasare relativă cu 136 de unităţi(pixeli din doc) mai josHPDF_Page_ShowText (page2, "abcd ABCD");def_font = HPDF_GetFont (pdf, "Symbol",NULL); //afişare utilizând fonturile “simbol”HPDF_Page_SetFontAndSize (page2, def_font, 24);HPDF_Page_MoveTextPos (page2, 0, 0-24);

166

Page 168: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Generarea în limbajul C a rapoartelor în fişiere format PDF

HPDF_Page_ShowText (page2, "abcd ABCD");def_font = HPDF_GetFont (pdf, "Times-Roman","CP1250"); //font Times-Roman cu encoding CP1250HPDF_Page_SetFontAndSize (page2, def_font, 24);HPDF_Page_EndText (page2);

//desenarea unor dreptunghiuri în prima paginăHPDF_Page_SetLineWidth(page1,1);HPDF_Page_SetDash(page1,NULL,0,0); //linie plină HPDF_Page_Rectangle (page1, rect1.left, rect1.bottom, rect1.right-

rect1.left, rect1.top-rect1.bottom);HPDF_Page_Rectangle (page1, rect2.left, rect2.bottom, rect2.right-

rect2.left, rect2.top-rect2.bottom);HPDF_Page_Rectangle (page1, rect3.left, rect3.bottom, rect3.right-

rect3.left, rect3.top-rect3.bottom);HPDF_Page_Stroke (page1);

HPDF_Page_SetFontAndSize (page2, def_font,16);unsigned char buf[2]; buf[1]=0;HPDF_Page_BeginText (page2);HPDF_Page_MoveTextPos (page2, 50, 600);for(int i=0;i<255;i++) { buf[0]=i;if(i % 20) HPDF_Page_ShowText(page2, (char*)buf);

else {HPDF_Page_MoveTextPos (page2, 0, 0-20); HPDF_Page_ShowTextNextLine(page2, (char*)buf); //scrie pe linia următoare }//end else

}//end forHPDF_Page_MoveTextPos2(page2, 0, 0-20);HPDF_Page_ShowText(page2,"DIACRITICE: ");

char diacritice[10]={0xAA,0xBA,0xC2,0xE2,0xC3,0xE3,0xCE,0xEE,0xDE,0xFE};for(int i=0;i<10;i++) { buf[0]=diacritice[i]; HPDF_Page_ShowText(page2, (char*)buf);}HPDF_Page_EndText (page2);

HPDF_SaveToFile (pdf,"pic.pdf"); //crearea fişierului PDF

} catch (...) {//în cazul în care nu a putut fi creat documentulHPDF_Free (pdf);//eliberarea resurselor alocatereturn 1;

}HPDF_Free (pdf); //eliberarea resurselor alocatereturn 0;

}

Înainte de lansarea executabilului, ce duce la crearea fişierului pic.pdf, se va verifica dacă nu există deschis un fişier cu acelaşi nume, existenţa unui astfel de fişier deschis generează eroare în momentul execuţiei. Erorile vor fi identificate conform: https://github.com/libharu/libharu/wiki/Error-handling.

167

Page 169: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

VII. Dezvoltarea unor module pentru logistica stocurilor

Pentru exemplificarea dezvoltării unor module din cadrul unei aplicaţii de baze de date cu interfaţă în C++ am ales o aplicaţie de logistica stocurilor (de gestiune) – LogX. Această aplicaţie este doar pentru gestiunile ce operează cu produse ce nu presupun existenţa unor termene de garanţie, altfel aplicaţia ar fi fost centrată pe loturile de produse.

LogX este o aplicaţie ce implementează doar o parte din operaţiile de bază aferente aplicaţiilor de tip warehouse management. Din cadrul acestei aplicaţii am implementat doar modulele: recepţie marfă (intrări), livrări şi consultare stocuri.

Această implementare este demonstrativă, nu a fost testată în condiţii de lucru şi nu utilizează clase ce implementează modele de date, aceasta se traduce într-o viteză mai mică de lucru şi o dependenţă mai mare de performanţele calculatorului client (limitările sunt doar la nivel de interfaţă, SGBD-ul PostgreSQL are performanţe comparabile cu SGBD-ul Oracle).

Stabilirea cerinţelorSă se proiecteze o aplicaţie pentru gestiunea stocurilor

având următoarele specificaţii:

➢ gestiunea este formată din mai multe depozite(dep), fiecare având amplasamente specifice (ampl);

➢ marfurile se pot transfera dintr-un depozit în altul sau de pe un amplasament pe altul în cadrul aceluiaşi depozit;

➢ fiecare item (obiect din cadrul mărfii) este caracterizat prin: referinţă comercială (ref_com), referinţă tehnică(ref_teh) şi o descriere (descr) corespunzătoare acestora;

➢ unele item-uri pot avea serie (serial_no);➢ opţional, se urmăreşte numărul comenzii (po – process order);➢ opţional, se urmăreşte furnizorul (supplier);➢ fiecare produs/item se poate afla într-o anumită stare (status);➢ operaţiile efectuate sunt: recepţie (intrare marfă), livrare

(ieşire marfă) şi transfer între depozite sau amplasamente.

1. Arhitectura aplicaţiei – LogX

1.1. Structura de bază a aplicaţiei

Proiectarea aplicaţiei se va realiza etapizat într-o manieră top-down.

168

Page 170: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Arhitectura aplicaţiei – LogX

P1: Pentru început putem considera un singur bloc intrare-ieşire.

Figura VII-1: Modelul intrare-ieşire, nivel aplicaţie

Datele din cadrul bazei de date se modifică în urma opera-ţiilor de editare. Aplicaţia LogX oferă: operaţii de editare şi generare rapoarte. P2: Aplicaţia este de tip desktop şi cuprinde interfaţa cu server-ul PostreSQL (dezvoltată în C++) şi funcţii pe partea de server ce implementează atât operaţiile de editare, cât şi construcţia rapoartelor.

Figura VII-2: Structura aplicaţiei

P2: Aplicaţia LogX o descompunem în modulele: intrări, transfer, ieşiri şi stoc. Operaţiile de editare a ieşirilor şi a trans-ferurilor utilizează modulul rapoarte stoc (selecţie stoc în vederea livrării sau a unui transfer).P3: Operaţiile de recepţie şi livrare presupun mai mulţi paşi, aceasta va duce la aparaţia de noi submodule. Punerea în evidenţă a unor resurse comune conduce, de asemenea, la noi submodule.Astfel putem avea următoarea structură:

169

AplicaţieLogX

OPERAŢII DE EDITARE: Receţie

Operaţii transferLivrări

RAPOARTE:Intrări TransferIeşiri Stoc (curent)

INTERFAŢĂ UTILIZATOR(dezvoltată

în C++)

EDITARE(SQL/plpgSQL)

RAPOARTE(SQL/plpgSQL)

DATE SERVERPostgreSQL

SERVER PostgreSQL

Page 171: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

Figura VII-3: Principalele module

1.2. Fluxul informaţional

Astfel, pentru a evita introducerea mai multor denumiri pentru descrierea aceluiaşi item, se va utiliza un nomenclator de produse (nom).

Recepţia se realizează, iniţial, în cadrul unui borderou de recepţie (BR), care apoi se validează. Borderourile de recepţie în curs de editare (ce nu sunt definitive/nevalidate) vor fi stocate într-un tabel PostgreSQL, pe măsură ce sunt validate, acestea vor fi eliminate din tabel.

Înainte de livrare se realizează rezervarea mărfii prin constituirea borderoului de preparare (BP), borderou ce se transformă în borderou de livrare (BL) în momentul validării borderoului de preparare (BP). Validarea borderoului de preparare este echivalentă cu constituirea borderoului de livrare (BL va păstra numărul de la BP).

Fiecare borderou (de preparare/livrare (BP/BL), de recepţie (BR), de transfer (BT) va avea câte un număr unic asociat. Fiecare borderou cuprinde unul sau mai multe item-uri. De asemenea, avem şi informaţii la nivel de borderou, în afară de numărul acestuia, precum: data constituirii borderoului, sursa, destinaţia etc.

Fluxul informaţional este dat de diagrama de mai jos.

170

STOC

INTRĂRI

TRANSFERURI

IEŞIRI

EDITARE INTRĂRI

EDITARE OPERAŢII TRANSFER

EDITARE IEŞIRI

RAPOARTE STOC

RAPOARTE IEŞIRI

RAPOARTE INTRĂRI

RAPOARTE TRANSFER

LogX

Page 172: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Arhitectura aplicaţiei – LogX

Figura VII-4: Fluxul informaţional

Operaţiile de editare a stocurilor sunt descrise prin:1 - introducerea de date manual sau prin import fişiere CSV;2 - validarea BR, adăugarea înregistrării în inx şi ştergerea înregistrărilor din tabelul br;3 - adăugare automată a înregistrărilor şi în stoc (ID-ul din inx se va copia şi în stx);4 - operatorul selectează din stoc liniile ce vor fi livrate;5 - rezervarea cantităţii (se scade cantitatea disponibilă);6 - validare BP, inserare înregistrări în outx;7 - actualizarea cantităţilor fizice în urma livrării;A - introducerea de coduri noi direct de la operator;B - actualizarea nomenclatorului pe baza intrărilor, modificări în intrări pe baza acestuia;C - introducerea de noi coduri de depozite şi amplasamente direct de operator;D - preluarea prin selecţie de noi coduri de depozite şi ampla-samente;E - selecţia depozitelor şi amplasamentelor din cadrul transfe-rurilor;F - selecţie din stoc în vederea transferurilor;

171

brVALIDARE

OPERATOR

FIŞIER CSV

inx

stx bp__bp

outx

VALIDARE

REZERVARE

ACTUALIZARE STOC

trx

ACTUALIZARE STOC

OPERATOR

OPERATOR

nom

loc

OPERATOROPERATOR

1 2

3

4

6

A B

CD

E

F

5

G

7

SELECŢIE

SELECŢIE

SELECŢIE

Page 173: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

G - actualizarea stocurilor în urma transferurilor.Livrarea mărfurilor se realizează în două etape:

1. Se realizează rezervarea mărfurilor prin constiutuirea BP;2. Se realizează validarea BP şi transformarea în BL.

În acest sens vom utiliza următoarele noţiuni de cantitate:☑ cantitate fizică (qty_fiz) – fizic, existent în stoc;☑ cantitate disponibilă (qty_disp) – poate deveni rezervată; ☑ cantitate rezervată (qty_rez) – rezervată în cadrul BP;☑ cantitate confirmată (qty_conf) – livrată efectiv.

Iniţial, qty_fiz=qty_disp, apoi prin crearea unui nou BP se realizează o rezervare de cantitate prin scăderea acesteia din cantitatea disponibilă. În momentul validării BP se verifică dacă întreaga cantitate care se livrează (este posibil ca unele produse să fie refuzate şi atunci cantitatea confirmată devine mai mică decât cea rezervată. Operaţiile asupra cantităţii sunt:

☑ Rezervare: qty_disp = qty_disp - qty_rez;☑ Livrare (validare BP):

qty_disp = qty_disp + (qty_disp - qty_conf);qty_fiz = qty_fiz - qty_conf.

unde:✗ qty_fiz ≥ qty_disp✗ qty_rez ≤ qty_disp✗ qty_conf ≤ qty_rez

1.3. Structura tabelelor PostgreSQL

Tabelele persistente vor fi create în cadrul schemei pic. Tabele ce vor fi create sunt:

Tabel Descriere Cheia primară Temp.

nom Nomenclatorul de produse idcode

inx Intrările în gestiune id

stx Stocul curent dep, ampl, id

outx Ieşirile din gestiune nrbl, id, dep, ampl

loc Depozite şi amplasamente dep, ampl

bp_ Tabel master pentru BP nrbp

_bp Tabel slave pentru BP nrbp,id,dep,ampl

itmp_bp Tabel pentru interfaţare BP nrbp,id,dep,ampl X

itmp_br Tabel pentru interfaţare BR nrbr, idx X

trx Transferuri EFECTUATE nrbt, nrlin

tr_ Tabel master pentru BT (nevalidate) nrbt

172

Page 174: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Arhitectura aplicaţiei – LogX

Tabel Descriere Cheia primară Temp.

_tr Tabel slave pentru BT (nevalidate) nrbt, id, dep_srs, ampl_srs

itmp_bt Tabel pentru interfaţare BT nrbt, id, dep_srs, ampl_srs

X

tmpselst Selecţie stoc ptr. BP sau TR - X

acces Conţine alias-urile, parolele (iniţiale, la nivel de aplicaţie) şi lista cu codurile depozitelor accesibile pentru fiecare utilizator

alias (codul privind numele utilizatorului)

tmpacc Conţine depozitele unde are acces utilizatorul curent (logat)

- X

În acest caz, tabelele temporare PostgreSQL sunt utilizate numai în vederea interfaţării cu utilizatorul. De asemenea tabelele master-slave tr_ şi _tr ce conţin transferurile în curs de editare nu sunt trecute în diagramă deoarece, împreună, conţin aceeaşi informaţie ca şi tabelul trx cu transferuri deja validate.

Tabelele PostgreSQL de interfaţare au structură asemănătoare cu cele pe care le reprezintă, sunt utilizate doar pentru a secu-riza transferul datelor din grid în tabelul PostgreSQL.

Structura tabelelor de bază este dată de diagrama din fig. 5. Tabelul cu drepturi de acces, denumit acces este utilizat doar pentru acces şi pentru crearea unui tabel temporar cu depozitele la care are acces utilizatorul curent (logat). Acest tabel intră în interogările în care apar şi depozite, astfel vor fi vizibile doar înregistrările pentru care codul depozitului se regăseşte în tabelul temporar de acces tmpacc.

Cheile externe pentru depozit şi amplasament (de tip 1:N, 1 fiind corespondent tabelului loc) nu permit existenţa altor depozite sau amplasamente în tabelele aplicaţiei care nu se regăsesc în tabelul loc. De asemenea cheile externe pentru câmpul id nu permite existenţa în alte tabele a unor valori ce nu se regăsesc în câmpul id din tabelul inx.

173

Page 175: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

Figura VII-5: Structura tabelelor

În tabelul următor sunt enumerate cheile externe:

Tabel Câmp tabelN câmp1:N

inx id stx id

trx id

outx id

_bt id

_bp id

nom idcode inx idcode

loc dep stx dep

inx depinit

Tabel Câmp tabelN câmp1:N

br depinit

_bp dep

trx dep_srs

trx dep_dest

tr_ dep_dest

_tr dep_srs

loc ampl stx ampl

inx amplinit

174

inx#id nrbrdatainidcodepostatussupplierserialnodepintamplinit qtyval

outx#nrbl #id#dep#ampldestinqtylivdataout

stx#dep

#ampl

#id

qtyfiz

qtydisp

trx#nrbt #nrlindep_srsampl_srsdep_destampl_destidqtytr

nom#idcodereftehrefcomdescrutilizdataora

loc#dep#ampl

bp_#nrbpdatabpdestin

br#nrbr #idxdatainidcodepostatussupplierserialnodepintamplinitqtyval

_bp#nrbp#id#dep#amplqtyrezqtyconf

bt_#nrbtdatabtdep_destampl_dest

_bt#nrbt#id#dep_srs#ampl_srsqtytr

Page 176: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Arhitectura aplicaţiei – LogX

Tabel Câmp tabelN câmp1:N

br amplinit

_bp ampl

trx ampl_srs

trx ampl_dest

Tabel Câmp tabelN câmp1:N

tr_ ampl_dest

_tr ampl_srs

bt_ nrbt _bt nrbt

bp_ nrbp _bp nrbp

Codul pentru crearea acestor tabele se regăseşte în anexe.

2. Dezvoltarea modulelor SQL/plpgSQL

2.1. Dezvoltarea modulelor SQL/plpgSQL pentru editare

Pentru separarea interfeţei utilizator, dezvoltată în C++, de comenzile SQL sau funcţiile plpgSQL s-au utilizat doar proceduri plpgSQL. Acestea sunt detaliate în cele ce urmează:NOMENCLATOR●nom_add(_idcode_ text,_refteh_ text,_refcom_ text,_descr_ text)Adaugă în nomenclator un produs/item. În cazul în care valoarea dată de idcode deja există în nomenclator întoarce un mesaj text de eroare altfel întoarce 'OK';

INTRARI/RECEPŢIE●br_nou() Adaugă o nouă linie în tabelul logx.br. Funcţia preia data curentă şi nu întoarce nimic;

●id_nou(_dep_ text) Funcţia preia depozitul curent şi întoarce un identificator id unic în sistem (de tip text);

●valid_br(_nrbr_ int) Validează borderoul de recepţie (BR) al cărui număr este transmis prin argument. Întoarce un text cu un mesaj de eroare dacă nu sunt verificate anumite restricţii, altfel întoarce 'OK';

IEŞIRI/LIVRĂRI●bp_nou(_destin_ text,_databp_ date DEFAULT CURRENT_DATE) Adaugă o nouă linie în tabelul bp_ şi nu întoarce nimic;

●prelSelST2(_nrbp_ int) Preia datele din stocul selectat în BP-ul al cărui număr este transmis prin argument şi nu întoarce nimic;

●valid_bp(_nrbp_ int) Validează BP-ul al cărui număr este transmis prin argument şi întoarce un mesaj de eroare sau 'OK'.TRANSFER

●bt_nou(_dep_dest_ text, _ampl_dest_ text, _databt_ date DEFAULT

175

Page 177: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

CURRENT_DATE);Adaugă o nouă linie în tabelul bt_ şi nu întoarce nimic;

●prelSelST_Tr(_nrbt_ int)Preia datele din stocul selectat în BT-ul al cărui număr este transmis prin argument. Nu întoarce nimic.

●tr_valid(_nrbt_ int)Validează BT-ul al cărui număr este transmis prin argument. Întoarce un mesaj de eroare sau 'OK'.

2.2. Dezvoltarea modulelor plpgSQL pentru rapoarte

Sunt patru tipuri de rapoarte: stoc curent, intrări, ieşiri, transfer. Interogările sunt concepute într-o manieră flexibilă, astfel pentru fiecare câmp există două bife, una în stânga şi una în partea dreaptă. Prin bifa din stânga se stabileşte dacă acel câmp va apare ca şi coloană în tabel. De exemplu, dacă nu este bifat decât câmpul supplier, va aparea un număr de linii egal cu numărul de furnizori, iar în coloana cantitate va fi trecută suma cantităţilor grupate după furnizor. Bifa din dreapta semnifică activarea sau dezactivarea filtrului pentru parametrul din stânga acesteia. Rezultatul interogării va fi pus în tabelul TEMPORAR dat de tipul interogării (q_tmp_in, q_tmp_st, q_tmp_out sau q_tmp_tr).

Toate cele patru interogări vor utiliza o singură funcţie ce se bazează pe construcţia dinamică a interogărilor şi are forma:q_x(_tipQ_ text,_nr_ smallint,_nume_ text[], _tip_ text[], _a_ boolean[], _s_ boolean[], _val1_ text[], _val2_ text[],_ord_ text)unde:●_tipQ_: tipul interogarii: IN-intrare, ST-stoc, STL-stoc selectat în vederea livrării, OUT-iesire, TR-transfer;

●_nr_: numărul de câmpuri ce sunt în fereastra de selecţie;●_nume_[]: vectorul cu numele câmpurilor/coloanelor;●_tabel_[]: vector cu tabelele corespondente pentru fiecare câmp/colană;

●_tip_[]: vectorul ce conţine tipul fiecărui câmp din fereastra de selecţie. Acesta poate fi:☑ C – şir de caractere – cautare exactă – case sensitive (ţine

cont de literă mare sau mică);☑ A – şir de caractere – cautare aproximativa – case

insensitive (nu ţine cont de litera mare sau mică);☑ D1 – data calendaristică: valoare exactă;☑ D2 – data calendaristică: data va fi preluată ca interval;☑ N1 – data de tip numeric: valoare exactă;☑ N2 – data de tip numeric: interval.

●_a_[]: vectorul cu bifele pentru afişarea câmpurilor;●_s_[]: vectorul cu bifele pentru selecţia/filtrarea câmpurilor;●_ord_: câmpul după care se face ordonarea (un singur câmp).

176

Page 178: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

3. Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

Aplicaţia va avea următoarele ferestre (cele scrise cu “italic” nu sunt implementate):●iFACC - ferestră de acces;●ferestre pentru editare:

➢ iFPB - fereastră ce conţine panoul cu butoane; ➢ iFEI - fereastră editare intrări/recepţii;➢ iFEBP - fereastră editare ieşiri/livrări;➢ FETR - fereastră editare transferurile;➢ iFNOM - fereastră editare/selecţie nomenclator;

●ferestre pentru rapoarte/selecţie:➢ FRIN - fereastră rapoarte intrări;➢ iFSTSEL - fereastră rapoarte stoc şi fereastră selecţie stoc pentru BP sau BT;

➢ FROUT - fereastră raport ieşiri;➢ FRTR - fereastră raport transferuri.

3.1. Fereastra de acces iFACC

Această fereastră este lansată înainte de fereastra principală şi este o fereastră modală (derivată din wxDialog, aplicaţia nu rulează mai departe decât după închiderea acestei ferestre). În cadrul acestei ferestre sunt implementate şi funcţiile de acces la nivel de aplicaţie – aplicaţia intră cu un utilizator (logx_sw) prede-finit şi în funcţie de alias generează un nou utilizator cu o parolă generată aleator, iar după crearea noului utilizator este cedat controlul acestuia (este schimbat utilizatorul curent). Această fereastră asigură următoarele funcţii:

☑ preluare nume utililizator(alias) şi a parolei în vederea accesului la baza de date;

☑ posibilitatea schimbării adresei server-ului PostgreSQL şi a portului asociat;

☑ posibilitatea schimbării codului de acces (parolei);☑ generarea utlizatorului la nivel de aplicaţie şi cedarea

controlului către acesta.Ierarhia obiectelor din cadrul ferestrei este redată în

177

Figura VII-6

Page 179: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

digrama următoare:

Figura VII-7:

Figura VII-8: Legendă obiecte

Semnificaţia controalelor este dată în legenda din partea dreaptă.

Fişierul header cu declaraţia clasei: #ifndef __facc__ //fişierul facc.h#define __facc__#include <wx/wx.h>#include "lx.h"class iFACC : public wxDialog {wxString rezX; public: static bool accesX; iFACC(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Acces"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(201,234), long style = wxDEFAULT_DIALOG_STYLE); ~iFACC();protected: wxStaticText* t1; wxTextCtrl* e_alias; wxStaticText* t2; wxTextCtrl* e_pw; wxButton* b42; wxStaticText* t3; wxTextCtrl* e_host; wxStaticText* t4; wxTextCtrl* e_port; wxButton* bAcces; virtual void schimbPW(wxCommandEvent& event); virtual void acces(wxCommandEvent& event);};#endif

Constructorul preia adresa ferestrei în care se deschide, în acest caz NULL deoarece este apelat înainte de crearea ferestrei principale (înainte de instanţierea clasei iFPB). Fereastra nu va avea identificator propriu, deci este preluat wxID_ANY, titlul ferestrei este “Acces”.

178

CB wxChoice/wxComboBox

wxBoxSizer(wxHORIZONTAL)

wxBoxSizer(wxVERTICAL)

wxFlexGridSizer

31.12.00 wxDatePickerCtrl

LEGENDĂ:wxDialog/wxFrame

wxPanelOK wxButton

wxChoicebook Edit wxTextCtrl Text wxStaticText

wxRadioBox

x wxCheckListBox wxGrid

s1

Text t1

Text t2

Edit e_alias

OBIECTELE GRAFICE DIN FEREASTRA iFACC

iFACC

s2 s3

Edit e_pw

Text t3 Text t4

Edit e_host

Edit e_port

OK b42 OK bAcces

Page 180: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

Notă: Pentru conversia din şir de caractere în obiect wxString se utilizează _(“sir”) când şirul este ASCII sau wxT(“şir”) când şirul este UNICODE (dacă şirul are diacritice se va utiliza wxT) sau _(L“şir”).

Răspunsul la evenimente este dat de următorul tabel:

<Controlul>funcţie ataşată

Evenimentul Tratare eveniment

<b42> iFACC ::schimbPW

wxEVT_COMMAND_BUTTON_CLICKED(apăsare buton)

●verifică corectitudinea parolei introduse;

●preia de două ori noua parolă şi veri-fică dacă sunt sunt identice;

●actualizează în tabelul logx.acces noua parolă.

<bAcces>iFACC ::acces

wxEVT_COMMAND_BUTTON_CLICKED(apăsare buton)

●verifică corectitudinea parolei intro-duse şi setează corespunzător variabila de acces ;

● şterge aliasul precedent (dacă există) creat pe baza actualului alias introdus;

●creează un nou utilizator şi cu o parolă generată aleator;

●conferă drepturi noului utilizator pentru grupul “LOGX”;

●cedează controlul noului utilizator.

3.2. Fereastra ce conţine panoul cu butoane iFPB

Este ferastra principală ce rămâne deschisă până la sfârşitul aplicaţiei. Această fereastră conţine un panou cu butoane. Constructorii obiectelor de tip fereastră (în acest caz, derivaţi din clasa wxDialog), ce vor fi executaţi în cadrul acestei ferestre (în momentul instanţierii claselor corespunzătoare celorlalte ferestre), vor prelua în lista de argumente (primul argument) adresa acestei ferestre (pentru ferestrele noi, aceasta va reprezenta fereastra părinte). Datorită acestei legături, fereastra principală nu va putea fi închisă decât după ce sunt închise ferestrele copil sau închiderea acesteia va duce la închiderea ferestrelor copil (în funcţie de atributele ferestrelor copil şi ale ferestrei principale –

179

Figura VII-9

Page 181: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

părinte).Ierarhia obiectelor din cadrul ferestrei este redată în

diagrama următoare:

Figura VII-10: Obiecze grafice iFPB

Fişierul header cu declaraţia clasei:#ifndef __main__#define __main__#include <wx/wx.h>class LogXApp : public wxApp //clasa ce implementează buclele de evenimente{public: virtual bool OnInit(); /* ieşirea din metoda OnInit echivalează cu ieşirea din aplicaţie */};DECLARE_APP(LogXApp)class iFPB : public wxFrame{ public:

iFPB(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("GESTIUNE STOCURI"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(230,251), long style = wxCAPTION|wxCLOSE_BOX|wxMINIMIZE_BOX|wxSTAY_ON_TOP|wxSYSTEM_MENU|wxTAB_TRAVERSAL);

virtual ~iFPB();protected: wxStaticText* t1; wxStaticText* t2; wxButton* be1; wxButton* be2; wxButton* be3; wxButton* be4; wxStaticText* t3; wxButton* br1; wxButton* br2; wxButton* br3; wxButton* br4;

virtual void apasa_be1(wxCommandEvent& event);

180

s1

s2

OBIECTELE GRAFICE DIN FEREASTRA iFPB

iFPB

s3

OK be4OK be2

OK be3OK be1

Text t1

Text t2

s3

OK br4OK br2

OK br3OK br1

Text t3

Page 182: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

virtual void apasa_be2(wxCommandEvent& event);virtual void apasa_be4(wxCommandEvent& event);virtual void apasa_br4(wxCommandEvent& event);

};#endif //__main__

Răspunsul la evenimente este dat de următorul tabel:<Controlul>

funcţie ataşatăEvenimentul Tratare eveniment

< be1 >apasa_be1

wxEVT_COMMAND_BUTTON_CLICKED(apăsare buton)

● lansează fereastra editare intrări (iFEI);

<be2 > apasa_be2

wxEVT_COMMAND_BUTTON_CLICKED

● lansează fereastra editare livrări (iFEBP);

<be4 >apasa_be4

wxEVT_COMMAND_BUTTON_CLICKED

● lansează fereastra editare nomenclator (iFNOM);

<br4 > apasa_br4

wxEVT_COMMAND_BUTTON_CLICKED

● lansează fereastra interogare stoc ● (iFSELST).

3.3. Fereastra de editare intrări (recepţii) iFEI

În cadrul acestei ferestre se realizează recepţiile în stoc. Mai multe linii de intrare având în comun un furnizor şi o dată calendaristică de intrare pot forma un Borderou de Recepţie (BR).

Figura VII-11: Fereastra pentru editarea intrărilor

Aceste borderouri de recepţie (BR) primesc numere unice la intrare. Fiecare linie recepţionată are un identificator ID unic la nivelul aplicaţiei. Acest identificator este construit automat pe baza codului depozitului iniţial în care intră marfa şi un contor unic la nivel de aplicaţie. Astfel fiecare linie de intrare este

181

Page 183: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

identificată unic în sistem.În cadrul controlului de tip grid se pot realiza o serie de

operaţii, precum cea de selecţie a status-ului (a stării) sau selecţia depozitelor şi amplasamentelor. Numai depozitele unde există drepturi de acces vor fi afişate. Aceasta se realizează prin construcţia unui tabel temporar cu depozitele unde este permis accesul pentru utilizatorul respectiv. Orice interogare ce utilizează depozite se va lega şi de acest tabel (tmpacces).

Figura VII-12: Selecţia amplasamentului (citire din baza de date)

Fişierul header cu declaraţia clasei:#ifndef __fei__ //fişierul fei.h#define __fei__#include <wx/wx.h>#include "lx.h"class iFEI : public wxDialog { lxComboBox *cx_nrbr; lxEditT *cx_supplier; lxDPC *cx_datain; lxGrid *cx_grid;public: iFEI(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("EDITARE INTRARI"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(700,549), long style = wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU|wxALWAYS_SHOW_SB);

virtual ~iFEI();protected: wxStaticText* t4; wxComboBox* cbBR; wxDatePickerCtrl* eDataBR; wxStaticText* t5; wxTextCtrl* eSupplierBR; wxButton* bAddBR; wxPanel* pBR; wxButton* bDelBR; wxButton* bSavBR; wxGrid* GD1; wxButton* bValidBR; wxButton* bAddLin; wxButton* bDelLin; wxButton* B_selNom;

virtual void afis_BR(wxCommandEvent& event);virtual void sav_BR(wxCommandEvent& event);virtual void add_BR(wxCommandEvent& event);virtual void add_Lin(wxCommandEvent& event);virtual void del_Lin(wxCommandEvent& event);virtual void sel_nom(wxCommandEvent& event); virtual void del_BR(wxCommandEvent& event);

182

Page 184: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

virtual void valid_BR(wxCommandEvent& event); virtual void GD1OnGridEditorShown(wxGridEvent& event);virtual void GD1OnGridCellChange(wxGridEvent& event);

};#endif //__fei__

Ierarhia obiectelor din cadrul ferestrei este redată în diagrama următoare:

Figura VII-13: Obiectele grafice din fereastra iFEI

Această fereastră asigură următoarele funcţii:☑ constituirea unui nou BR;☑ modificarea unui BR existent;☑ ştergerea parţială sau completă a unui BR;☑ validarea unui BR.

Răspunsul la evenimente este dat de următorul tabel:

183

pBR

s1

s2

s3 Text t4

Text t5 GD1

Edit eSupplierBR

OK bAddBR

CB cbBR

OK bSelNom

OK bValidBR

31.12.00 eDataBR

OK bDelLinOK bAddLin

OK bDelBR

OK bSavBR

OBIECTELE GRAFICE DIN FEREASTRA iFEI

iFEI

s4 s5

Page 185: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

<Controlul>funcţie ataşată

Evenimentul Tratare eveniment

<cbBR> iFEI::afis_BR

wxEVT_COMMAND_COMBOBOX_SELECTED(selecţie combobox)

●actualizează afişarea pentru furnizor din baza de date;

●actualizează afişarea datei calendaristice de intrare;

●creează tabelul temporar temp_br ce conţine datele din tabelul br corespunzătoare numărului BR selectat;

●apelează funcţia de afişare a datelor în grid (din clasa lxGrid)

<bAddBR> iFEI::add_BR

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●execută funcţia plpgSQL br_nou();● reîncarcă lista din combobox-ul cu

numerele BR afişate (apelează o metodă din clasa lxComboBox)

<bDelBR> iFEI::del_BR

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

● şterge din tabelul br toate liniile afişate în grid

<bSavBR> iFEI::sav_BR

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

● .apelează metoda din clasa lxGrid pentru salvarea datelor din grid în tabelul temporar ataşat (temp_br);

●actualizează tabelul br pe baza datelor din temp_br

<GD1>iFEI::

GD1OnGridCellChange

wxEVT_GRID_CELL_CHANGE (modificare conţinut celulă)

●preia poziţia celulei modificate şi schimbă culoarea de scriere în roşu

<GD1>iFEI::

GD1OnGridEditorShown

wxEVT_GRID_EDITOR_SHOWN (afişare editor corespunzător celulei)

●preia poziţia din tabel (rând + coloană) şi pe baza valorii celulei ce conţine depozitul se construieşte lista de selecţie a amplasamentelor (corespunzătoare depozitului selectat în acel rând)

<bValidBR>iFEI::valid_BR

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●apelează metoda pentru salvarea BR●apelează funcţia plpgSQL valid_BR

pentru BR selectat

<bAddLin>iFEI::add_Lin

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●adaugă o linie în grid

<bDelLin>iFEI::del_Lin

wxEVT_COMMAND_BUTTON_CLICKED

● şterge din tabelul br linia selectată;●apelează funcţia afis_BR

184

Page 186: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

<Controlul>funcţie ataşată

Evenimentul Tratare eveniment

(apasă buton)

<B_selNom>iFEI::sel_nom

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●deschide fereastra cu nomenclatorul;●preia datele selectate

3.4. Fereastra de editare ieşiri/livrări iFEBP

Livrările de marfă se realizează în două etape:➢ Rezervarea din stoc în vederea livrării. În această fază se

scade din stoc doar cantitatea rezervată din cantitatea disponibilă. Această etapă se concretizează prin constituirea borderoului de preparare (BP);

➢ Livrarea efectivă. Cantitatea confirmată (în momentul livrării) se scade din cantitatea fizică. De asemenea, în cazul în care cantitatea confirmată diferă de cantitatea rezervată, se realizează corecţia asupra cantităţii disponibile din stoc. Livrarea efectivă corespunde validării BP. Liniile validate vor fi şterse din BP şi vor fi regăsite în tabelul cu ieşirile outx.Rezervarea mărfurilor se realizează prin intermediul ferestrei de interogare a stocurilor.

Figura VII-14: Afişarea BP-ului selectat

Această fereastră asigură următoarele funcţii:☑ constituirea unui nou BP;☑ ştergerea parţială sau completă a unui BP;☑ validarea unui BP.

185

Page 187: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

Figura VII-15:Selecţie în vederea constituirii unui BP

Fişierul header cu declaraţia clasei:#ifndef __febp__ //fişier febp.h#define __febp__#include <wx/wx.h>#include "lx.h"class iFEBP : public wxDialog {public:iFEBP(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("LIVRĂRI"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(598,499), long style = wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER);

virtual ~iFEBP();protected: wxStaticText* t1; wxComboBox* cbBP; wxButton* bAddBP; wxDatePickerCtrl* eDataBP; wxStaticText* t2; wxTextCtrl* eDestinBP; wxButton* bDelBP; wxPanel* pBP; wxGrid* GD1; wxButton* bDelLin; wxButton* bSelST; wxButton* bValidBP;

virtual void afis_BP(wxCommandEvent& event);virtual void addBP(wxCommandEvent& event);virtual void delBP(wxCommandEvent& event);virtual void delLin(wxCommandEvent& event);virtual void selST(wxCommandEvent& event);virtual void validBP(wxCommandEvent& event);

186

Page 188: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

wxString achBP; lxEditT *cx_destin;lxComboBox *cx_nrbp; lxDPC *cx_databp; lxGrid *cx_grid;};#endif //__febp__

Ierarhia obiectelor din cadrul ferestrei este redată în diagrama următoare:

Figura VII-16: Obiectele grafice din fereastra iFBP

Răspunsul la evenimente este dat de următorul tabel:

<Controlul>funcţie ataşată

Evenimentul Tratare eveniment

<cbBP>iFEBP::afis_BP

wxEVT_COMMAND_COMBOBOX_SELECTED(selecţie combobox)

●actualizează afişarea pentru Destinatar din baza de date;

●actualizează afişarea datei calendaristice pentru BP;

●creează tabelul temporar temp_bp, ce conţine datele din tabelul _bp, corespunzătoare numărului BP selectat şi

187

pBP

s1

s2

s4

Text t1

Text t2

GD1

Edit eDestinBPOK bAddBP

CB cbBP

OK bValidBP

31.12.00 eDataBP

OK bDelLin

OK bDelBP

OK bSelST

OBIECTELE GRAFICE DIN FEREASTRA iFBP

iFBP

s3

Page 189: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

<Controlul>funcţie ataşată

Evenimentul Tratare eveniment

implicit a liniei corespondente din tabelul părinte bp_. Pe lângă datele din tabelul _bp, tabelul temporar conţine şi date din nomenclatorul nom sau din tabelul cu intrări inx;

●apelează funcţia de afişare a datelor în grid (din clasa lxGrid)

<bAddBP> iFEBP::addBP

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●execută funcţia plpgSQL bp_nou;● reîncarcă lista din combobox-ul cu numerele

BP afişate (apelează metodă din clasa lxComboBox)

<bDelBP>iFEBP::delBP

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

● şterge din tabelele bp_ şi _bp toate liniile corespondente cu cele afişate în grid

<bDelLin>iFEBP::delLin

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●anulează din tabelul _bp linia selectată;●apelează funcţia afis_BP

<bSelST>iFEBP::selST

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●deschide fereastra de interogare a stocului în vederea operaţiei de rezervare;

●apelează funcţia afis_BP în vederea actualizării datelor

<bValidBP>iFEBP::validBP

wxEVT_COMMAND_BUTTON_CLICKED(apasă buton)

●apelează metoda pentru validarea BP-ului.●actualizează cantitatea confirmată din grid

în tabelul temporar temp_bp;●apelează funcţia plpgSQL valid_bp pentru

BP selectat;● reîncarcă lista din combobox-ul cu numerele

BP afişate;●apelează funcţia afis_BP

3.5. Fereastra editare/selecţie nomenclator iFNOM

Descrierea completă a unui produs/item se regăseşte în nomenclator. În momentul editării sau căutării este mai simplă selecţia tuturor caracteristicilor unui produs din nomenclator decât preluarea acestora de la tastatură. Această fereastră este utilizată atât în modulul de editare intrări, cât şi în modulele de construcţie a rapoartelor.

188

Page 190: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

Figura VII-17: Apelul ferestrei cu nomenclatorul

De asemenea această fereastră permite editarea nomenclatorului. Ordinea de afişare este stabilită cu ajutorul unui control de tip radiobuton. În cadrul nomenclatorului coloana IDCode este unică. În operaţiile de modificare a nomenclatorului nu se va modifica IDCode deoarece aceasta ar echivala cu introducerea unei noi linii. Interfaţarea între tabelul nom şi controlul de tip grid este realizată prin intermediul unui tabel temporar itmp_nom.

Această fereastră asigură următoarele funcţii:☑ selecţia unei înregistrări din nomenclator în vederea

completării câmpurilor corespunzătoare din cadrul ferestrelor de editare sau de raportare;

☑ ştergerea unor item-uri din nomenclator;☑ adăugarea de noi item-uri în nomenclator;☑ modificarea item-urilor deja existente în nomenclator.

Ierarhia obiectelor din cadrul ferestrei este redată în

189

Figura VII-18: Editarea nomenclatorului

Page 191: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

diagrama următoare:

Figura VII-19: Obiectele din fereastra iFNOM

Fişierul header cu declaraţia clasei:#define __fnom__#include <wx/wx.h>#include "lx.h"class iFNOM : public wxDialog {public:iFNOM(wxWindow* parent, wxArrayString* rez1, wxWindowID id = wxID_ANY, const wxString& title = wxT("Nomenclator produse"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER);

virtual ~iFNOM();protected:wxRadioBox* rOrd; wxGrid* GD1; wxPanel* pEdit; wxButton* bAdd; wxButton* bDel; wxButton* bSav; wxButton* bRenEdit; wxButton* bEdit; wxButton* bSel; wxButton* bRenNom;

void afis_NOM();virtual void ordoneaza(wxCommandEvent& event); virtual void add_Lin(wxCommandEvent& event);virtual void del_Lin(wxCommandEvent& event); virtual void salveaza(wxCommandEvent& event); virtual void ren_Edit(wxCommandEvent& event);virtual void editare(wxCommandEvent& event);virtual void selecteaza(wxCommandEvent& event);virtual void ren_Nom(wxCommandEvent& event);

190

pEdit

s1

s2 GD1

OK bRenNom

OK bEdit

OK bSel

OBIECTELE GRAFICE DIN FEREASTRA iFNOM

iFNOM

rOrd

s2Nom

OK bRenEditOK bDel

OK bSav

OK bAdd

Page 192: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

wxArrayString *rez, ord; int nr_ord; lxGrid *cx_grid; };#endif

Răspunsul la evenimente este dat de următorul tabel:

<Controlul>funcţie ataşată

EvenimentulTratare eveniment

<rOrd> iFNOM::ordoneaza

wxEVT_COMMAND_RADIOBOX_SELECTED(selecţie radiobuton)

●apelează funcţia afis_NOM pentru reactualizarea afişării din grid conform noului criteriu de ordonare

<bAdd>iFNOM::add_Lin

wxEVT_COMMAND_BUTTON_CLICKED(apăsare buton)

●adaugă o linie în grid şi redi-mensionează controlul

<bDel>iFNOM::del_Lin

wxEVT_COMMAND_BUTTON_CLICKED

●şterge linia selectată din grid

<bSav>iFNOM::salveaza

wxEVT_COMMAND_BUTTON_CLICKED

●actualizează în tabelul nom liniile care au fost modificate;

●adaugă liniile ce nu se regăsesc în tabelul nom

<bRenEdit>iFNOM::ren_Edit

wxEVT_COMMAND_BUTTON_CLICKED

●închide fereastra de editare

<bEdit>iFNOM::editare

wxEVT_COMMAND_BUTTON_CLICKED

●afişează panoul de editare

<bSel>iFNOM::selecteaza

wxEVT_COMMAND_BUTTON_CLICKED

●copiază datele liniei selectate într-o variabilă de tip (wxArrayString*);

●închide fereastra

<bRenNom>iFNOM::ren_Nom

wxEVT_COMMAND_BUTTON_CLICKED

●renunţă la selecţie (închide fereastra)

3.6. Fereastra pentru rapoarte / selecţie stoc iFSTSEL

Această fereastră este utilizată atât pentru rapoartele stoc, cât şi pentru rezervarea din stoc în vederea livrării sau pentru constituirea borderourilor de transfer. Acest lucru se realizează cu ajutorul unui panou (un obiect al clasei wxPanel), ce este ascuns sau vizibil în funcţie de rolul ferestrei.

Câmpurile selectate pentru afişare (în lista cu căsuţe de selecţie) se constituie în coloane ale grid-ului, iar câmpurile selectate pentru selecţie/filtrare se constituie în filtru pentru interogare. Afişarea în grid va cuprinde întodeauna cantităţile fizice qtyfizic şi cantităţile disponibile qtydisp. Astfel, dacă nu selectăm pentru afişare nimic, se vor afişa doar cantităţile totale

191

Page 193: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

(valabil pentru modul raportare). Dacă fereastra este apelată din cadrul borderoului de preparare sau cel de transfer, indiferent de selecţia de afişare se vor afişa şi câmpurile: id, dep şi ampl.

Figura VII-20: Fereastra "raport stoc"

Datele rezultate ce vor fi afişate în grid vor putea fi ordonate după un câmp selectat printr-un control de tip combobox (lista din combobox este identică cu lista câmpurilor din cadrul afişării).

Dacă fereastra este apelată din cadrul borderoului de preparare sau cel de transfer, va mai exista un grid destinaţie. În cazul apelului din cadrul BP, liniile sunt constituite pe baza structurii tabelului copil _bp, având în plus câmpurile idcode şi descr.

Primul grid (GD1) preia datele din tabelul temporar q_tmp_st, tabel creat de funcţia plpgSQL pentru interogare q_x. Al doilea grid (GD2) utilizează pe post de tabel intermediar tabelul temporar tmpselst. Ambele grid-uri doar afişează date (sunt de tip read-only).

Această fereastră asigură următoarele funcţii:☑ construcţie raport cu posibilitatea grupării informaţiei şi

a alegerii filtrelor;☑ rezervarea item-urilor din cadrul stocului în vederea reali-

zării borderoului de preparare;☑ preluarea item-urilor în borderourile de transfer (neimple-

mentat).

192

Page 194: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

Figura VII-21: Apel fereastră din iFEBP

Ierarhia obiectelor din cadrul ferestrei este redată în fig.VII-22. Fişierul header cu declaraţia clasei:#ifndef __fselst__ //fişier selst.h#define __fselst__#include <wx/wx.h>#include <wx/choicebk.h>#include "lx.h"class iFSELST : public wxDialog { wxArrayString listaN,listaT,val1,val2; lxGrid *cx_grid1, *cx_grid2; lxComboBox *cx_dep, *cx_ampl; wxArrayString aL,sL,valL,aListaInit;//lista cu câmpuri ptr. afişare şi selecţie wxString achBP; //numărul BP pentru care se face selecţia public:iFSELST(wxWindow* parent, wxString achBP1, wxWindowID id = wxID_ANY, const wxString& title = wxT("SELECŢIE STOC"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(800,650), long style = wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE);virtual ~iFSELST();

193

Page 195: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

Figura VII-22: Ierarhia obiectelor din cadrul ferestrei iFSELST

194

OBIECTELE GRAFICE DIN

FEREASTRA iFSELST

pSelBP

s1

s2

GD1

s3s4

s5

s17

Text t8

Text

t9

CBP

s35

s14

OKbQ

PQtyPrep

p9GD2

Text t12

Edit

eQtyPrep

OK Rezerva

s15

OK bDelLin

OKbBP

OK bCopiaza

Text t13

CB cbOrd

p1p2

p3p4

p5p6

p7p10

s6

OK bNom

s7

Text t1

Edit

eSupplier

OK bRetFurnizor

s8

s9 OK

bRetData

31.1

2.00

eData1

Text t2

31.1

2.00

eData2

s10

Text t3

Text t4

OK bRetDepAmpl

CB cbAmpl

CB cbDep

s11

Text t5

Edit ePO

OK bRetPO

s12

OK bRetStatus

Text t6

CB

cbStatus

s13

Text t7

Edit

eSerialNo

OK b

RetSerialNo

s16

Text t10

Edit eIDOK bRetID

iFSTSEL

x cblA

x cblS

CB wxChoice/wComboBox

wxBoxSizer(

wxHORIZONTAL)

wxBoxSizer(

wxVERTICAL)

wxFlexGridSizer

31.12.00

wxDatePickerCtrl

LEGENDĂ

:wxDialog/wxFrame

wxPanel

OK wxButton

wxChoicebook

Edit wxTextCtrl

Text wxStaticText

wxRadioBox

x wxCheckListBox

wxGrid

Page 196: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

protected: wxStaticText* t8; wxCheckListBox* cblA; wxStaticText* t9; wxCheckListBox* cblS; wxChoicebook* CBP; wxPanel* p1; wxButton* bNom; wxPanel* p2; wxStaticText* t1; wxTextCtrl* eSupplier; wxButton* bRetFurnizor; wxPanel* p3; wxDatePickerCtrl* eData1; wxStaticText* t2; wxDatePickerCtrl* eData2;wxButton* bRetData; wxPanel* p4; wxStaticText* t3; wxComboBox* cbDep; wxStaticText* t4; wxComboBox* cbAmpl; wxButton* bRetDepAmp; wxPanel* p5; wxStaticText* t5; wxTextCtrl* ePO; wxButton* bRetPO; wxPanel* p6; wxStaticText* t6; wxChoice* cbStatus; wxButton* bRetStatus; wxPanel* p7; wxStaticText* t7; wxTextCtrl* eSerialNo; wxButton* bRetSerialNo;

wxPanel* p10; wxStaticText* t10; wxTextCtrl* eID; wxButton* bRetID; wxStaticText* t13; wxChoice* cbOrd; wxButton* bCopiaza; wxButton* bQ; wxGrid* GD1; wxPanel* pSelBP; wxPanel* P_QtyPrep;

wxStaticText* t12; wxTextCtrl* eQtyPrep; wxButton* bRezerva; wxGrid* GD2; wxPanel* p9; wxButton* bDelLin; wxButton* bBP;virtual void selNom(wxCommandEvent& event);//Selecţie NOMENCLATOR virtual void retineFurnizor(wxCommandEvent& event);//selectează furnizorvirtual void retineData(wxCommandEvent& event);//selectează filtru data calendaristică de intrarevirtual void selDep(wxCommandEvent& event);//Schimbă lista cu amplasamentele în funcţie de depozitul selectatvirtual void retineDepAmp(wxCommandEvent& event);//selectează depozitul şi amplasamentul curent virtual void retinePO(wxCommandEvent& event);//selectează POvirtual void retineID(wxCommandEvent& event);//selectează ID virtual void retineSTATUS(wxCommandEvent& event);//selectează STATUSvirtual void retineSerialNo(wxCommandEvent& event);//selectează SerialNovirtual void qST(wxCommandEvent& event);//FUNCŢIA DE INTEROGARE A STOCULUIvirtual void rezervaQtySelST(wxCommandEvent& event);//Rezervă item-urivirtual void delLinSelST(wxCommandEvent& event);//Şterge linia selectatăvirtual void transferBP(wxCommandEvent& event);//Închide fereastra de sel.virtual void copiaza(wxCommandEvent& event);//Copiază din GRID în CLIPBOARDvirtual void afis_sel(); // AFIŞARE PANOU SELECŢIE --FILTRE};#endif //__fselst__

Răspunsul la evenimente este dat de următorul tabel:<Controlul>

funcţie ataşată Evenimentul Tratare eveniment

<bNom>iFSELST::selNom

wxEVT_COMMAND_BUTTON_CLICKED(apăsare buton)

●preia în lista de selecţie valorile câmpurilor selectate în fereastra iFNOM;

●apelează funcţia de afişare selecţie

<bRetFurnizor>iFSELST::retineFu

rnizor

wxEVT_COMMAND_BUTTON_CLICKED

●preia valoarea pentru câmpul supplier în lista de selecţie;

●apelează funcţia de afişare selecţie

<bRetData> wxEVT_COMMAND ●preia valoarile pentru intervalul dată de

195

Page 197: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

<Controlul>funcţie ataşată Evenimentul Tratare eveniment

iFSELST::retineData

_BUTTON_CLICKEDintrare în lista de selecţie;

●apelează funcţia de afişare selecţie

<cbDep>iFSELST::selDep

wxEVT_COMMAND_COMBOBOX_SELECTED

●actualizează lista de selecţie pentru controlul cbAmpl prin interogare asupra bazei de date cu filtrul dat de selecţia cbDep

<bRetDepAmp> iFSELST::retine

DepAmp

wxEVT_COMMAND_BUTTON_CLICKED

●preia valoarile pentru câmpurile dep şi ampl în lista de selecţie (acestea sunt separate în lista pentru constituirea filtrului – putem avea filtru numai pentru depozit);

●apelează funcţia de afişare selecţie

<bRetPO>iFSELST::retinePO

wxEVT_COMMAND_BUTTON_CLICKED

●preia valoarea pentru câmpul po în lista de selecţie;

●apelează funcţia de afişare selecţie

<bRetStatus> iFSELST::retine

STATUS

wxEVT_COMMAND_BUTTON_CLICKED

●preia valoarea pentru câmpul status în lista de selecţie;

●apelează funcţia de afişare selecţie

<bRetSerialNo>iFSELST::retineSe

rialNo

wxEVT_COMMAND_BUTTON_CLICKED

●preia valoarea pentru câmpul serialno în lista de selecţie;

●apelează funcţia de afişare selecţie

<bRetID>iFSELST::retineID

wxEVT_COMMAND_BUTTON_CLICKED

●preia valoarea pentru câmpul id în lista de selecţie;

●apelează funcţia de afişare selecţie

<bCopiaza>iFSELST::copiaza

wxEVT_COMMAND_BUTTON_CLICKED

●citeşte datele din grid şi le transmite în memoria CLIPBOARD

<bQ>iFSELST::qST

wxEVT_COMMAND_BUTTON_CLICKED

●construieşte comanda SQL pentru interogare pornind de la listele de afişare şi cele de selecţie;

●apelează funcţia plpgSQL q_st, ce implementează interogarea pentru constituirea raportului;

● în cazul în care este utilizată pentru rezervarea item-urilor, creează tabelul temporar de selecţie tmpselst pe baza datelor din tabelul copil _bp

<bRezerva> wxEVT_COMMAND_BUTTON_CLICKED

●preia din controlul de editare cantitatea

196

Page 198: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Dezvoltarea în C++ a modulelor de interfaţare grafică cu utilizatorul

<Controlul>funcţie ataşată Evenimentul Tratare eveniment

iFSELST::rezervaQtySelST

rezervată şi apelează funcţia plpgSQL add_bp_

● reactualizează tabelul tmpselst;● reactualizează afişarea în cele două grid-

uri

<bDelLin>iFSELST::delLinSe

lST

wxEVT_COMMAND_BUTTON_CLICKED

●pentru linia selectată, apelează funcţia plpgSQL del_bp

● reactualizează tabelul tmpselst;● reactualizează afişarea în cele două grid-

uri

<bBP> iFSELST::transfer

BP

wxEVT_COMMAND_BUTTON_CLICKED

● şterge datele din tabelul tmpselst;● închide fereastra

4. Dezvoltarea interfeţei SQL/plpgSQL – controale grafice

Pentru simplificarea dezvoltării aplicaţiei, au fost dezvoltate câteva clase care să ofere suportul interfaţării între specificul controlului şi popularea sau extragerea de date din acesta. Codurile sursă pentru fişierele de tip header sunt prezentate în acest subcapitol, iar codul sursă pentru fişierele cu extensia cpp sunt prezentate în anexă.

Pentru fiecare control grafic a fost definită câte o clasă de interfaţare, toate acestea având clasa de bază lxCtrl, clasă ce gestionează conexiunea cu baza de date.

Astfel au fost dezvoltate clasele:☑ lxCtrl - clasă de bază ce gestiunează conexiunea;☑ lxComboBox - clasă ce permite o legătură între un control de

tip combobox şi o bază de date;☑ lxDPC - clasă ce permite setarea şi preluarea datei calen-

daristice (legătura cu un control wxDatePickerCtrl);☑ lxEditN - clasă ce permite legătura dintre un control de tip

editare şi baza de date pentru date de tip numeric;☑ lxEditT - clasă ce permite legătura dintre un control de tip

editare şi baza de date pentru date de tip text;☑ lxGrid - clasă ce permite legătura dintre un control de tip

grid şi un control wxGrid(tabel).

197

Page 199: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

4.1. Clasa lxCtrl

Asigură conectarea şi deconectarea cu baza de date. Metodele din cadrul clasei sunt:

✗ Constructorul clasei lxCtrl(), nu realizează nimic;✗ Funcţia void lxCtrl::conectare(wxString dbname, wxString

user, wxString pw, wxString host, wxString port) construieşte şirul de conectare, apelează funcţia pentru conectare din biblioteca libpq şi testează realizarea conexiunii;

✗ Funcţia wxString lxCtrl::cda(wxString achQ) permite execuţia unei comenzi dată de şirul achQ şi întoarce rezultatul execuţiei comenzii transmis de către serverul PostgreSQL. Rezultatul întors poate fi o singură valoare (un câmp pe un rând) sau un mesaj transmis de către server către client;

✗ Funcţia wxString lxCtrl::lista(wxString achQ, wxArrayString& a) permite execuţia comenzii dată de şirul achQ şi întoarce rezultatul într-un vector cu obiecte wxString, rezultatul interogării trebuie să conţină un singur câmp. Această funcţie este utilă pentru controalele specializate pentru selecţia de tip listă.

Fişierul cu declaraţiile corespunzătoare clasei este://fişierul lx_ctrl.h#ifndef _lxCtrl_ //previne includerea multipla : dacă nu EXISTA _lxCtrl_#define _lxCtrl_ // defineste _lxCtrl_#include <libpq-fe.h>#include <wx/wx.h>class lxCtrl{public: static PGconn *conexiune0; lxCtrl(); static void conectare(wxString dbname, wxString user, wxString pw, wxString host, wxString port); static void deconectare(); static wxString cda(wxString achSQL); static wxString lista(wxString achQ, wxArrayString& a);/*comandă ce are ca rezultat un singur câmp, valorile rezultate vor fi transmise prin referinţă sub forma unei liste cu elemente de tip wxString */ virtual int refreshlx();};#endif //închide condiţia

Metodele sunt de tip static, acestea sunt apelate indiferent de instanţierile clasei lxCtrl.

198

Page 200: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Dezvoltarea interfeţei SQL/plpgSQL – controale grafice

4.2. Clasa lxComboBox

Această clasă permite o legătură între un control de tip combobox şi o bază de date. Este necesar ca atât conexiunea cu baza de date, cât şi obiectul de tip wxComboBox să existe.

Metodele din cadrul clasei sunt:✗ Constructorul clasei lxComboBox::lxComboBox(wxComboBox *cb1,

wxString achQ) preia adresa controlului şi şirul ce conţine comanda SQL, ce asigură, prin execuţia sa de către server-ul PostgreSQL, lista din cadrul controlului;

✗ Funcţia int lxComboBox::rdLista(wxString achQ) citeşte în control un nou şir rezultat în urma execuţiei comenzii SQL (înlocuieşte vechea listă de selecţie);

✗ Funcţia wxString lxComboBox::getSel() întoarce şirul selectat din cadrul controlului;

✗ Funcţia int lxComboBox::refreshlx() reface lista de selecţie din control conform comenzii SQL transmise prin constructor.

Fişierul cu declaraţiile corespunzătoare clasei este:#ifndef _lxComboBox_ //fişierul lx_combobox.h#define _lxComboBox_ #include <wx/wx.h>#include "lx_ctrl.h"//clasa asigură o legătură între un contrl ComboBox şi o bază de date// se presupune că ambele există înainte de instanţierea claseiclass lxComboBox:public lxCtrl{wxComboBox *cb; int tipdata; wxString achQRD; public: lxComboBox(wxComboBox *cb1, wxString achQ1);int rdLista(wxString achQ1);//reactualizeaza lista în urma actualizării bazei de dateint refreshlx();wxString getSel();};#endif

4.3. Clasa lxDPC

Realizează legătura cu baza de date pentru un control wxDatePickerCtrl. Este necesar ca atât conexiunea cu baza de date cât şi obiectul de tip wxDatePickerCtrl să existe.Metodele din cadrul clasei sunt:

✗ Constructorul clasei lxDPC::lxDPC(wxDatePickerCtrl *dpc1) preia adresa controlului;

✗ Funcţia int lxDPC::rdSQL(wxString rdachQ) citeşte din baza

199

Page 201: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

de date în control, funcţia preia comanda SQL pentru citire;✗ Funcţia int lxDPC::wrSQL(wxString wrachQ) scrie valoarea din

control în baza de date, preia comanda de scriere (valoarea din control este transmisă prin şirul format - wrachQ);

✗ Funcţia wxString lxDPC::getValFormatStr() returnează valoa-rea controlului în formatul 'yyyy-mm-dd' pentru a putea fi utilizată cu uşurinţă în comenzile SQL.

Fişierul cu declaraţiile corespunzătoare clasei este:#ifndef _lxDPC_ //fişierul lx_dpc.h#define _lxDPC_ #include <wx/wx.h>#include <wx/datectrl.h>#include "lx_ctrl.h"class lxDPC:public lxCtrl{ wxDatePickerCtrl *dpc;public: lxDPC(wxDatePickerCtrl *dpc1);int rdSQL(wxString rdachQ1);int wrSQL(wxString wrachQ1);wxString getValFormatStr();};#endif

4.4. Clasa lxEditN

Realizează legătura cu baza de date, pentru un control wxTextCtrl ce preia şi afişează valori de tip numeric. Este necesar ca atât conexiunea cu baza de date cât şi obiectul de tip wxTextCtrl să existe.

Metodele din cadrul clasei sunt:✗ Constructorul clasei lxEditN::lxEditN(wxTextCtrl *ed1) preia

adresa controlului;✗ Funcţia int lxEditN::rdSQL(wxString rdachQ) citeşte din baza

de date în control, funcţia preia comanda SQL pentru citire;✗ Funcţia int lxEditN::wrSQL(wxString wrachQ) scrie valoarea

din control în baza de date, preia comanda de scriere (valoarea din control este transmisă prin şirul format – wrachQ);

✗ Funcţia wxString lxEditN::getValFormatStr() returnează va-loarea controlului.Fişierul cu declaraţiile corespunzătoare clasei este:

#ifndef _lxEditN_ //fişierul lx_edit_n.h#define _lxEditN_ #include <wx/wx.h>#include "lx_ctrl.h"/*clasa asigură o legătură între un contrl wxTextControl şi o valoare dintr-o bază de date de tip numeric, se presupune că ambele există înainte de instanţierea clasei */

200

Page 202: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Dezvoltarea interfeţei SQL/plpgSQL – controale grafice

class lxEditN:public lxCtrl{wxTextCtrl *ed; public:lxEditN(wxTextCtrl *ed1);int rdSQL(wxString rdachQ1);int wrSQL(wxString wrachQ1);wxString getValFormatStr();};#endif

4.5. Clasa lxEditT

Realizează legătura cu baza de date pentru un control wxTextCtrl. Este necesar ca atât conexiunea cu baza de date, cât şi obiectul de tip wxTextCtrl să existe.

Metodele din cadrul clasei sunt:✗ Constructorul clasei lxEditT::lxEditT(wxTextCtrl *ed1) preia

adresa controlului;✗ Funcţia int lxEditT::rdSQL(wxString rdachQ) citeşte din baza

de date în control, funcţia preia comanda SQL pentru citire;✗ Funcţia int lxEditT::wrSQL(wxString wrachQ) scrie valoarea

din control în baza de date, preia comanda de scriere (valoarea din control este transmisă prin şirul format);

✗ Funcţia wxString lxEditT::getValFormatStr() returnează va-loarea controlului pentru a putea fi utilizată cu uşurinţă în comenzile SQL.Fişierul cu declaraţiile corespunzătoare clasei este:

#ifndef _lxEditT_ //fişierul lx_edit_t.h#define _lxEditT_ #include <wx/wx.h>#include "lx_ctrl.h"/*clasa asigură o legătură între un contrl wxTextControl şi o valoare dintr-o bază de date de tip text, se presupune că ambele există înainte de instanţierea clasei */class lxEditT: public lxCtrl{wxTextCtrl *ed; public: lxEditT(wxTextCtrl *ed1);int rdSQL(wxString rdachQ1);int wrSQL(wxString wrachQ1);wxString getValFormatStr(); };#endif

4.6. Clasa lxGrid

Realizează legătura cu baza de date pentru un control wxGrid (tip tabel). Este necesar ca atât conexiunea cu baza de date, cât şi obiectul de tip wxGrid să existe.

Metodele din cadrul clasei sunt:✗ Constructorul clasei lxGrid::lxGrid(wxGrid *gridX1, wxString

tabelBD1, wxArrayString dencol1) preia adresa controlului,

201

Page 203: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

numele tabelului PostgreSQL asupra căruia efectuează operaţii de citire şi scriere. Opţional, poate prelua şi lista cu denumirile coloanelor ce vor fi afişate în capul de tabel reprezentat prin wxGrid (altfel vor fi preluate denumirile câmpurilor – caz în care numărul de elemente din dencol1 va fi zero);

✗ Destructorul clasei lxGrid::~lxGrid() eliberează memoria în urma alocărilor dinamice efectuate (nu este necesară eliberarea memoriei pentru controalele grafice ataşate ferestrei deoarece în momentul eliberării memoriei pentru o fereastră wxFrame/wxDialog se vor dealoca toate obiectele grafice ataşate ferestrei);

✗ Funcţia void lxGrid::salvare() realizează copierea datelor din grid în tabelul PostgreSQL (de obicei temporar) atşat. Copierea se realizează pentru toate câmpurile şi pentru toate înregistrările. În momentul copierii se ţine cont de tipul de dată (de exemplu, pentru data calendaristică trebuie utilizată funcţia de conversie din PostgreSQL to_date);

✗ Funcţia void lxGrid::preluareVarColRow() – această funcţie preia datele dintr-un tabel PostgreSQL într-un control grid. Grid-ul va fi redimensionat conform numărului de coloane şi numărului de înregistrări din tabelul PostgreSQL ataşat. Dacă există o listă cu denumirile coloanelor aceasta va fi preluată altfel vor fi preluate denumirile câmpurilor din tabelul PostgreSQL. Liniile afişate vor avea culori alternante.Fişierul cu declaraţiile corespunzătoare clasei este:

#ifndef _lxGrid_ //fişierul lx_grid.h#define _lxGrid_ #include <wx/wx.h>#include <wx/grid.h>#include "lx_ctrl.h"//clasa asigură o legătura între un control wxGrid şi un tabel PostgreSQL, se presupune că ambele există înainte de instanţierea claseiclass lxGrid:public lxCtrl{protected: wxGrid *gridX; int *tipCol;// tipul fiecărei coloane (nr. OID din tabelul pg_catalog.pg_type) PGresult *rezultatRx; wxString tabelBD;//tabel temporar wxArrayString dencol; //denumiri coloane wxString sirRcampuri;//şirul cu denumirile câmpurilor, mai puţin tcu public: lxGrid(wxGrid *gridX1, wxString tabelBD1, wxArrayString dencol1); ~lxGrid(); void preluareVarColRow(); // din tabel BD în GRID

202

Page 204: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Dezvoltarea interfeţei SQL/plpgSQL – controale grafice

void salvare(); //din grid în tabel}; #endif

Aceste fişiere cu declaraţii sunt reunite în fişierul lx.h.#include "RES_LX/lx_ctrl.h" //fişier lx.h#include "RES_LX/lx_combobox.h"#include "RES_LX/lx_edit_n.h"#include "RES_LX/lx_edit_t.h"#include "RES_LX/lx_grid.h"#include "RES_LX/lx_dpc.h" //fişierele sunt puse într-un subdirector-RES_LX

5. Integrarea modulelor aplicaţiei LogX

Funcţiile plpgSQL pot fi testate plecând de la datele iniţiale de test şi apoi apelând funcţiile cu argumentele stabilite în funcţie de context. Dacă baza de date picdb nu există, se va crea manual. După deschiderea bazei de date picdb, se va rula din pgAdminIII blocul SQL din capitolul ANEXE. În urma execuţiei secvenţei SQL, se vor crea utilizatorul logx_sw, grupul de utilizatori LOGX şi schema logx cu funcţiile, secvenţele şi tabelele asociate.

Se contituie un proiect într-un mediu de dezvoltare (ex. CodeLite, Code Blocks etc.) cu opţiunea wxWidgets activată (setarea pentru compilare şi linkeditare pentru utilizarea bibliotecilor wxWidgets. În cadrul proiectului se vor adăuga opţiunile pentru încluderea bibliotecii libpq, specificate în capitolul VI.2.

În funcţia bool LogXApp::OnInit() este realizată conexiunea cu server-ul de baze de date a utilizatorului logx_sw. Dacă conexiunea reuşeşte să se realizeze, este instanţiată clasa iFACC ce permite gestiunea drepturilor de acces. După introducerea alias-ului pentru utilizator şi a codului de acces corespunzător este verificată existenţa acestora în tabelul de acces şi este închisă fereastra. În cazul în care nu există perechea alias-parolă în tabelul de acces (iFACC::accesX == false), se iese din funcţia LogXApp::OnInit() cu valoarea de adevăr false, ceea ce duce la închiderea aplicaţiei LogX. În cazul în care este găsită corespondenţa alias-parolă, este instanţiată clasa cu panelul cu butoane iFPB.

Figura VII-23: Intrarea în aplicaţie

Ferestrele de lucru sunt apelate din cadrul ferestrei iFPB. Constructorul clasei iFSELST este apelat cu un parametru

203

new iFACC(NULL) new iFPB(NULL) lxCtrl::conectare

Page 205: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

VII.Dezvoltarea unor module pentru logistica stocurilor

suplimentar faţă ce celelalte ferestre similare; prin acest parametru se transmite numărul borderoului curent pentru care se face selecţia sau “#” dacă este realizat un raport privind situaţia stocurilor.

Datele sunt preluate în controale prin intermediul claselor din ierarhia lxCtrl.

Figura VII-24: Instanţierea unor clase

În continuare este prezentat un tabel cu instanţierea clase-lor.

clasa clase instanţiate Fişier

LogXApp iFACC; iFPB main.cpp

iFPB iFEI; iFNOM; iFSELST; iFEBP main.cpp

iFEI lxCtrl; lxComboBox; lxEditT; lxDPC; lxGrid; iFNOM fei.cpp

iFNOM lxCtrl; lxGrid fnom.cpp

iFEBP lxCtrl; lxEditT; lxComboBox; lxDPC; lxGrid; iFSELST febp.cpp

iFSELST lxCtrl; lxEditT; lxComboBox; lxDPC; lxGrid; iFNOM selst.cpp

Aplicaţia LogX cuprinde:✗ schema logx din cadrul bazei de date picdb;✗ grupul de acces LOGX şi utilizatorul logx_sw;✗ fişierele sursă: main.h, main.cpp, fei.h, fei.cpp, fnom.h,

fnom.cpp, febp.h, febp.cpp, selst.h, selst.cpp, lx.h, RES_LX/lx_combobox.h, RES_LX/lx_combobox.cpp, RES_LX/lx_ctrl.h, RES_LX/lx_ctrl.cpp, RES_LX/lx_dpc.h, RES_LX/lx_dpc.cpp, RES_LX/lx_edit_n.h, RES_LX/lx_edit_n.cpp, RES_LX/lx_edit_t.h, RES_LX/lx_edit_t.cpp, RES_LX/lx_grid.h,

204

schema: logxtabele,secvenţe

schema: logxfuncţii plpgSQL

GRUPURI şiUTILIZATORI

SERVER POSTGRESQL

iFNOM

iFEI

iFEBP

iSELST

UTILIZATORClasaiFPB

Clasele de interfaţare LX

Page 206: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Integrarea modulelor aplicaţiei LogX

RES_LX/lx_grid.cpp.Server-ul de baze utilizat a fost PostgreSQL 9.2, iar

versiunea de CodeLite utilizată a fost 6.0 cu wxWidgets 3.01. Pentru simplificarea construcţiei interfeţei, se poate utiliza wxFormBuilder sau echivalent, însă acestea pot fi utilile doar pentru interfeţele simple. Notă: Dacă se utilizează platforma Windows, recomand ca numele directoarelor/subdirectoarelor în care se instalează ColdeLite şi mai ales wxWidgets să nu conţină semne de punctuaţie sau alte caractere de acest tip.

În capitolul ANEXE se regăsec fişierele cu extensia cpp din cadrul aplicaţiei şi codul SQL pentru construcţia structurii de pe server-ul PostgreSQL.

205

Page 207: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

ANEXE

1. Secvenţe din sintaxa SQL/postgreSQL simplificată

Sunt prezentate pe scurt câteva comenzi SQL frecvent utilizate. Opţiunile pentru aceste comenzi sunt mult mai numeroase, am prezentat doar câteva opţiuni, frecvent utilizate.

Parantezele drepte “[opţional]” cuprind opţiuni ale comenzii SQL (parantezele drepte nu vor fi scrise). Simbolul “|” este utilizat cu semnificaţia de SAU. Acoladele “{ }” semnifică repetiţie. Simbolurile “a[, …]“ semnifică o listă de cu elemente de tipul a separate prin virgulă.

☑ Comanda ALTER ROLE Modifică parametrii pentru un utilizator sau grup

Opţiune Descriere

SUPERUSER | NOSUPERUSER Cu drept de superuser sau nu

CREATEDB | NOCREATEDB Poate sau nu să creeze baze de date

CREATEROLE | NOCREATEROLE Poate sau nu să creeze alţi utilizatori sau grupuri

LOGIN | NOLOGIN Poate sau nu să se conecteze (este user sau grup)

PASSWORD 'password' Schimbare parolă

VALID UNTIL 'timestamp' Momentul până la care este valabilă parola

Sau modifică denumirea corespunzătoare unui utilizator sau grup

☑ Comanda ALTER TABLE

Modifică structura unui tabel

206

ALTER ROLE nume_rol [ [ WITH ] opţiuni [ ... ] ]ALTER ROLE nume_rol [ [ WITH ] opţiuni [ ... ] ]

ALTER ROLE nume_vechi RENAME TO nume_nouALTER ROLE nume_vechi RENAME TO nume_nou

ALTER TABLE [ IF EXISTS ] nume opţiune [, ... ]ALTER TABLE [ IF EXISTS ] nume opţiune [, ... ]

Page 208: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Secvenţe din sintaxa SQL/postgreSQL simplificată

Opţiune Descriere

ADD COLUMN nume_câmp tip_dată Adaugă un câmp/coloană

DROP COLUMN [IF EXISTS] nume_câmp Şterge un câmp

ALTER COLUMN nume TYPE tip_dată Schimbarea tipului de dată (un câmp)

ALTER nume_câmp SET DEFAULT valoare Setare valoare implicită câmp

ENABLE | DISABLE TRIGGER Activează/Dezactivează trigger

Redenumeşte un tabel

☑ Comanda COPYCopiază datele dintr-un tabel într-un fişier format CSV.

Copiază datele dintr-un fişier de tip CSV într-un tabel.

Opţiune Descriere

FORMAT nume_format Formatul poate fi: CSV, text sau binary

DELIMITER 'caracter_delimitator' Pentru CSV este virgula “,” (implicit)

NULL În lipsa datelor scrie NULL (nerecomandat)

HEADER Prima linie din fişier este antetul

ENCODING Implicit este cel al bazei de date

☑ Comanda CREATE TABLE

Creează un tabel, persistent sau temporar.

unde restricţie_coloană poate fi:

207

ALTER TABLE [ IF EXISTS ] nume_vechi RENAME TO nume_nouALTER TABLE [ IF EXISTS ] nume_vechi RENAME TO nume_nou

CREATE [ TEMPORARY ] TABLE nume_tabel ( { nume_coloană tip_dată [ restricţie_colană] | restricţie_tabel })

CREATE [ TEMPORARY ] TABLE nume_tabel ( { nume_coloană tip_dată [ restricţie_colană] | restricţie_tabel })

COPY {nume_tabel[( nume_coloană [, ...] )] | (rezultat_interogare )} TO {'nume_fişier' | STDOUT } [ [ WITH ] ( opţiune [, ...] ) ]

COPY {nume_tabel[( nume_coloană [, ...] )] | (rezultat_interogare )} TO {'nume_fişier' | STDOUT } [ [ WITH ] ( opţiune [, ...] ) ]

COPY table_name[( nume_coloană [, ...] )] FROM {'nume_fişier'| STDIN } [ [ WITH ] ( opţiune [, ...] ) ]

COPY table_name[( nume_coloană [, ...] )] FROM {'nume_fişier'| STDIN } [ [ WITH ] ( opţiune [, ...] ) ]

Page 209: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

iar restricţie_tabel poate fi:

☑ Comanda DELETEŞterge înregistrările dintr-un tabel. Atenţie: a nu fi confundată cu comanda DROP, care şterge întreaga structură a obiectului (în acest caz, tabelul)!

Dacă nu se specifică o condiţie sau dacă expresie este întotdeauna adevărată, se vor şterge toate înregistrările din cadrul tabelului

☑ Comanda INSERTComanda INSERT este utilizată pentru popularea bazei de date.

Se pot adăuga valorile implicite sau o listă de valori (eventual obţinute din evaluarea unor expresii) sau se poate adăuga rezultatul unei interogări (query).

☑ Comanda SELECTEste cea mai complexă comandă din SQL.

Unele instrucţiuni, precum [NATURAL], sunt redundante (NATURAL JOIN = JOIN)

208

[ CONSTRAINT nume_restricţie ] {CHECK(expresie) | UNIQUE | PRIMARY KEY ( nume_câmp [, ... ] ) | FOREIGN KEY ( nume_câmp [, ... ] ) REFERENCES nume_tabel_referinţă [ ( nume_coloană_referinţă [, ... ] ) ]}

[ CONSTRAINT nume_restricţie ] {CHECK(expresie) | UNIQUE | PRIMARY KEY ( nume_câmp [, ... ] ) | FOREIGN KEY ( nume_câmp [, ... ] ) REFERENCES nume_tabel_referinţă [ ( nume_coloană_referinţă [, ... ] ) ]}

[CONSTRAINT nume_restricţie] { NOT NULL | NULL | CHECK ( expresie ) | DEFAULT valoare_implicită | PRIMARY KEY}

[CONSTRAINT nume_restricţie] { NOT NULL | NULL | CHECK ( expresie ) | DEFAULT valoare_implicită | PRIMARY KEY}

DELETE FROM nume_tabel [USING nume_tabele_legătură] [WHERE expresie]DELETE FROM nume_tabel [USING nume_tabele_legătură] [WHERE expresie]

INSERT INTO nume_tabel [ ( nume_câmp [, ...] ) ] { DEFAULT VALUES | VALUES ( { valoare_expresie | DEFAULT } [, ...] ) [, ...] | interogare }

INSERT INTO nume_tabel [ ( nume_câmp [, ...] ) ] { DEFAULT VALUES | VALUES ( { valoare_expresie | DEFAULT } [, ...] ) [, ...] | interogare }

SELECT [ ALL | DISTINCT [ ON ( expresie_1 [, ...] ) ] ] * | expressie_1 [ [ AS ] denumire_nouă_câmp_rezultat ] [, ...] [ FROM tabel_sau_interogare

[ NATURAL ] join_type tabel_sau_interogare [ ON join_condiţie | USING ( join_column [, ...] ) ] ]

[ WHERE expresie_2 ] [ GROUP BY expresie_3 [, ...] ] [ HAVING expresie_4 [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ] [ ORDER BY expresie_5 [ ASC | DESC ] [, ...] ] [ LIMIT { count | ALL } ] [ OFFSET start [ ROW | ROWS ] ]

SELECT [ ALL | DISTINCT [ ON ( expresie_1 [, ...] ) ] ] * | expressie_1 [ [ AS ] denumire_nouă_câmp_rezultat ] [, ...] [ FROM tabel_sau_interogare

[ NATURAL ] join_type tabel_sau_interogare [ ON join_condiţie | USING ( join_column [, ...] ) ] ]

[ WHERE expresie_2 ] [ GROUP BY expresie_3 [, ...] ] [ HAVING expresie_4 [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ] [ ORDER BY expresie_5 [ ASC | DESC ] [, ...] ] [ LIMIT { count | ALL } ] [ OFFSET start [ ROW | ROWS ] ]

Page 210: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

1.Secvenţe din sintaxa SQL/postgreSQL simplificată

Opţiune Descriere

expresie_1 Câmpul sau o expresie cu sau fără câmpuri

tabel_sau_interogareSursa datelor poate să fie formată din tabele sau să rezulte din alte interogări

join_typePoate fi: INNER JOIN, LEFT OUTER JOIN, RIGHT JOIN, FULL OUTER JOIN

startOfsetul de la care începe returnarea înregistrărilor

count Numărul maxim de înregistrări ce vor fi întoarse

select O nouă interogare executată separat

☑ Comanda UPDATEEste comanda prin care sunt actualizate informaţiile existente în tabele.

Opţiune Descriere

nume_câmp Numele câmpurilor care se actualizează

expresie_1 Condiţia ce trebuie îndeplinită pentru actualizarea înregistrării

nume_tabele Dacă pentru actualizare sunt utilizate şi informaţii din alte tabele

expresie_2 Condiţie actualizare + Legătura între tabele

Atenţie: comanda UPDATE nume_tabel SET nume_câmp = NULL;diferă de comanda: UPDATE nume_tabel SET nume_câmp = '';deoarece a doua comandă (în care sunt scrise două caractere apostrof alăturate) presupune că acel câmp a fost „setat”, dar nu au existat valori. Practic, este aceeaşi diferenţă ca între noţiunile EMPTY şi NULL din cadrul claselor cu date de tip Variant. În al doilea caz, putem avea un câmp cheie primară care să nu conţină valori ceea ce încalcă regulile SQL.

209

UPDATE nume_tabel SET { nume_câmp = { expresie_1 | DEFAULT } | ( nume_câmp [, ...] ) = ( { expresie_1 | DEFAULT } [, ...] ) } [, ...] [ FROM nume_tabele ] [ WHERE expresie_2 ]

UPDATE nume_tabel SET { nume_câmp = { expresie_1 | DEFAULT } | ( nume_câmp [, ...] ) = ( { expresie_1 | DEFAULT } [, ...] ) } [, ...] [ FROM nume_tabele ] [ WHERE expresie_2 ]

Page 211: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

2. Principalele tipuri de variabile în limbajul C

Tip variabilă

Reprezentare *)

Valori posibile

Descriere

char 8 biţi -27 +→ 27-1caracter utilizat şi pentru codurile ASCII (0-127)

unsigned char 8 biţi 0 +→ 216-1

caracter şi utilizat pentru codurile ASCII (0-255)

int 8/16/32/64 -231 +→ 231-1întreg cu semn (dependent de sistem 8/16/32/64 biţi)

unsigned int 8/16/32/64 0 +→ 232-1

întreg fără semn (dependent de sistem 8/16/32/64 biţi)

short 16 biţi -215 +→ 215-1 întreg scurt cu semn

unsigned short 16 biţi 0 +→ 216-1 întreg scurt fără semn

long 32 biţi -215 +→ 215-1 întreg lung cu semn

long long 64 biţi -231 +→ 231-1 Ptr. compilatoare de tip g++

int64 64 biţi -231 +→ 231-1 Ptr. Visual C++

unsigned long 32 biţi 0 +→ 216-1 întreg lung fără semn

float 32 biţicca. 10−38 → 1038, 6 cifre semnificative

Număr real reprezentat pe 32 de biţi

double 64 biţi

cca. 10−308 → 10308, 15 cifre semnificative

Număr real reprezentat pe 64 de biţi (cel mai des utilizat)

long double 80 biţi

Număr real reprezentat pe 80 de biţi

bool 8 true / false boolean

void 8/16/32/64 Nimic / vid

*) Reprezentare în memorie (număr de biţi)

210

Page 212: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

3.Operatori C/C++

3. Operatori C/C++

☑ A.Operatori unariSIMBOLUL FORMA Operaţia realizată Exemplu

- -a negarea lui a -3+ +a valoarea lui a 3

+ +

a++ Postincrementare:preia valoare, apoi creşte cu 1

a=3++;a are val. 3

++a Preincrementare: mai întâi creşte cu 1, apoi preia valoarea

a=++3;a are val. 4

- -

a-- Postdecrementare:preia valoarea, apoi scade cu 1

a=3--;a are val. 3

--a Predecrementare: mai întâi scade cu 1, apoi preia valoarea

a=--3;a are val. 2

☑ B.Operatori binari aritmetici – aditivi şi multiplicativiSIMBOLUL FORMA Operaţia realizată Exemplu

+ a + b a adunat cu b 3.7+5.3- a - b b scăzut din a 3.1-5.0* a * b a înmuţit cu b 1.2*4.1/ a / b a împărţit la b 1.2/4.1

% a % b a modulo b (restul împărţirii) 5%4

☑ C.Operatori de atribuire aritmeticiSIMBOLUL FORMA Operaţia realizată

= a = bAsignare/atribuire: a preia valoarea lui b

+= a += b a=a(fostul conţinut)+b-= a -= b a=a-b/= a /= b a=a/b%= a %= b a=a%b

☑ F.Operatori relaţionali (0 este false, diferit de 0 este adevărat, ex.:-0.0000007 are valoare de adevăr TRUE)

SIMBOLUL FORMA Operaţia realizată> a > b dacă a>b, atunci true, altfel false

>= a >= b dacă a>=b atunci true, altfel false< a < b dacă a<b atunci true, altfel false

<= a <= b dacă a<=b atunci true, altfel false== a == b dacă a identic cu b, atunci true, altfel false!= a != b dacă a diferă de b, atunci true, altfel false

211

Page 213: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

☑ G.Operatorii logici SIMBOLUL FORMA Operaţia

&& a && b ŞI / AND|| a || b SAU / OR! ! a NEGAT / NOT

(T – true, F – false)x y x&&y x||y !xF F F F TF T F T TT F F T FT T T T

☑ H.Operatorul castSIMBOLUL FORMA Operaţia realizată

(tip) (tip)a a este convertit la tipul tip, operaţie de tip cast

Precedenţa operatorilor: 1) ( … ), [ … ], , ::, .(referire membru);2) operatori unari;3) operatori multiplicativi;4) acces la membri;5) operator aditivi;6) operatori de deplasare;7) operatori relaţionali;8) opertori logici la nivel de bit;9) operatori logici;10)operatorul condiţional;11)operatori de asignare;12)operatorul virgulă;

Citirea expresiilor se face de la dreapta spre stânga.

212

Page 214: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Codul sursă SQL pentru aplicaţia LogX

4. Codul sursă SQL pentru aplicaţia LogX

-- dacă nu există baza de date : CREATE DATABASE picdb;DROP schema IF EXISTS logx CASCADE; -- CASCADE STERGE ŞI LEGATURILE CU CELELALTE OBIECTEcreate schema logx;

--##### CREARE TABELE ###################-- creare tabel NOMDROP TABLE IF EXISTS logx.nom;CREATE TABLE logx.nom(idcode varchar(20) PRIMARY KEY, refteh varchar(30),refcom varchar(20), descr varchar(100), utiliz varchar(30) DEFAULT CURRENT_USER, data date DEFAULT CURRENT_DATE, ora time DEFAULT CURRENT_TIME);-- creare tabel LOCDROP TABLE IF EXISTS logx.loc;CREATE TABLE logx.loc(dep char(3), ampl varchar(10), CONSTRAINT loc_pk PRIMARY KEY(dep,ampl));-- creare tabel BR DROP TABLE IF EXISTS logx.br;CREATE TABLE logx.br(nrbr int,datain date DEFAULT CURRENT_DATE, idcode varchar(20), po varchar(10), status varchar(15), supplier varchar(50), serialno varchar(50), depinit char(3), amplinit varchar(10), qty int, val numeric, idx serial PRIMARY KEY);ALTER TABLE logx.br ADD CONSTRAINT br_f1 FOREIGN KEY (idcode) REFERENCES logx.nom (idcode); ALTER TABLE logx.br ADD CONSTRAINT br_f2 FOREIGN KEY (depinit,amplinit) REFERENCES logx.loc (dep,ampl); -- creare tabel INXCREATE TABLE logx.inx(id varchar(11) PRIMARY KEY, nrbr int, datain date DEFAULT CURRENT_DATE, idcode varchar(20), po varchar(10), status varchar(15), supplier varchar(50), serialno varchar(50), depinit char(3), amplinit varchar(10), qty int, val numeric);ALTER TABLE logx.inx ADD CONSTRAINT in_f1 FOREIGN KEY (idcode) REFERENCES logx.nom (idcode); ALTER TABLE logx.inx ADD CONSTRAINT in_f2 FOREIGN KEY (depinit,amplinit) REFERENCES logx.loc (dep,ampl); -- creare tabel STXCREATE TABLE logx.stx(dep char(3),ampl varchar(10), id varchar(11), qtyfiz int, qtydisp int, CONSTRAINT st_pk PRIMARY KEY(dep,ampl,id));ALTER TABLE logx.stx ADD CONSTRAINT st_f1 FOREIGN KEY (id) REFERENCES logx.inx (id); ALTER TABLE logx.stx ADD CONSTRAINT st_f2 FOREIGN KEY (dep,ampl) REFERENCES logx.loc (dep,ampl); -- creare tabele BT_ şi _BTDROP TABLE IF EXISTS logx._bt; DROP TABLE IF EXISTS logx.bt_;CREATE TABLE logx.bt_(nrbt int PRIMARY KEY, databt date, dep_dest char(3), ampl_dest varchar(10), CONSTRAINT f2_bt_ FOREIGN KEY(dep_dest,

213

Page 215: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

ampl_dest) REFERENCES logx.loc(dep,ampl));CREATE TABLE logx._bt(nrbt int, id varchar(11), qtytr int DEFAULT 1, dep_srs varchar(3), ampl_srs varchar(10), CONSTRAINT k__bt PRIMARY KEY(nrbt,id,dep_srs,ampl_srs), CONSTRAINT f1__bt FOREIGN KEY(id) REFERENCES logx.inx(id) , CONSTRAINT f2__bt FOREIGN KEY(dep_srs,ampl_srs) REFERENCES logx.loc(dep,ampl), CONSTRAINT f0__bt FOREIGN KEY(nrbt) REFERENCES logx.bt_(nrbt));-- creare tabel TRXCREATE TABLE logx.trx(nrbt int,datatr date,nrlin serial,dep_srs char(3),ampl_srs varchar(10),dep_dest char(3),ampl_dest varchar(10), id varchar(11), qtytr int, CONSTRAINT k_tr PRIMARY KEY(nrbt,nrlin));ALTER TABLE logx.trx ADD CONSTRAINT tr_f1 FOREIGN KEY (id) REFERENCES logx.inx (id); ALTER TABLE logx.trx ADD CONSTRAINT tr_f21 FOREIGN KEY (dep_srs,ampl_srs) REFERENCES logx.loc (dep,ampl); ALTER TABLE logx.trx ADD CONSTRAINT tr_f22 FOREIGN KEY (dep_dest,ampl_dest) REFERENCES logx.loc (dep,ampl); -- creare tabele BP_ şi _BPCREATE TABLE logx.bp_(nrbp int PRIMARY KEY,databp date,destin varchar(30));CREATE TABLE logx._bp(nrbp int,id varchar(11),qtyrez int DEFAULT 0,qtyconf int DEFAULT 0,dep varchar(3), ampl varchar(10), CONSTRAINT k__bp PRIMARY KEY(nrbp,id,dep,ampl), CONSTRAINT f1__bp FOREIGN KEY(id) REFERENCES logx.inx(id) , CONSTRAINT f2__bp FOREIGN KEY(dep,ampl) REFERENCES logx.loc(dep,ampl), CONSTRAINT f0__bp FOREIGN KEY(nrbp) REFERENCES logx.bp_(nrbp));-- creare tabel ieşiri (INX)CREATE TABLE logx.outx(nrbl int,destin varchar(30),id varchar(11),qtyliv int,dep varchar(3), ampl varchar(10),dataout date, CONSTRAINT k_out PRIMARY KEY(nrbl,id,dep,ampl), CONSTRAINT f1__out FOREIGN KEY(id) REFERENCES logx.inx(id) , CONSTRAINT f2__out FOREIGN KEY(dep,ampl) REFERENCES logx.loc(dep,ampl));-- creare tabel acces (ACCES)CREATE TABLE logx.acces(alias varchar(30) PRIMARY KEY, pw varchar(50), nume_utilizator varchar(100), date_contact varchar(200), dep varchar(100)[]);--############## CREARE CONTOARE ##############-- creare secvenţa parte numerica IDDROP SEQUENCE IF EXISTS logx.id_seq; CREATE SEQUENCE logx.id_seq INCREMENT 1 MINVALUE 1 START 1;--verificare index: select nextval('logx.id_seq');-- creare secvenţa NUMĂR BRDROP SEQUENCE IF EXISTS logx.br_seq; CREATE SEQUENCE logx.br_seq INCREMENT 1 MINVALUE 1 START 10;--verificare index: select nextval('logx.br_seq');-- creare secvenţa NUMĂR BPDROP SEQUENCE IF EXISTS logx.bp_seq; CREATE SEQUENCE logx.bp_seq INCREMENT 1 MINVALUE 1 START 10;--verificare index: select nextval('logx.bp_seq');

214

Page 216: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Codul sursă SQL pentru aplicaţia LogX

--############# FUNCŢII "SERVER SIDE" ###################--creare funcţie de adăugare în nomenclatorCREATE OR REPLACE FUNCTION logx.nom_add(_idcode_ text,_refteh_ text,_refcom_ text, _descr_ text)RETURNS text AS$$DECLAREf boolean;ach text;BEGIN--testare existenţă idcode în nomSELECT EXISTS(SELECT * FROM logx.nom WHERE idcode=_idcode_) INTO f;IF f THENSELECT 'Există deja în nom.'||_idcode_||'-- refteh:'||refteh||' recom:'||refcom||' Descriere:'||descr ||' User:'||utiliz||'-Data:'||data||'-Ora:'||ora FROM logx.nom WHERE idcode=_idcode_ INTO ach;return ach;END IF;INSERT INTO logx.nom(idcode, refteh, refcom, descr) VALUES (_idcode_, _refteh_, _refcom_, _descr_);RETURN 'OK'; END$$LANGUAGE 'plpgsql';

---## BR NOU ##-------------create or replace function logx.br_nou(_datain_ date DEFAULT CURRENT_DATE)returns void as$$begininsert into logx.br(nrbr,datain) VALUES ((select nextval('logx.br_seq')),_datain_);end$$language 'plpgsql';

-----------## CONSTITUIRE ID NOU ##----------CREATE OR REPLACE FUNCTION logx.id_nou(_dep_ text)RETURNS text AS$$DECLAREi int;BEGINSELECT nextval('logx.id_seq') INTO i;return _dep_||i::text;END;$$LANGUAGE 'plpgsql';

215

Page 217: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

----------------## VALIDARE BR ##-----------CREATE OR REPLACE FUNCTION logx.valid_br(_nrbr_ int)RETURNS text AS$$DECLAREf boolean;BEGIN--verificare introducere itemcodeSELECT EXISTS(SELECT * FROM logx.br WHERE idcode IS NULL) INTO f;IF f THEN return 'Introduceti itemcode!'; END IF;--verificare introducere cantităţiSELECT EXISTS(SELECT * FROM logx.br WHERE qty<1) INTO f;IF f THEN return 'Introduceti cantitatea!'; END IF;--verificare introducere datainSELECT EXISTS(SELECT * FROM logx.br WHERE datain IS NULL) INTO f;IF f THEN return 'Introduceti DATA!'; END IF;--NOTA: funcţia se execută intr-o singura tranzitie--adăugare în logx.inxINSERT INTO logx.inx( id, nrbr, datain, idcode, po, status, supplier, serialno, depinit, amplinit, qty, val)SELECT logx.id_nou(depinit), nrbr, datain, idcode, po, status, supplier, serialno, depinit, amplinit, qty, val FROM logx.br WHERE nrbr=_nrbr_; --adaugă în stocINSERT INTO logx.stx(dep, ampl, id, qtyfiz, qtydisp) SELECT depinit,amplinit,id,qty,qty FROM logx.inx WHERE inx.nrbr=_nrbr_; --şterge din BR DELETE FROM logx.br USING logx.inx WHERE inx.nrbr=br.nrbr; RETURN 'OK';END;$$LANGUAGE 'plpgsql';

-----------## BP NOU ##----------create or replace function logx.bp_nou(_destin_ text,_databp_ date DEFAULT CURRENT_DATE) returns void as$$begininsert into logx.bp_(nrbp,databp,destin) VALUES ((select nextval('logx.bp_seq')), _databp_,_destin_);end$$language 'plpgsql';

---------------## ADAUGARE LINIE _BP ##-------CREATE OR REPLACE FUNCTION logx.add_bp_id(_nrbp_ integer,_id_ text,_dep_ text,_ampl_ text,_qtyrez_ int) RETURNS text AS$BODY$DECLARE

216

Page 218: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Codul sursă SQL pentru aplicaţia LogX

f boolean;begin--verificare existenţă linie deja adăugatăselect exists (select * from logx._bp where _bp.nrbp=_nrbp_ AND _bp.id=_id_ AND _bp.dep=_dep_ AND _bp.ampl=_ampl_) INTO f;if f then return 'Exisă deja un item de acest tip introdus în BP-ul curent!'; end if;INSERT INTO logx._bp(nrbp,id,dep,ampl,qtyrez) VALUES(_nrbp_,_id_,_dep_,_ampl_,_qtyrez_);UPDATE logx.stx set qtydisp=qtydisp-_bp.qtyrez FROM logx._bp WHERE _bp.id=stx.id AND _bp.dep=stx.dep AND _bp.ampl=stx.ampl AND _bp.nrbp=_nrbp_ AND _bp.id=_id_ AND _bp.dep=_dep_ AND _bp.ampl=_ampl_;return 'OK';end$BODY$ LANGUAGE plpgsql;

-------------## ŞTERGERE LINIE _BP ---------------CREATE OR REPLACE FUNCTION logx.del_bp_id(_nrbp_ integer, _id_ text, _dep_ text, _ampl_ text) RETURNS text AS$BODY$DECLAREf boolean;beginUPDATE logx.stx set qtydisp=qtydisp+_bp.qtyrez FROM logx._bp WHERE _bp.id=stx.id AND _bp.dep=stx.dep AND _bp.ampl=stx.ampl AND _bp.nrbp=_nrbp_ AND _bp.id=_id_ AND _bp.dep=_dep_ AND _bp.ampl=_ampl_;DELETE FROM logx._bp WHERE _bp.nrbp=_nrbp_ AND _bp.id=_id_ AND _bp.dep=_dep_ AND _bp.ampl=_ampl_;DELETE FROM tmpselst WHERE tmpselst.nrbp=_nrbp_ AND tmpselst.id=_id_ AND tmpselst.dep=_dep_ AND tmpselst.ampl=_ampl_;return 'OK';end$BODY$ LANGUAGE plpgsql;

-----------## VALIDARE BP ##-------create or replace function logx.valid_bp(_nrbp_ int)returns text as$$DECLAREf boolean;BEGINselect EXISTS(select * from logx._bp where _bp.nrbp=_nrbp_ and _bp.qtyconf>_bp.qtyrez) INTO f;IF f THEN return 'Există cantitati confirmate mai mari decat cantitatile rezervate'; END IF;-- adaugă în iesiri (tabelul outx ce contine borderourile de livrare)INSERT INTO logx.outx(nrbl, destin, id, qtyliv, dep, ampl,dataout) SELECT _bp.nrbp,bp_.destin,_bp.id,_bp.qtyrez,_bp.dep,_bp.ampl, bp_.databp FROM logx.bp_,logx._bp WHERE bp_.nrbp=_bp.nrbp AND _bp.nrbp=_nrbp_;

217

Page 219: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

--actualizare stoc -- identificarea se face pentru intreaga cheie primara din tabelul logx.stxUPDATE logx.stx SET qtyfiz=stx.qtyfiz-_bp.qtyconf, qtydisp=stx.qtydisp+_bp.qtyrez-_bp.qtyconf FROM logx._bp WHERE stx.dep=_bp.dep AND stx.ampl=_bp.ampl AND stx.id=_bp.id AND _bp.nrbp=_nrbp_;--sterge linii ramase cu qtyfiz=0 din stocDELETE FROM logx.stx WHERE qtyfiz<1;--sterge din BPDELETE FROM logx._bp WHERE _bp.nrbp=_nrbp_;DELETE FROM logx.bp_ WHERE bp_.nrbp=_nrbp_;RETURN 'OK';END$$language 'plpgsql';

----## VALIDARE BT ##-------------CREATE OR replace function logx.bt_valid(_nrbt_ int)RETURNS text AS$$DECLAREf boolean;BEGIN--verifică dacă toate cantităţile ce urmează a fi transferate sunt disponibileSELECT EXISTS(SELECT * FROM logx.stx,logx._bt

WHERE stx.dep=_bt.dep_srs AND stx.ampl=_bt.ampl_srs AND stx.id=_bt.id AND stx.qtydisp<qtytr)INTO f;IF f THEN RETURN 'Există cantităţi ce nu sunt disponibile ptr. tranfer!'; END IF;--adaugă în tabelul cu transferurile efectuateINSERT INTO logx.trx(nrbt, datatr, dep_srs, ampl_srs, dep_dest, ampl_dest, id, qtytr) SELECT bt_.nrbt, bt_.databt, _bt.dep_srs, _bt.ampl_srs, bt_.dep_dest, bt_.ampl_dest, _bt.id, _bt.qtytr FROM logx.bt_,logx._bt WHERE _bt.nrbt=bt_.nrbt AND _bt.nrbt=_nrbt_; --dacă există înregistrări le actualizează cu noile cantităţiUPDATE logx.stx SET qtyfiz=qtyfiz+_bt.qtytr, qtydisp=qtydisp+_bt.qtytr FROM logx._bt,logx.bt_ WHERE bt_.dep_dest=stx.dep AND bt_.ampl_dest=stx.ampl AND _bt.id=stx.id AND _bt.nrbt=bt_.nrbt AND _bt.nrbt=_nrbt_;--dacă nu există înregistrarile noi (dep,loc,id) le adaugă DOAR pe cele care NU se regăsesc în stoc(dep,ampl,id)INSERT INTO logx.stx(dep, ampl, id, qtyfiz, qtydisp) SELECT par.dep,par.ampl,par.id, _bt.qtytr, _bt.qtytr FROM (SELECT bt_.dep_dest as dep, bt_.ampl_dest as ampl, _bt.id FROM logx._bt,logx.bt_ WHERE _bt.nrbt=bt_.nrbt AND _bt.nrbt=_nrbt_ EXCEPT SELECT stx.dep,stx.ampl,stx.id FROM logx.stx,logx.bt_ WHERE bt_.dep_dest=stx.dep AND bt_.ampl_dest=stx.ampl -- se poate şi fără ultima condiţie dar poate creşte timpul de

218

Page 220: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Codul sursă SQL pentru aplicaţia LogX

interogare )par,logx._bt,logx.bt_ WHERE _bt.id=par.id AND bt_.dep_dest=par.dep AND bt_.ampl_dest=par.ampl AND _bt.nrbt=bt_.nrbt AND _bt.nrbt=_nrbt_;--ATENŢIE: se va realiza mai intâi UPDATE şi apoi INSERT altfel cantităţile se pot dubla

-- SE realizează scăderea din stoc (pentru SURSA)UPDATE logx.stx SET qtyfiz=qtyfiz-_bt.qtytr, qtydisp=qtydisp-_bt.qtytr FROM logx._bt WHERE _bt.dep_srs=stx.dep AND _bt.ampl_srs=stx.ampl AND _bt.id=stx.id AND _bt.nrbt=_nrbt_;

-- dacă în urma scăderii qtyfiz =0 aceste linii se vor ştergeDELETE FROM logx.stx WHERE qtyfiz=0;--şterge liniile din tabelele naster-slave (bt_ şi _bt) corespunzatoare _nrbt_DELETE FROM logx._bt WHERE nrbt=_nrbt_;DELETE FROM logx.bt_ WHERE nrbt=_nrbt_;RETURN 'OK'; END$$ language plpgsql;

-------------## INTEROGARE GENERALĂ ##------------------- Function: logx.q_x(text, smallint, text[], text[], boolean[], boolean[], text[], text[], text)CREATE OR REPLACE FUNCTION logx.q_x(_tipq_ text, _nr_ smallint, _nume_ text[], _tip_ text[], _a_ boolean[], _s_ boolean[], _val1_ text[], _val2_ text[], _ord_ text) RETURNS text AS$BODY$DECLAREvald1_ date[];vald2_ date[];valn1_ numeric[];valn2_ numeric[];valAC_ text[];valb_ boolean[]; exeQ text; -- conţine şirul final pe baza căruia se realizează interogarea (comanda SQL finala)codR text; -- răspunsul funcţiei : OK - ieşire cu execuţie până la capat a interogariiachA text; -- şirul format pentru alcătuirea exeQ ce conţine partea de afişare a coloanelor/câmpurilor din cda SQLachS text; -- şirul format pentru alcătuirea exeQ ce conţine partea cu contitiile de selecţie din cda SQLachG text; -- şirul format pentru alcătuirea exeQ ce conţine partea cu GRUPUL din cadrul czii SQLachO text; -- şirul format pentru alcătuirea exeQ ce conţine partea cu ORDER BY din cadrul czii SQLachLegTab text;--inner joinachFROM text;

219

Page 221: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

achTmpTable text;--nume tabel rezultati int; f boolean; r int; ach text;BEGIN-- REZULTATUL interogarii va fi pus în tabelul TEMPORAR dat de achTmpTable achA:='';achS:='';achG:='#';achO:='';codR:='OK';f:=false;-- testare existenţă date pentru filtru selecţie FOR i IN 1.._nr_ LOOP IF _s_[i] AND (_val1_[i] IS NULL OR _val1_[i]='NULL') THEN codR='Selectie fara valoare pentru '||_nume_[i]||'!'; RETURN codR; END IF; IF _s_[i] AND (_tip_[i]='N2' OR _tip_[i]='D2') AND (_val2_[i] IS NULL OR _val2_[i]='NULL') THEN codR='Selectie fara valoare pentru '||_nume_[i]||'!'; RETURN codR; END IF; IF _a_[i] AND _nume_[i]=_ord_ THEN f:=true; END IF; IF _ord_='---' THEN f:=true; END IF; END LOOP; IF NOT f THEN codR:='Câmpul dupa care se realizeaza ordonarea trebuie să se regaseasca în optiunile de afisare pentru coloane !'; RETURN codR; END IF;--conversie date FOR i IN 1.._nr_ LOOP IF _val1_[i]='NULL' THEN CONTINUE; END IF; IF _tip_[i]='D1' THEN vald1_[i]:=_val1_[i];END IF; IF _tip_[i]='D2' THEN vald1_[i]:=_val1_[i];vald2_[i]:=_val2_[i];END IF; IF _tip_[i]='N1' THEN valn1_[i]:=_val1_[i];END IF; IF _tip_[i]='N2' THEN valn1_[i]:=_val1_[i];valn2_[i]:=_val2_[i];END IF; IF _tip_[i]='B' THEN valb_[i]:=_val1_[i];END IF; IF _tip_[i]='A' OR _tip_[i]='C' THEN valAC_[i]:=_val1_[i];END IF; END LOOP;-- constructie cda SQL FOR i IN 1.._nr_ LOOP IF _a_[i] THEN

achA := achA ||','|| _nume_[i]; --intai va fi sum(qty)if achG='#' then achG:=''; ELSE achG := achG ||','; end if;achG := achG || _nume_[i];

END IF; IF _s_[i] AND _tip_[i]='A' THEN achS:=achS||' AND '||_nume_[i]||' ILIKE ''%'||valAC_[i]||'%'''; END IF; IF _s_[i] AND _tip_[i]='C' THEN achS:=achS||' AND '||_nume_[i]||' = '||quote_literal(valAC_[i]); END IF; IF _s_[i] AND _tip_[i]='B' THEN achS:=achS||' AND '||_nume_[i]||' IS '||_valb_[i]; END IF; IF _s_[i] AND _tip_[i]='N1' THEN achS:=achS||' AND '||_nume_[i]||' = '||valn1_[i]; END IF; IF _s_[i] AND _tip_[i]='N2' THEN achS:=achS||' AND '||_nume_[i]||' >= '||valn1_[i]||' AND '||_nume_[i]||' <= '||valn2_[i]; END IF; IF _s_[i] AND _tip_[i]='D1' THEN achS:=achS||' AND '||_nume_[i]||' =

220

Page 222: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Codul sursă SQL pentru aplicaţia LogX

to_date('||quote_literal(vald1_[i])||','||quote_literal('dd.mm.yyyy')||')';END IF; IF _s_[i] AND _tip_[i]='D2' THEN achS:=achS||' AND '||_nume_[i]||' >= to_date('||quote_literal(vald1_[i])||','||quote_literal('dd.mm.yyyy')||') AND '||_nume_[i]||' <= to_date('||quote_literal(vald2_[i])||','||quote_literal('dd.mm.yyyy')||')';END IF; END LOOP; --creare tabele sursă şi tabele de legătură-- utilizatorii pot vedea doar anumite magazii --- DOAR MAGAZIILE/DEPOZITELE cu drepturi de acces valide vor fi luate în rezultatul interogarii (tmpacc)! DROP TABLE IF EXISTS tmpacc; CREATE TEMP TABLE tmpacc AS SELECT dep[s] FROM (select acces.*, generate_subscripts(dep,1) as s from logx.acces)par; IF _tipQ_ ='IN' THEN achTmpTable:='q_tmp_in'; achFROM:=' FROM logx.inx,logx.nom,tmpacc '; achLegTab:=' nom.idcode=inx.idcode AND depinit=tmpacc.dep'; END IF; IF _tipQ_ ='ST' OR _tipQ_ ='STL' THEN achTmpTable:='q_tmp_st'; achFROM:=' FROM logx.inx,logx.nom,logx.stx,tmpacc '; achLegTab:=' nom.idcode=inx.idcode AND inx.id=stx.id AND stx.dep=tmpacc.dep'; END IF; IF _tipQ_ ='OUT' THEN achTmpTable:='q_tmp_out';achFROM:=' FROM logx.inx,logx.nom,logx.outx,tmpacc '; achLegTab:=' nom.idcode=inx.idcode AND inx.id=outx.id AND outx.dep=tmpacc.dep'; END IF; IF _tipQ_ ='TR' THEN achTmpTable:='q_tmp_tr';achFROM:=' FROM logx.inx,logx.nom,logx.trx,tmpacc '; achLegTab:=' nom.idcode=inx.idcode AND inx.id=tr.id AND trx.dep_srs=tmpacc.dep AND trx.dep_dest=tmpacc.dep'; END IF; IF achG !='#' THEN achG:=' GROUP BY '||achG; ELSE achG:=''; END IF; achS:=' WHERE '||achLegTab||achS; IF _tipQ_ ='STL' THEN achS:=achS||' AND stx.qtydisp>0 '; END IF; IF _ord_!='---' THEN achO:=' ORDER BY '||_ord_; ELSE achO:=''; END IF; IF _tipQ_ = 'ST' OR _tipQ_ ='STL' THEN ach:= ' AS SELECT SUM(qtyfiz) as qtyfiz, SUM(qtydisp) as qtydisp '; ELSE ach:= ' AS SELECT SUM(qty) as qty ';END IF; exeQ:='DROP TABLE IF EXISTS '||achTmpTable||' ; CREATE TEMPORARY TABLE '||achTmpTable||ach||achA|| achFROM||achS||achG||achO||';'; RAISE NOTICE 'Interogarea: % ',exeQ; EXECUTE exeQ; GET DIAGNOSTICS r := ROW_COUNT; RAISE NOTICE 'Rez: %: % inregistrari', achTmpTable, r; RETURN codR; END$BODY$ LANGUAGE plpgsql VOLATILE COST 100;ALTER FUNCTION logx.q_x(text, smallint, text[], text[], boolean[], boolean[], text[], text[], text) OWNER TO postgres;COMMENT ON FUNCTION logx.q_x(text, smallint, text[], text[], boolean[],

221

Page 223: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

boolean[], text[], text[], text) IS '© 2014, Liviu Serbanescu, Hyperion University Bucharest, v.001';

--------------------------------------------------------------------------########### POPULAREA CU DATE DE TEST ###############INSERT INTO logx.acces(alias, pw, dep) VALUES('u1','0',ARRAY['DP1','DP2']),('u2','abc',ARRAY['DP2','DP3']);INSERT INTO logx.nom(idcode,descr) VALUES ('A1','DescrA1'),('A2','DescrA2'),('B1','DescrB1'),('B2','DescrZ2'),('C1','DescrC1'),('C2','DescrC2');INSERT INTO logx.loc(dep, ampl) VALUES ('DP1','AA1'),('DP1','AA2'),('DP2','AA1'),('DP2','AB1'),('DP2','AC1'),('DP2','AA2'),('DP3','AA1'),('DP3','AA2');INSERT INTO logx.br(nrbr, datain, idcode, status, supplier, serialno, qty,depinit,amplinit) VALUES(1,'2012-04-17','A1','functional','Furniz1','SS1',1,'DP1','AA1'),(1,'2012-04-17','A2','rebut','Furniz1','SS2',1,'DP1','AA1'),(1,'2012-04-17','B2','functional','Furniz1',NULL,10,'DP1','AA1'),(2,'2012-04-18','B2','incert','Furniz1',NULL,15,'DP2','AA1'),(2,'2012-04-18','C1','defect','Furniz1','SS3',1,'DP2','AA1'),(3,'2012-04-18','C1','defect','Furniz1','SS3',1,'DP3','AA1'),(3,'2012-04-18','B2','functional','Furniz2',NULL,25,'DP3','AA1');-- select logx.valid_br(1) as rez;

--########## DREPTURI DE ACCES ########################--pentru a putea şterge utilizatorii şi drepturile de acces trebuie să ne asigurăm că nu mai există obiecte create de aceştia, obiectele sunt trecute în posesia utilizatorului postgres--DROP OWNED BY "LOGX";-- LA A DOUA RULARE A FIŞIERULUI SE VA ŞTERGE COMENTARIUL !!!DROP ROLE IF EXISTS logx_sw ; DROP ROLE IF EXISTS "LOGX";CREATE ROLE logx_sw LOGIN PASSWORD 'gugu' SUPERUSER INHERIT NOCREATEDB CREATEROLE; COMMENT ON ROLE logx_sw IS 'supervizor logx';--se crează GRUPUL DE ACCES LOGXCREATE ROLE "LOGX";-- se oferă acces utlizatorului logx_sw la grupul LOGXGRANT logx_sw TO "LOGX";--asignări accesGRANT CONNECT, TEMPORARY ON DATABASE picdb TO GROUP "LOGX";GRANT ALL ON SCHEMA logx TO "LOGX";GRANT EXECUTE ON FUNCTION logx.add_bp_id(integer, text, text, text, integer) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.bp_nou(text, date) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.br_nou(date) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.bt_valid(integer) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.del_bp_id(integer, text, text, text) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.id_nou(text) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.nom_add(text, text, text, text) TO GROUP "LOGX";

222

Page 224: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

4.Codul sursă SQL pentru aplicaţia LogX

GRANT EXECUTE ON FUNCTION logx.q_x(text, smallint, text[], text[], boolean[], boolean[], text[], text[], text) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.valid_bp(integer) TO GROUP "LOGX";GRANT EXECUTE ON FUNCTION logx.valid_br(integer) TO GROUP "LOGX";GRANT ALL ON SEQUENCE logx.bp_seq TO GROUP "LOGX";GRANT ALL ON SEQUENCE logx.br_idx_seq TO GROUP "LOGX";GRANT ALL ON SEQUENCE logx.br_seq TO GROUP "LOGX";GRANT ALL ON SEQUENCE logx.id_seq TO GROUP "LOGX";GRANT ALL ON SEQUENCE logx.trx_nrlin_seq TO GROUP "LOGX";GRANT ALL ON TABLE logx._bp TO GROUP "LOGX";GRANT ALL ON TABLE logx._bt TO GROUP "LOGX";GRANT ALL ON TABLE logx.acces TO GROUP "LOGX";GRANT ALL ON TABLE logx.bp_ TO GROUP "LOGX";GRANT ALL ON TABLE logx.br TO GROUP "LOGX";GRANT ALL ON TABLE logx.bt_ TO GROUP "LOGX";GRANT ALL ON TABLE logx.inx TO GROUP "LOGX";GRANT ALL ON TABLE logx.loc TO GROUP "LOGX";GRANT ALL ON TABLE logx.nom TO GROUP "LOGX";GRANT ALL ON TABLE logx.outx TO GROUP "LOGX";GRANT ALL ON TABLE logx.stx TO GROUP "LOGX";GRANT ALL ON TABLE logx.trx TO GROUP "LOGX";--drepturile de acces de tip public se pot şterge şi manual din pgAdinin III--#############################

5. Codul sursă pentru biblioteca LX

În continuare este prezentat codul sursă pentru fişierele “.cpp”, pentru fişierele de tip header codul se regăseşte în capitolul anterior.

☑ Fişierul pentru clasa lxComboBox #include "lx_combobox.h" //lx_combobox.cpplxComboBox::lxComboBox(wxComboBox *cb1, wxString achQ):lxCtrl(){ cb=cb1; tipdata=0; achQRD=achQ; rdLista(achQ); }int lxComboBox::rdLista(wxString achQ){PGresult *rezultat; int nrInregistrari; wxString ach,ach_dmy; rezultat = PQexec(lxCtrl::conexiune0,achQ); if(PQresultStatus(rezultat) != PGRES_TUPLES_OK) { wxString ach; ach=ach.FromAscii(PQresultErrorMessage(rezultat)); wxMessageBox(_("EROARE LA CITIRE: ")+achQ+_(" ("+ach+")!")); return -1; } nrInregistrari=PQntuples(rezultat); cb->Clear(); int tipData=PQftype(rezultat,0);

wxDateTime achT1;for(int i = 0; i < nrInregistrari; i++) {

if(tipData==1082) { //1082 date

223

Page 225: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

ach=ach.FromAscii(PQgetvalue(rezultat, i, 0));achT1.ParseISODate(ach);achT1.ParseFormat(ach,wxT("%d.%m.%Y"));cb->AppendString(ach);}

else {ach=ach.FromAscii(PQgetvalue(rezultat, i, 0));cb->AppendString(ach);} //end if

}//endfor ireturn -1;}//-----------------------------------------------------------------wxString lxComboBox::getSel(){ return cb->GetStringSelection();}//-----------------------------------------------------------------int lxComboBox::refreshlx(){ rdLista(achQRD); return 0;}

☑ Fişierul pentru clasa lxCtrl#include "lx_ctrl.h" //fişierul lx_ctrl.cpplxCtrl::lxCtrl() { }//-----------------------------------------------------------------void lxCtrl::conectare(wxString dbname, wxString user, wxString pw, wxString host, wxString port) {wxString ach; char sir_conexiune[500]; ach=wxT(" dbname=")+dbname+wxT(" user=")+user+wxT(" password=")+pw+wxT(" host=")+host+wxT(" port=")+port; strcpy(sir_conexiune,ach.c_str());lxCtrl::conexiune0 = PQconnectdb(sir_conexiune); if (PQstatus(lxCtrl::conexiune0) != CONNECTION_OK) {PQfinish(lxCtrl::conexiune0); wxMessageBox("EROARE LA CONECTARE!");} } void lxCtrl::deconectare() {PQfinish(lxCtrl::conexiune0); }//------------------------------------------------------------------- int lxCtrl::refreshlx() {return 0;}//-----------------------------------------------------------------wxString lxCtrl::cda(wxString achQ){PGresult *rezultat; rezultat = PQexec(lxCtrl::conexiune0,achQ); if((PQresultStatus(rezultat) != PGRES_COMMAND_OK) && (PQresultStatus(rezultat) != PGRES_TUPLES_OK))

{ wxString ach; ach=ach.FromAscii(PQresultErrorMessage(rezultat)); wxMessageBox(_("EROARE CDA: ")+achQ+_(" ("+ach+")!")); return _(ach);} if(PQresultStatus(rezultat) == PGRES_TUPLES_OK) { wxString achR=_("#"); int nrCampuri = PQnfields(rezultat);

224

Page 226: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Codul sursă pentru biblioteca LX

int nrInregistrari=PQntuples(rezultat); if(nrCampuri==1 && nrInregistrari==1) achR=achR.FromUTF8(PQgetvalue(rezultat, 0, 0)); return achR; }return _("OK");}//------------------------------------------------------------------//comanda ce întoarce o listawxString lxCtrl::lista(wxString achQ, wxArrayString & a){PGresult *rezultat; rezultat = PQexec(lxCtrl::conexiune0,achQ); if((PQresultStatus(rezultat) != PGRES_COMMAND_OK) && (PQresultStatus(rezultat) != PGRES_TUPLES_OK)) { wxString ach; ach=ach.FromAscii(PQresultErrorMessage(rezultat)); wxMessageBox(_("EROARE CDA: ")+achQ+_(" ("+ach+")!")); return _(ach);} if(PQresultStatus(rezultat) == PGRES_TUPLES_OK)

{ wxString achR=_("#");int nrCampuri = PQnfields(rezultat); int

nrInregistrari=PQntuples(rezultat); if(nrCampuri!=1) return wxT("Comanda SQL întoarce mai mult de o coloană !"); a.Clear(); for(int i=0; i<nrInregistrari; i++) a.Add(achR.FromUTF8(PQgetvalue(rezultat, i, 0)));

return achR; }

return _("OK");}

☑ Fişierul pentru clasa lxDPC#include "lx_dpc.h" //fişirul lx_dpc.cpplxDPC::lxDPC(wxDatePickerCtrl *dpc1):lxCtrl(){ dpc=dpc1;}//----------------------------------------------------------------//citirea DIN baza de date (BD) în cutia de editareint lxDPC::rdSQL(wxString rdachQ) //rdachSQKL1 - cda de citire DIN BD{PGresult *rezultat; wxString ach; rezultat = PQexec(lxCtrl::conexiune0,rdachQ); //comanda rdachQ trebuie să întoarcă o singură valoare if(PQresultStatus(rezultat) != PGRES_TUPLES_OK) { wxMessageBox(_("Interogare ptr. preluare eronata: ") + rdachQ + _(" !")); return -1;} wxDateTime achT1;// wxMessageBox(rdachQ); if(((int)PQftype(rezultat, 0))!=1082) {wxMessageBox(_("Valoarea nu este de tip data calendaristica!"));return -1;} ach=ach.FromAscii(PQgetvalue(rezultat, 0, 0)); achT1.ParseISODate(ach);

dpc->SetValue(achT1); return 0;

225

Page 227: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

}//-----------------------------------------------------------------int lxDPC::wrSQL(wxString wrachQ) //wrachSQKL1 - cda de scrirere în baza de date { PGresult *rezultat; rezultat=PQexec(lxCtrl::conexiune0,wrachQ); if(PQresultStatus(rezultat) != PGRES_COMMAND_OK)

{ wxMessageBox(_("Comanda actualizare eronata: ") + wrachQ + _(" !")); return -1;} wxMessageBox("ACTUALIZAT !"); return 0;}//------------------------------------------------------------------wxString lxDPC::getValFormatStr(){ if(!dpc->GetValue().IsValid()) return _("NULL");

return _("'")+this->dpc->GetValue().FormatISODate()+_("'");}

☑ Fişierul pentru clasa lxEditN#include "lx_edit_n.h" // fişierul lx_edit_n.cpplxEditN::lxEditN(wxTextCtrl *ed1):lxCtrl(){ ed=ed1;}//-------------------------------------------------------------------//citirea DIN baza de date în cutia de editareint lxEditN::rdSQL(wxString rdachQ) // - cda de citire DIN baza de date{PGresult *rezultat; wxString ach; rezultat = PQexec(lxCtrl::conexiune0,rdachQ);/*comanda din rdachQ trebuie să întoarca o singură valoare (o înregistrare - un câmp)*/if(PQresultStatus(rezultat) != PGRES_TUPLES_OK){wxString ach; ach=ach.FromAscii(PQresultErrorMessage(rezultat)); wxMessageBox(_("EROARE LA CITIRE: ")+rdachQ+_(" ("+ach+")!"));return -1; } ach=ach.FromAscii(PQgetvalue(rezultat, 0, 0)); ed->SetValue(ach);return 0; }//--------------------------------------------------------------int lxEditN::wrSQL(wxString wrachQ) // - cda de scrirere în baza de date {PGresult *rezultat; wxString ach,achQ; ach=ed->GetValue(); rezultat=PQexec(lxCtrl::conexiune0,wrachQ); if(PQresultStatus(rezultat) != PGRES_COMMAND_OK) {wxString ach; ach=ach.FromAscii(PQresultErrorMessage(rezultat)); wxMessageBox(_("EROARE LA SCRIERE: ")+achQ+_(" ("+ach+")!"));return -1; } wxMessageBox("ACTUALIZAT !"); return 0;}

226

Page 228: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Codul sursă pentru biblioteca LX

//------------------------------------------------------------------wxString lxEditN::getValFormatStr(){ if(ed->GetValue().IsEmpty()) return _("NULL");

return this->ed->GetValue();}

☑ Fişierul pentru clasa lxEditT#include "lx_edit_t.h" //fişierul lx_edit_t.cpplxEditT::lxEditT(wxTextCtrl *ed1):lxCtrl(){ ed=ed1;}//------------------------------------------------------------------//citirea DIN baza de date(BD) în cutia de editareint lxEditT::rdSQL(wxString rdachQ)//rdSQL1-cda de citire DIN BD{PGresult *rezultat; wxString ach; rezultat = PQexec(lxCtrl::conexiune0,rdachQ); /*comanda rdachQ trebuie să întoarca o singură valoare (o înregistrare cu un singur câmp) */if(PQresultStatus(rezultat) != PGRES_TUPLES_OK) {wxString ach; ach=ach.FromAscii(PQresultErrorMessage(rezultat)); wxMessageBox(_("EROARE LA CITIRE: ")+rdachQ+_(" ("+ach+")!"));return -1; } ach=ach.FromAscii(PQgetvalue(rezultat, 0, 0)); if(ach.IsEmpty()||ach.IsNull()) ach=""; ed->SetValue(ach); return 0;}//--------------------------------------------------------------------int lxEditT::wrSQL(wxString wrachQ)//wrSQL1-cda scrirere în baza de date {PGresult *rezultat; wxString ach,achQ; ach=ed->GetValue(); rezultat=PQexec(lxCtrl::conexiune0,wrachQ); if(PQresultStatus(rezultat) != PGRES_COMMAND_OK) { wxString ach; ach=ach.FromAscii(PQresultErrorMessage(rezultat)); wxMessageBox(_("EROARE LA SCRIERE: ")+achQ+_(" ("+ach+")!"));return -1; } wxMessageBox("ACTUALIZAT !"); return 0;}//--------------------------------------------------------------------wxString lxEditT::getValFormatStr(){ if(ed->GetValue().IsEmpty()) return _("NULL");

return _("'")+this->ed->GetValue()+_("'");}

☑ Fişierul pentru clasa lxEditT#include "lx_grid.h" //fişierul lx_grid.cpplxGrid::lxGrid(wxGrid *gridX1, wxString tabelBD1, wxArrayString dencol1):lxCtrl(){ gridX=gridX1; tabelBD=tabelBD1; dencol=dencol1; tipCol=NULL;/*se trece null ptr. a putea face verificarea în destructor - dacă a

227

Page 229: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

fost sau nu alocată memorie*/}//-------------------------------------------------------------------lxGrid::~lxGrid(){ if(tipCol) delete[] tipCol;}/* 1043 varchar ; 1082 date; 1083 time; 11579 seq; 21 int2 ; 23 int4; 20 int8; 16 bool; 25 text ; 700 float4; 701 float8; 25 text- tabelele temporare de interfaţă NU vor conţine date de tip serial, acestea pot fi doar în tabelul sursă*///--------------------------------------------------------------------void lxGrid::salvare(){ wxString achQ,ach;

int nrCampuri=gridX->GetNumberCols();int nrInregistrari=gridX->GetNumberRows();

//construim interogare pentru fiecare linie achQ=" DELETE FROM "+tabelBD+"; INSERT INTO "+tabelBD+" VALUES "; for(int i=0;i<nrInregistrari;i++) {for(int j=0;j<nrCampuri;j++) {if(!j) ach=wxT("("); else ach=ach+",";

if(gridX->GetCellValue(i,j).IsEmpty()) ach=ach+" NULL "; else

switch(tipCol[j]) {case 1042: case 1043: case 1083: case 25: case 16:

ach=ach+_("'")+gridX->GetCellValue(i,j)+_("'"); break; case 1082: ach=ach+_("to_date('")+gridX->GetCellValue(i,j)+_("','dd.mm.yyyy'"); break;

case 11579: case 21: case 23: case 20: case 700: case 701: ach=ach+gridX->GetCellValue(i,j); break;

default: wxMessageBox(_("Tip de date neidentificat !")); }

} ach=ach+")"; if(i) achQ=achQ+wxT(","); achQ=achQ+ach; } rezultatRx = PQexec(conexiune0, achQ.ToUTF8()); if(PQresultStatus(rezultatRx) != PGRES_COMMAND_OK) {wxMessageBox(_("Eroare salvare din grid în ")+tabelBD+_("!")); } return; }//--------------------------------------------------------------------void lxGrid::preluareVarColRow(){ wxString achY; /*dacă nu există denumire a coloanelor transmisă şi există coloane în grid se vor şterge celelalte coloane */if(!dencol.GetCount() && gridX->GetNumberCols()>0)

gridX->DeleteCols(0,gridX->GetNumberCols()); //dacă există linii în grid acestea se vor ştergeif(gridX->GetNumberRows()>0) gridX->DeleteRows(0,gridX->GetNumberRows());//preia datele din tabelul "tabelBD" în structura rezultatRx

228

Page 230: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

5.Codul sursă pentru biblioteca LX

wxString ach,achQ; achQ=_("SELECT * FROM ")+tabelBD+_(";"); rezultatRx = PQexec(conexiune0,achQ);//testează operaţia de preluare a datelorif(PQresultStatus(rezultatRx) != PGRES_TUPLES_OK)

wxMessageBox(_("Interogare ptr. preluare eronata: ")+achQ+_(" !"));int nrCampuri = PQnfields(rezultatRx); int nrInregistrari=PQntuples(rezultatRx);if(((unsigned int)nrCampuri !=dencol.GetCount()) && dencol.GetCount()>0) {wxMessageBox("Nr. de coloane din grid diferea de cele din tabel!");return;}if(gridX->GetNumberCols()<1) gridX->AppendCols(nrCampuri);gridX->AppendRows(nrInregistrari);/*dacă există denumiri ptr. coloane, transmise, acestea vor fi setate cu denumirile transmise, altfel preia den. câmpurilor*/if(dencol.GetCount()) for(unsigned int j=0;j<dencol.Count();j++) gridX->SetColLabelValue(j,dencol[j]);else for(int j = 0; j<nrCampuri; j++) {ach=ach.FromUTF8(PQfname(rezultatRx,j));gridX->SetColLabelValue(j,ach);}//determină tipul de dată pentru fiecare câmp şi îl stochează într-un vectortipCol = new int[nrCampuri]; for(int j=0;j<nrCampuri;j++) tipCol[j]= (int)PQftype(rezultatRx, j);sirRcampuri=""; for(unsigned int j=1;j<dencol.GetCount();j++) {if(j>1) sirRcampuri=sirRcampuri+_(","); ach=ach.FromUTF8(PQfname(rezultatRx,j)); sirRcampuri=sirRcampuri+ach; } for(int i = 0; i < nrInregistrari; i++) { for(int j = 0; j < nrCampuri; j++) {ach=ach.FromUTF8(PQgetvalue(rezultatRx, i, j)); gridX->SetCellValue(i,j,ach); } } //setarea gridului în modul "selecţie rând"gridX->SetSelectionMode(wxGrid::wxGridSelectRows);//setare culori alternate pentru randuri//ATENŢIE ! Pentru fiecare atribuire este necesară o instanţiere !for(int i=0; i<gridX->GetNumberRows(); i++) { if(i%2)

{ wxGridCellAttr *A_rand = new wxGridCellAttr(); A_rand->SetBackgroundColour(wxColor(220,250,150));

gridX->SetRowAttr(i,A_rand); } else { wxGridCellAttr *A_rand = new wxGridCellAttr();

A_rand->SetBackgroundColour(wxColor(248,253,217)); gridX->SetRowAttr(i,A_rand);

} }//endfor gridX->AutoSize(); gridX->Fit(); this->refresh();}

229

Page 231: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

6. Codul sursă pentru aplicaţia LogX

☑ Fişierul pentru clasa iFACC#include "facc.h" //fişierul facc.cppiFACC::iFACC(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style){ this->SetSizeHints(wxDefaultSize, wxDefaultSize);wxBoxSizer* s1; s1 = new wxBoxSizer(wxVERTICAL);wxFlexGridSizer* s2; s2 = new wxFlexGridSizer(0, 2, 0, 0);s2->SetFlexibleDirection(wxBOTH);s2->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);t1 = new wxStaticText(this, wxID_ANY, wxT("Utilizator"), wxDefaultPosition, wxDefaultSize, 0);t1->Wrap(-1); s2->Add(t1, 0, wxALL, 5);e_alias = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);s2->Add(e_alias, 0, wxALL, 5);t2 = new wxStaticText(this, wxID_ANY, wxT("Cod acces"), wxDefaultPosition, wxDefaultSize, 0);t2->Wrap(-1); s2->Add(t2, 0, wxALL, 5);e_pw = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD|wxTE_PROCESS_ENTER); s2->Add(e_pw, 0, wxALL, 5);s1->Add(s2, 0, wxEXPAND, 5);b42 =new wxButton(this,wxID_ANY,wxT("SCHIMBARE PAROLĂ"),wxDefaultPosition,wxDefaultSize,0);b42->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 94, 90, false, wxEmptyString));s1->Add(b42, 0, wxALIGN_CENTER|wxALL, 5);wxFlexGridSizer* s3; s3 = new wxFlexGridSizer(0, 2, 0, 0);s3->SetFlexibleDirection(wxBOTH);s3->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);t3 = new wxStaticText(this, wxID_ANY, wxT("IP server PG"), wxDefaultPosition, wxDefaultSize, 0);t3->Wrap(-1); s3->Add(t3, 0, wxALL, 5);e_host = new wxTextCtrl(this, wxID_ANY, wxT("localhost"), wxDefaultPosition, wxDefaultSize, 0);s3->Add(e_host, 0, wxALL, 5);t4 = new wxStaticText(this, wxID_ANY, wxT("Port"), wxDefaultPosition, wxDefaultSize, 0);t4->Wrap(-1); s3->Add(t4, 0, wxALL, 5);e_port = new wxTextCtrl(this, wxID_ANY, wxT("5435"), wxDefaultPosition, wxDefaultSize, 0);s3->Add(e_port, 0, wxALL, 5); s1->Add(s3, 0, wxEXPAND, 5);bAcces = new wxButton(this, wxID_ANY, wxT("ACCES"), wxDefaultPosition, wxDefaultSize, 0);bAcces->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString));s1->Add(bAcces, 0, wxALIGN_CENTER|wxALL, 5);this->SetSizer(s1); this->Layout(); this->Centre(wxBOTH);b42->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFACC::schimbPW), NULL, this);bAcces->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFACC::acces), NULL, this);iFACC::accesX=false;}//------------------------------------------------------------------iFACC::~iFACC() {b42->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFACC::schimbPW), NULL, this);bAcces->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFACC::acces), NULL, this);}//----------------------------------------------------------------

230

Page 232: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

void iFACC::schimbPW(wxCommandEvent& event) { wxString pw1,pw2; rezX=lxCtrl::cda(_("SELECT EXISTS(select * FROM logx.acces WHERE alias='")+e_alias->GetValue()+_("' AND pw='")+e_pw->GetValue()+_("') AS acces_permis;")); if(rezX!=_("t")) { wxMessageBox(wxT("Alias nume sau parolă incorecte!")); return;} pw1=wxGetPasswordFromUser(wxT("1.Introduceţi noul cod de acces!")); pw2=wxGetPasswordFromUser(wxT("1.Introduceţi noul cod de acces!")); if(pw1!=pw2) { wxMessageBox(wxT("Cele două parole nu coincid!")); return;} rezX=lxCtrl::cda(_("UPDATE logx.acces SET pw='")+pw1+_("' WHERE alias='")+e_alias->GetValue()+_("';")); wxMessageBox(rezX); }//--------------------------------------------------------------- void iFACC::acces(wxCommandEvent& event) { wxString pw1,pw2,pw, pwN,ach; rezX=lxCtrl::cda(_("SELECT EXISTS(select * FROM logx.acces WHERE alias='")+e_alias->GetValue()+_("' AND pw='")+e_pw->GetValue()+_("') AS acces_permis;"));if(rezX!=_("t")) { wxMessageBox(wxT("Alias nume sau parolă incorecte!")); iFACC::accesX=false; return; } srand(time(NULL));//iniţializare generator numere aleatoarepwN = _("123-")+ach.FromDouble(rand());rezX=lxCtrl::cda(_("DROP ROLE IF EXISTS \"#")+e_alias->GetValue()+_("#\"; CREATE ROLE \"#")+e_alias->GetValue()+_("#\" LOGIN PASSWORD '")+pwN + _("' CONNECTION LIMIT 1; GRANT \"LOGX\" TO \"#")+e_alias->GetValue()+_("#\"; SET ROLE \"#")+e_alias->GetValue()+_("#\";"));if(rezX!=_("OK")) wxGetTextFromUser(_("Mesaj de eroare"), _("Err 101"), rezX); iFACC::accesX=((rezX==_("t"))||(rezX==_("OK")));this->Destroy();//distruge fereara principală şi continuă codul din OnInit() }

☑ Fişierul pentru clasa iFEBP#include <wx/clipbrd.h> //fişierul febp.cpp#include "febp.h"#include "selst.h"iFEBP::iFEBP(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style){ this->SetSizeHints(wxDefaultSize, wxDefaultSize);wxBoxSizer* s1; s1 = new wxBoxSizer(wxVERTICAL);wxBoxSizer* s2; s2 = new wxBoxSizer(wxHORIZONTAL);t1 = new wxStaticText(this, wxID_ANY, wxT("BP nr:"), wxDefaultPosition, wxDefaultSize, 0);t1->Wrap(-1); s2->Add(t1, 0, wxALL, 5);

231

Page 233: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

cbBP = new wxComboBox(this, wxID_ANY, wxT("0000"), wxDefaultPosition, wxSize(60,-1),0,NULL,0); s2->Add(cbBP, 0, wxALL, 5);bAddBP = new wxButton(this, wxID_ANY, wxT("Adaugă BP"), wxDefaultPosition, wxSize(-1,25),0); s2->Add(bAddBP, 0, wxALL, 5);eDataBP = new wxDatePickerCtrl(this, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, DEFAULT|wxDP_DROPDOWN); s2->Add(eDataBP, 0, wxALL, 5);t2 = new wxStaticText(this,wxID_ANY,wxT("Destinaţie"), wxDefaultPosition, wxDefaultSize,0); t2->Wrap(-1); s2->Add(t2, 0, wxALL, 5);eDestinBP = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,0); s2->Add(eDestinBP, 0, wxALL, 5);bDelBP = new wxButton(this, wxID_ANY, wxT("Anulează BP"), wxDefaultPosition, wxDefaultSize, 0); s2->Add(bDelBP, 0, wxALL, 5); s1->Add(s2, 0, wxEXPAND, 5);pBP = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s4; s4 = new wxBoxSizer(wxVERTICAL);GD1 = new wxGrid(pBP, wxID_ANY, wxDefaultPosition,wxSize(-1,400), wxALWAYS_SHOW_SB);GD1->CreateGrid(0, 0); GD1->EnableEditing(true); GD1->EnableGridLines(true);GD1->EnableDragGridSize(false); GD1->SetMargins(0, 0);GD1->AutoSizeColumns();GD1->EnableDragColMove(false);GD1->EnableDragColSize(true);GD1->SetColLabelSize(30);GD1->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE);GD1->AutoSizeRows(); GD1->EnableDragRowSize(true);GD1->SetRowLabelSize(80);GD1->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE);GD1->SetDefaultCellBackgroundColour(wxColour(237, 250, 237));GD1->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP);GD1->SetBackgroundColour(wxColour(238, 251, 236));s4->Add(GD1, 1, wxALL|wxEXPAND, 5);wxBoxSizer* s3; s3 = new wxBoxSizer(wxHORIZONTAL);bDelLin = new wxButton(pBP, wxID_ANY, wxT("Şterge linia"), wxDefaultPosition, wxDefaultSize,0);s3->Add(bDelLin, 0, wxALL, 5); s3->Add(0, 0, 1, wxEXPAND, 5);bSelST =new wxButton(pBP, wxID_ANY,wxT("Adaugă din STOC"),wxDefaultPosition,wxDefaultSize,0); s3->Add(bSelST, 0, wxALL, 5); s3->Add(0, 0, 1, wxEXPAND, 5);bValidBP=new wxButton(pBP, wxID_ANY, wxT("VALIDEAZĂ BP"),wxDefaultPosition,wxDefaultSize,0); s3->Add(bValidBP, 0, wxALL, 5); s4->Add(s3,0,wxEXPAND,5);pBP->SetSizer(s4); pBP->Layout(); s4->Fit(pBP);s1->Add(pBP, 0, wxEXPAND | wxALL, 5);this->SetSizer(s1); this->Layout(); this->Centre(wxBOTH);cbBP->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(iFEBP::afis_BP), NULL, this);bAddBP->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::addBP), NULL, this);bDelBP->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::delBP), NULL, this);bDelLin->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::delLin), NULL, this);bSelST->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::selST), NULL, this);bValidBP->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::validBP), NULL, this); pBP->Hide();cx_nrbp = new lxComboBox(cbBP,_("SELECT DISTINCT nrbp::text FROM logx.bp_ ORDER BY nrbp;"));cx_destin=new lxEditT(eDestinBP); cx_databp=new lxDPC(eDataBP);wxArrayString a; cx_grid=new lxGrid(GD1,_("itmp_bp"),a);GD1->SetColMinimalAcceptableWidth(0);

232

Page 234: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

}//-------------------------------------------------------------iFEBP::~iFEBP() {cbBP->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(iFEBP::afis_BP), NULL, this);bAddBP->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::addBP), NULL, this);bDelBP->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::delBP), NULL, this);bDelLin->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::delLin), NULL, this);bSelST->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::selST), NULL, this);bValidBP->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEBP::validBP), NULL, this);}//-------------------------------------------------------------void iFEBP::afis_BP(wxCommandEvent& event){if(cbBP->GetCount()<1) { pBP->Hide(); return;} cx_destin->rdSQL(_("SELECT destin::text FROM logx.bp_ WHERE nrbp=")+cx_nrbp->getSel()+_(" LIMIT 1;")); cx_databp->rdSQL(_("SELECT databp::date FROM logx.bp_ WHERE nrbp=")+cx_nrbp->getSel()+_(" LIMIT 1;")); lxCtrl::cda(_("DROP TABLE IF EXISTS itmp_bp; CREATE TEMPORARY TABLE itmp_bp AS SELECT (_bp.nrbp::text||'->'||_bp.id::text||'->'||_bp.dep::text||'->'||_bp.ampl::text) AS tcu, _bp.nrbp, _bp.id, nom.idcode, nom.refcom, nom.refteh, nom.descr, inx.po, inx.status, inx.serialno, _bp.dep, _bp.ampl, _bp.qtyrez, _bp.qtyconf FROM logx._bp,logx.inx,logx.nom WHERE nom.idcode=inx.idcode AND nrbp=")+cx_nrbp->getSel()+_(" AND inx.id=_bp.id;"));/*tcu contor unic pentru a realiza legătura între cele două tabele, în grid va fi în prima coloana care va fi setată pe invizibil(dimensiune zero)*/ cx_grid->preluareVarColRow();GD1->SetColSize(0,0);pBP->Show();}//-------------------------------------------------------------void iFEBP::addBP(wxCommandEvent& event){lxCtrl::cda(_("select logx.bp_nou(")+cx_destin->getValFormatStr()+_(",")+cx_databp->getValFormatStr()+_(");")); cx_nrbp->rdLista(_("SELECT DISTINCT nrbp::text FROM logx.bp_ ORDER BY nrbp;")); cbBP->SetSelection(cbBP->GetCount()-1); afis_BP(event);}//-------------------------------------------------------------void iFEBP::delLin(wxCommandEvent& event){wxMessageDialog *x = new wxMessageDialog(this,wxT("Doriţi ştergerea liniei curente?"), _(""), wxYES_NO|wxICON_QUESTION); x->SetYesNoLabels(_("&Nu"),_("&Da"));if(x->ShowModal() == wxID_NO) { lxCtrl::cda(_("DELETE FROM logx._bp USING itmp_bp WHERE itmp_bp.tcu = (bp.nrbp::text||'->'||bp.id::text||'->'||_bp.dep::text||'->'||_bp.ampl::text) AND tcu='") + GD1->GetCellValue(GD1->GetSelectedRows()[0],0) +_("'; DELETE FROM itmp_bp WHERE itmp_bp.tcu='") + GD1->GetCellValue(GD1->GetSelectedRows()[0],0) +_("';"));GD1->DeleteRows(GD1->GetSelectedRows()[0],1);GD1->Fit(); }afis_BP(event);

233

Page 235: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

}//-------------------------------------------------------------void iFEBP::delBP(wxCommandEvent& event){ wxMessageDialog *x = new wxMessageDialog(this,wxT("Doriţi ştergerea BPORDEROULUI curent?"), _(""),wxYES_NO|wxICON_QUESTION); x->SetYesNoLabels(_("&Nu"),_("&Da"));if(x->ShowModal() == wxID_NO) //&Nu corespunde lui wxID_YESlxCtrl::cda(_("UPDATE logx.stx SET qtydisp=qtydisp+qtyrez FROM itmp_bp WHERE stx.id=itmp_bp.id AND stx.dep=itmp_bp.dep AND stx.ampl=itmp_bp.ampl AND itmp_bp.nrbp = ")+cx_nrbp->getSel()+_("; \DELETE FROM logx._bp WHERE nrbp = ")+cx_nrbp->getSel()+_("; DELETE FROM logx.bp_ WHERE nrbp = ")+cx_nrbp->getSel()+_(";"));int s=cbBP->GetSelection(); cx_nrbp->refreshlx(); cbBP->Select(s-1); afis_BP(event);}//-------------------------------------------------------------void iFEBP::selST(wxCommandEvent& event){ iFSELST* x; x=new iFSELST(this, cx_nrbp->getSel()); x->ShowModal(); afis_BP(event);}//-------------------------------------------------------------void iFEBP::validBP(wxCommandEvent& event){ wxString achQ,ach; if(cbBP->GetSelection()<0) wxMessageBox(_("Nimic de selectat!")); //actualizare în BP qtyconf for(int i=0;i<GD1->GetNumberRows();i++) lxCtrl::cda(_("UPDATE logx._bp SET qtyconf=") + GD1->GetCellValue(i, GD1->GetNumberCols() - 1) + _(" FROM itmp_bp WHERE itmp_bp.tcu = (_bp.nrbp::text || '->' || _bp.id::text || '->' || _bp.dep::text || '->' || _bp.ampl::text) AND itmp_bp.tcu='")+GD1->GetCellValue(i,0)+_("';"));

if((ach=lxCtrl::cda(_("SELECT logx.valid_bp(")+cx_nrbp->getSel()+");"))==_("OK")) wxMessageBox(_("Validat!")); else wxMessageBox(ach); cx_nrbp->refreshlx(); afis_BP(event);}

☑ Fişierul pentru clasa iFEI#include "fei.h" //fişierul fei.cpp#include "fnom.h"#define _COLDEP_ 8#define _COLAMPL_ 9#define _COLSTATUS_ 6iFEI::iFEI(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style){ this->SetSizeHints(wxDefaultSize, wxDefaultSize); wxBoxSizer* s1; s1 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s2; s2 = new wxBoxSizer(wxHORIZONTAL); t4=new wxStaticText(this,wxID_ANY,wxT("BR nr:"),wxDefaultPosition,wxDefaultSize,0);

234

Page 236: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

t4->Wrap(-1);s2->Add(t4, 0, wxALL|wxEXPAND, 5); cbBR =new wxComboBox(this,wxID_ANY,wxT("Combo!"),wxDefaultPosition, wxDefaultSize,0,NULL,0); s2->Add(cbBR, 0, wxALL, 5); eDataBR = new wxDatePickerCtrl(this, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DEFAULT|wxDP_DROPDOWN); s2->Add(eDataBR, 0, wxALL, 5); t5 = new wxStaticText(this, wxID_ANY, wxT("Supplier"), wxDefaultPosition, wxDefaultSize, 0); t5->Wrap(-1); s2->Add(t5, 0, wxALL, 5); SupplierBR=new wxTextCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxDefaultSize,0); s2->Add(eSupplierBR, 0, wxALL, 5); bAddBR = new wxButton(this, wxID_ANY, wxT("Adaugă BR"), wxDefaultPosition,wxSize(-1,25),0); s2->Add(bAddBR, 0,wxALL,5);s1->Add(s2,0, wxEXPAND, 5); pBR = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxRAISED_BORDER|wxTAB_TRAVERSAL); wxBoxSizer* s3; s3 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s4; s4 = new wxBoxSizer(wxHORIZONTAL); bDelBR = new wxButton(pBR, wxID_ANY, wxT("ŞTERGE BR"), wxDefaultPosition, wxSize(-1,25),0); bDelBR->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); s4->Add(bDelBR, 0, wxALL, 5); s4->Add(0, 0, 1, wxEXPAND, 5); bSavBR = new wxButton(pBR,wxID_ANY,wxT("SALVEAZĂ BR"),wxDefaultPosition,wxSize(-1,25),0); s4->Add(bSavBR, 0, wxALL, 5);s3->Add(s4,0,wxEXPAND,5); GD1 = new wxGrid(pBR, wxID_ANY, wxDefaultPosition, wxSize(600,400), wxALWAYS_SHOW_SB); GD1->CreateGrid(0,0);GD1->EnableEditing(true); GD1->EnableGridLines(true); GD1->EnableDragGridSize(false); GD1->SetMargins(0, 0); GD1->AutoSizeColumns();GD1->EnableDragColMove(false); GD1->EnableDragColSize(true); GD1->SetColLabelSize(30); GD1->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD1->AutoSizeRows();GD1->EnableDragRowSize(true); GD1->SetRowLabelSize(80); GD1->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD1->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP); s3->Add(GD1, 1, wxALL|wxEXPAND, 5); wxBoxSizer* s5; s5 = new wxBoxSizer(wxHORIZONTAL); bValidBR=new wxButton(pBR,wxID_ANY,wxT("VALIDEAZĂ BR"),wxDefaultPosition,wxSize(-1,25),0); s5->Add(bValidBR, 0, wxALL, 5); bAddLin =new wxButton(pBR, wxID_ANY,wxT("ADAUGĂ LINIE"),wxDefaultPosition,wxSize(-1,25),0); s5->Add(bAddLin, 0, wxALL, 5); bDelLin =new wxButton(pBR, wxID_ANY,wxT("ŞTERGE LINIE"),wxDefaultPosition, wxSize(-1,25),0); s5->Add(bDelLin, 0, wxALL, 5); s5->Add(0, 0, 1, wxEXPAND, 5); B_selNom = new wxButton(pBR,wxID_ANY,wxT("SELECŢIE NOMENCLATOR"), wxDefaultPosition, wxSize(-1,25),0); s5->Add(B_selNom, 0, wxALL, 5); s3->Add(s5, 0, wxEXPAND, 5); pBR->SetSizer(s3);pBR->Layout(); s3->Fit(pBR);s1->Add(pBR,1,wxEXPAND,5); this->SetSizer(s1); this->Layout();cbBR->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(iFEI::afis_BR), NULL, this);bAddBR->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::add_BR), NULL, this);bDelBR->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::del_BR), NULL, this);bSavBR->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::sav_BR), NULL, this);

235

Page 237: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

GD1->Connect(wxEVT_GRID_CELL_CHANGE, wxGridEventHandler(iFEI::GD1OnGridCellChange), NULL, this);GD1->Connect(wxEVT_GRID_EDITOR_SHOWN, wxGridEventHandler(iFEI::GD1OnGridEditorShown), NULL, this);bValidBR->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::valid_BR), NULL, this);bAddLin->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::add_Lin), NULL, this);bDelLin->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::del_Lin), NULL, this);B_selNom->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::sel_nom), NULL, this); pBR->Hide(); cx_nrbr = new lxComboBox(cbBR,_("SELECT DISTINCT nrbr::text FROM logx.br ORDER BY nrbr;")); cx_supplier=new lxEditT(eSupplierBR); cx_datain=new lxDPC(eDataBR); const char* ach[]={"tcu","IDCode","RefCom","RefTeh","Descr","PO","Status", "SerialNo","DepInit","Ampl.Init","Qty"}; wxArrayString a; for(int i=0;i<11;i++) a.Add(ach[i]); cx_grid=new lxGrid(GD1,_("itmp_br"),a); GD1->SetColMinimalAcceptableWidth(0); //adăugare control combobox în grid pentru STATUS wxGridCellAttr *A_col= new wxGridCellAttr(); wxString sel[] = { wxT("Funcţional"), wxT("Defect"), wxT("Rebut"), wxT("Incert"), wxT("Casare") }; A_col->SetEditor(new wxGridCellChoiceEditor(5, sel)); GD1->SetColAttr(_COLSTATUS_, A_col);//adaugare controale combobox pentru depozite şi amplasamente, lista pentru amplasament va cuprinde selecţia pentru primul depozit afişat */lxCtrl::lista(_("DROP TABLE IF EXISTS tmpacc; CREATE TEMP TABLE tmpacc AS SELECT dep[s] FROM (select acces.*, generate_subscripts(dep,1) as s from logx.acces where ('#'||alias||'#') = CURRENT_USER)par; SELECT DISTINCT loc.dep FROM logx.loc,tmpacc WHERE loc.dep=tmpacc.dep ORDER BY loc.dep;"),a); A_col= new wxGridCellAttr(); A_col->SetEditor(new wxGridCellChoiceEditor(a)); GD1->SetColAttr(_COLDEP_ ,A_col);/*obiectul de tip combobox pentru amplasament este pus şi aici doar pentru agenerarea evenimentelor de afişare control în celulă */ lxCtrl::lista(_("SELECT DISTINCT ampl FROM logx.loc WHERE dep=(SELECT DISTINCT dep FROM tmpacc ORDER BY dep LIMIT 1) ORDER BY ampl;"),a); A_col= new wxGridCellAttr(); A_col->SetEditor(new wxGridCellChoiceEditor(a)); GD1->SetColAttr(_COLAMPL_,A_col);}//--------------------------------------------------------------------------iFEI::~iFEI() {cbBR->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(iFEI::afis_BR), NULL, this);bAddBR->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::add_BR), NULL, this);bDelBR->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::del_BR), NULL, this);bSavBR->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::sav_BR), NULL, this);GD1->Disconnect(wxEVT_GRID_CELL_CHANGE, wxGridEventHandler(iFEI::GD1OnGridCellChange), NULL, this);GD1->Disconnect(wxEVT_GRID_EDITOR_SHOWN, wxGridEventHandler(iFEI::GD1OnGridEditorShown), NULL, this);bValidBR->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::valid_BR), NULL, this);bAddLin->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::add_Lin), NULL, this);bDelLin->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::del_Lin), NULL, this);

236

Page 238: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

B_selNom->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFEI::sel_nom), NULL, this);}//-------------------------------------------------------------------void iFEI::afis_BR(wxCommandEvent& event){ cx_supplier->rdSQL(_("SELECT supplier::text FROM logx.br WHERE nrbr=")+cx_nrbr->getSel()+_(" LIMIT 1;")); cx_datain->rdSQL(_("SELECT datain::date FROM logx.br WHERE nrbr=")+cx_nrbr->getSel()+_(" LIMIT 1;")); lxCtrl::cda(_("DROP TABLE IF EXISTS itmp_br; CREATE TEMPORARY TABLE itmp_br AS SELECT (br.nrbr::text||'->'||br.idx::text) AS tcu, br.idcode,refcom,refteh,descr,po,status,serialno,depinit,amplinit,qty FROM logx.br,logx.nom WHERE nom.idcode=br.idcode AND nrbr=")+cx_nrbr->getSel()+_(";"));//tcu contor unic pentru a realiza legaătura între cele două tabele, în grid va fi în prima coloana care va fi setată pe invizibil cx_grid->preluareVarColRow(); GD1->SetColSize(0,0); pBR->Show();}//---------------------------------------------------------------------void iFEI::sav_BR(wxCommandEvent& event){ wxString achQ; cx_grid->salvare(); // copiere din celule gridului în tabelul temporar//şterge borderoul curent pentru numărul selectat şi adaugă în acesta noua informaţie if(!lxCtrl::cda(_("DELETE FROM logx.br USING itmp_br WHERE itmp_br.tcu=(br.nrbr::text||'->'||br.idx); \INSERT INTO logx.br(nrbr,datain,supplier,idcode,po,status,serialno,depinit, amplinit,qty) \ SELECT ")+cx_nrbr->getSel()+_(",")+cx_datain->getValFormatStr()+_(",")+cx_supplier->getValFormatStr()+ _(" ,idcode,po,status,serialno,depinit,amplinit,qty FROM itmp_br; ")));wxMessageBox(_("Salvat!")); }//---------------------------------------------------------------------void iFEI::add_BR(wxCommandEvent& event){lxCtrl::cda(_("select logx.br_nou();")); cx_nrbr->rdLista(_("SELECT DISTINCT nrbr::text FROM logx.br ORDER BY nrbr;")); cbBR->SetSelection(cbBR->GetCount()-1); afis_BR(event);}//---------------------------------------------------------------------void iFEI::add_Lin(wxCommandEvent& event){ GD1->AppendRows(); GD1->Fit();}//--------------------------------------------------------------------void iFEI::del_Lin(wxCommandEvent& event){ wxMessageDialog *x = new wxMessageDialog(this, wxT("Doriţi ştergerea liniei curente?"), _(""),wxYES_NO|wxICON_QUESTION); x->SetYesNoLabels(_("&Nu"),_("&Da"));

237

Page 239: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

if(x->ShowModal() == wxID_NO) //DA=ID_NO {// ştergere linia unde valoarea tpu = cu expresia formată în BR lxCtrl::cda(_("DELETE FROM logx.br WHERE '") + GD1->GetCellValue(GD1->GetSelectedRows()[0],0) + ("'=(br.nrbr::text||'->'||br.idx)")); afis_BR(event); }}//--------------------------------------------------------------------void iFEI::del_BR(wxCommandEvent& event){ wxMessageDialog *x = new wxMessageDialog(this,wxT("Doriţi ştergerea BPORDEROULUI curent?"),_(""),wxYES_NO|wxICON_QUESTION); x->SetYesNoLabels(_("&Nu"),_("&Da"));if(x->ShowModal() == wxID_NO) //&Nu corespunde lui wxID_YES lxCtrl::cda(_("DELETE FROM logx.br USING itmp_br WHERE itmp_br.tcu=(br.nrbr::text||'->'||br.idx);")); pBR->Hide(); cx_nrbr->refreshlx(); }//-------------------------------------------------------------------void iFEI::sel_nom(wxCommandEvent& event){ if(!GD1->IsSelection()) {wxMessageBox(wxT("Selectaţi linia!")); return;}

wxArrayString* rez=new wxArrayString; iFNOM* x; x=new iFNOM(this,rez); x->ShowModal(); if(rez->GetCount()<1)

{wxMessageBox("Nu a fost selectat nimic >>>>>!"); return;} for(int j=0; j<4; j++)

GD1->SetCellValue(GD1->GetSelectedRows()[0],j+1,rez->Item(j));}//--------------------------------------------------------------------void iFEI::valid_BR(wxCommandEvent& event){ wxString achQ, achR; sav_BR(event); if((achR=lxCtrl::cda(_("SELECT logx.valid_br(")+cx_nrbr->getSel()+");"))==_("OK")) wxMessageBox(_("Validat!")); else wxMessageBox(achR); pBR->Hide(); cx_nrbr->refreshlx(); }//--------------------------------------------------------------------void iFEI::GD1OnGridEditorShown(wxGridEvent& event) {if(event.GetCol()!=_COLAMPL_) return; wxArrayString a; lxCtrl::lista(_("SELECT DISTINCT ampl FROM logx.loc WHERE dep='") + GD1->GetCellValue(event.GetRow(),_COLDEP_) + _("' ORDER BY ampl;"),a); wxGridCellAttr *A_col= new wxGridCellAttr(); A_col->SetEditor(new wxGridCellChoiceEditor(a)); GD1->SetColAttr(_COLAMPL_,A_col);}//----------------------------------------------------------------------

238

Page 240: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

//modifică culuarea de scriere în roşu pentru celulele cu conţinut modificatvoid iFEI::GD1OnGridCellChange(wxGridEvent& event) { GD1->SetCellTextColour(event.GetRow(),event.GetCol(),wxColour(wxT("RED")));}

☑ Fişierul pentru clasa iFNOM#include <wx/valgen.h>#include "fnom.h"iFNOM::iFNOM(wxWindow* parent, wxArrayString* rez1, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style){this->SetSizeHints(wxDefaultSize, wxDefaultSize); wxBoxSizer* s1; s1 = new wxBoxSizer(wxVERTICAL); wxString rOrdChoices[] = { wxT("RefCom"), wxT("RefTeh"), wxT("Descriere"), wxT("idCode") }; int rOrdNChoices = sizeof(rOrdChoices) / sizeof(wxString); rOrd = new wxRadioBox(this, wxID_ANY, wxT("Ordonare după:"), wxDefaultPosition, wxDefaultSize, rOrdNChoices, rOrdChoices, 1, wxRA_SPECIFY_ROWS); rOrd->SetSelection(2); rOrd->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); rOrd->SetValidator(wxGenericValidator(&nr_ord));s1->Add(rOrd,0,wxALL,5); GD1 = new wxGrid(this, wxID_ANY, wxDefaultPosition, wxSize(300,200), 0); GD1->CreateGrid(0,0); GD1->EnableEditing(true); GD1->EnableGridLines(true); GD1->EnableDragGridSize(false); GD1->SetMargins(0, 0); GD1->EnableDragColMove(false); GD1->EnableDragColSize(true); GD1->SetColLabelSize(30); GD1->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD1->EnableDragRowSize(true);GD1->SetRowLabelSize(80); GD1->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD1->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP); s1->Add(GD1, 1, wxALL|wxEXPAND, 5); pEdit = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s2Nom; s2Nom = new wxBoxSizer(wxHORIZONTAL); bAdd = new wxButton(pEdit, wxID_ANY, wxT("ADAUGĂ"), wxDefaultPosition, wxDefaultSize, 0); s2Nom->Add(bAdd, 0, wxALL|wxEXPAND, 5); bDel = new wxButton(pEdit, wxID_ANY, wxT("ŞTERGE"), wxDefaultPosition, wxDefaultSize, 0); s2Nom->Add(bDel, 0, wxALL|wxEXPAND, 5); bSav = new wxButton(pEdit, wxID_ANY, wxT("SALVEAZĂ"), wxDefaultPosition, wxDefaultSize, 0); s2Nom->Add(bSav, 0, wxALL|wxEXPAND, 5); bRenEdit=new wxButton(pEdit, wxID_ANY, wxT("RENUNŢĂ"), wxDefaultPosition, wxDefaultSize, 0); s2Nom->Add(bRenEdit, 0, wxALL|wxEXPAND, 5); pEdit->SetSizer(s2Nom); pEdit->Layout(); s2Nom->Fit(pEdit); s1->Add(pEdit, 0, wxALIGN_BOTTOM|wxEXPAND, 5); wxBoxSizer* s2; s2 = new wxBoxSizer(wxHORIZONTAL); bEdit = new wxButton(this, wxID_ANY, wxT("EDITARE"), wxDefaultPosition, wxDefaultSize, 0); s2->Add(bEdit, 0, wxALL, 5); bSel = new wxButton(this, wxID_ANY, wxT("SELECTEAZĂ"), wxDefaultPosition, wxDefaultSize, 0); bSel->SetDefault(); bSel->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString)); s2->Add(bSel, 0, wxALL, 5);

239

Page 241: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

bRenNom = new wxButton(this, wxID_ANY, wxT("RENUNŢĂ"), wxDefaultPosition, wxDefaultSize, 0); s2->Add(bRenNom, 0, wxALL, 5); s1->Add(s2, 0, wxEXPAND, 5); this->SetSizer(s1);this->Layout(); s1->Fit(this);this->Centre(wxBOTH);// Evenumente de conectarerOrd->Connect(wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler(iFNOM::ordoneaza), NULL, this);bAdd->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::add_Lin), NULL, this);bDel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::del_Lin), NULL, this);bSav->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::salveaza), NULL, this);bRenEdit->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::ren_Edit), NULL, this);bEdit->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::editare), NULL, this);bSel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::selecteaza), NULL, this);bRenNom->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::ren_Nom), NULL, this); const char* ach[]={"ID Code","RefCom","RefTeh","Descriere"}; const char* ord1[]={"refcom","refteh","descr","idcode"}; wxArrayString a; nr_ord=2; for(int i=0;i<4;i++) {a.Add(ach[i]); ord.Add(ord1[i]);} if(rez1) {rez=rez1; rez->Clear();} else bSel->Hide(); cx_grid=new lxGrid(GD1,_("itmp_nom"),a); pEdit->Hide(); GD1->EnableEditing(false); GD1->SetSelectionMode(wxGrid::wxGridSelectRows); afis_NOM();}//--------------------------------------------------------------------------iFNOM::~iFNOM() {rOrd->Disconnect(wxEVT_COMMAND_RADIOBOX_SELECTED,wxCommandEventHandler(iFNOM::ordoneaza),NULL,this);bAdd->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::add_Lin), NULL, this);bDel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::del_Lin), NULL, this);bSav->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::salveaza), NULL, this);bRenEdit->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(iFNOM::ren_Edit),NULL,this);bEdit->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::editare), NULL, this);bSel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFNOM::selecteaza), NULL, this);bRenNom->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(iFNOM::ren_Nom),NULL,this);}//------------------------------------------------------------------void iFNOM::afis_NOM(){ nr_ord=rOrd->GetSelection(); lxCtrl::cda(_("DROP TABLE IF EXISTS itmp_nom; CREATE TEMPORARY TABLE itmp_nom AS SELECT idcode,refcom,refteh,descr FROM logx.nom ORDER BY ") + ord.Item(nr_ord)+_(";")); cx_grid->preluareVarColRow(); }//-------------------------------------------------------------------void iFNOM::salveaza(wxCommandEvent& event){ lxCtrl::cda(_("DROP TABLE IF EXISTS itmp_nom; CREATE TEMPORARY TABLE itmp_nom AS SELECT idcode,refcom,refteh,descr FROM logx.nom;")); wxString achQ; cx_grid->salvare(); if(!lxCtrl::cda(_("UPDATE logx.nom SET refcom=itmp_nom.refcom,refteh=itmp_nom.refteh,descr=itmp_nom.descr \FROM itmp_nom WHERE itmp_nom.idcode=nom.idcode; \

240

Page 242: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

INSERT INTO logx.nom SELECT par.* FROM (SELECT idcode,refcom,refteh,descr FROM itmp_nom EXCEPT SELECT idcode,refcom,refteh,descr FROM logx.nom)par;"))) wxMessageBox(_("Salvat!")); }//--------------------------------------------------------------------void iFNOM::editare(wxCommandEvent& event){ pEdit->Show();GD1->EnableEditing(true); this->Fit(); GD1->SetSelectionMode(wxGrid::wxGridSelectCells); }//------------------------------------------------------------------void iFNOM::ren_Edit(wxCommandEvent& event) { pEdit->Hide();GD1->EnableEditing(false); GD1->SetSelectionMode(wxGrid::wxGridSelectRows); }//------------------------------------------------------------------ void iFNOM::selecteaza(wxCommandEvent& event){ if(!GD1->IsSelection()) {wxMessageBox(wxT("Selectaţi linia!")); return;} //dacă există selecţie în cadrul gridului for(int i=0;i<4;i++) rez->Add(GD1->GetCellValue(GD1->GetSelectedRows()[0],i)); this->Close(); }//--------------------------------------------------------------------void iFNOM::ren_Nom(wxCommandEvent& event) { this->Close(); }//------------------------------------------------------------------- void iFNOM::add_Lin(wxCommandEvent& event){ GD1->AppendRows(); GD1->Fit(); } //------------------------------------------------------------------ void iFNOM::del_Lin(wxCommandEvent& event){ wxMessageDialog *x = new wxMessageDialog(this,wxT("Doriţi ştergerea liniei curente?"), _(""),wxYES_NO|wxICON_QUESTION); x->SetYesNoLabels(_("&Nu"),_("&Da"));if(x->ShowModal() == wxID_NO) {GD1->DeleteRows(GD1->GetGridCursorRow(),1);GD1->Fit(); }} //--------------------------------------------------------------void iFNOM::ordoneaza(wxCommandEvent& event){ afis_NOM();}

☑ Fişierul pentru clasa iFSELST#include <wx/clipbrd.h> //fişierul selst.cpp#include "selst.h"#include "fnom.h"iFSELST::iFSELST(wxWindow* parent, wxString achBP1, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) :

241

Page 243: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

wxDialog(parent, id, title, pos, size, style){this->SetBackgroundColour(wxColour(228, 243, 235));//setare culoare fundal wxBoxSizer* s1; s1 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s2; s2 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* s3; s3 = new wxBoxSizer(wxVERTICAL); t8 = new wxStaticText(this,wxID_ANY,wxT("AFIŞARE"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTRE); t8->Wrap(-1); s3->Add(t8, 0, wxALIGN_CENTER|wxALL, 5); wxString cblAChoices[] = { wxT("ID Code"), wxT("Ref Com"), wxT("Ref Teh."), wxT("Descriere"), wxT("Furnizor"), wxT("Data IN"), wxT("SerialNo"), wxT("Status"), wxT("Comandă (PO)"), wxT("Depozit"), wxT("Amplasament"), wxT("ID") }; int cblANChoices = sizeof(cblAChoices) / sizeof(wxString); cblA=new wxCheckListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, cblANChoices, cblAChoices,0); cblA->SetBackgroundColour(wxColour(252, 253, 223)); s3->Add(cblA, 0, wxALL, 5); s2->Add(s3, 0, wxEXPAND, 5); wxBoxSizer* s4; s4 = new wxBoxSizer(wxVERTICAL); t9 = new wxStaticText(this, wxID_ANY, wxT("SELECŢIE"), wxDefaultPosition, wxDefaultSize,0); t9->Wrap(-1); s4->Add(t9, 0, wxALIGN_CENTER|wxALL, 5); wxString cblSChoices[] = { wxT("ID Code"), wxT("Ref Com"), wxT("Ref Teh."), wxT("Descriere"), wxT("Furnizor"), wxT("Data IN"), wxT("SerialNo"), wxT("Staus"), wxT("Comandă (PO)"), wxT("Depozit"), wxT("Amplasament"), wxT("ID") }; int cblSNChoices = sizeof(cblSChoices) / sizeof(wxString); cblS=new wxCheckListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, cblSNChoices, cblSChoices,0); cblS->SetBackgroundColour(wxColour(231, 238, 254)); s4->Add(cblS, 1, wxALL|wxEXPAND, 5); s2->Add(s4, 1, wxEXPAND, 5); wxBoxSizer* s5; s5 = new wxBoxSizer(wxVERTICAL); CBP = new wxChoicebook(this,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxCHB_DEFAULT); CBP->SetBackgroundColour(wxColour(217, 234, 215)); p1 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); p1->SetBackgroundColour(wxColour(231, 245, 226)); wxBoxSizer* s6; s6 = new wxBoxSizer(wxVERTICAL); bNom =new wxButton(p1, wxID_ANY, wxT("NOMENCLATOR"), wxDefaultPosition, wxDefaultSize, 0); s6->Add(bNom, 0,wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL,5); p1->SetSizer(s6); p1->Layout(); s6->Fit(p1); CBP->AddPage(p1, wxT("ID Code/ RefCom/ RefTeh/ Descriere"), false); p2 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s7; s7 = new wxBoxSizer(wxHORIZONTAL); t1 = new wxStaticText(p2, wxID_ANY, wxT("="), wxDefaultPosition, wxDefaultSize, 0); t1->Wrap(-1); s7->Add(t1, 0, wxALL, 5); eSupplier=new wxTextCtrl(p2, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); s7->Add(eSupplier, 1, wxALL, 5);bRetFurnizor=new wxButton(p2, wxID_ANY, wxT("Reţine"),wxDefaultPosition,wxSize(60,-1),0); s7->Add(bRetFurnizor, 0, wxALL, 5); p2->SetSizer(s7); p2->Layout(); s7->Fit(p2); CBP->AddPage(p2, wxT("Furnizor"), false);

242

Page 244: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

p3 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); p3->SetBackgroundColour(wxColour(217, 244, 225)); wxBoxSizer* s8; s8 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s9; s9 = new wxBoxSizer(wxHORIZONTAL); eData1= new wxDatePickerCtrl(p3, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, 0); s9->Add(eData1, 0, wxALL, 5); t2 = new wxStaticText(p3, wxID_ANY, wxT(">->"), wxDefaultPosition, wxDefaultSize, 0); t2->Wrap(-1); s9->Add(t2, 0, wxALL, 5); eData2=new wxDatePickerCtrl(p3, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize,0); s9->Add(eData2, 0, wxALL, 5); s8->Add(s9, 0, wxEXPAND, 5); bRetData = new wxButton(p3, wxID_ANY, wxT("Reţine"), wxDefaultPosition, wxSize(60,-1), 0); s8->Add(bRetData, 0, wxALIGN_CENTER|wxALL, 5); p3->SetSizer(s8); p3->Layout(); s8->Fit(p3); CBP->AddPage(p3, wxT("Data IN"), false); p4 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxFlexGridSizer* s10; s10 = new wxFlexGridSizer(0, 2, 0, 0); s10->SetFlexibleDirection(wxBOTH); s10->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); t3 = new wxStaticText(p4, wxID_ANY, wxT("Depozit"), wxDefaultPosition, wxDefaultSize, 0); t3->Wrap(-1); s10->Add(t3, 0, wxALL, 5);cbDep=new wxComboBox(p4, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,0, NULL,0); s10->Add(cbDep, 0, wxALL, 5);t4=new wxStaticText(p4, wxID_ANY, wxT("Amplasament"), wxDefaultPosition, wxDefaultSize, 0); t4->Wrap(-1); s10->Add(t4, 0, wxALL, 5);cbAmpl=new wxComboBox(p4, wxID_ANY, wxEmptyString,wxDefaultPosition,wxDefaultSize,0,NULL,0); s10->Add(cbAmpl,0,wxALL,5); s10->Add(0, 0, 1, wxEXPAND, 5); bRetDepAmp=new wxButton(p4, wxID_ANY, wxT("Reţine"), wxDefaultPosition, wxDefaultSize, 0); s10->Add(bRetDepAmp,0,wxALL,5); p4->SetSizer(s10); p4->Layout(); s10->Fit(p4); CBP->AddPage(p4, wxT("Depozit/ Amplasament"), false); p5 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s11; s11 = new wxBoxSizer(wxHORIZONTAL); t5 = new wxStaticText(p5, wxID_ANY, wxT("="), wxDefaultPosition, wxDefaultSize, 0); t5->Wrap(-1); s11->Add(t5, 0, wxALL, 5); ePO = new wxTextCtrl(p5, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); s11->Add(ePO, 1, wxALL, 5); bRetPO=new wxButton(p5, wxID_ANY, wxT("Reţine"), wxDefaultPosition, wxSize(60,-1), 0); s11->Add(bRetPO,0,wxALL,5); p5->SetSizer(s11); p5->Layout(); s11->Fit(p5); CBP->AddPage(p5, wxT("Comandă (PO)"), false); p6 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s12; s12 = new wxBoxSizer(wxHORIZONTAL); t6 = new wxStaticText(p6, wxID_ANY, wxT("="), wxDefaultPosition, wxDefaultSize,0); t6->Wrap(-1); s12->Add(t6, 0, wxALL, 5); wxString cbStatusChoices[] = { wxT("Funcţional"), wxT("Defect"), wxT("Rebut"), wxT("Incert"), wxT("Casare") }; int cbStatusNChoices = sizeof(cbStatusChoices) / sizeof(wxString);cbStatus=new

243

Page 245: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

wxChoice(p6,wxID_ANY,wxDefaultPosition,wxDefaultSize,cbStatusNChoices,cbStatusChoices,0); cbStatus->SetSelection(2); s12->Add(cbStatus, 0, wxALL, 5); bRetStatus=new wxButton(p6, wxID_ANY, wxT("Reţine"), wxDefaultPosition, wxSize(60,-1), 0); s12->Add(bRetStatus,0,wxALL,5);p6->SetSizer(s12); p6->Layout();s12->Fit(p6); CBP->AddPage(p6, wxT("STATUS"), true); p7 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s13; s13 = new wxBoxSizer(wxHORIZONTAL); t7 = new wxStaticText(p7, wxID_ANY, wxT("="), wxDefaultPosition, wxDefaultSize, 0); t7->Wrap(-1); s13->Add(t7, 0, wxALL, 5); eSerialNo=new wxTextCtrl(p7, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); s13->Add(eSerialNo, 1, wxALL, 5);bRetSerialNo=new wxButton(p7, wxID_ANY, wxT("Reţine"), wxDefaultPosition, wxSize(60,-1),0); s13->Add(bRetSerialNo, 0, wxALL, 5); p7->SetSizer(s13); p7->Layout(); s13->Fit(p7); CBP->AddPage(p7, wxT("SerialNo"), false); p10 = new wxPanel(CBP, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s16; s16 = new wxBoxSizer(wxHORIZONTAL); t10 = new wxStaticText(p10, wxID_ANY, wxT("="), wxDefaultPosition, wxDefaultSize, 0); t10->Wrap(-1); s16->Add(t10, 0, wxALL, 5); eID = new wxTextCtrl(p10, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); s16->Add(eID, 1, wxALL, 5); bRetID = new wxButton(p10, wxID_ANY, wxT("Reţine"), wxDefaultPosition, wxSize(60,-1), 0); s16->Add(bRetID, 0, wxALL, 5); p10->SetSizer(s16); p10->Layout();s16->Fit(p10); CBP->AddPage(p10, wxT("ID"), false); s5->Add(CBP, 1, wxEXPAND | wxALL, 5); wxBoxSizer* s35; s35 = new wxBoxSizer(wxHORIZONTAL); t13=new wxStaticText(this, wxID_ANY, wxT("Sortare:"), wxDefaultPosition,wxDefaultSize, 0); t13->Wrap(-1); s35->Add(t13, 0, wxALL, 5); wxString cbOrdChoices[] = { wxT("ID Code"), wxT("Ref Com"), wxT("Ref Teh."), wxT("Descriere"), wxT("Furnizor"), wxT("Data IN"), wxT("SerialNo"), wxT("Depozit"), wxT("Status"), wxT("Amplasament"), wxT("Comandă (PO)"), wxT("ID"), wxT("Neordonat") }; int cbOrdNChoices = sizeof(cbOrdChoices) / sizeof(wxString); cbOrd = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, cbOrdNChoices, cbOrdChoices, 0); cbOrd->SetSelection(12); s35->Add(cbOrd, 1, wxALL, 5); bCopiaza = new wxButton(this,wxID_ANY,wxT("Copiază"),wxDefaultPosition, wxSize(-1,-1),wxBU_EXACTFIT); s35->Add(bCopiaza, 0, wxALL, 5); s5->Add(s35, 0, wxEXPAND, 5); bQ =new wxButton(this, wxID_ANY,wxT("INTEROGARE STOC"), wxDefaultPosition,wxDefaultSize, 0); bQ->SetFont(wxFont(13, 70, 90, 92, false, wxEmptyString)); bQ->SetForegroundColour(wxColour(109, 143, 71)); s5->Add(bQ, 0, wxALL|wxEXPAND, 5); s2->Add(s5, 0, wxEXPAND, 5); s1->Add(s2, 0, wxEXPAND, 5); GD1 = new wxGrid(this, wxID_ANY, wxDefaultPosition, wxSize(-1,150), wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE); GD1->CreateGrid(0,0); GD1->EnableEditing(true);

244

Page 246: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

GD1->EnableGridLines(true); GD1->EnableDragGridSize(false); GD1->SetMargins(0, 0); GD1->AutoSizeColumns(); GD1->EnableDragColMove(false); GD1->EnableDragColSize(true); GD1->SetColLabelSize(20); GD1->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD1->AutoSizeRows(); GD1->EnableDragRowSize(true); GD1->SetRowLabelSize(80); GD1->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD1->SetDefaultCellBackgroundColour(wxColour(226, 249, 250)); GD1->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP); GD1->SetBackgroundColour(wxColour(236, 250, 251)); s1->Add(GD1, 1, wxALL|wxEXPAND, 5); pSelBP = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* s17; s17 = new wxBoxSizer(wxVERTICAL); P_QtyPrep = new wxPanel(pSelBP,wxID_ANY, wxPoint(-1,-1), wxSize(-1,40), wxTAB_TRAVERSAL); P_QtyPrep->SetBackgroundColour(wxColour(247, 244, 232)); P_QtyPrep->SetMinSize(wxSize(-1,40)); wxBoxSizer* s14; s14 = new wxBoxSizer(wxHORIZONTAL); s14->Add(0, 0, 1, wxALL|wxEXPAND, 5); t12 = new wxStaticText(P_QtyPrep,wxID_ANY,wxT("Qty Preparată:"),wxDefaultPosition, wxDefaultSize,0); t12->Wrap(-1); s14->Add(t12, 0, wxALL, 5); eQtyPrep = new wxTextCtrl(P_QtyPrep, wxID_ANY, wxT("1"), wxDefaultPosition, wxSize(30,-1), 0); s14->Add(eQtyPrep, 0, wxALL, 5); bRezerva = new wxButton(P_QtyPrep,wxID_ANY,wxT("Rezervă !"),wxDefaultPosition, wxSize(-1,-1),0); s14->Add(bRezerva, 0, wxALL, 5); s14->Add(0,0,1,wxALL|wxEXPAND,5); P_QtyPrep->SetSizer(s14);P_QtyPrep->Layout(); s17->Add(P_QtyPrep,0,wxALL|wxEXPAND,5); GD2 = new wxGrid(pSelBP,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE); GD2->CreateGrid(0,0); GD2->EnableEditing(true); GD2->EnableGridLines(true); GD2->EnableDragGridSize(false);GD2->SetMargins(0, 0); GD2->AutoSizeColumns(); GD2->EnableDragColMove(false); GD2->EnableDragColSize(true); GD2->SetColLabelSize(20); GD2->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD2->AutoSizeRows(); GD2->EnableDragRowSize(true); GD2->SetRowLabelSize(80); GD2->SetRowLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE); GD2->SetDefaultCellBackgroundColour(wxColour(247, 224, 223)); GD2->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP); GD2->SetMinSize(wxSize(-1,200)); s17->Add(GD2,1,wxALL|wxEXPAND,5); p9 = new wxPanel(pSelBP,wxID_ANY,wxPoint(-1,-1),wxSize(-1,40),wxTAB_TRAVERSAL); p9->SetBackgroundColour(wxColour(243, 245, 220)); wxBoxSizer* s15; s15 = new wxBoxSizer(wxHORIZONTAL); bDelLin=new wxButton(p9, wxID_ANY, wxT("Şterge linia"), wxDefaultPosition, wxDefaultSize,0); s15->Add(bDelLin, 0, wxALL, 5); s15->Add(0, 0, 1, wxEXPAND, 5); bBP = new wxButton(p9,wxID_ANY,wxT("OK"),wxDefaultPosition,wxDefaultSize,0); bBP->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(),70,90,92,false, wxEmptyString));

245

Page 247: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

bBP->SetForegroundColour(wxColour(128, 49, 72)); bBP->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); s15->Add(bBP, 0, wxALL, 5); p9->SetSizer(s15); p9->Layout(); s17->Add(p9, 0, wxALL|wxEXPAND, 5); pSelBP->SetSizer(s17); pSelBP->Layout(); s17->Fit(pSelBP); s1->Add(pSelBP,1,wxEXPAND|wxALL,5); this->SetSizer(s1);this->Layout();this->Centre(wxBOTH);bNom->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::selNom), NULL, this);bRetFurnizor->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineFurnizor), NULL, this); bRetData->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineData), NULL, this);cbDep->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(iFSELST::selDep), NULL, this);bRetDepAmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineDepAmp), NULL, this); bRetPO->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retinePO), NULL, this);bRetStatus->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineSTATUS),NULL,this);bRetSerialNo->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineSerialNo), NULL, this); bRetID->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineID), NULL, this);bCopiaza->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::copiaza), NULL, this);bQ->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::qST), NULL, this);bRezerva->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::rezervaQtySelST), NULL, this); bDelLin->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::delLinSelST), NULL, this);bBP->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::transferBP), NULL, this);const char* achN[] = {"inx.idcode", "refcom", "refteh", "descr", "supplier", "datain", "serialno","status","po", "stx.dep","stx.ampl","stx.id"};const char* achT[] = {"C","C","C","A","C","D2","C","C","C","C","C","C"};wxArrayString a; achBP=achBP1; for(unsigned int i=0;i<cblS->GetCount();i++) {listaN.Add(achN[i]); listaT.Add(achT[i]);}aListaInit=cblS->GetStrings();for(unsigned int j=0;j<cblS->GetCount();j++) { val1.Add("NULL"); val2.Add("NULL");}cx_grid1=new lxGrid(GD1,_("q_tmp_st"),a);if(achBP != _("#")) cx_grid2=new lxGrid(GD2,_("tmpselst"),a); else pSelBP->Hide(); cx_dep = new lxComboBox(cbDep, _("DROP TABLE IF EXISTS tmpacc; CREATE TEMP TABLE tmpacc AS SELECT dep[s] FROM (select acces.*, generate_subscripts(dep,1) as s from logx.acces)par; SELECT DISTINCT loc.dep FROM logx.loc,tmpacc WHERE loc.dep=tmpacc.dep ORDER BY loc.dep;"));//lista ptr.amplasament va cuprinde selecţia pentru primul depozitcx_ampl = new lxComboBox(cbAmpl,_("SELECT DISTINCT ampl FROM logx.loc WHERE dep = (SELECT DISTINCT dep FROM logx.loc ORDER BY dep LIMIT 1) ORDER BY ampl;"));}//-------------------------------------------------------------------iFSELST::~iFSELST() {bNom->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::selNom), NULL, this);bRetFurnizor->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineFurnizor), NULL, this);

246

Page 248: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

bRetData->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineData), NULL, this);cbDep->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(iFSELST::selDep), NULL, this);bRetDepAmp->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineDepAmp), NULL, this); bRetPO->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retinePO), NULL, this);bRetStatus->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineSTATUS), NULL, this); bRetSerialNo->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineSerialNo), NULL, this); bRetID->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::retineID), NULL, this);bCopiaza->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::copiaza), NULL, this);bQ->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::qST), NULL, this);bRezerva->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::rezervaQtySelST), NULL, this);bDelLin->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::delLinSelST), NULL, this);bBP->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFSELST::transferBP), NULL, this);}//-----------------------------------------------------------------//FUNCŢIA DE INTEROGARE A STOCULUIvoid iFSELST::qST(wxCommandEvent& event){wxString achListaCampuri, achTipCampuri, achAfisare, achSelectie, achVal1, achVal2, achOrd, achR, ach;wxArrayInt b;//selecţie obligatorie ptr. Dep,Ampl,IDif(achBP!=_("#")) for(int j=0;j<3;j++) cblA->Check(cblA->GetCount()-1-j); cblA->GetCheckedItems(b);for(unsigned int j=0;j<12;j++) {if(!achListaCampuri.IsEmpty()) achListaCampuri=achListaCampuri+_(","); achListaCampuri=achListaCampuri+_("'")+listaN[j]+_("'"); if(!achTipCampuri.IsEmpty()) achTipCampuri = achTipCampuri+_(","); achTipCampuri=achTipCampuri+_("'")+listaT[j]+_("'"); if(!achAfisare.IsEmpty()) achAfisare=achAfisare+_(","); if(cblA->IsChecked(j)) achAfisare=achAfisare+_("'t'"); else achAfisare=achAfisare+_("'f'"); if(!achSelectie.IsEmpty()) achSelectie=achSelectie+_(","); if(cblS->IsChecked(j)) achSelectie=achSelectie+_("'t'"); else achSelectie=achSelectie+_("'f'"); if(j) achVal1=achVal1+_(","); achVal1=achVal1+val1[j]; if(j) achVal2=achVal2+_(","); achVal2=achVal2+val2[j]; if(cbOrd->GetSelection()<12) achOrd=listaN[cbOrd->GetSelection()]; else achOrd=_("---"); }//endforif(achBP==_("#")) ach = _("ST"); else ach = _("STL"); //dacă interogarea este pentru rezervare (STL -stoc cu qtzdisp > 0if((achR = lxCtrl::cda(_("SELECT logx.q_x('")+ach+_("'::text, 12::smallint, ARRAY[") + achListaCampuri+_("]::text[], ARRAY[") + achTipCampuri + _("]::text[], ARRAY[") + achAfisare + _("]::boolean[], ARRAY[") + achSelectie +_("]::boolean[], ARRAY[") + achVal1+_("]::text[], ARRAY[") + achVal2+_("]::text[], '")+achOrd+_("'::text);")))!=_("OK")) wxMessageBox(achR);GD1->SetRowLabelSize(20);

247

Page 249: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

cx_grid1->preluareVarColRow(); if(achBP != _("#")) //dacă este selecţie pentru BPlxCtrl::cda(_("DROP TABLE IF EXISTS tmpselst;CREATE TEMPORARY TABLE tmpselst as SELECT _bp.nrbp, _bp.qtyrez, inx.idcode, nom.descr, _bp.id, _bp.dep, _bp.ampl FROM logx.inx, logx.nom, logx._bp WHERE inx.idcode=nom.idcode AND _bp.id= inx.id AND _bp.nrbp=")+achBP+_(" ;"));}//------------------------------------------------------------------// AFIŞARE PANOU SELECŢIE --FILTRE void iFSELST::afis_sel()//afişare panou selecţie - filtrare{wxString ach;wxArrayString aLista;aLista=aListaInit; cblS->Clear();for(unsigned int j=0;j<aLista.GetCount();j++) {ach = aLista[j]; if(val1[j]!=_("NULL")) //diferit de ŞIRUL ce conţine caracterele N U L L! {if(val2[j]!=_("NULL") && (listaT[j]==_("N2") || listaT[j]==_("D2"))) ach = val1[j] + wxT(" ≤ ") + aLista[j] + wxT(" ≤ ") +val2[j]; if(val2[j]==_("NULL") && (listaT[j]==_("N1") || listaT[j]==_("D1"))) ach= aLista[j] + _(" = ") + val1[j]; if(val2[j]==_("NULL") && listaT[j]==_("C")) ach= aLista[j] + wxT(" ") + val1[j]; ≡ if(val2[j]==_("NULL") && listaT[j]==_("A")) ach= val1[j] +wxT(" є ") + aLista[j] ; if(val2[j]==_("NULL") && listaT[j]==_("B")) ach= aLista[j] + _(" : ") + val1[j]; } //endif cblS->Append(ach); } //endfor}//------------------------------------------------------------------//Selecţie NOMENCLATORvoid iFSELST::selNom(wxCommandEvent& event){wxArrayString* rez=new wxArrayString; iFNOM* x; x=new iFNOM(this,rez); x->ShowModal(); if(rez->GetCount()<1) {wxMessageBox("Nu a fost selectat nimic !"); return;} for(int j=0; j<4; j++) val1[j]=_("'")+rez->Item(j)+_("'");afis_sel();}//Şterge linia selectatăvoid iFSELST::delLinSelST(wxCommandEvent& event) { wxArrayString achS;//dacă există selecţie în cadrul griduluiif(!GD2->IsSelection()) {wxMessageBox(wxT("Selectaţi linia!")); return;} for(int j=0; j<GD2->GetNumberCols(); j++) achS.Add(GD2->GetCellValue(GD2->GetSelectedRows()[0],j));

248

Page 250: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

wxString ach = lxCtrl::cda(_("SELECT logx.del_bp_id(")+ achBP+ _("::int,'")+achS[achS.GetCount()-1]+_("'::text,'")+achS[achS.GetCount()-3]+_("'::text,'")+achS[achS.GetCount()-2]+_("'::text,")+eQtyPrep->GetValue()+_("::int);"));if(ach != _("OK")) { wxMessageBox(ach); return;}if(achBP != _("#")) //dacă este selecţie pentru BPlxCtrl::cda(_("DROP TABLE IF EXISTS tmpselst; CREATE TEMPORARY TABLE tmpselst as SELECT _bp.nrbp, _bp.qtyrez, inx.idcode, nom.descr, _bp.id, _bp.dep, _bp.ampl FROM logx.inx, logx.nom, logx._bp WHERE inx.idcode=nom.idcode AND _bp.id= inx.id AND _bp.nrbp=")+achBP+_(" ;"));cx_grid2->preluareVarColRow(); GD2->Refresh();}//--------------------------------------------------------------------//Rezervă cantitate din stocvoid iFSELST::rezervaQtySelST(wxCommandEvent& event){wxArrayString achS;if(!GD1->IsSelection()) {wxMessageBox(wxT("Selectaţi linia!")); return;} //dacă există selecţie în cadrul griduluifor(int j=0; j<GD1->GetNumberCols(); j++) achS.Add(GD1->GetCellValue(GD1->GetSelectedRows()[0],j));if(eQtyPrep->IsEmpty()) {wxMessageBox(wxT("Completaţi cantitatea!")); return;} wxString ach = lxCtrl::cda(_("SELECT logx.add_bp_id(")+ achBP+ _("::int,'")+achS[achS.GetCount()-1]+_("'::text,'")+achS[achS.GetCount()-3]+_("'::text,'")+achS[achS.GetCount()-2]+_("'::text,")+eQtyPrep->GetValue()+_("::int);"));if(ach != _("OK")) { wxMessageBox(ach); return;}if(achBP != _("#")) //dacă este selecţie pentru BP lxCtrl::cda(_("DROP TABLE IF EXISTS tmpselst; CREATE TEMPORARY TABLE tmpselst as SELECT _bp.nrbp, _bp.qtyrez, inx.idcode, nom.descr, _bp.id, _bp.dep, _bp.ampl FROM logx.inx, logx.nom, logx._bp WHERE inx.idcode = nom.idcode AND _bp.id = inx.id AND _bp.nrbp =")+achBP+_(" ;"));GD1->DeleteRows(GD1->GetSelectedRows()[0]);cx_grid2->preluareVarColRow(); GD1->Refresh(); GD2->Refresh();}//-------------------------------------------------------------------//Închide fereastra de selecţie din stocvoid iFSELST::transferBP(wxCommandEvent& event){ lxCtrl::cda(_("DELETE FROM tmpselst USING logx._bp WHERE _bp.nrbp=tmpselst.nrbp AND _bp.id=tmpselst.id AND _bp.dep=tmpselst.dep AND _bp.ampl=tmpselst.ampl;"));this->Close();}//---------------------------------------------------------------//Schimbă lista cu amplasamentele în funcţie de depozitul selectatvoid iFSELST::selDep(wxCommandEvent& event) {cx_ampl->rdLista(_("SELECT DISTINCT ampl::text FROM logx.loc WHERE dep='")+cx_dep->getSel()+("' ORDER BY ampl;")); }

249

Page 251: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

//------------------------------------------------------------------//selectează depozitul şi amplasamentul curentvoid iFSELST::retineDepAmp(wxCommandEvent& event) { for(unsigned int j=0;j<listaN.GetCount();j++) { if(listaN[j]==_("stx.dep")) val1[j]=_("'")+cx_dep->getSel()+_("'"); if(listaN[j]==_("stx.ampl")) val1[j]=_("'")+cx_ampl->getSel()+_("'"); } afis_sel();}//--------------------------------------------------------------------//selectează POvoid iFSELST::retinePO(wxCommandEvent& event) { for(unsigned int j=0;j<listaN.GetCount();j++) { if(listaN[j]==_("po") && !ePO->GetValue().IsEmpty()) val1[j]=_("'")+ePO->GetValue()+_("'"); } afis_sel();}//----------------------------------------------------------------//selectează furnizorvoid iFSELST::retineFurnizor(wxCommandEvent& event) { for(unsigned int j=0;j<listaN.GetCount();j++) { if(listaN[j]==_("supplier") && !eSupplier->GetValue().IsEmpty()) val1[j]=_("'")+eSupplier->GetValue()+_("'"); } afis_sel(); }//------------------------------------------------------------------//selectează STATUSvoid iFSELST::retineSTATUS(wxCommandEvent& event) { for(unsigned int j=0;j<listaN.GetCount();j++) { if(listaN[j]==_("status") && !cbStatus->GetStringSelection().IsEmpty()) val1[j]=_("'")+cbStatus->GetStringSelection()+_("'"); } afis_sel(); }//-----------------------------------------------------------------//selectează SerialNovoid iFSELST::retineSerialNo(wxCommandEvent& event) { for(unsigned int j=0;j<listaN.GetCount();j++) { if(listaN[j]==_("serialno") && !eSerialNo->GetValue().IsEmpty()) val1[j]=_("'")+eSerialNo->GetValue()+_("'"); } afis_sel(); }//-------------------------------------------------------------------//selectează ID void iFSELST::retineID(wxCommandEvent& event) { for(unsigned int j=0;j<listaN.GetCount();j++)

250

Page 252: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

{ if(listaN[j]==_("stx.id") && !eID->GetValue().IsEmpty()) val1[j]=_("'")+eID->GetValue()+_("'"); } afis_sel();}//-------------------------------------------------------------------//selectează filtru data calendaristică de intrare void iFSELST::retineData(wxCommandEvent& event) { for(unsigned int j=0;j<listaN.GetCount();j++) {if(listaN[j]==_("datain")) val1[j]=_("'")+eData1->GetValue().FormatISODate()+_("'"); if(listaN[j]==_("datain")) val2[j]=_("'")+eData2->GetValue().FormatISODate()+_("'"); }afis_sel();}//-------------------------------------------------------------------//copiază datele din GRID ÎN CLIPBOARD în vederea exportuluivoid iFSELST::copiaza(wxCommandEvent& event) { wxString ach,dx; for(int j=0;j<GD1->GetNumberCols();j++) { if(j) dx=dx+_(",");

dx = dx + GD1->GetColLabelValue(j); } for(int i=0;i<GD1->GetNumberRows();i++)

{ dx=dx+_("\n"); for(int j=0;j<GD1->GetNumberCols();j++) { if(j) dx=dx+_(","); dx=dx+GD1->GetCellValue(i,j); }}

if (wxTheClipboard->Open()) {wxTheClipboard->SetData(new wxTextDataObject(dx)); wxTheClipboard->Close(); wxMessageBox(_("Au fost copiate "+ach.FromDouble(GD1->GetNumberRows())) + _(" linii !")); } /*funcţia se poate extinde prin testarea existenţei virgulei în şir şi punerea între ghilimele a acestor şiruri etc*/}

☑ Fişierul pentru clasele iFPB şi LogXApp (main.cpp)#include "main.h"#include "fei.h"#include "fnom.h"#include "selst.h"#include "febp.h"#include "facc.h"#include "lx.h"PGconn *lxCtrl::conexiune0;

251

Page 253: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

ANEXE

IMPLEMENT_APP(LogXApp);bool iFACC::accesX=false;//-------------------------------------------------------------------bool LogXApp::OnInit(){ lxCtrl::conexiune0=NULL;/*conexiunea iniţială pentru verificarea parolei de acces - se conectează cu parola la nivel de aplicaţie*/lxCtrl::conectare(_("picdb"),_("logx_sw"),_("lilo"),_("localhost"),_("5435"));/* Prin "return true" se asigură menţinerea în aplicaţie în buclele de citire a evenimentelor şi de tratare a acestora*/ (new iFACC(NULL))->ShowModal(); if(iFACC::accesX) {(new iFPB(NULL))->Show(); return true;} //este lansată fereastra cu panoul cu butoane, nu este fereastră modală, else return false;}//-------------------------------------------------------------------iFPB::iFPB(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style): wxFrame(parent, id, title, pos, size, style){ this->SetSizeHints(wxDefaultSize, wxDefaultSize); this->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(),70,90,90,false, wxEmptyString)); this->SetBackgroundColour(wxColour(244, 244, 244)); wxBoxSizer* s1; s1 = new wxBoxSizer(wxVERTICAL); t1 = new wxStaticText(this, wxID_ANY, wxT("LogX"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); t1->Wrap(-1); t1->SetFont(wxFont(18,72,90,92,false,wxEmptyString)); t1->SetHelpText(wxT("Exemplu pentru o aplicaţie simplă de gestiune a stocurilor.")); s1->Add(t1, 0, wxALIGN_CENTER|wxALL, 5); wxBoxSizer* s2; s2 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* s3; s3 = new wxBoxSizer(wxVERTICAL); t2 = new wxStaticText(this,wxID_ANY,wxT("EDITARE"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); t2->Wrap(-1); t2->SetFont(wxFont(12,75,90,92,false,wxEmptyString)); s3->Add(t2, 0, wxALIGN_CENTER|wxALL, 5); be1 = new wxButton(this, wxID_ANY, wxT("INTRĂRI"), wxDefaultPosition, wxDefaultSize, 0); be1->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(),70,90,90,false, wxEmptyString)); s3->Add(be1, 0, wxALL|wxEXPAND, 5); be2 = new wxButton(this, wxID_ANY, wxT("LIVRĂRI"), wxDefaultPosition, wxDefaultSize, 0); be2->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(),70,90,90,false, wxEmptyString)); s3->Add(be2, 0, wxALL|wxEXPAND, 5); be3 = new wxButton(this, wxID_ANY, wxT("TRANSFER"), wxDefaultPosition, wxDefaultSize, 0); be3->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(),70,90,90,false, wxEmptyString)); be3->Enable(false); s3->Add(be3, 0, wxALL|wxEXPAND, 5); be4 = new wxButton(this,wxID_ANY,wxT("NOMENCLATOR"),wxDefaultPosition, wxDefaultSize, 0); s3->Add(be4, 0, wxALL|wxEXPAND, 5); s2->Add(s3, 1, wxEXPAND, 5); wxBoxSizer* s4; s4 = new wxBoxSizer(wxVERTICAL); t3 = new wxStaticText(this,wxID_ANY,wxT("RAPOARTE"),wxDefaultPosition, wxDefaultSize,

252

Page 254: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

6.Codul sursă pentru aplicaţia LogX

wxALIGN_CENTRE); t3->Wrap(-1); t3->SetFont(wxFont(12,75,90,92,false,wxEmptyString)); s4->Add(t3, 0, wxALIGN_CENTER|wxALL, 5); br1 = new wxButton(this, wxID_ANY, wxT("INTRĂRI"), wxDefaultPosition, wxDefaultSize, 0); br1->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString)); br1->Enable(false); s4->Add(br1, 0, wxALL|wxEXPAND, 5); br2=new wxButton(this, wxID_ANY, wxT("LIVRĂRI"), wxDefaultPosition, wxDefaultSize, 0); br2->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString)); br2->Enable(false); s4->Add(br2, 0, wxALL|wxEXPAND, 5); br3=new wxButton(this, wxID_ANY, wxT("TRANSFER"), wxDefaultPosition, wxDefaultSize, 0); br3->Enable(false); s4->Add(br3, 0, wxALL|wxEXPAND, 5); br4 = new wxButton(this, wxID_ANY, wxT("STOC"), wxDefaultPosition, wxDefaultSize, 0); s4->Add(br4, 0, wxALL|wxEXPAND, 5); s2->Add(s4, 1, wxEXPAND, 5); s1->Add(s2, 1, wxEXPAND, 5); this->SetSizer(s1); this->Layout();// Evenimente pentru conectarebe1->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_be1), NULL, this);be2->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_be2), NULL, this);be4->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_be4), NULL, this);br4->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_br4), NULL, this);}//-----------------------------------------------------------------iFPB::~iFPB(){ lxCtrl::deconectare();be1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_be1), NULL, this);be2->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_be2), NULL, this);be4->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_be4), NULL, this);br4->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(iFPB::apasa_br4), NULL, this);}//------------------------------------------------------------------void iFPB::apasa_be1(wxCommandEvent& event){ (new iFEI(this))->ShowModal(); }//------------------------------------------------------------------void iFPB::apasa_be4(wxCommandEvent& event){ (new iFNOM(this,NULL))->ShowModal(); }//-----------------------------------------------------------------void iFPB::apasa_br4(wxCommandEvent& event){ (new iFSELST(this,_("#")))->ShowModal(); }//--------------------------------------------------------------------void iFPB::apasa_be2(wxCommandEvent& event){(new iFEBP(this))->ShowModal(); }

253

Page 255: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++

Bibliografie

Bibliografie

[1] Kacsó, A., Kacsó, D, Turbo C, Tehnici de programare, Editura MicroInformatica, Cluj, 1992.

[2] Somnea, D., Turturea, D., Introducere în C++. Programarea orientată pe obiecte, Editura Tehnica, Bucureşti, 1993.

[3] www.postgresql.org.

[4] http://en.cppreference.com/w/

[5] http://www.delorie.com/djgpp/doc/libc/

[6] http://codelite.org/

[7] http://libharu.org/

[8] http://sourceforge.net/projects/wxformbuilder/

254

Page 256: Dezvoltarea aplicatiilor de baze de date cu interfata grafica in C++