DatabaseUtilities.cpp 26 KB

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