DatabaseUtilities.cpp 26 KB

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