Skip to content

Commit b85ca6a

Browse files
Added README for Rust & refactored other README's
1 parent 71fcd7d commit b85ca6a

6 files changed

Lines changed: 287 additions & 105 deletions

File tree

C-method/README.md

Lines changed: 40 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# AC SQL
22

33
În cadrul acestui proiect am implementat o bază de date pentru gestionarea informațiilor
4-
despre studenți, materii și relațiile dintre acestea dintr-o facultate.
4+
despre studenți, materii și relațiile dintre acestea dintr-o facultate.
55

66
Baza de date este administrată printr-un sistem de interogare și actualizare denumit **AC SQL**,
77
care include criptarea memoriei cu un algoritm simplificat de tip **CBC**.
88

9+
10+
911
## Structuri de Date folosite
1012

1113
Baza de date **secretariat** conține:
@@ -27,7 +29,7 @@ struct secretariat {
2729
```
2830

2931
### Intrare din tabela **studenti**
30-
Câmpuri: ID unic, nume complet, an de studiu, statut (`buget` / `taxă`), medie generală.
32+
Câmpuri: ID unic, nume complet, an de studiu, statut (`buget` / `taxă`), medie generală.
3133

3234
```c
3335
struct student {
@@ -51,7 +53,7 @@ struct materie {
5153
```
5254

5355
### Intrare din tabela **inrolari**
54-
Câmpuri: ID student, ID materie, note (laborator, parțial, final).
56+
Câmpuri: ID student, ID materie, note (laborator, parțial, final).
5557

5658
```c
5759
struct inrolare {
@@ -67,32 +69,17 @@ Funcția `citeste_secretariat` încarcă baza de date în memorie dintr-un fiși
6769
- numele tabelelor sunt scrise între paranteze drepte (`[STUDENTI]`, `[MATERII]`, `[INROLARI]`)
6870
- valorile din fiecare intrare sunt separate prin `,`
6971

70-
```txt
71-
[STUDENTI]
72-
0, Andrei Popescu, 2, b
73-
1, Ioana Ionescu, 1, t
74-
75-
[MATERII]
76-
0, PCLP, Radu Bran
77-
1, USO, Maria Sandu
78-
79-
[INROLARI]
80-
1, 1, 3.10 3.80 2.10
81-
2, 2, 2.65 1.20 3.00
82-
```
83-
84-
85-
Pentru delimitarea secțiunilor am folosit un `enum Table`.
72+
Pentru delimitarea secțiunilor am folosit un `enum Table`.
8673
Atunci când citesc o linie `[ ... ]`, actualizez un **flag** de tip `Table`.
87-
Astfel știu în ce tabel să inserez datele următoare.
74+
Astfel știu în ce tabel să inserez datele următoare.
8875

89-
Parsarea liniilor se face cu funcții standard pe șiruri: `strtok`, `snprintf`/`strncpy`, `strcmp`.
76+
Parsarea liniilor se face cu funcții standard pe șiruri: `strtok`, `snprintf`/`strncpy`, `strcmp`.
9077

9178
La început, vectorii pentru studenți/materii/înrolari au dimensiune 0.
92-
Fiecare linie parsată este adăugată la final prin `realloc`.
79+
Fiecare linie parsată este adăugată la final prin `realloc`.
9380

9481
Media generală a unui student se calculează ca
95-
suma notelor obținute la materiile unde este înrolat, împărțită la numărul lor.
82+
suma notelor obținute la materiile unde este înrolat, împărțită la numărul lor.
9683

9784
```c
9885
void calculeaza_medii_generale(secretariat *s);
@@ -104,20 +91,20 @@ void calculeaza_medii_generale(secretariat *s);
10491
10592
## `>_` Task 2: interpretor de comenzi SQL
10693
107-
După încărcarea bazei de date, comenzile SQL sunt citite de la tastatură (**stdin**).
94+
După încărcarea bazei de date, comenzile SQL sunt citite de la tastatură (**stdin**).
10895
109-
Am implementat un parser capabil să proceseze:
110-
- `SELECT`interogări
111-
- `UPDATE`modificări condiționate
112-
- `DELETE`ștergeri de intrări
96+
Am implementat un parser capabil să proceseze:
97+
- `SELECT`: interogări
98+
- `UPDATE`: modificări condiționate
99+
- `DELETE`: ștergeri de intrări
113100
114-
Utilizatorul introduce un număr `n`, apoi cele `n` query-uri.
101+
Utilizatorul introduce un număr `n`, apoi cele `n` query-uri.
115102
116103
### Filtrare cu WHERE
117104
118-
Clauza `WHERE` este opțională. Condițiile sunt salvate într-o structură dedicată (`camp`, operator de comparație, valoare).
105+
Clauza `WHERE` este opțională. Condițiile sunt salvate într-o structură dedicată (`camp`, operator de comparație, valoare).
119106
120-
Pentru potrivire am implementat funcții de tip pattern matching pentru fiecare tabel, plus variante care verifică toate condițiile dintr-un array.
107+
Pentru potrivire am implementat funcții de tip "pattern matching" pentru fiecare tabel, plus variante care verifică toate condițiile dintr-un array.
121108
122109
```c
123110
typedef struct {
@@ -136,21 +123,21 @@ int match_inrolare_on_all_conditii(inrolare inrolare, int nr_conditii, conditie
136123
```
137124

138125
### SELECT
139-
- Suportă `*` (toate câmpurile) sau coloane specifice (cu un flag pentru globbing).
140-
- Poate fi combinat cu `WHERE`.
126+
- Suportă `*` (toate câmpurile) sau coloane specifice (cu un **flag** pentru globbing).
127+
- Poate fi combinat cu `WHERE`.
141128

142129
### UPDATE
143-
- Iterează toate intrările unui tabel.
144-
- Dacă intrarea respectă condițiile, se face **pattern matching** pe numele câmpului din `SET` și valoarea se actualizează.
130+
- Iterează toate intrările unui tabel.
131+
- Dacă intrarea respectă condițiile, se face **pattern matching** pe numele câmpului din `SET` și valoarea se actualizează.
145132

146133
### DELETE
147-
- Intrările care respectă condițiile sunt șterse:
148-
- memoria intrării e eliberată
134+
- Intrările care respectă condițiile sunt șterse:
135+
- memoria intrării e eliberată
149136
- vectorul este **shiftat la stânga**
150-
- numărul de elemente se decrementează
151-
- vectorul e redimensionat cu `realloc` sau eliberat complet dacă devine gol
137+
- numărul de elemente se decrementează
138+
- vectorul e redimensionat cu `realloc` sau eliberat complet dacă devine gol
152139

153-
Ștergerile din `studenti` și `materii` afectează automat și tabela `inrolari`.
140+
Ștergerile din `studenti` și `materii` afectează automat și tabela `inrolari`.
154141

155142
```c
156143
typedef enum {
@@ -164,36 +151,19 @@ void DELETE_FROM_inrolari_by_id(secretariat *secretariat, id_type type, int id);
164151
165152
166153
## 🔐 Task 3: criptarea bazei de date
154+
- Am folosit `unsigned char` pentru a reprezenta valori hexadecimale.
155+
- **Serializarea** vectorului de studenți în octeți:
156+
- dimensiunea unui student se calculează adunând dimensiunile câmpurilor (nu cu `sizeof(struct student)`)
157+
- pentru fiecare student, copiez câmpurile în buffer cu `memcpy`,
158+
iar poziția curentă se actualizează prin aritmetică pe pointeri (incrementare cu dimensiunea câmpului serializat)
159+
- Funcțiile `XOR` și `P_BOX` modifică datele in-place.
160+
- `P_BOX` copiază într-un buffer auxiliar, aplică permutarea și rescrie vectorul original.
167161
168-
Pentru a proteja datele, vectorul de studenți este criptat cu o variantă simplificată de **CBC (Cipher Block Chaining)**.
169-
170-
Pașii algoritmului:
171-
1. Transform vectorul de studenți într-o succesiune de octeți, stocată într-o variabilă `bytes_studenti`.
172-
2. Aflu dimensiunea **padding-ului**.
173-
3. Aflu dimensiunea totală a vectorului de octeți, cu tot cu padding `0x00`.
174-
4. Împart vectorul în 4 blocuri de lungime egală (ultimul bloc completat cu `0x00` dacă e nevoie).
175-
5. Criptez primul bloc:
176-
5.1. `XOR` între `block[0]` și `iv` (initialization vector).
177-
5.2. S-Box (`XOR`) cu cheia de criptare.
178-
5.3. P-Box (permutare) pe `block[0]`.
179-
6. Criptez celelalte blocuri:
180-
6.1. `XOR` între `block[i]` și `block[i-1]`.
181-
6.2. S-Box (`XOR`) cu cheia.
182-
6.3. P-Box (permutare).
183-
7. Blocurile rezultate sunt scrise byte cu byte în fișierul de ieșire.
184-
185-
Observații:
186-
- Am folosit `unsigned char` pentru a reprezenta valori hexadecimale.
187-
- `XOR` și `P_BOX` modifică datele in-place.
188-
- `P_BOX` copiază într-un buffer auxiliar, aplică permutarea și rescrie vectorul original.
189-
190-
191-
---
192162
193163
## Practici de Coding Style
194-
- Am folosit funcții sigure (`snprintf`, `strncpy`) în locul lui `strcpy`.
195-
- Gestionarea memoriei dinamice a fost făcută atent (alocare și eliberare la timp).
196-
- Acoladele nu se deschid pe o linie nouă.
164+
- Am folosit funcții sigure (`snprintf`, `strncpy`) în locul lui `strcpy`.
165+
- Gestionarea memoriei dinamice a fost făcută atent (alocare și eliberare la timp).
166+
- Acoladele nu se deschid pe o linie nouă.
197167
198168
199169
@@ -206,10 +176,10 @@ Provocările principale pe care le-am întâmpinat:
206176
207177
- Transformarea vectorului de studenți într-o secvență de octeți a fost mai complicată decât părea:
208178
nu am putut să folosesc direct `sizeof(struct student)`,
209-
ci am calculat dimensiunea fiecărui câmp în bytes.
179+
ci am calculat dimensiunea fiecărui câmp în bytes.
210180
211-
- **Precizia numerelor zecimale**
181+
- **Precizia numerelor zecimale**
212182
Am învățat că pentru calculele de medii,
213-
`double` oferă precizie mult mai bună decât `float`.
183+
`double` oferă precizie mult mai bună decât `float`.
214184
215185
- Operațiile pe sirurile de caractere în C

README.md

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
# ⛃ AC SQL
22

3-
Un mic experiment de SQL făcut de la zero, în C.
3+
Un mic experiment de SQL făcut de la zero, în C și Rust.
44
Am construit o bază de date pentru o facultate (studenți, materii, înscrieri) și un interpretor care înțelege comenzi,
5-
de exemplu `SELECT`, `UPDATE` și `DELETE`.
5+
de exemplu `SELECT`, `UPDATE` și `DELETE`.
66
Pe deasupra, am adăugat și criptare cu un algoritm simplificat de tip **CBC** (Cipher Block Chaining), ca să protejez datele.
77

8-
Practic, am vrut să văd cât de greu e să faci un mini–Postgres în C.
8+
Practic, am vrut să văd cât de greu e să faci un "mini–Postgres" în C și Rust.
99

1010
Răspunsul meu: **greu**, dar extrem de fun.
1111

12-
> Citește și [README-technical.md](./README-technical.md) pentru a înțelege implementarea proiectului.
1312

1413
## 🗂 Structura bazei de date
1514

@@ -23,40 +22,66 @@ Datele sunt ținute în structuri C și gestionate dinamic (cu `malloc`, `reallo
2322

2423
## ⚙️ Cum funcționează
2524

26-
1. **Citirea bazei de date**
27-
- Pornesc de la un fișier text (o combinație de TOML + CSV).
28-
- Îl parsez linie cu linie și încarc structurile în memorie.
25+
1. **Citirea bazei de date**
26+
- Pornesc de la un fișier text (o combinație de TOML + CSV).
27+
- Îl parsez linie cu linie și încarc structurile în memorie.
28+
- Folosesc un **flag** pentru a ști din ce tabel fac parte liniile citite.
2929

30-
2. **Interpretor SQL**
31-
- Comenzile se citesc de la tastatură (`stdin`).
32-
- Sunt implementate:
33-
- `SELECT`afișare, cu suport pentru `WHERE`
34-
- `UPDATE`modificare condiționată
35-
- `DELETE`ștergere (inclusiv relațiile aferente din alte tabele)
30+
2. **Interpretor SQL**
31+
- Comenzile se citesc de la tastatură (`stdin`).
32+
- Sunt implementate:
33+
- `SELECT`: afișare, cu suport pentru `WHERE`
34+
- `UPDATE`: modificare condiționată
35+
- `DELETE`: ștergere (inclusiv relațiile aferente din alte tabele)
3636

3737
Am scris un parser simplu care sparge query-urile și le aplică pe datele din memorie.
38-
Aici am simțit cel mai mult ce înseamnă să scrii un interpretor „de mână”.
38+
Aici am simțit cel mai mult ce înseamnă să scrii un interpretor "de mână".
39+
40+
3. **Criptare**
41+
- Vectorul de studenți poate fi criptat.
42+
- Am folosit un **CBC** simplificat: `XOR`, permutări (`P-Box`) și un `IV`.
43+
- Totul se face byte cu byte: cu `unsigned char` în C, respectiv `u8` în Rust.
44+
45+
## 🔐 Criptarea bazei de date
46+
47+
Pentru a proteja datele, vectorul de studenți este criptat cu o variantă simplificată de **CBC (Cipher Block Chaining)**.
48+
49+
Pașii algoritmului **CBC**:
50+
1. Transform vectorul de studenți într-o succesiune de octeți.
51+
2. Împart vectorul în 4 blocuri de lungimi egale (ultimul bloc completat cu **padding** de `0x00` dacă e nevoie).
52+
3. Criptez primul bloc:
53+
3.1. `XOR` între `block[0]` și `iv` (initialization vector).
54+
3.2. S-Box (`XOR`) cu cheia de criptare.
55+
3.3. P-Box (permutare) pe `block[0]`.
56+
4. Criptez celelalte blocuri:
57+
4.1. `XOR` între `block[i]` și `block[i-1]`.
58+
4.2. S-Box (`XOR`) cu cheia.
59+
4.3. P-Box (permutare).
60+
6. Blocurile rezultate sunt scrise byte cu byte în fișierul de ieșire.
3961

40-
3. **Criptare**
41-
- Vectorul de studenți poate fi criptat.
42-
- Am folosit un CBC simplificat: `XOR`, permutări (`P-Box`) și un `IV`.
43-
- Totul se face byte cu byte, cu `unsigned char`.
62+
## 💡 Ce am învățat
4463

4564

46-
## 💡 Ce am învățat
65+
Idei generale:
66+
- Cum să parsezi text și să construiești un interpretor minimal
67+
- Cât de complicat (și interesant) e să implementezi corect ceva ce pare banal în SQL
4768

48-
- Gestionarea memoriei dinamice în C și evitarea **memory leak**-urilor
49-
- Cum să parsezi text și să construiești un interpretor minimal
50-
- Cât de complicat (și interesant) e să implementezi corect ceva ce pare banal în SQL
69+
Implementarea în C:
70+
- Gestionarea memoriei dinamice în C și evitarea **memory leak**-urilor
5171
- De ce merită să folosești funcții sigure (`snprintf`, `strncpy`) și să eviți clasicul `strcpy`
5272

73+
Implementarea în Rust:
74+
- Cum să structurez un proiect Rust **modular**, pe foldere și fișiere
75+
- Propagarea erorilor într-un mod elegant folosind **pattern matching**, operatorul `?` și `.unwrap()`
76+
- Scrierea de **teste unitare table-based**, reutilizând aceeași funcție generică alături de framework-ul [rstest](https://crates.io/crates/rstest)
77+
- Folosirea **funcțiilor generice** pentru a elimina cod duplicat prin **polimorfism**
5378

5479
## 🔎 De ce mi se pare interesant proiectul
5580

56-
Am plecat de la niște structuri C și am ajuns cu un mini–SQL engine care:
57-
- știe să ruleze interogări,
58-
- respectă relații între tabele,
59-
- și poate chiar să cripteze datele.
81+
Am plecat de la niște structuri C/Rust și am ajuns cu un mini–SQL engine care:
82+
- știe să ruleze interogări,
83+
- respectă relații între tabele,
84+
- și poate chiar să cripteze datele.
6085

6186
Un fel de *bază de date în miniatură*, dar care m-a făcut să înțeleg mai bine
6287
ce se află în spatele unui **SGBD** real.

0 commit comments

Comments
 (0)