DatabaseUtilities.cpp 24 KB

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