YATiSh
Yet Another TIme SHeet
yatishDBmysql.cpp
Go to the documentation of this file.
1 /********************************************************************
2  * Name: yatishDBmysql.cpp
3  * Purpose: Implements the mysql controller
4  * Author: Nicolas PĂ©renne (nicolas.perenne@eif-services.eu)
5  * Created: 2020-04-16
6  * Copyright: EIF-services (https://www.eif-services.eu/yatish)
7  * License: GPLv3
8  ********************************************************************/
9 
10 #include "wx_pch.h"
11 #include "yatishDBmysql.h"
12 
13 #undef CATCH // avoids a warning before redefining (in order to store errorCode)
14 #define CATCH(returnValue) catch (wxDatabaseException& e) {\
15  errorCode = e.GetErrorCode();\
16  wxLogError ( "[%d] %s", errorCode, e.GetErrorMessage() );\
17  return returnValue; }
18 
19 wxDatabase * yatishDBmysql::slaveDB = nullptr;
20 
27  wxASSERT_MSG (slaveDB == nullptr, "There can be only one instance of yatishDBmysql.");
28  slaveDB = GetDatabase ("");
29  if (!slaveDB) return;
30  try {
31  if (slaveDB->GetTypeName() != "MYSQL")
32  throw ( wxDatabaseException (-4, _("Slave DB must be MySQL") ) );
33  if ( !TablesOk (slaveDB) && !NewTables() )
34  throw ( wxDatabaseException (-5, _("Yatish tables not created (MySQL)") ) );
35  }
36  catch (wxDatabaseException& e) {
37  wxLogError ( "[%d] %s", e.GetErrorCode(), e.GetErrorMessage() );
38  slaveDB->Close();
39  delete slaveDB;
40  slaveDB = nullptr;
41  }
42  errorCode = 0;
43 }
44 
50  if (!slaveDB) return false;
51  try {
52  if ( slaveDB->TableExists ("yatish_client") )
53  slaveDB->RunQuery ("DELETE FROM yatish_client;");
54  else
55  slaveDB->RunQuery ("CREATE TABLE yatish_client ("
56  "id INT NOT NULL AUTO_INCREMENT,"
57  "name VARCHAR (20) NOT NULL UNIQUE,"
58  "PRIMARY KEY (id));");
59  if ( slaveDB->TableExists ("yatish_project") )
60  slaveDB->RunQuery ("DELETE FROM yatish_project;");
61  else
62  slaveDB->RunQuery ("CREATE TABLE yatish_project ("
63  "id INT NOT NULL AUTO_INCREMENT,"
64  "name VARCHAR (20) NOT NULL UNIQUE,"
65  "client_id INT NOT NULL,"
66  "PRIMARY KEY (id),"
67  "FOREIGN KEY (client_id) REFERENCES yatish_client (id)"
68  "ON DELETE CASCADE ON UPDATE CASCADE);");
69  if ( slaveDB->TableExists ("yatish_task") )
70  slaveDB->RunQuery ("DELETE FROM yatish_task;");
71  else
72  slaveDB->RunQuery ("CREATE TABLE yatish_task ("
73  "id INT NOT NULL AUTO_INCREMENT,"
74  "name VARCHAR (20) NOT NULL UNIQUE,"
75  "PRIMARY KEY (id));");
76  if ( slaveDB->TableExists ("yatish_tool") )
77  slaveDB->RunQuery ("DELETE FROM yatish_tool;");
78  else
79  slaveDB->RunQuery ("CREATE TABLE yatish_tool ("
80  "id INT NOT NULL AUTO_INCREMENT,"
81  "name VARCHAR (20) NOT NULL UNIQUE,"
82  "PRIMARY KEY (id));");
83  if ( slaveDB->TableExists ("yatish_activity") )
84  slaveDB->RunQuery ("DELETE FROM yatish_activity;");
85  else
86  slaveDB->RunQuery ("CREATE TABLE yatish_activity ("
87  "id INT NOT NULL AUTO_INCREMENT,"
88  "project_id INT NOT NULL,"
89  "task_id INT NOT NULL,"
90  "tool_id INT NOT NULL,"
91  "PRIMARY KEY (id),"
92  "UNIQUE (project_id,task_id,tool_id),"
93  "FOREIGN KEY (project_id) REFERENCES yatish_project (id)"
94  "ON DELETE CASCADE ON UPDATE CASCADE,"
95  "FOREIGN KEY (task_id) REFERENCES yatish_task (id)"
96  "ON DELETE CASCADE ON UPDATE CASCADE,"
97  "FOREIGN KEY (tool_id) REFERENCES yatish_tool (id)"
98  "ON DELETE CASCADE ON UPDATE CASCADE);");
99  if ( slaveDB->TableExists ("yatish_timeslot") )
100  slaveDB->RunQuery ("DELETE FROM yatish_timeslot;");
101  else
102  slaveDB->RunQuery ("CREATE TABLE yatish_timeslot ("
103  "id INT NOT NULL AUTO_INCREMENT,"
104  "start DATETIME,"
105  "stop DATETIME,"
106  "activity_id INT NOT NULL,"
107  "PRIMARY KEY (id),"
108  "FOREIGN KEY (activity_id) REFERENCES yatish_activity (id)"
109  "ON DELETE CASCADE ON UPDATE CASCADE);");
110  }
111  CATCH (false);
112  return true;
113 }
114 
116  if (!slaveDB) return;
117  slaveDB->Close();
118  delete slaveDB;
119  slaveDB = nullptr;
120 }
121 
127  if (!slaveDB || !masterDB) return 0;
130  Delete();
131  return errorCode;
132 }
133 
139  if (!slaveDB || !masterDB) return 0;
140  Commit() && // first ensure that any locally modified records are cleared out (including local CASCADE...)
143  return errorCode;
144 }
145 
151  if (!slaveDB || !masterDB) return 0;
152  EmptyMasterTables() &&
154  return errorCode;
155 }
156 
162  if (!slaveDB) return false;
163  try {
164  slaveDB->RunQuery ("DELETE FROM yatish_client;");
165  slaveDB->RunQuery ("DELETE FROM yatish_project;");
166  slaveDB->RunQuery ("DELETE FROM yatish_task;");
167  slaveDB->RunQuery ("DELETE FROM yatish_tool;");
168  slaveDB->RunQuery ("DELETE FROM yatish_activity;");
169  slaveDB->RunQuery ("DELETE FROM yatish_timeslot;");
170  }
171  CATCH (false);
172  errorCode = 0;
173  return true;
174 }
175 
181  if (!masterDB) return false;
182  try {
183  masterDB->RunQuery ("DELETE FROM yatish_client;");
184  masterDB->RunQuery ("DELETE FROM yatish_project;");
185  masterDB->RunQuery ("DELETE FROM yatish_task;");
186  masterDB->RunQuery ("DELETE FROM yatish_tool;");
187  masterDB->RunQuery ("DELETE FROM yatish_activity;");
188  masterDB->RunQuery ("DELETE FROM yatish_timeslot;");
189  }
190  CATCH (false);
191  errorCode = 0;
192  return true;
193 }
194 
200  if (!masterDB) return false;
201  try {
202  masterDB->RunQuery ("UPDATE yatish_client SET sync = 'I';");
203  masterDB->RunQuery ("UPDATE yatish_project SET sync = 'I';");
204  masterDB->RunQuery ("UPDATE yatish_task SET sync = 'I';");
205  masterDB->RunQuery ("UPDATE yatish_tool SET sync = 'I';");
206  masterDB->RunQuery ("UPDATE yatish_activity SET sync = 'I';");
207  masterDB->RunQuery ("UPDATE yatish_timeslot SET sync = 'I';");
208  }
209  CATCH (false);
210  errorCode = 0;
211  return true;
212 }
213 
220  if (!slaveDB || !masterDB) return false;
221  wxString sql;
222  long id;
223  for (int i = 0; i < 6; i++) {
224  try {
225  const char * n = tableName[i];
226  sql.Printf("SELECT id FROM yatish_%s WHERE sync = 'D';", n);
227  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
228  while ( results->Next() ) {
229  id = results->GetResultLong (1);
230  sql.Printf ("DELETE FROM yatish_%s WHERE id = %ld;", n, id);
231  slaveDB->RunQuery (sql);
232  }
233  masterDB->CloseResultSet (results);
234  sql.Printf("DELETE FROM yatish_%s WHERE sync = 'D';", n);
235  masterDB->RunQuery (sql);
236  }
237  CATCH (false)
238  }
239  errorCode = 0;
240  return true;
241 }
242 
251  if (!slaveDB || !masterDB) return false;
252  wxString sql, name;
253  long id;
254  for (int i = 0; i < 3; i++) {
255  try {
256  const char * n = tableName[i];
257  sql.Printf("SELECT id,name FROM yatish_%s WHERE sync = 'I';", n);
258  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
259  while ( results->Next() ) {
260  id = results->GetResultLong (1);
261  name = results->GetResultString (2);
262  sql.Printf ("INSERT INTO yatish_%s (id,name) VALUES (%ld,'%s');", n, id, name);
263  slaveDB->RunQuery (sql);
264  }
265  masterDB->CloseResultSet (results);
266  sql.Printf("UPDATE yatish_%s SET sync='S' WHERE sync = 'I';", n);
267  masterDB->RunQuery (sql);
268  }
269  CATCH (false)
270  }
271  errorCode = 0;
272  return true;
273 }
274 
283  if (!slaveDB || !masterDB) return false;
284  wxString sql, name;
285  long id;
286  for (int i = 0; i < 3; i++) {
287  try {
288  masterDB->BeginTransaction(); // quicker (1/2)
289  const char * n = tableName[i];
290  sql.Printf("SELECT id,name FROM yatish_%s;", n);
291  wxDatabaseResultSet * results = slaveDB->RunQueryWithResults (sql);
292  while ( results->Next() ) {
293  id = results->GetResultLong (1);
294  name = results->GetResultString (2);
295  sql.Printf ("INSERT INTO yatish_%s (id,name,sync) VALUES (%ld,'%s','S');", n, id, name);
296  masterDB->RunQuery (sql);
297  }
298  slaveDB->CloseResultSet (results);
299  masterDB->Commit(); // quicker (2/2)
300  }
301  CATCH (false)
302  }
303  errorCode = 0;
304  return true;
305 }
306 
315  if (!slaveDB || !masterDB) return false;
316  wxString sql, name;
317  long id;
318  for (int i = 0; i < 3; i++) {
319  try {
320  const char * n = tableName[i];
321  sql.Printf("SELECT id,name FROM yatish_%s WHERE sync = 'U';", n);
322  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
323  while ( results->Next() ) {
324  id = results->GetResultLong (1);
325  name = results->GetResultString (2);
326  sql.Printf ("UPDATE yatish_%s SET name='%s' WHERE id = %ld;", n, name, id);
327  slaveDB->RunQuery (sql);
328  }
329  masterDB->CloseResultSet (results);
330  sql.Printf ("UPDATE yatish_%s SET sync='S' WHERE sync = 'U';", n);
331  masterDB->RunQuery (sql);
332  }
333  CATCH (false)
334  }
335  errorCode = 0;
336  return true;
337 }
338 
344  if (!slaveDB || !masterDB) return false;
345  wxString sql, name;
346  long id, client_id;
347  try {
348  sql.Printf("SELECT id,name,client_id FROM yatish_project WHERE sync = 'I';");
349  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
350  while ( results->Next() ) {
351  id = results->GetResultLong (1);
352  name = results->GetResultString (2);
353  client_id = results->GetResultLong (3);
354  sql.Printf ("INSERT INTO yatish_project (id,name,client_id)"
355  " VALUES (%ld,'%s',%ld);", id, name, client_id);
356  slaveDB->RunQuery (sql);
357  }
358  masterDB->CloseResultSet (results);
359  sql.Printf ("UPDATE yatish_project SET sync='S' WHERE sync = 'I';");
360  masterDB->RunQuery (sql);
361  }
362  CATCH (false)
363  errorCode = 0;
364  return true;
365 }
366 
372  if (!slaveDB || !masterDB) return false;
373  wxString sql, name;
374  long id, client_id;
375  try {
376  masterDB->BeginTransaction(); // quicker (1/2)
377  sql.Printf("SELECT id,name,client_id FROM yatish_project;");
378  wxDatabaseResultSet * results = slaveDB->RunQueryWithResults (sql);
379  while ( results->Next() ) {
380  id = results->GetResultLong (1);
381  name = results->GetResultString (2);
382  client_id = results->GetResultLong (3);
383  sql.Printf ("INSERT INTO yatish_project (id,name,client_id,sync)"
384  " VALUES (%ld,'%s',%ld,'S');", id, name, client_id);
385  masterDB->RunQuery (sql);
386  }
387  slaveDB->CloseResultSet (results);
388  masterDB->Commit(); // quicker (2/2)
389  }
390  CATCH (false)
391  errorCode = 0;
392  return true;
393 }
394 
400  if (!slaveDB || !masterDB) return false;
401  wxString sql, name;
402  long id, client_id;
403  try {
404  sql.Printf("SELECT id,name,client_id FROM yatish_project WHERE sync = 'U';");
405  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
406  while ( results->Next() ) {
407  id = results->GetResultLong (1);
408  name = results->GetResultString (2);
409  client_id = results->GetResultLong (3);
410  sql.Printf ("UPDATE yatish_project SET name='%s',client_id=%ld"
411  " WHERE id = %ld;", name, client_id, id);
412  slaveDB->RunQuery (sql);
413  }
414  masterDB->CloseResultSet (results);
415  sql.Printf ("UPDATE yatish_project SET sync='S' WHERE sync = 'U';");
416  masterDB->RunQuery (sql);
417  }
418  CATCH (false)
419  errorCode = 0;
420  return true;
421 }
422 
428  if (!slaveDB || !masterDB) return false;
429  wxString sql;
430  long id1, id2, id3, id4;
431  try {
432  sql.Printf("SELECT id,project_id,task_id,tool_id FROM yatish_activity WHERE sync = 'I';");
433  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
434  while ( results->Next() ) {
435  id1 = results->GetResultLong (1);
436  id2 = results->GetResultLong (2);
437  id3 = results->GetResultLong (3);
438  id4 = results->GetResultLong (4);
439  sql.Printf ("INSERT INTO yatish_activity (id,project_id,task_id,tool_id)"
440  " VALUES (%ld,%ld,%ld,%ld);", id1, id2, id3, id4);
441  slaveDB->RunQuery (sql);
442  }
443  masterDB->CloseResultSet (results);
444  sql.Printf ("UPDATE yatish_activity SET sync='S' WHERE sync = 'I';");
445  masterDB->RunQuery (sql);
446  }
447  CATCH (false)
448  errorCode = 0;
449  return true;
450 }
451 
457  if (!slaveDB || !masterDB) return false;
458  wxString sql;
459  long id1, id2, id3, id4;
460  try {
461  masterDB->BeginTransaction(); // quicker (1/2)
462  sql.Printf("SELECT id,project_id,task_id,tool_id FROM yatish_activity;");
463  wxDatabaseResultSet * results = slaveDB->RunQueryWithResults (sql);
464  while ( results->Next() ) {
465  id1 = results->GetResultLong (1);
466  id2 = results->GetResultLong (2);
467  id3 = results->GetResultLong (3);
468  id4 = results->GetResultLong (4);
469  sql.Printf ("INSERT INTO yatish_activity (id,project_id,task_id,tool_id,sync)"
470  " VALUES (%ld,%ld,%ld,%ld,'S');", id1, id2, id3, id4);
471  masterDB->RunQuery (sql);
472  }
473  slaveDB->CloseResultSet (results);
474  masterDB->Commit(); // quicker (2/2)
475  }
476  CATCH (false)
477  errorCode = 0;
478  return true;
479 }
480 
486  if (!slaveDB || !masterDB) return false;
487  wxString sql;
488  long id1, id2, id3, id4;
489  try {
490  sql.Printf("SELECT id,project_id,task_id,tool_id FROM yatish_activity WHERE sync = 'U';");
491  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
492  while ( results->Next() ) {
493  id1 = results->GetResultLong (1);
494  id2 = results->GetResultLong (2);
495  id3 = results->GetResultLong (3);
496  id4 = results->GetResultLong (4);
497  sql.Printf ("UPDATE yatish_activity SET project_id=%ld,task_id=%ld,tool_id=%ld"
498  " WHERE id = %ld;", id2, id3, id4, id1);
499  slaveDB->RunQuery (sql);
500  }
501  masterDB->CloseResultSet (results);
502  sql.Printf ("UPDATE yatish_activity SET sync='S' WHERE sync = 'U';");
503  masterDB->RunQuery (sql);
504  }
505  CATCH (false)
506  errorCode = 0;
507  return true;
508 }
509 
515  if (!slaveDB || !masterDB) return false;
516  wxString sql, start, stop;
517  long id, activity_id;
518  try {
519  sql.Printf("SELECT id,start,stop,activity_id FROM yatish_timeslot WHERE sync = 'I';");
520  // masterDB->RunQueryWithResults before the loop
521  // is much faster than
522  // masterDB->RunQuery inside the loop
523  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
524  wxPreparedStatement * prepareSlave = slaveDB->PrepareStatement (
525  "INSERT INTO yatish_timeslot (id,start,stop,activity_id) VALUES (?,?,?,?);" );
526  while ( results->Next() ) {
527  id = results->GetResultLong (1);
528  start = results->GetResultString (2);
529  stop = results->GetResultString (3);
530  activity_id = results->GetResultLong (4);
531  prepareSlave->SetParamInt (1, id); // no SetParamLong()...
532  prepareSlave->SetParamString (2, start);
533  prepareSlave->SetParamString (3, stop);
534  prepareSlave->SetParamInt (4, activity_id); // no SetParamLong()...
535  prepareSlave->RunQuery();
536  }
537  slaveDB->CloseStatement (prepareSlave);
538  masterDB->CloseResultSet (results);
539  sql.Printf ("UPDATE yatish_timeslot SET sync='S' WHERE sync='I';");
540  masterDB->RunQuery (sql);
541  }
542  CATCH (false)
543  errorCode = 0;
544  return true;
545 }
546 
552  if (!slaveDB || !masterDB) return false;
553  wxString sql, start, stop;
554  long id, activity_id;
555  try {
556  masterDB->BeginTransaction(); // quicker (1/2)
557  sql.Printf("SELECT id,start,stop,activity_id FROM yatish_timeslot;");
558  wxDatabaseResultSet * results = slaveDB->RunQueryWithResults (sql);
559  while ( results->Next() ) {
560  id = results->GetResultLong (1);
561  start = results->GetResultDate (2) .FormatISOCombined (' ');
562  stop = results->GetResultDate (3) .FormatISOCombined (' ');
563  activity_id = results->GetResultLong (4);
564  sql.Printf ("INSERT INTO yatish_timeslot (id,start,stop,activity_id,sync)"
565  " VALUES (%ld,'%s','%s',%ld,'S');", id, start, stop, activity_id);
566  masterDB->RunQuery (sql);
567  }
568  slaveDB->CloseResultSet (results);
569  masterDB->Commit(); // quicker (2/2)
570  }
571  CATCH (false)
572  errorCode = 0;
573  return true;
574 }
575 
581  if (!slaveDB || !masterDB) return false;
582  wxString sql, start, stop;
583  long id, activity_id;
584  try {
585  sql.Printf("SELECT id,start,stop,activity_id FROM yatish_timeslot WHERE sync = 'U';");
586  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
587  while ( results->Next() ) {
588  id = results->GetResultLong (1);
589  start = results->GetResultString (2);
590  stop = results->GetResultString (3);
591  activity_id = results->GetResultLong (4);
592  sql.Printf ("UPDATE yatish_timeslot SET start='%s',stop='%s',activity_id=%ld"
593  " WHERE id = %ld;", start, stop, activity_id, id);
594  slaveDB->RunQuery (sql);
595  }
596  masterDB->CloseResultSet (results);
597  sql.Printf ("UPDATE yatish_timeslot SET sync='S' WHERE sync = 'U';");
598  masterDB->RunQuery (sql);
599  }
600  CATCH (false)
601  errorCode = 0;
602  return true;
603 }
static wxDatabase * masterDB
Definition: yatishDB.h:46
bool TablesOk(wxDatabase *)
Returns false if any of the yatish table is missings.
Definition: yatishDB.cpp:83
static const char * tableName[]
Must be defined in the same order as enum tableID.
Definition: yatishDB.h:44
wxDatabase * GetDatabase(const wxString &)
Sets up a (configuration) flux using its argument then calls wxDatabase::GetDatabase().
Definition: yatishDB.cpp:48
int Download()
Downloads slaveDB into masterDB.
bool UpdateTimeslot()
Takes care of UPDATEs in yatish_timeslot.
bool Insert()
Takes care of INSERTs in yatish tables with a single name column.
bool DownloadProject()
Downloads yatish_project.
bool InsertActivity()
Takes care of INSERTs in yatish_activity.
bool DownloadNames()
Downloads yatish tables with a single name column.
bool UpdateProject()
Takes care of UPDATEs in yatish_project.
bool DownloadActivity()
Downloads yatish_activity.
bool EmptyMasterTables()
Empties all yatish tables in masterDB.
bool Delete()
Takes care of DELETEs in yatish tables.
bool EmptySlaveTables()
Empties all yatish tables in slaveDB.
bool NewTables()
Creates the yatish tables.
bool UpdateActivity()
Takes care of UPDATEs in yatish_activity.
bool InsertTimeslot()
Takes care of INSERTs in yatish_timeslot.
bool DownloadTimeslot()
Download yatish_timeslot.
bool OutdateMasterTables()
Sets the sync field to 'I' in all records of all yatish tables in masterDB.
bool Update()
Takes care of UPDATEs in yatish tables with a single name column.
yatishDBmysql()
Mainly connects to the MySQL database specified in yatish.auth
int Upload()
Uploads masterDB into slaveDB.
int Commit()
Updates slaveDB with records of masterDB where the sync field is not 'S'.
static wxDatabase * slaveDB
Definition: yatishDBmysql.h:27
bool InsertProject()
Takes care of INSERTs in yatish_project.
#define CATCH(returnValue)