DatabaseUtilities.cpp 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. // DatabaseUtilites.cpp: implementation of the CDatabaseUtilites class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "CP_Main.h"
  6. #include "DatabaseUtilities.h"
  7. #include "ProcessPaste.h"
  8. #include <io.h>
  9. #include "AccessToSqlite.h"
  10. #include "Path.h"
  11. #include "InternetUpdate.h"
  12. //////////////////////////////////////////////////////////////////////
  13. // Construction/Destruction
  14. //////////////////////////////////////////////////////////////////////
  15. BOOL CreateBackup(CString csPath)
  16. {
  17. CString csOriginal;
  18. int count = 0;
  19. // create a backup of the existing database
  20. do
  21. {
  22. count++;
  23. csOriginal = csPath + StrF(_T(".%03d"), count);
  24. // in case of some weird infinite loop
  25. if( count > 50 )
  26. {
  27. ASSERT(0);
  28. return FALSE;
  29. }
  30. } while( !::CopyFile(csPath, csOriginal, TRUE));
  31. return TRUE;
  32. }
  33. CString GetDBName()
  34. {
  35. return CGetSetOptions::GetDBPath();
  36. }
  37. CString GetOLDDefaultDBName()
  38. {
  39. CString csDefaultPath;
  40. LPMALLOC pMalloc;
  41. if(SUCCEEDED(::SHGetMalloc(&pMalloc)))
  42. {
  43. LPITEMIDLIST pidlPrograms;
  44. SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidlPrograms);
  45. TCHAR string[MAX_PATH];
  46. SHGetPathFromIDList(pidlPrograms, string);
  47. pMalloc->Free(pidlPrograms);
  48. pMalloc->Release();
  49. csDefaultPath = string;
  50. csDefaultPath += "\\Ditto\\";
  51. csDefaultPath += "DittoDB.mdb";
  52. }
  53. return csDefaultPath;
  54. }
  55. CString GetDefaultDBName()
  56. {
  57. CString csDefaultPath = _T("c:\\program files\\Ditto\\");
  58. //If portable then default to the running path
  59. if(CGetSetOptions::GetIsPortableDitto())
  60. {
  61. csDefaultPath.Empty();
  62. }
  63. else
  64. {
  65. LPMALLOC pMalloc;
  66. if(SUCCEEDED(::SHGetMalloc(&pMalloc)))
  67. {
  68. LPITEMIDLIST pidlPrograms;
  69. SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidlPrograms);
  70. TCHAR string[MAX_PATH];
  71. SHGetPathFromIDList(pidlPrograms, string);
  72. pMalloc->Free(pidlPrograms);
  73. pMalloc->Release();
  74. csDefaultPath = string;
  75. }
  76. FIX_CSTRING_PATH(csDefaultPath);
  77. csDefaultPath += "Ditto\\";
  78. }
  79. CString csTempName = csDefaultPath + "Ditto.db";
  80. int i = 1;
  81. while(FileExists(csTempName))
  82. {
  83. csTempName.Format(_T("%sDitto_%d.db"), csDefaultPath, i);
  84. i++;
  85. }
  86. csDefaultPath = csTempName;
  87. return csDefaultPath;
  88. }
  89. BOOL CheckDBExists(CString csDBPath)
  90. {
  91. //If this is the first time running this version then convert the old database to the new db
  92. if(csDBPath.IsEmpty())
  93. {
  94. csDBPath = GetDefaultDBName();
  95. if(FileExists(csDBPath) == FALSE && CGetSetOptions::GetIsPortableDitto() == FALSE)
  96. {
  97. CString csOldDB = CGetSetOptions::GetDBPathOld();
  98. if(csOldDB.IsEmpty())
  99. {
  100. csOldDB = GetOLDDefaultDBName();
  101. }
  102. if(FileExists(csOldDB))
  103. {
  104. //create the new sqlite db
  105. CreateDB(csDBPath);
  106. CAccessToSqlite Convert;
  107. Convert.ConvertDatabase(csDBPath, csOldDB);
  108. }
  109. }
  110. }
  111. BOOL bRet = FALSE;
  112. if(FileExists(csDBPath) == FALSE)
  113. {
  114. csDBPath = GetDefaultDBName();
  115. nsPath::CPath FullPath(csDBPath);
  116. CString csPath = FullPath.GetPath().GetStr();
  117. if(csPath.IsEmpty() == false && FileExists(csDBPath) == FALSE)
  118. {
  119. CreateDirectory(csPath, NULL);
  120. }
  121. // -- create a new one
  122. bRet = CreateDB(csDBPath);
  123. }
  124. else
  125. {
  126. if(ValidDB(csDBPath) == FALSE)
  127. {
  128. //Db existed but was bad
  129. CString csMarkAsBad;
  130. csMarkAsBad = csDBPath;
  131. csMarkAsBad.Replace(_T("."), _T("_BAD."));
  132. CString csPath = GetDefaultDBName();
  133. CString cs;
  134. cs.Format(_T("%s \"%s\",\n")
  135. _T("%s \"%s\",\n")
  136. _T("%s,\n")
  137. _T("\"%s\""),
  138. theApp.m_Language.GetString("Database_Format", "Unrecognized Database Format"),
  139. csDBPath,
  140. theApp.m_Language.GetString("File_Renamed", "the file will be renamed"),
  141. csMarkAsBad,
  142. theApp.m_Language.GetString("New_Database", "and a new database will be created"),
  143. csPath);
  144. AfxMessageBox(cs);
  145. CFile::Rename(csDBPath, csMarkAsBad);
  146. csDBPath = csPath;
  147. bRet = CreateDB(csDBPath);
  148. }
  149. else
  150. {
  151. bRet = TRUE;
  152. }
  153. }
  154. if(bRet)
  155. {
  156. bRet = OpenDatabase(csDBPath);
  157. }
  158. return bRet;
  159. }
  160. BOOL OpenDatabase(CString csDB)
  161. {
  162. try
  163. {
  164. theApp.m_db.close();
  165. theApp.m_db.open(csDB);
  166. CGetSetOptions::SetDBPath(csDB);
  167. theApp.m_db.setBusyTimeout(CGetSetOptions::GetDbTimeout());
  168. return TRUE;
  169. }
  170. CATCH_SQLITE_EXCEPTION
  171. return FALSE;
  172. }
  173. void ReOrderStickyClips(int parentID, CppSQLite3DB &db)
  174. {
  175. try
  176. {
  177. Log(StrF(_T("Start of ReOrderStickyClips, ParentId %d"), parentID));
  178. //groups where created with 0 in these fields, fix them up if they are 0
  179. if(parentID == -1)
  180. {
  181. db.execDMLEx(_T("Update Main Set stickyClipOrder = -(2147483647) where bIsGroup = 1 AND stickyClipOrder = 0"));
  182. db.execDMLEx(_T("Update Main Set stickyClipGroupOrder = -(2147483647) where bIsGroup = 1 AND stickyClipGroupOrder = 0"));
  183. }
  184. CppSQLite3Query qGroup = db.execQueryEx(_T("SELECT lID, mText FROM Main WHERE bIsGroup = 1 AND lParentID = %d"), parentID);
  185. if (qGroup.eof() == false)
  186. {
  187. while (!qGroup.eof())
  188. {
  189. //Get all sticky clips at the top level or group
  190. CString sql = StrF(_T("SELECT lID FROM Main WHERE stickyClipOrder <> -(2147483647) AND lParentID = %d ORDER BY stickyClipOrder DESC"), parentID);
  191. if (parentID > -1)
  192. {
  193. sql = StrF(_T("SELECT lID FROM Main WHERE stickyClipGroupOrder <> -(2147483647) AND lParentID = %d ORDER BY stickyClipGroupOrder DESC"), parentID);
  194. }
  195. CppSQLite3Query qSticky = db.execQueryEx(sql);
  196. int order = 1;
  197. if (qSticky.eof() == false)
  198. {
  199. while (!qSticky.eof())
  200. {
  201. //set the new order
  202. if (parentID > -1)
  203. {
  204. db.execDMLEx(_T("Update Main Set stickyClipGroupOrder = %d where lID = %d"), order, qSticky.getIntField(_T("lID")));
  205. }
  206. else
  207. {
  208. db.execDMLEx(_T("Update Main Set stickyClipOrder = %d where lID = %d"), order, qSticky.getIntField(_T("lID")));
  209. }
  210. qSticky.nextRow();
  211. order--;
  212. }
  213. }
  214. ReOrderStickyClips(qGroup.getIntField(_T("lID")), db);
  215. qGroup.nextRow();
  216. }
  217. }
  218. Log(StrF(_T("End of ReOrderStickyClips, ParentId %d"), parentID));
  219. }
  220. CATCH_SQLITE_EXCEPTION
  221. }
  222. BOOL ValidDB(CString csPath, BOOL bUpgrade)
  223. {
  224. CDittoPopupWindow *popUpMsg = NULL;
  225. try
  226. {
  227. BOOL didBackup = FALSE;
  228. CString backupFilePrefix = _T("Before_Update_To");
  229. CppSQLite3DB db;
  230. db.open(csPath);
  231. db.execQuery(_T("SELECT lID, lDate, mText, lShortCut, lDontAutoDelete, ")
  232. _T("CRC, bIsGroup, lParentID, QuickPasteText ")
  233. _T("FROM Main"));
  234. db.execQuery(_T("SELECT lID, lParentID, strClipBoardFormat, ooData FROM Data"));
  235. db.execQuery(_T("SELECT lID, TypeText FROM Types"));
  236. try
  237. {
  238. db.execDML(_T("DROP TRIGGER delete_data_trigger"));
  239. }
  240. catch(CppSQLite3Exception& e)
  241. {
  242. e.errorCode();
  243. }
  244. try
  245. {
  246. db.execDML(_T("DROP TRIGGER delete_copy_buffer_trigger"));
  247. }
  248. catch(CppSQLite3Exception& e)
  249. {
  250. e.errorCode();
  251. }
  252. //This was added later so try to add each time and catch the exception here
  253. try
  254. {
  255. db.execDML(_T("CREATE TRIGGER delete_data_trigger BEFORE DELETE ON Main FOR EACH ROW\n")
  256. _T("BEGIN\n")
  257. _T("INSERT INTO MainDeletes VALUES(old.lID, datetime('now'));\n")
  258. _T("END\n"));
  259. }
  260. catch(CppSQLite3Exception& e)
  261. {
  262. if(didBackup == FALSE)
  263. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  264. e.errorCode();
  265. }
  266. //This was added later so try to add each time and catch the exception here
  267. try
  268. {
  269. db.execQuery(_T("SELECT lID, lClipID, lCopyBuffer FROM CopyBuffers"));
  270. }
  271. catch(CppSQLite3Exception& e)
  272. {
  273. if(didBackup == FALSE)
  274. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  275. e.errorCode();
  276. db.execDML(_T("CREATE TABLE CopyBuffers(")
  277. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  278. _T("lClipID INTEGER,")
  279. _T("lCopyBuffer INTEGER)"));
  280. }
  281. //This was added later so try to add each time and catch the exception here
  282. try
  283. {
  284. db.execQuery(_T("SELECT clipId FROM MainDeletes"));
  285. }
  286. catch(CppSQLite3Exception& e)
  287. {
  288. if(didBackup == FALSE)
  289. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  290. e.errorCode();
  291. db.execDML(_T("CREATE TABLE MainDeletes(")
  292. _T("clipID INTEGER,")
  293. _T("modifiedDate)"));
  294. db.execDML(_T("CREATE TRIGGER MainDeletes_delete_data_trigger BEFORE DELETE ON MainDeletes FOR EACH ROW\n")
  295. _T("BEGIN\n")
  296. _T("DELETE FROM CopyBuffers WHERE lClipID = old.clipID;\n")
  297. _T("DELETE FROM Data WHERE lParentID = old.clipID;\n")
  298. _T("END\n"));
  299. }
  300. try
  301. {
  302. db.execDML(_T("CREATE INDEX Main_ParentId on Main(lParentID DESC)"));
  303. db.execDML(_T("CREATE INDEX Main_IsGroup on Main(bIsGroup DESC)"));
  304. db.execDML(_T("CREATE INDEX Main_ShortCut on Main(lShortCut DESC)"));
  305. }
  306. catch(CppSQLite3Exception& e)
  307. {
  308. e.errorCode();
  309. }
  310. try
  311. {
  312. db.execQuery(_T("SELECT clipOrder, clipGroupOrder FROM Main"));
  313. }
  314. catch(CppSQLite3Exception& e)
  315. {
  316. if(didBackup == FALSE)
  317. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  318. db.execDML(_T("ALTER TABLE Main ADD clipOrder REAL"));
  319. db.execDML(_T("ALTER TABLE Main ADD clipGroupOrder REAL"));
  320. db.execDML(_T("Update Main set clipOrder = lDate, clipGroupOrder = lDate"));
  321. db.execDML(_T("CREATE INDEX Main_ClipOrder on Main(clipOrder DESC)"));
  322. db.execDML(_T("CREATE INDEX Main_ClipGroupOrder on Main(clipGroupOrder DESC)"));
  323. db.execDML(_T("DROP INDEX Main_Date"));
  324. e.errorCode();
  325. }
  326. try
  327. {
  328. db.execQuery(_T("SELECT globalShortCut FROM Main"));
  329. }
  330. catch(CppSQLite3Exception& e)
  331. {
  332. if(didBackup == FALSE)
  333. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  334. db.execDML(_T("ALTER TABLE Main ADD globalShortCut INTEGER"));
  335. e.errorCode();
  336. }
  337. try
  338. {
  339. db.execQuery(_T("SELECT lastPasteDate FROM Main"));
  340. }
  341. catch(CppSQLite3Exception& e)
  342. {
  343. if(didBackup == FALSE)
  344. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  345. db.execDML(_T("ALTER TABLE Main ADD lastPasteDate INTEGER"));
  346. db.execDML(_T("Update Main set lastPasteDate = lDate"));
  347. db.execDMLEx(_T("Update Main set lastPasteDate = %d where lastPasteDate <= 0"), (int)CTime::GetCurrentTime().GetTime());
  348. e.errorCode();
  349. }
  350. try
  351. {
  352. db.execQuery(_T("SELECT stickyClipOrder FROM Main"));
  353. }
  354. catch (CppSQLite3Exception& e)
  355. {
  356. if (didBackup == FALSE)
  357. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  358. db.execDML(_T("ALTER TABLE Main ADD stickyClipOrder REAL"));
  359. db.execDML(_T("ALTER TABLE Main ADD stickyClipGroupOrder REAL"));
  360. e.errorCode();
  361. }
  362. try
  363. {
  364. CppSQLite3Query q = db.execQuery(_T("PRAGMA index_info(Main_NoGroup);"));
  365. int count = 0;
  366. while (q.eof() == false)
  367. {
  368. count++;
  369. q.nextRow();
  370. }
  371. if(count == 0)
  372. {
  373. if (didBackup == FALSE)
  374. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  375. db.execDML(_T("Update Main set stickyClipOrder = -(2147483647) where stickyClipOrder IS NULL;"));
  376. db.execDML(_T("Update Main set stickyClipGroupOrder = -(2147483647) where stickyClipGroupOrder IS NULL;"));
  377. db.execDML(_T("Update Main set stickyClipOrder = -(2147483647) where stickyClipOrder = 0;"));
  378. db.execDML(_T("Update Main set stickyClipGroupOrder = -(2147483647) where stickyClipGroupOrder = 0;"));
  379. db.execDML(_T("CREATE INDEX Main_NoGroup ON Main(bIsGroup ASC, stickyClipOrder DESC, clipOrder DESC);"));
  380. db.execDML(_T("CREATE INDEX Main_InGroup ON Main(lParentId ASC, bIsGroup ASC, stickyClipGroupOrder DESC, clipGroupOrder DESC);"));
  381. db.execDML(_T("CREATE INDEX Data_ParentId_Format ON Data(lParentID COLLATE BINARY ASC, strClipBoardFormat COLLATE NOCASE ASC);"));
  382. }
  383. }
  384. catch (CppSQLite3Exception& e)
  385. {
  386. if (didBackup == FALSE)
  387. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  388. e.errorCode();
  389. }
  390. try
  391. {
  392. db.execQuery(_T("SELECT MoveToGroupShortCut FROM Main"));
  393. db.execQuery(_T("SELECT GlobalMoveToGroupShortCut FROM Main"));
  394. }
  395. catch(CppSQLite3Exception& e)
  396. {
  397. if(didBackup == FALSE)
  398. didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg);
  399. db.execDML(_T("ALTER TABLE Main ADD MoveToGroupShortCut INTEGER"));
  400. db.execDML(_T("ALTER TABLE Main ADD GlobalMoveToGroupShortCut INTEGER"));
  401. e.errorCode();
  402. }
  403. }
  404. CATCH_SQLITE_EXCEPTION_AND_RETURN(FALSE)
  405. if(popUpMsg != NULL &&
  406. IsWindow(popUpMsg->m_hWnd))
  407. {
  408. popUpMsg->CloseWindow();
  409. popUpMsg->DestroyWindow();
  410. delete popUpMsg;
  411. popUpMsg = NULL;
  412. }
  413. return TRUE;
  414. }
  415. BOOL BackupDB(CString dbPath, CString prefix, CDittoPopupWindow **popUpMsg)
  416. {
  417. if ((*popUpMsg) == NULL)
  418. {
  419. CRect r;
  420. GetMonitorRect(0, r);
  421. *popUpMsg = new CDittoPopupWindow();
  422. (*popUpMsg)->Create(CRect(r.right - 400, r.bottom - 130, r.right - 10, r.bottom - 10), NULL);
  423. ::SetWindowPos((*popUpMsg)->m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
  424. (*popUpMsg)->ShowWindow(SW_SHOW);
  425. (*popUpMsg)->UpdateText(_T("Backing up Ditto's Database"));
  426. }
  427. CString backup = GetFilePath(dbPath);
  428. CInternetUpdate update;
  429. long runningVersion = update.GetRunningVersion();
  430. CString versionString = update.GetVersionString(runningVersion);
  431. backup += GetFileName(dbPath) += _T("_") + prefix + _T("_") + versionString;
  432. backup.Replace(_T(".db"), _T(""));
  433. backup.Replace(_T("."), _T("_"));
  434. CString temp = backup;
  435. temp += _T(".db");
  436. int i = 1;
  437. while(FileExists(temp))
  438. {
  439. temp.Format(_T("%s_%d.db"), backup, i);
  440. i++;
  441. }
  442. backup = temp;
  443. BOOL ret = FALSE;
  444. try
  445. {
  446. CFile file;
  447. CFileException ex;
  448. if(file.Open(dbPath, CFile::modeRead|CFile::typeBinary|CFile::shareDenyNone, &ex))
  449. {
  450. ULONGLONG fileSize = file.GetLength();
  451. ULONGLONG totalReadSize = 0;
  452. int percentageComplete = 0;
  453. UINT readBytes = 0;
  454. char *pBuffer = new char[65536];
  455. if(pBuffer != NULL)
  456. {
  457. CFile writeFile;
  458. if(writeFile.Open(backup, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyNone, &ex))
  459. {
  460. do
  461. {
  462. readBytes = file.Read(pBuffer, 65536);
  463. writeFile.Write(pBuffer, readBytes);
  464. totalReadSize+= readBytes;
  465. int percent = ((totalReadSize * 100) / fileSize);
  466. if(percent != percentageComplete)
  467. {
  468. percentageComplete = percent;
  469. (*popUpMsg)->SetProgressBarPercent(percentageComplete);
  470. }
  471. }while(readBytes >= 65536);
  472. writeFile.Close();
  473. ret = TRUE;
  474. }
  475. }
  476. file.Close();
  477. }
  478. }
  479. catch(...)
  480. {
  481. }
  482. //BOOL ret = CopyFile(dbPath, backup, TRUE);
  483. if ((*popUpMsg) != NULL)
  484. {
  485. (*popUpMsg)->HideProgressBar();
  486. (*popUpMsg)->UpdateText(_T("Running Ditto database scripts ..."));
  487. }
  488. return ret;
  489. }
  490. BOOL CreateDB(CString csFile)
  491. {
  492. try
  493. {
  494. CppSQLite3DB db;
  495. db.open(csFile);
  496. db.execDML(_T("PRAGMA auto_vacuum = 1"));
  497. db.execDML(_T("CREATE TABLE Main(")
  498. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  499. _T("lDate INTEGER, ")
  500. _T("mText TEXT, ")
  501. _T("lShortCut INTEGER, ")
  502. _T("lDontAutoDelete INTEGER, ")
  503. _T("CRC INTEGER, ")
  504. _T("bIsGroup INTEGER, ")
  505. _T("lParentID INTEGER, ")
  506. _T("QuickPasteText TEXT, ")
  507. _T("clipOrder REAL, ")
  508. _T("clipGroupOrder REAL, ")
  509. _T("globalShortCut INTEGER, ")
  510. _T("lastPasteDate INTEGER, ")
  511. _T("stickyClipOrder REAL, ")
  512. _T("stickyClipGroupOrder REAL, ")
  513. _T("MoveToGroupShortCut INTEGER, ")
  514. _T("GlobalMoveToGroupShortCut INTEGER);"));
  515. db.execDML(_T("CREATE TABLE Data(")
  516. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  517. _T("lParentID INTEGER, ")
  518. _T("strClipBoardFormat TEXT, ")
  519. _T("ooData BLOB);"));
  520. db.execDML(_T("CREATE TABLE Types(")
  521. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  522. _T("TypeText TEXT);"));
  523. db.execDML(_T("CREATE UNIQUE INDEX Main_ID on Main(lID ASC)"));
  524. db.execDML(_T("CREATE UNIQUE INDEX Data_ID on Data(lID ASC)"));
  525. db.execDML(_T("CREATE INDEX Main_ClipOrder on Main(clipOrder DESC)"));
  526. db.execDML(_T("CREATE INDEX Main_ClipGroupOrder on Main(clipGroupOrder DESC)"));
  527. db.execDML(_T("CREATE INDEX Main_ParentId on Main(lParentID DESC)"));
  528. db.execDML(_T("CREATE INDEX Main_IsGroup on Main(bIsGroup DESC)"));
  529. db.execDML(_T("CREATE INDEX Main_ShortCut on Main(lShortCut DESC)"));
  530. db.execDML(_T("CREATE TRIGGER delete_data_trigger BEFORE DELETE ON Main FOR EACH ROW\n")
  531. _T("BEGIN\n")
  532. _T("INSERT INTO MainDeletes VALUES(old.lID, datetime('now'));\n")
  533. _T("END\n"));
  534. db.execDML(_T("CREATE TABLE CopyBuffers(")
  535. _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ")
  536. _T("lClipID INTEGER, ")
  537. _T("lCopyBuffer INTEGER)"));
  538. db.execDML(_T("CREATE TABLE MainDeletes(")
  539. _T("clipID INTEGER,")
  540. _T("modifiedDate)"));
  541. db.execDML(_T("CREATE TRIGGER MainDeletes_delete_data_trigger BEFORE DELETE ON MainDeletes FOR EACH ROW\n")
  542. _T("BEGIN\n")
  543. _T("DELETE FROM CopyBuffers WHERE lClipID = old.clipID;\n")
  544. _T("DELETE FROM Data WHERE lParentID = old.clipID;\n")
  545. _T("END\n"));
  546. db.execDML(_T("CREATE INDEX Main_NoGroup ON Main(bIsGroup ASC, stickyClipOrder DESC, clipOrder DESC);"));
  547. db.execDML(_T("CREATE INDEX Main_InGroup ON Main(lParentId ASC, bIsGroup ASC, stickyClipGroupOrder DESC, clipGroupOrder DESC);"));
  548. db.execDML(_T("CREATE INDEX Data_ParentId_Format ON Data(lParentID COLLATE BINARY ASC, strClipBoardFormat COLLATE NOCASE ASC);"));
  549. db.close();
  550. }
  551. CATCH_SQLITE_EXCEPTION_AND_RETURN(FALSE)
  552. return TRUE;
  553. }
  554. BOOL CompactDatabase()
  555. {
  556. // if(!theApp.CloseDB())
  557. // return FALSE;
  558. //
  559. // CString csDBName = GetDBName();
  560. // CString csTempDBName = csDBName;
  561. // csTempDBName.Replace(".mdb", "TempDBName.mdb");
  562. //
  563. // //Compact the database
  564. // try
  565. // {
  566. // CDaoWorkspace::CompactDatabase(csDBName, csTempDBName);//, dbLangGeneral, 0, "andrew");//DATABASE_PASSWORD);
  567. // }
  568. // catch(CDaoException* e)
  569. // {
  570. // AfxMessageBox(e->m_pErrorInfo->m_strDescription);
  571. // DeleteFile(csTempDBName);
  572. // e->Delete();
  573. // return FALSE;
  574. // }
  575. // catch(CMemoryException* e)
  576. // {
  577. // AfxMessageBox("Memory Exception");
  578. // DeleteFile(csTempDBName);
  579. // e->Delete();
  580. // return FALSE;
  581. // }
  582. //
  583. // //Since compacting the database creates a new db delete the old one and replace it
  584. // //with the compacted db
  585. // if(DeleteFile(csDBName))
  586. // {
  587. // try
  588. // {
  589. // CFile::Rename(csTempDBName, csDBName);
  590. // }
  591. // catch(CFileException *e)
  592. // {
  593. // e->ReportError();
  594. // e->Delete();
  595. // return FALSE;
  596. // }
  597. // }
  598. // else
  599. // AfxMessageBox("Error Compacting Database");
  600. return TRUE;
  601. }
  602. BOOL RepairDatabase()
  603. {
  604. // if(!theApp.CloseDB())
  605. // return FALSE;
  606. // try
  607. // {
  608. // CDaoWorkspace::RepairDatabase(GetDBName());
  609. // }
  610. // catch(CDaoException *e)
  611. // {
  612. // AfxMessageBox(e->m_pErrorInfo->m_strDescription);
  613. // e->Delete();
  614. // return FALSE;
  615. // }
  616. return TRUE;
  617. }
  618. BOOL RemoveOldEntries(bool checkIdleTime)
  619. {
  620. Log(StrF(_T("Beginning of RemoveOldEntries MaxEntries: %d - Keep days: %d"), CGetSetOptions::GetMaxEntries(), CGetSetOptions::GetExpiredEntries()));
  621. try
  622. {
  623. CppSQLite3DB db;
  624. CString csDbPath = CGetSetOptions::GetDBPath();
  625. db.open(csDbPath);
  626. if(CGetSetOptions::GetCheckForMaxEntries())
  627. {
  628. long lMax = CGetSetOptions::GetMaxEntries();
  629. if(lMax >= 0)
  630. {
  631. CClipIDs IDs;
  632. int clipId;
  633. CppSQLite3Query q = db.execQueryEx(_T("SELECT lID, lShortCut, lParentID, lDontAutoDelete, stickyClipOrder, stickyClipGroupOrder FROM Main WHERE bIsGroup = 0 ORDER BY clipOrder DESC LIMIT -1 OFFSET %d"), lMax);
  634. while(q.eof() == false)
  635. {
  636. int shortcut = q.getIntField(_T("lShortCut"));
  637. int dontDelete = q.getIntField(_T("lDontAutoDelete"));
  638. int parentId = q.getIntField(_T("lParentID"));
  639. double stickyClipOrder = q.getFloatField(_T("stickyClipOrder"));
  640. double stickyClipGroupOrder = q.getFloatField(_T("stickyClipGroupOrder"));
  641. //Only delete entries that have no shortcut and don't have the flag set and aren't in groups and
  642. if(shortcut == 0 &&
  643. dontDelete == 0 &&
  644. parentId <= 0 &&
  645. stickyClipOrder == -(2147483647) &&
  646. stickyClipGroupOrder == -(2147483647))
  647. {
  648. clipId = q.getIntField(_T("lID"));
  649. IDs.Add(clipId);
  650. Log(StrF(_T("From MaxEntries - Deleting Id: %d"), clipId));
  651. }
  652. q.nextRow();
  653. }
  654. if(IDs.GetCount() > 0)
  655. {
  656. IDs.DeleteIDs(false, db);
  657. }
  658. }
  659. }
  660. if(CGetSetOptions::GetCheckForExpiredEntries())
  661. {
  662. long lExpire = CGetSetOptions::GetExpiredEntries();
  663. if(lExpire)
  664. {
  665. CTime now = CTime::GetCurrentTime();
  666. now -= CTimeSpan(lExpire, 0, 0, 0);
  667. CClipIDs IDs;
  668. CppSQLite3Query q = db.execQueryEx(_T("SELECT lID FROM Main ")
  669. _T("WHERE lastPasteDate < %d AND ")
  670. _T("bIsGroup = 0 AND lShortCut = 0 AND lParentID <= 0 AND lDontAutoDelete = 0 AND stickyClipOrder = -(2147483647) AND stickyClipGroupOrder = -(2147483647)"), (int)now.GetTime());
  671. while(q.eof() == false)
  672. {
  673. IDs.Add(q.getIntField(_T("lID")));
  674. Log(StrF(_T("From Clips Expire - Deleting Id: %d"), q.getIntField(_T("lID"))));
  675. q.nextRow();
  676. }
  677. if(IDs.GetCount() > 0)
  678. {
  679. IDs.DeleteIDs(false, db);
  680. }
  681. }
  682. }
  683. int toDeleteCount = db.execScalar(_T("SELECT COUNT(clipID) FROM MainDeletes"));
  684. Log(StrF(_T("Before Deleting emptied out data, count: %d, Idle Seconds: %f"), toDeleteCount, IdleSeconds()));
  685. //Only delete 1 at a time, was finding that it was taking a long time to delete clips, locking the db and causing other queries
  686. //to lock up
  687. CppSQLite3Query q = db.execQueryEx(_T("SELECT * FROM MainDeletes LIMIT %d"), CGetSetOptions::GetMainDeletesDeleteCount());
  688. int deleteCount = 0;
  689. while(q.eof() == false)
  690. {
  691. double idleSeconds = IdleSeconds();
  692. if(checkIdleTime == false || idleSeconds > CGetSetOptions::GetIdleSecondsBeforeDelete())
  693. {
  694. //delete any data items sitting out there that the main table data was deleted
  695. //this was done to speed up deleted from the main table
  696. deleteCount = db.execDMLEx(_T("DELETE FROM MainDeletes WHERE clipID=%d"), q.getIntField(_T("clipID")));
  697. }
  698. else
  699. {
  700. Log(StrF(_T("Computer has not been idle long enough to delete clips, Min Idle: %d, current Idle: %d"),
  701. CGetSetOptions::GetIdleSecondsBeforeDelete(), idleSeconds));
  702. break;
  703. }
  704. q.nextRow();
  705. }
  706. toDeleteCount = db.execScalar(_T("SELECT COUNT(clipID) FROM MainDeletes"));
  707. Log(StrF(_T("After Deleting emptied out data rows, Count: %d, toDelete: %d"), deleteCount, toDeleteCount));
  708. }
  709. CATCH_SQLITE_EXCEPTION
  710. Log(_T("End of RemoveOldEntries"));
  711. return TRUE;
  712. }
  713. BOOL EnsureDirectory(CString csPath)
  714. {
  715. TCHAR drive[_MAX_DRIVE];
  716. TCHAR dir[_MAX_DIR];
  717. TCHAR fname[_MAX_FNAME];
  718. TCHAR ext[_MAX_EXT];
  719. SPLITPATH(csPath, drive, dir, fname, ext);
  720. CString csDir(drive);
  721. csDir += dir;
  722. if(FileExists(csDir) == FALSE)
  723. {
  724. if(CreateDirectory(csDir, NULL))
  725. return TRUE;
  726. }
  727. else
  728. return TRUE;
  729. return FALSE;
  730. }
  731. // BOOL RunZippApp(CString csCommandLine)
  732. // {
  733. // CString csLocalPath = GETENV(_T("U3_HOST_EXEC_PATH"));
  734. // FIX_CSTRING_PATH(csLocalPath);
  735. //
  736. // CString csZippApp = GETENV(_T("U3_DEVICE_EXEC_PATH"));
  737. // FIX_CSTRING_PATH(csZippApp);
  738. // csZippApp += "7za.exe";
  739. //
  740. // csZippApp += " ";
  741. // csZippApp += csCommandLine;
  742. //
  743. // Log(csZippApp);
  744. //
  745. // STARTUPINFO StartupInfo;
  746. // PROCESS_INFORMATION ProcessInformation;
  747. //
  748. // ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  749. // StartupInfo.cb = sizeof(StartupInfo);
  750. // ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
  751. //
  752. // StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  753. // StartupInfo.wShowWindow = SW_HIDE;
  754. //
  755. // BOOL bRet = CreateProcess(NULL, csZippApp.GetBuffer(csZippApp.GetLength()), NULL, NULL, FALSE,
  756. // CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, csLocalPath,
  757. // &StartupInfo, &ProcessInformation);
  758. //
  759. // if(bRet)
  760. // {
  761. // WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
  762. //
  763. // DWORD dwExitCode;
  764. // GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
  765. //
  766. // CString cs;
  767. // cs.Format(_T("Exit code from unzip = %d"), dwExitCode);
  768. // Log(cs);
  769. //
  770. // if(dwExitCode != 0)
  771. // {
  772. // bRet = FALSE;
  773. // }
  774. // }
  775. // else
  776. // {
  777. // bRet = FALSE;
  778. // Log(_T("Create Process Failed"));
  779. // }
  780. //
  781. // csZippApp.ReleaseBuffer();
  782. //
  783. // return bRet;
  784. // }
  785. // BOOL CopyDownDatabase()
  786. // {
  787. // BOOL bRet = FALSE;
  788. //
  789. // CString csZippedPath = GETENV(_T("U3_APP_DATA_PATH"));
  790. // FIX_CSTRING_PATH(csZippedPath);
  791. //
  792. // CString csUnZippedPath = csZippedPath;
  793. // csUnZippedPath += "Ditto.db";
  794. //
  795. // csZippedPath += "Ditto.7z";
  796. //
  797. // CString csLocalPath = GETENV(_T("U3_HOST_EXEC_PATH"));
  798. // FIX_CSTRING_PATH(csLocalPath);
  799. //
  800. // if(FileExists(csZippedPath))
  801. // {
  802. // CString csCommandLine;
  803. //
  804. // //e = extract
  805. // //surround command line arguments with quotes
  806. // //-aoa = overight files with extracted files
  807. //
  808. // csCommandLine += "e ";
  809. // csCommandLine += "\"";
  810. // csCommandLine += csZippedPath;
  811. // csCommandLine += "\"";
  812. // csCommandLine += " -o";
  813. // csCommandLine += "\"";
  814. // csCommandLine += csLocalPath;
  815. // csCommandLine += "\"";
  816. // csCommandLine += " -aoa";
  817. //
  818. // bRet = RunZippApp(csCommandLine);
  819. //
  820. // csLocalPath += "Ditto.db";
  821. // }
  822. // else if(FileExists(csUnZippedPath))
  823. // {
  824. // csLocalPath += "Ditto.db";
  825. // bRet = CopyFile(csUnZippedPath, csLocalPath, FALSE);
  826. // }
  827. //
  828. // if(FileExists(csLocalPath) == FALSE)
  829. // {
  830. // Log(_T("Failed to copy files from device zip file"));
  831. // }
  832. //
  833. // g_Opt.nLastDbWriteTime = GetLastWriteTime(csLocalPath);
  834. //
  835. // return bRet;
  836. // }
  837. //BOOL CopyUpDatabase()
  838. //{
  839. // CStringA csZippedPath = "C:\\";//getenv("U3_APP_DATA_PATH");
  840. // FIX_CSTRING_PATH(csZippedPath);
  841. // csZippedPath += "Ditto.zip";
  842. // CStringA csLocalPath = GetDBName();//getenv("U3_HOST_EXEC_PATH");
  843. // //FIX_CSTRING_PATH(csLocalPath);
  844. // //csLocalPath += "Ditto.db";
  845. //
  846. // CZipper Zip;
  847. //
  848. // if(Zip.OpenZip(csZippedPath))
  849. // {
  850. // Zip.AddFileToZip(csLocalPath);
  851. // }
  852. //
  853. // return TRUE;
  854. //}