1 //-< TESTDB.CPP >----------------------------------------------------*--------*
2 // FastDB                    Version 1.0         (c) 1999  GARRET    *     ?  *
3 // (Main Memory Database Management System)                          *   /\|  *
4 //                                                                   *  /  \  *
5 //                          Created:     10-Dec-98    K.A. Knizhnik  * / [] \ *
6 //                          Last update: 12-Dec-98    K.A. Knizhnik  * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Sample of database application: supplier/contract/details database
9 //-------------------------------------------------------------------*--------*
10 
11 #include "fastdb.h"
12 #include <stdio.h>
13 
14 USE_FASTDB_NAMESPACE
15 
16 class Contract;
17 
18 class Detail {
19   public:
20     char const* name;
21     char const* material;
22     char const* color;
23     real4       weight;
24 
25     dbArray< dbReference<Contract> > contracts;
26 
27     TYPE_DESCRIPTOR((KEY(name, INDEXED|HASHED),
28                      KEY(material, HASHED),
29                      KEY(color, HASHED),
30                      KEY(weight, INDEXED),
31                      RELATION(contracts, detail)));
32 };
33 
34 class Supplier {
35   public:
36     char const* company;
37     char const* location;
38     bool        foreign;
39 
40     dbArray< dbReference<Contract> > contracts;
41 
42     TYPE_DESCRIPTOR((KEY(company, INDEXED|HASHED),
43                      KEY(location, HASHED),
44                      FIELD(foreign),
45                      RELATION(contracts, supplier)));
46 };
47 
48 
49 class Contract {
50   public:
51     dbDateTime            delivery;
52     int4                  quantity;
53     db_int8               price;
54     dbReference<Detail>   detail;
55     dbReference<Supplier> supplier;
56 
57     TYPE_DESCRIPTOR((KEY(delivery, HASHED|INDEXED),
58                      KEY(quantity, INDEXED),
59                      KEY(price, INDEXED),
60                      RELATION(detail, contracts),
61                      RELATION(supplier, contracts)));
62 };
63 
64 
65 REGISTER(Detail);
66 REGISTER(Supplier);
67 REGISTER(Contract);
68 
input(char const * prompt,char * buf,size_t buf_size)69 void input(char const* prompt, char* buf, size_t buf_size)
70 {
71     char* p;
72     do {
73         printf(prompt);
74         *buf = '\0';
75         fgets(buf,(int) buf_size, stdin);
76         p = buf + strlen(buf);
77     } while (p <= buf+1);
78 
79     if (*(p-1) == '\n') {
80         *--p = '\0';
81     }
82 }
83 
main()84 int main()
85 {
86     const int maxStrLen = 256;
87 
88     dbDatabase db;
89 
90     char buf[maxStrLen];
91     char name[maxStrLen];
92     char company[maxStrLen];
93     char material[maxStrLen];
94     char address[maxStrLen];
95 
96     int d, m, y;
97     int i, n;
98     int choice;
99     int quantity;
100     db_int8 price;
101 
102     dbDateTime from, till;
103 
104     Contract contract;
105     Supplier supplier;
106     Detail detail;
107 
108     dbQuery q1, q2, q3, q4, q6, q9, q10;
109     q1 = "exists i:(contracts[i].supplier.company=",company,")";
110     q2 = "name like",name;
111     q3 = "supplier.location =",address;
112     q4 = between("delivery", from, till),"and price >",price,
113         "order by",dbDateTime::ascent("delivery");
114     q6 = "price >=",price,"or quantity >=",quantity;
115     q9 = "company =",company;
116     q10 = "supplier.company =",company,"and detail.name like",name;
117 
118     dbCursor<Detail>   details;
119     dbCursor<Contract> contracts;
120     dbCursor<Supplier> suppliers;
121     dbCursor<Contract> updateContracts(dbCursorForUpdate);
122 
123     if (db.open(_T("testdb"))) {
124         while (true) {
125             printf(
126 "\n\n    MENU:\n\
127 1.  Details shipped by supplier\n\
128 2.  Suppliers of the detail\n\
129 3.  Contracts from specified city\n\
130 4.  Expensive details to be delivered in specified period\n\
131 5.  Foreign suppliers\n\
132 6.  Important contracts\n\
133 7.  New supplier\n\
134 8.  New detail\n\
135 9.  New contract\n\
136 10. Cancel contract\n\
137 11. Update contract\n\
138 12. Exit\n\n");
139             input(">> ", buf, sizeof buf);
140             if (sscanf(buf, "%d", &choice) != 1) {
141                 continue;
142             }
143             switch (choice) {
144               case 1:
145                 printf("Details shipped by supplier\n");
146                 input("Supplier company: ", company, sizeof company);
147                 if (details.select(q1) > 0) {
148                     printf("Detail\tMaterial\tColor\tWeight\n");
149                     do {
150                         printf("%s\t%s\t%s\t%f\n",
151                                details->name, details->material,
152                                details->color, details->weight);
153                     } while (details.next());
154                 } else {
155                     printf("No details shipped by this supplier\n");
156                 }
157                 break;
158               case 2:
159                 printf("Suppliers of the detail\n");
160                 input("Regular expression for detail name: ",name,sizeof name);
161                 if (details.select(q2) > 0) {
162                     printf("Detail\tCompany\tLocation\tPrice\n");
163                     do {
164                         n = (int)details->contracts.length();
165                         for (i = 0; i < n; i++) {
166                             contracts.at(details->contracts[i]);
167                             suppliers.at(contracts->supplier);
168                             printf("%s\t%s\t%s\t" INT8_FORMAT "\n",
169                                    details->name,
170                                    suppliers->company, suppliers->location,
171                                    contracts->price);
172                         }
173                     } while (details.next());
174                 } else {
175                     printf("No such details\n");
176                 }
177                 break;
178               case 3:
179                 printf("Contracts from specified city\n");
180                 input("City: ", address, sizeof address);
181                 if (contracts.select(q3) > 0) {
182                     printf("Detail\tCompany\tQuantity\n");
183                     do {
184                         printf("%s\t%s\t%d\n",
185                                details.at(contracts->detail)->name,
186                                suppliers.at(contracts->supplier)->company,
187                                contracts->quantity);
188                     } while (contracts.next());
189                 } else {
190                     printf("No contracts with companies in this city");
191                 }
192                 break;
193               case 4:
194                 printf("Expensive details to be delivered in specified period\n");
195                 input("Delivered after (DD-MM-YYYY): ", buf, sizeof buf);
196                 if (sscanf(buf, "%d-%d-%d\n", &d, &m, &y) != 3) {
197                     printf("Wrong date\n");
198                     continue;
199                 }
200                 from = dbDateTime(y, m, d);
201                 input("Delivered before (DD-MM-YYYY): ", buf, sizeof buf);
202                 if (sscanf(buf, "%d-%d-%d\n", &d, &m, &y) != 3) {
203                     printf("Wrong date\n");
204                     continue;
205                 }
206                 till = dbDateTime(y, m, d);
207                 input("Minimal contract price: ", buf, sizeof buf);
208                 if (sscanf(buf, INT8_FORMAT, &price) != 1) {
209                     printf("Bad value\n");
210                     continue;
211                 }
212                 if (contracts.select(q4) > 0) {
213                     printf("Detail\tDate\tPrice\n");
214                     do {
215                         printf("%s\t%s\t" INT8_FORMAT "\n",
216                                details.at(contracts->detail)->name,
217                                contracts->delivery.asString(buf, sizeof buf),
218                                contracts->price);
219                     } while (contracts.next());
220                 } else {
221                     printf("No such contracts\n");
222                 }
223                 break;
224               case 5:
225                 printf("Foreign suppliers\n");
226                 if (suppliers.select("foreign and length(contracts) > 0") > 0){
227                     printf("Company\tLocation\n");
228                     do {
229                         printf("%s\t%s\n", suppliers->company,
230                                suppliers->location);
231                     } while (suppliers.next());
232                 } else {
233                     printf("No such suppliers\n");
234                 }
235                 break;
236               case 6:
237                 printf("Important contracts\n");
238                 input("Minimal contract price: ", buf, sizeof buf);
239                 if (sscanf(buf, INT8_FORMAT, &price) != 1) {
240                     printf("Bad value\n");
241                     continue;
242                 }
243                 input("Minimal contract quantity: ", buf, sizeof buf);
244                 if (sscanf(buf, "%d", &quantity) != 1) {
245                     printf("Bad value\n");
246                     continue;
247                 }
248                 if (contracts.select(q6) > 0) {
249                     printf("Company\tPrice\tQuantity\tDelivery\n");
250                     do {
251                         printf("%s\t" INT8_FORMAT "\t%d\t%s\n",
252                                suppliers.at(contracts->supplier)->company,
253                                contracts->price, contracts->quantity,
254                                contracts->delivery.asString(buf, sizeof buf,
255                                                             "%A %x"));
256                     } while (contracts.next());
257                 } else {
258                     printf("No such contracts\n");
259                 }
260                 break;
261               case 7:
262                 printf("New supplier\n");
263                 input("Company name: ", company, sizeof company);
264                 input("Company location: ", address, sizeof address);
265                 input("Foreign company (y/n): ", buf, sizeof buf);
266                 supplier.company = company;
267                 supplier.location = address;
268                 supplier.foreign = (*buf == 'y');
269                 insert(supplier);
270                 break;
271               case 8:
272                 printf("New detail\n");
273                 input("Detail name: ", name, sizeof name);
274                 input("Detail material: ", material, sizeof material);
275                 input("Detail weight: ", buf, sizeof buf);
276                 sscanf(buf, "%f", &detail.weight);
277                 input("Detail color: ", buf, sizeof buf);
278                 detail.name = name;
279                 detail.material = material;
280                 detail.color = buf;
281                 insert(detail);
282                 break;
283               case 9:
284                 printf("New contract\n");
285                 db.lock(); // prevent deadlock
286                 input("Supplier company: ", company, sizeof company);
287                 if (suppliers.select(q9) == 0) {
288                     printf("No such supplier\n");
289                     continue;
290                 }
291                 input("Detail name: ", name, sizeof name);
292                 if (details.select(q2) == 0) {
293                     printf("No such detail\n");
294                     continue;
295                 } else if (details.getNumberOfRecords() != 1) {
296                     printf("More than one record match this pattern");
297                     continue;
298                 }
299                 input("Contract price: ", buf, sizeof buf);
300                 sscanf(buf, INT8_FORMAT, &contract.price);
301                 input("Contract quantity: ", buf, sizeof buf);
302                 sscanf(buf, "%d", &contract.quantity);
303                 input("Delivered after (days): ", buf, sizeof buf);
304                 sscanf(buf, "%d", &d);
305                 contract.delivery =
306                     dbDateTime::currentDate() + dbDateTime(24*d,0);
307                 contract.supplier = suppliers.currentId();
308                 contract.detail = details.currentId();
309                 insert(contract);
310                 break;
311               case 10:
312                 printf("Cancel contract\n");
313                 input("Supplier company: ", company, sizeof company);
314                 input("Detail name pattern: ", name, sizeof name);
315                 if (updateContracts.select(q10) == 0) {
316                     printf("No such contracts\n");
317                 } else {
318                     updateContracts.removeAllSelected();
319                     // Just test rollback
320                     input("Really cancel contract (y/n) ? ", buf, sizeof buf);
321                     if (*buf != 'y') {
322                         printf("Not confirmed\n");
323                         db.rollback();
324                         continue;
325                     }
326                 }
327                 break;
328               case 11:
329                 printf("Update contract\n");
330                 input("Supplier company: ", company, sizeof company);
331                 input("Detail name pattern: ", name, sizeof name);
332                 if (updateContracts.select(q10) == 0) {
333                     printf("No such contracts\n");
334                     break;
335                 }
336                 do {
337                     printf("Contract with company %s for shipping %d details "
338                            "%s for $" INT8_FORMAT " at %s\n",
339                            suppliers.at(updateContracts->supplier)->company,
340                            updateContracts->quantity,
341                            details.at(updateContracts->detail)->name,
342                            updateContracts->price,
343                            updateContracts->delivery.asString(buf,sizeof buf));
344                     input("Change this contract (y/n) ? ", buf, sizeof buf);
345                     if (*buf == 'y') {
346                         input("New contract price: ", buf, sizeof buf);
347                         sscanf(buf, INT8_FORMAT, &updateContracts->price);
348                         input("New number of details: ", buf, sizeof buf);
349                         sscanf(buf, "%d", &updateContracts->quantity);
350                         updateContracts.update();
351                     }
352                 } while (updateContracts.next());
353                 break;
354               case 12:
355                 input("Do you really want to exit (y/n) ? ", buf, sizeof buf);
356                 if (*buf == 'y') {
357                     printf("Close database session\n");
358                     db.close();
359                     return EXIT_SUCCESS;
360                 }
361                 break;
362               default:
363                 printf("Please choose menu items 1..12\n");
364                 continue;
365             }
366             printf("Press any key to continue...\n");
367             getchar();
368             db.commit();
369         }
370     } else {
371         printf("failed to open database\n");
372         return EXIT_FAILURE;
373     }
374 }
375 
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 
389