DatabaseUtilities.cpp 26 KB

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