ECDatabaseUpdate.cpp 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/zcdefs.h>
  18. #include <utility>
  19. #include <kopano/platform.h>
  20. #include "ECDatabase.h"
  21. #include "ECDatabaseUpdate.h"
  22. #include <kopano/stringutil.h>
  23. #include <kopano/ECDefs.h>
  24. #include "ECDBDef.h"
  25. #include "ECUserManagement.h"
  26. #include <kopano/ecversion.h>
  27. #include <mapidefs.h>
  28. #include <mapitags.h>
  29. #include "ECConversion.h"
  30. #include "SOAPUtils.h"
  31. #include "ECSearchFolders.h"
  32. #include "ics.h"
  33. #include <kopano/charset/convert.h>
  34. #include "ECStringCompat.h"
  35. #include "ECMAPI.h"
  36. #include <zlib.h>
  37. #include <kopano/mapiext.h>
  38. #include <edkmdb.h>
  39. namespace KC {
  40. bool searchfolder_restart_required; //HACK for rebuild the searchfolders with an upgrade
  41. /*
  42. database upgrade
  43. Version 4.20 (not include)
  44. * Add table object
  45. * Add table objectproperty
  46. * Add table objectrelation
  47. * Change user table structure
  48. * Converting users and group
  49. Optional 4.20 / 5.0 (not include)
  50. * Change database engine to INNODB
  51. * Remove key val_string on the table mvproperties and properties
  52. * Change the primary key, "ht" key and "hierarchyid" key on the hierarchy table
  53. * Change externid to field to VARBINARY(255) and add externid key
  54. Version 4.21 (not include)
  55. * change the "parent" key on the hierarchy table
  56. Version 5.00 (not included)
  57. * Add column storeid in properties table and update the ids
  58. * Add freebusy folders in public store
  59. * Set the permissions on the free/busy folders
  60. Version 5.10
  61. * Add table version
  62. * Add table searchfolders
  63. * Update non-login from 10 to 1
  64. * (Beta update) Add flags in search table
  65. * rebuild searchfolders
  66. Version 5.20
  67. * Create table changes
  68. * Create table syncs
  69. * Create table indexedproperties
  70. * Create table settings
  71. * Insert server guid into settings table
  72. * Create from object id a sourcekeys and add them into indexedproperties
  73. Version 6.00
  74. * Create from object id an entryid and add them into indexedproperties
  75. * Update Search criteria
  76. * Update users table to have 'type' field instead of 'isgroup' and 'isnonactive'
  77. * Update users table to have 'signature' field
  78. * Add source_key_auto_increment setting
  79. * Fix unique key in users table
  80. Version 6.10
  81. * Add company column
  82. * Add company in user table
  83. * Add company in objectproperty table
  84. Version 6.20
  85. * Move public folders and remove favorites
  86. Version 6.30
  87. * Add externid column to object table (changed between beta's)
  88. * Add reference table for Single Instance Attachments
  89. * Add distributed lock when upgrading to 6.30 (distributed only on clean 6.30)
  90. * Add abchanges table to hold ab sourcekeys (since they don't fit in the changes table anymore)
  91. * Set tag column in singleinstance to correct tag value (beta's have wrong value)
  92. Version 6.40
  93. * Rename object_type columns to objectclass, and fix their contents with the new defined values (in 2 steps)
  94. * Add objectmvproperties table (for offline synced addressbook details)
  95. * Add syncedmessages table for keeping track of messages that were synchronized with a restriction
  96. * Update the primary key on the 'outgoingqueue' table
  97. * Update the primary key on the 'acl' table
  98. * Update externid in users and object table to be blob, so mysql 4.1 leaves trailing 0's
  99. * Update changes table primary key
  100. * Update mvproperties table primary key
  101. * Update objectclass for DB plugin groups to be security enabled
  102. * Update objectrelation table to switch send-as settings
  103. Version 7.00
  104. * Print error howto "convert", or if admin forced do the upgrade of tables with text fields to unicode.
  105. * Update stores table to store the username in a char field.
  106. * Update rules xml blobs to unicode.
  107. * Update searchfolder xml blobs to unicode.
  108. Version 7.0.1
  109. * update receive folder to unicode and increase the messageclass column size
  110. Version 7.1.0
  111. * update WLINK entries to new record key format
  112. Version independed
  113. * Add setting for IMAP
  114. * Change primary key in changetable and add an extra move key
  115. * Force addressbook resync
  116. */
  117. struct SObject {
  118. SObject(unsigned int id, unsigned int type) {ulId = id; ulType = type;}
  119. bool operator<(const SObject &rhs) const {return (ulId < rhs.ulId || (ulId == rhs.ulId && ulType < rhs.ulType));}
  120. unsigned int ulId;
  121. unsigned int ulType;
  122. };
  123. struct SRelation {
  124. SRelation(unsigned int objectId, unsigned int parentObjectId, unsigned int relationType) {
  125. ulObjectId = objectId; ulParentObjectId = parentObjectId; ulRelationType = relationType;
  126. }
  127. unsigned int ulObjectId;
  128. unsigned int ulParentObjectId;
  129. unsigned int ulRelationType;
  130. };
  131. // 1
  132. ECRESULT UpdateDatabaseCreateVersionsTable(ECDatabase *lpDatabase)
  133. {
  134. return lpDatabase->DoInsert(Z_TABLEDEF_VERSIONS);
  135. }
  136. // 2
  137. ECRESULT UpdateDatabaseCreateSearchFolders(ECDatabase *lpDatabase)
  138. {
  139. return lpDatabase->DoInsert(Z_TABLEDEF_SEARCHRESULTS);
  140. }
  141. // 3
  142. ECRESULT UpdateDatabaseFixUserNonActive(ECDatabase *lpDatabase)
  143. {
  144. return lpDatabase->DoUpdate("UPDATE users SET nonactive=1 WHERE nonactive=10");
  145. }
  146. // 4
  147. ECRESULT UpdateDatabaseCreateSearchFoldersFlags(ECDatabase *lpDatabase)
  148. {
  149. return lpDatabase->DoUpdate("ALTER TABLE searchresults ADD COLUMN flags int(11) unsigned NOT NULL default '0'");
  150. }
  151. // 5
  152. ECRESULT UpdateDatabasePopulateSearchFolders(ECDatabase *lpDatabase)
  153. {
  154. searchfolder_restart_required = 1;
  155. return erSuccess;
  156. }
  157. // 6
  158. ECRESULT UpdateDatabaseCreateChangesTable(ECDatabase *lpDatabase)
  159. {
  160. return lpDatabase->DoInsert(Z_TABLEDEF_CHANGES);
  161. }
  162. // 7
  163. ECRESULT UpdateDatabaseCreateSyncsTable(ECDatabase *lpDatabase)
  164. {
  165. return lpDatabase->DoInsert(Z_TABLEDEF_SYNCS);
  166. }
  167. // 8
  168. ECRESULT UpdateDatabaseCreateIndexedPropertiesTable(ECDatabase *lpDatabase)
  169. {
  170. return lpDatabase->DoInsert(Z_TABLEDEF_INDEXED_PROPERTIES);
  171. }
  172. // 9
  173. ECRESULT UpdateDatabaseCreateSettingsTable(ECDatabase *lpDatabase)
  174. {
  175. return lpDatabase->DoInsert(Z_TABLEDEF_SETTINGS);
  176. }
  177. ECRESULT InsertServerGUID(ECDatabase *lpDatabase)
  178. {
  179. GUID guid;
  180. if (CoCreateGuid(&guid) != S_OK) {
  181. ec_log_err("InsertServerGUID(): CoCreateGuid failed");
  182. return KCERR_DATABASE_ERROR;
  183. }
  184. return lpDatabase->DoInsert("INSERT INTO `settings` VALUES ('server_guid', " + lpDatabase->EscapeBinary(reinterpret_cast<unsigned char *>(&guid), sizeof(GUID)) + ")");
  185. }
  186. // 10
  187. ECRESULT UpdateDatabaseCreateServerGUID(ECDatabase *lpDatabase)
  188. {
  189. return InsertServerGUID(lpDatabase);
  190. }
  191. // 11
  192. ECRESULT UpdateDatabaseCreateSourceKeys(ECDatabase *lpDatabase)
  193. {
  194. ECRESULT er = erSuccess;
  195. string strQuery;
  196. DB_RESULT lpResult;
  197. DB_ROW lpDBRow = NULL;
  198. DB_LENGTHS lpDBLenths = NULL;
  199. strQuery = "SELECT `value` FROM `settings` WHERE `name` = 'server_guid'";
  200. er = lpDatabase->DoSelect(strQuery, &lpResult);
  201. if(er != erSuccess)
  202. return er;
  203. lpDBRow = lpDatabase->FetchRow(lpResult);
  204. lpDBLenths = lpDatabase->FetchRowLengths(lpResult);
  205. if(lpDBRow == NULL || lpDBRow[0] == NULL || lpDBLenths == NULL || lpDBLenths[0] != sizeof(GUID)) {
  206. ec_log_err("UpdateDatabaseCreateSourceKeys(): row or columns NULL");
  207. return KCERR_DATABASE_ERROR;
  208. }
  209. //Insert source keys for folders
  210. strQuery = "INSERT INTO indexedproperties (tag, hierarchyid, val_binary) SELECT 26080, h.id, CONCAT(" + lpDatabase->EscapeBinary((unsigned char*)lpDBRow[0], sizeof(GUID));
  211. strQuery += ", CHAR(h.id&0xFF, h.id>>8&0xFF, h.id>>16&0xFF, h.id>>24&0xFF))";
  212. strQuery += " FROM hierarchy AS h WHERE h.type = 3";
  213. er = lpDatabase->DoInsert(strQuery);
  214. if(er != erSuccess)
  215. return er;
  216. //Insert source keys for messages
  217. strQuery = "INSERT INTO indexedproperties (tag, hierarchyid, val_binary) SELECT 26080, h.id, CONCAT(" + lpDatabase->EscapeBinary((unsigned char*)lpDBRow[0], sizeof(GUID));
  218. strQuery += ", CHAR(h.id&0xFF, h.id>>8&0xFF, h.id>>16&0xFF, h.id>>24&0xFF))";
  219. strQuery += " FROM hierarchy AS h LEFT JOIN hierarchy AS p ON h.parent = p.id WHERE h.type = 5 AND p.type = 3";
  220. return lpDatabase->DoInsert(strQuery);
  221. }
  222. // 12
  223. ECRESULT UpdateDatabaseConvertEntryIDs(ECDatabase *lpDatabase)
  224. {
  225. ECRESULT er = erSuccess;
  226. string strQuery;
  227. DB_RESULT lpResult;
  228. DB_ROW lpDBRow = NULL;
  229. DB_LENGTHS lpDBLenths = NULL;
  230. int i, nStores;
  231. strQuery = "SELECT `guid`, `hierarchy_id` FROM `stores`";
  232. er = lpDatabase->DoSelect(strQuery, &lpResult);
  233. if(er != erSuccess)
  234. return er;
  235. nStores = lpDatabase->GetNumRows(lpResult);
  236. ec_log_notice(" Stores to convert: %d", nStores);
  237. for (i = 0; i < nStores; ++i) {
  238. lpDBRow = lpDatabase->FetchRow(lpResult);
  239. lpDBLenths = lpDatabase->FetchRowLengths(lpResult);
  240. if(lpDBRow == NULL || lpDBRow[0] == NULL || lpDBRow[1] == NULL ||
  241. lpDBLenths == NULL || lpDBLenths[0] != sizeof(GUID) )
  242. {
  243. ec_log_crit(" Failed to convert store \"%s\"", (lpDBRow && lpDBRow[1])?lpDBRow[1]:"Unknown");
  244. if(lpDBRow == NULL || lpDBRow[0] == NULL || lpDBLenths == NULL || lpDBLenths[0] != sizeof(GUID) )
  245. ec_log_crit(" The table \"stores\" includes a wrong GUID");
  246. else
  247. ec_log_crit(" Check the data in table \"stores\"");
  248. return KCERR_DATABASE_ERROR;
  249. }
  250. ec_log_notice(" Converting entryids of store %d", atoui(lpDBRow[1]));
  251. er = CreateRecursiveStoreEntryIds(lpDatabase, atoui(lpDBRow[1]), (unsigned char*)lpDBRow[0]);
  252. if(er != erSuccess) {
  253. ec_log_crit(" Failed to convert store %d", atoui(lpDBRow[1]));
  254. return er;
  255. }
  256. }
  257. return erSuccess;
  258. }
  259. ECRESULT CreateRecursiveStoreEntryIds(ECDatabase *lpDatabase, unsigned int ulStoreHierarchyId, unsigned char* lpStoreGuid)
  260. {
  261. ECRESULT er;
  262. string strQuery, strInsertQuery, strDefaultQuery;
  263. string strInValues;
  264. DB_RESULT lpDBResult;
  265. DB_ROW lpDBRow = NULL;
  266. // FIXME: use ECListInt and ECListIntIterator (in ECGenericObjectTable.h)
  267. std::list<unsigned int> lstFolders; // The list of folders
  268. // Insert the entryids
  269. strDefaultQuery = "REPLACE INTO indexedproperties (tag, hierarchyid, val_binary) ";
  270. strDefaultQuery+= "SELECT 0x0FFF, h.id, CONCAT('\\0\\0\\0\\0', "+ lpDatabase->EscapeBinary(lpStoreGuid, sizeof(GUID));
  271. strDefaultQuery+= ", '\\0\\0\\0\\0', CHAR(h.type&0xFF, h.type>>8&0xFF, h.type>>16&0xFF, h.type>>24&0xFF), ";
  272. strDefaultQuery+= "CHAR(h.id&0xFF, h.id>>8&0xFF, h.id>>16&0xFF, h.id>>24&0xFF), '\\0\\0\\0\\0')";
  273. strDefaultQuery+= " FROM hierarchy AS h WHERE h.id IN ";
  274. // Add the master id
  275. lstFolders.push_back( ulStoreHierarchyId );
  276. auto iterFolders = lstFolders.begin();
  277. while (iterFolders != lstFolders.cend()) {
  278. // Make parent list
  279. strInValues.clear();
  280. while (iterFolders != lstFolders.cend()) {
  281. strInValues += stringify(*iterFolders);
  282. ++iterFolders;
  283. if (strDefaultQuery.size() + strInValues.size() * 2 > lpDatabase->GetMaxAllowedPacket())
  284. break;
  285. if (iterFolders != lstFolders.cend())
  286. strInValues += ",";
  287. }
  288. // Remove the added entries
  289. lstFolders.erase(lstFolders.begin(), iterFolders);
  290. // Insert the entryids
  291. er = lpDatabase->DoInsert(strDefaultQuery + "(" + strInValues + ")");
  292. if(er != erSuccess)
  293. return er;
  294. // Get the new parents
  295. strQuery= "SELECT id FROM hierarchy WHERE parent IN ( "+strInValues+")";
  296. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  297. if (er != erSuccess)
  298. return er;
  299. while(true) {
  300. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  301. if (lpDBRow == NULL)
  302. break;
  303. if (lpDBRow[0] == NULL) {
  304. ec_log_err("CreateRecursiveStoreEntryIds(): column is NULL");
  305. return KCERR_DATABASE_ERROR;
  306. }
  307. lstFolders.push_back(atoui(lpDBRow[0]));
  308. }
  309. iterFolders = lstFolders.begin();
  310. } //while
  311. return erSuccess;
  312. }
  313. // 13
  314. ECRESULT UpdateDatabaseSearchCriteria(ECDatabase *lpDatabase)
  315. {
  316. ECRESULT er = erSuccess;
  317. std::string strQuery;
  318. DB_RESULT lpDBResult;
  319. DB_ROW lpDBRow = NULL;
  320. unsigned int ulStoreLast = 0;
  321. unsigned int ulStoreId = 0;
  322. struct searchCriteria *lpNewSearchCriteria = NULL;
  323. // Search for all folders with PR_EC_SEARCHCRIT that are not deleted
  324. strQuery = "SELECT properties.storeid, hierarchy.id, properties.val_string FROM hierarchy LEFT JOIN properties ON properties.hierarchyid=hierarchy.id AND properties.tag=" + stringify(PROP_ID(PR_EC_SEARCHCRIT)) +" AND properties.type=" + stringify(PROP_TYPE(PR_EC_SEARCHCRIT)) + " WHERE hierarchy.type=3 AND hierarchy.flags=2 ORDER BY properties.storeid";
  325. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  326. if(er != erSuccess)
  327. goto exit;
  328. while(true) {
  329. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  330. if (lpDBRow == NULL)
  331. break;
  332. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL) continue;
  333. ulStoreId = atoui(lpDBRow[0]);
  334. if (ulStoreLast != ulStoreId) {
  335. ec_log_notice(" Convert store %d", ulStoreId);
  336. ulStoreLast = ulStoreId;
  337. }
  338. // convert the entryidlist
  339. if (ConvertSearchCriteria52XTo6XX(lpDatabase, lpDBRow[2], &lpNewSearchCriteria) != erSuccess)
  340. {
  341. ec_log_crit(" WARNING: Unable to convert the search criteria of folder %d", atoui(lpDBRow[1]));
  342. goto next;
  343. }
  344. // Save criteria in new format
  345. er = ECSearchFolders::SaveSearchCriteria(lpDatabase, atoui(lpDBRow[0]), atoui(lpDBRow[1]), lpNewSearchCriteria);
  346. if (er != erSuccess) {
  347. ec_log_crit(" Unable to save the new search criteria of folder %d", atoui(lpDBRow[1]));
  348. goto exit;
  349. }
  350. next: //Free
  351. if (lpNewSearchCriteria) {
  352. FreeSearchCriteria(lpNewSearchCriteria);
  353. lpNewSearchCriteria = NULL;
  354. }
  355. }
  356. exit:
  357. if (lpNewSearchCriteria)
  358. FreeSearchCriteria(lpNewSearchCriteria);
  359. return er;
  360. }
  361. // 14
  362. ECRESULT UpdateDatabaseAddUserObjectType(ECDatabase *lpDatabase)
  363. {
  364. ECRESULT er;
  365. /*
  366. * First we create the object_type column and initialize the values
  367. * based on the isgroup and nonactive columns. Once that is done we should
  368. * drop the columns. This will make the users table use the same format as
  369. * the DBUserPlugin which already made use of the object_type column.
  370. */
  371. er = lpDatabase->DoUpdate("ALTER TABLE users ADD COLUMN object_type int(11) NOT NULL default '0'");
  372. if(er != erSuccess)
  373. return er;
  374. er = lpDatabase->DoUpdate("UPDATE users SET object_type=5 WHERE nonactive != 0"); /* USEROBJECT_TYPE_NONACTIVE */
  375. if(er != erSuccess)
  376. return er;
  377. er = lpDatabase->DoUpdate("UPDATE users SET object_type=2 WHERE isgroup != 0"); /* USEROBJECT_TYPE_GROUP */
  378. if(er != erSuccess)
  379. return er;
  380. /*
  381. * All other entries should be considered as users.
  382. * This is safe since there are at this time no other valid object types.
  383. */
  384. er = lpDatabase->DoUpdate("UPDATE users SET object_type=1 WHERE object_type = 0"); /* USEROBJECT_TYPE_USER */
  385. if(er != erSuccess)
  386. return er;
  387. er = lpDatabase->DoUpdate("ALTER TABLE users DROP COLUMN nonactive");
  388. if(er != erSuccess)
  389. return er;
  390. er = lpDatabase->DoUpdate("ALTER TABLE users DROP INDEX externid, DROP COLUMN isgroup, ADD INDEX externid (`externid`, `object_type`)");
  391. if(er != erSuccess)
  392. return er;
  393. /*
  394. * Another change is that for the DB plugin, the 'objects' table should now show type 5 for nonactive users (instead of 1)
  395. */
  396. return lpDatabase->DoUpdate("UPDATE object SET objecttype=5 WHERE id IN (SELECT objectid FROM objectproperty WHERE propname='isnonactive' AND value != 0)");
  397. }
  398. // 15
  399. ECRESULT UpdateDatabaseAddUserSignature(ECDatabase *lpDatabase)
  400. {
  401. return lpDatabase->DoUpdate("ALTER TABLE users ADD COLUMN signature varchar(255) NOT NULL default '0'");
  402. }
  403. // 16
  404. ECRESULT UpdateDatabaseAddSourceKeySetting(ECDatabase *lpDatabase)
  405. {
  406. return lpDatabase->DoUpdate("INSERT INTO `settings` VALUES ('source_key_auto_increment' , (SELECT CHAR(MAX(`id`)&0xFF, MAX(`id`)>>8&0xFF, MAX(`id`)>>16&0xFF, MAX(`id`)>>24&0xFF, 0x00, 0x00, 0x00, 0x00) FROM `hierarchy`))");
  407. }
  408. // 17
  409. ECRESULT UpdateDatabaseRestrictExternId(ECDatabase *lpDatabase)
  410. {
  411. /*
  412. * The previous upgrade script created an INDEX instead of an UNIQUE INDEX,
  413. * this will result in incorrect behavior when multiple entries with the
  414. * same externid and object_type are inserted.
  415. */
  416. return lpDatabase->DoUpdate("ALTER TABLE users DROP INDEX externid, ADD UNIQUE INDEX externid (`externid`, `object_type`)");
  417. }
  418. // 18
  419. ECRESULT UpdateDatabaseAddUserCompany(ECDatabase *lpDatabase)
  420. {
  421. ECRESULT er;
  422. er = lpDatabase->DoUpdate("ALTER TABLE users ADD COLUMN company int(11) NOT NULL default '0'");
  423. if(er != erSuccess)
  424. return er;
  425. return lpDatabase->DoInsert("INSERT INTO `users` (`externid`, `object_type`, `signature`, `company`) VALUES (NULL, 4, '', 0)");
  426. }
  427. // 19
  428. ECRESULT UpdateDatabaseAddObjectRelationType(ECDatabase *lpDatabase)
  429. {
  430. ECRESULT er;
  431. er = lpDatabase->DoUpdate("ALTER TABLE objectrelation ADD COLUMN relationtype tinyint(11) unsigned NOT NULL");
  432. if(er != erSuccess)
  433. return er;
  434. er = lpDatabase->DoUpdate("ALTER TABLE objectrelation DROP PRIMARY KEY");
  435. if(er != erSuccess)
  436. return er;
  437. er = lpDatabase->DoUpdate("ALTER TABLE objectrelation ADD PRIMARY KEY (`objectid`, `parentobjectid`, `relationtype`)");
  438. if (er != erSuccess)
  439. return er;
  440. return lpDatabase->DoUpdate("UPDATE objectrelation SET relationtype = " + stringify(OBJECTRELATION_GROUP_MEMBER));
  441. }
  442. // 20
  443. ECRESULT UpdateDatabaseDelUserCompany(ECDatabase *lpDatabase)
  444. {
  445. ECRESULT er;
  446. er = lpDatabase->DoDelete(
  447. "DELETE FROM `users` "
  448. "WHERE externid IS NULL "
  449. "AND object_type = 4");
  450. if (er != erSuccess)
  451. return er;
  452. return lpDatabase->DoDelete(
  453. "DELETE FROM `objectproperty` "
  454. "WHERE `propname` = 'companyid' "
  455. "AND `value` = 'default'");
  456. }
  457. // 21
  458. ECRESULT UpdateDatabaseAddCompanyToStore(ECDatabase *lpDatabase)
  459. {
  460. ECRESULT er;
  461. er = lpDatabase->DoUpdate("ALTER TABLE stores ADD COLUMN user_name varbinary(255) NOT NULL default ''");
  462. if (er != erSuccess)
  463. return er;
  464. er = lpDatabase->DoUpdate("ALTER TABLE stores ADD COLUMN company smallint(11) NOT NULL default 0");
  465. if (er != erSuccess)
  466. return er;
  467. /*
  468. * The user_name column should contain the actual username, but resolving the username for each
  469. * entry will be quite tiresome without much to gain. Instead we just push the userid as
  470. * username and only force the real username for new entries.
  471. * The company column contains the company id to which the user belongs, we can fetch this
  472. * information from the 'users' table. Note that this will always be correct regardless of
  473. * hosted is enabled or disabled since the default value in the 'users' table is 0.
  474. */
  475. return lpDatabase->DoUpdate("UPDATE stores SET user_name = user_id, company = IFNULL( (SELECT company FROM users WHERE users.id = user_id), 0)");
  476. }
  477. // 22
  478. ECRESULT UpdateDatabaseAddIMAPSequenceNumber(ECDatabase *lpDatabase)
  479. {
  480. ECRESULT er = erSuccess;
  481. DB_RESULT lpResult;
  482. er = lpDatabase->DoSelect("SELECT * FROM settings WHERE name='imapseq'", &lpResult);
  483. if(er != erSuccess)
  484. return er;
  485. if(lpDatabase->GetNumRows(lpResult) == 0) {
  486. er = lpDatabase->DoInsert("INSERT INTO settings (name, value) VALUES('imapseq',(SELECT max(id)+1 FROM hierarchy))");
  487. if(er != erSuccess)
  488. return er;
  489. }
  490. return erSuccess;
  491. }
  492. // 23
  493. ECRESULT UpdateDatabaseKeysChanges(ECDatabase *lpDatabase)
  494. {
  495. ECRESULT er = erSuccess;
  496. string strQuery;
  497. DB_RESULT lpResult;
  498. DB_ROW lpDBRow = NULL;
  499. BOOL bFirst = TRUE;
  500. unsigned int ulRows = 0;
  501. // Remove duplicates
  502. do {
  503. bFirst = TRUE;
  504. er = lpDatabase->DoSelect("SELECT id FROM changes GROUP BY parentsourcekey, change_type, sourcekey HAVING COUNT(*) > 1", &lpResult);
  505. if(er != erSuccess)
  506. return er;
  507. ulRows = lpDatabase->GetNumRows(lpResult);
  508. if(ulRows > 0) {
  509. strQuery = "DELETE FROM changes WHERE id IN (";
  510. while(true) {
  511. lpDBRow = lpDatabase->FetchRow(lpResult);
  512. if (lpDBRow == NULL)
  513. break;
  514. if (lpDBRow[0] == NULL) {
  515. ec_log_err("UpdateDatabaseKeysChanges(): column is NULL");
  516. return KCERR_DATABASE_ERROR;
  517. }
  518. if (!bFirst)
  519. strQuery += ",";
  520. bFirst = FALSE;
  521. strQuery += lpDBRow[0];
  522. }
  523. strQuery += ")";
  524. er = lpDatabase->DoUpdate(strQuery);
  525. if (er != erSuccess)
  526. return er;
  527. }
  528. }while(ulRows > 0);
  529. // Change index
  530. return lpDatabase->DoUpdate("ALTER TABLE changes DROP PRIMARY KEY, DROP KEY `duplicate`, ADD PRIMARY KEY(`parentsourcekey`,`change_type`,`sourcekey`), ADD UNIQUE KEY `changeid` (`id`), ADD KEY `moved` (`moved_from`)");
  531. }
  532. // 24, Move public folders and remove favorites
  533. ECRESULT UpdateDatabaseMoveFoldersInPublicFolder(ECDatabase *lpDatabase)
  534. {
  535. ECRESULT er = erSuccess;
  536. string strQuery;
  537. DB_RESULT lpResult;
  538. DB_ROW lpDBRow = NULL;
  539. unsigned int ulStoreId = 0;
  540. unsigned int ulSubtreeFolder = 0;
  541. unsigned int ulPublicFolder = 0;
  542. unsigned int ulFavoriteFolder = 0;
  543. unsigned int ulAffRows = 0;
  544. bool bUseStoreAcls = false;
  545. // Find public stores (For every company)
  546. // Join the subtree, publicfolders and favorites entryid
  547. strQuery ="SELECT s.hierarchy_id, isub.hierarchyid, ipf.hierarchyid, iff.hierarchyid FROM users AS u "
  548. "JOIN stores AS s ON s.user_id=u.id "
  549. "JOIN properties AS psub ON "
  550. "psub.tag = 0x35E0 AND psub.type = 0x102 AND psub.storeid = s.hierarchy_id " // PR_IPM_SUBTREE_ENTRYID
  551. "JOIN indexedproperties AS isub ON "
  552. "isub.tag=0xFFF AND isub.val_binary = psub.val_binary "
  553. "LEFT JOIN properties AS pf ON "
  554. "pf.tag = 0x6631 AND pf.type = 0x102 AND pf.storeid = s.hierarchy_id " //PR_IPM_PUBLIC_FOLDERS_ENTRYID
  555. "LEFT JOIN indexedproperties AS ipf ON "
  556. "ipf.tag=0xFFF AND ipf.val_binary = pf.val_binary "
  557. "LEFT JOIN properties AS ff ON "
  558. "ff.tag = 0x6630 AND ff.type = 0x102 AND ff.storeid = s.hierarchy_id " //PR_IPM_FAVORITES_ENTRYID
  559. "LEFT JOIN indexedproperties AS iff ON "
  560. "iff.tag=0xFFF AND iff.val_binary = ff.val_binary "
  561. "WHERE u.object_type=4 OR u.id = 1"; // object_type=USEROBJECT_TYPE_COMPANY or id=KOPANO_UID_EVERYONE
  562. er = lpDatabase->DoSelect(strQuery, &lpResult);
  563. if(er != erSuccess)
  564. return er;
  565. while(true) {
  566. lpDBRow = lpDatabase->FetchRow(lpResult);
  567. if (lpDBRow == NULL)
  568. break;
  569. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL) {
  570. ec_log_crit(" Skip store: Unable to get the store information for storeid \"%s\"", (lpDBRow[0])?lpDBRow[0]:"Unknown");
  571. continue;
  572. }
  573. ulAffRows = 0;
  574. bUseStoreAcls = false;
  575. ulStoreId = atoui(lpDBRow[0]);
  576. ulSubtreeFolder = atoui(lpDBRow[1]);
  577. ulPublicFolder = (lpDBRow[2])?atoui(lpDBRow[2]):0;
  578. ulFavoriteFolder = (lpDBRow[3])?atoui(lpDBRow[3]):0;
  579. if (ulPublicFolder > 0) {
  580. // Move the publicfolder folders and messages to the subtree
  581. strQuery ="UPDATE hierarchy SET parent="+stringify(ulSubtreeFolder)+" WHERE parent="+stringify(ulPublicFolder);
  582. er = lpDatabase->DoUpdate(strQuery);
  583. if(er != erSuccess)
  584. return er;
  585. // Mark the old folder as deleted
  586. strQuery = "UPDATE hierarchy SET flags=flags|1024 WHERE id="+stringify(ulPublicFolder);
  587. er = lpDatabase->DoUpdate(strQuery);
  588. if(er != erSuccess)
  589. return er;
  590. // Remove acl's from the subtree folder
  591. strQuery = "DELETE FROM acl WHERE hierarchy_id="+stringify(ulSubtreeFolder);
  592. er = lpDatabase->DoDelete(strQuery);
  593. if(er != erSuccess)
  594. return er;
  595. // Move the Public folder acls to the subtree folder
  596. strQuery = "UPDATE acl SET hierarchy_id="+stringify(ulSubtreeFolder)+" WHERE hierarchy_id="+stringify(ulPublicFolder);
  597. er = lpDatabase->DoUpdate(strQuery, &ulAffRows);
  598. if(er != erSuccess)
  599. return er;
  600. if (ulAffRows == 0)
  601. bUseStoreAcls = true;
  602. } else {
  603. bUseStoreAcls = true;
  604. }
  605. if (bUseStoreAcls) {
  606. // Move the store acls to the subtree folder
  607. strQuery = "UPDATE acl SET hierarchy_id="+stringify(ulSubtreeFolder)+" WHERE hierarchy_id="+stringify(ulStoreId);
  608. er = lpDatabase->DoUpdate(strQuery);
  609. if(er != erSuccess)
  610. return er;
  611. }
  612. if(ulFavoriteFolder > 0) {
  613. // Move the favoritefolder folders and messages to the subtree
  614. strQuery ="UPDATE hierarchy SET parent="+stringify(ulSubtreeFolder)+" WHERE parent="+stringify(ulFavoriteFolder);
  615. er = lpDatabase->DoUpdate(strQuery);
  616. if(er != erSuccess)
  617. return er;
  618. // Mark the old folder as deleted
  619. strQuery = "UPDATE hierarchy SET flags=flags|1024 WHERE id="+stringify(ulFavoriteFolder);
  620. er = lpDatabase->DoUpdate(strQuery);
  621. if(er != erSuccess)
  622. return er;
  623. // Remove acl's from the favorite folder
  624. strQuery = "DELETE FROM acl WHERE hierarchy_id="+stringify(ulFavoriteFolder);
  625. er = lpDatabase->DoDelete(strQuery);
  626. if(er != erSuccess)
  627. return er;
  628. }
  629. // Remove acl's from the store
  630. strQuery = "DELETE FROM acl WHERE hierarchy_id="+stringify(ulStoreId);
  631. er = lpDatabase->DoDelete(strQuery);
  632. if(er != erSuccess)
  633. return er;
  634. // Remove the unused properties
  635. strQuery = "DELETE FROM properties "
  636. "WHERE (tag = 0x6631 AND type=0x102 AND storeid = "+stringify(ulStoreId) + ") OR " //PR_IPM_PUBLIC_FOLDERS_ENTRYID
  637. "(tag = 0x6630 AND type = 0x102 AND storeid = "+stringify(ulStoreId) + ")";//PR_IPM_FAVORITES_ENTRYID
  638. er = lpDatabase->DoUpdate(strQuery);
  639. if(er != erSuccess)
  640. return er;
  641. }
  642. return erSuccess;
  643. }
  644. // 25
  645. ECRESULT UpdateDatabaseAddExternIdToObject(ECDatabase *lpDatabase)
  646. {
  647. ECRESULT er = erSuccess;
  648. string strQuery;
  649. DB_RESULT lpResult;
  650. DB_ROW lpDBRow = NULL;
  651. DB_LENGTHS lpDBLen = NULL;
  652. unsigned int ulNewId = 0;
  653. unsigned int ulNewParentId = 0;
  654. bool bFirstResult;
  655. std::list<SObject> sObjectList;
  656. std::map<SObject,unsigned int> sObjectMap;
  657. std::map<SObject,unsigned int>::const_iterator sObjectMapIter;
  658. std::list<SRelation> sRelationList;
  659. #define Z_TABLEDEF_OBJECT_R630 "CREATE TABLE object ( \
  660. `id` int(11) unsigned NOT NULL auto_increment, \
  661. `externid` varbinary(255), \
  662. `objecttype` int(11) unsigned NOT NULL default '0', \
  663. PRIMARY KEY (`id`, `objecttype`), \
  664. UNIQUE KEY id (`id`), \
  665. UNIQUE KEY externid (`externid`, `objecttype`) \
  666. ) ENGINE=InnoDB;"
  667. // Create the new object table.
  668. strQuery = Z_TABLEDEF_OBJECT_R630;
  669. strQuery.replace(strQuery.find("object"), 6, "object_temp");
  670. er = lpDatabase->DoInsert(strQuery);
  671. if (er != erSuccess)
  672. goto exit;
  673. // Create the new objectproperty table.
  674. strQuery = Z_TABLEDEF_OBJECT_PROPERTY;
  675. strQuery.replace(strQuery.find("objectproperty"), 14, "objectproperty_temp");
  676. er = lpDatabase->DoInsert(strQuery);
  677. if (er != erSuccess)
  678. goto exit;
  679. // Create the new objectrelation table.
  680. strQuery = Z_TABLEDEF_OBJECT_RELATION;
  681. strQuery.replace(strQuery.find("objectrelation"), 14, "objectrelation_temp");
  682. er = lpDatabase->DoInsert(strQuery);
  683. if (er != erSuccess)
  684. goto exit;
  685. // Create a list of all current objects from the object table.
  686. strQuery = "SELECT id, objecttype FROM object ORDER BY objecttype";
  687. er = lpDatabase->DoSelect(strQuery, &lpResult);
  688. if (er != erSuccess)
  689. goto exit;
  690. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  691. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL) {
  692. er = KCERR_DATABASE_ERROR;
  693. ec_log_err(" object table contains invalid NULL records");
  694. goto exit;
  695. }
  696. sObjectList.push_back(SObject(atoi(lpDBRow[0]), atoi(lpDBRow[1])));
  697. }
  698. // Recreate the objects in the object_temp table and on the fly create the queries to regenerate
  699. // their properties in the objectpropert_temp table.
  700. for (const auto &obj : sObjectList) {
  701. strQuery = (string)"INSERT INTO object_temp (objecttype, externid) VALUES (" +
  702. stringify(obj.ulType) + ", '" + stringify(obj.ulId) + "')";
  703. er = lpDatabase->DoInsert(strQuery, &ulNewId);
  704. if (er != erSuccess)
  705. goto exit;
  706. // Add to the map for later use
  707. sObjectMap[obj] = ulNewId;
  708. // Find the properties for this object
  709. strQuery = (string)"SELECT propname, value FROM objectproperty WHERE objectid=" +
  710. stringify(obj.ulId);
  711. er = lpDatabase->DoSelect(strQuery, &lpResult);
  712. if (er != erSuccess)
  713. goto exit;
  714. strQuery.clear();
  715. bFirstResult = true;
  716. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  717. lpDBLen = lpDatabase->FetchRowLengths(lpResult);
  718. if (lpDBLen == NULL) {
  719. er = KCERR_DATABASE_ERROR;
  720. ec_log_err("UpdateDatabaseAddExternIdToObject(): FetchRowLengths failed");
  721. goto exit;
  722. }
  723. if (lpDBRow[0] == NULL) {
  724. er = KCERR_DATABASE_ERROR;
  725. ec_log_err("UpdateDatabaseAddExternIdToObject(): column NULL");
  726. goto exit;
  727. }
  728. if (strQuery.empty())
  729. strQuery = "INSERT INTO objectproperty_temp (objectid, propname, value) VALUES ";
  730. if (!bFirstResult)
  731. strQuery += ",";
  732. else
  733. bFirstResult = false;
  734. strQuery +=
  735. "(" + stringify(ulNewId) + "," +
  736. lpDatabase->EscapeBinary((unsigned char*)lpDBRow[0], lpDBLen[0]) + ",";
  737. if (lpDBRow[1] == NULL)
  738. strQuery += "NULL)";
  739. else
  740. strQuery += lpDatabase->EscapeBinary((unsigned char*)lpDBRow[1], lpDBLen[1]) + ")";
  741. }
  742. if (!strQuery.empty()) {
  743. er = lpDatabase->DoInsert(strQuery);
  744. if (er != erSuccess)
  745. goto exit;
  746. }
  747. er = lpDatabase->DoDelete("DELETE FROM objectproperty WHERE objectid=" + stringify(obj.ulId));
  748. if (er != erSuccess)
  749. goto exit;
  750. }
  751. // Now repopulate the objectrelation table.
  752. strQuery = "SELECT objectid, parentobjectid, relationtype FROM objectrelation";
  753. er = lpDatabase->DoSelect(strQuery, &lpResult);
  754. if (er != erSuccess)
  755. goto exit;
  756. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  757. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL) {
  758. er = KCERR_DATABASE_ERROR;
  759. ec_log_crit(" objectrelation table contains invalid NULL records");
  760. goto exit;
  761. }
  762. sRelationList.push_back(SRelation(atoi(lpDBRow[0]), atoi(lpDBRow[1]), atoi(lpDBRow[2])));
  763. }
  764. strQuery.clear();
  765. bFirstResult = true;
  766. for (const auto &rel : sRelationList) {
  767. // Find the new parentId, if not found: ignore so they disappear .. would have been invalid relations anyway.
  768. switch (rel.ulRelationType) {
  769. case OBJECTRELATION_QUOTA_USERRECIPIENT:
  770. case OBJECTRELATION_USER_SENDAS:
  771. sObjectMapIter = sObjectMap.find(SObject(rel.ulParentObjectId, 1 /* USEROBJECT_TYPE_USER */));
  772. if (sObjectMapIter == sObjectMap.cend())
  773. sObjectMapIter = sObjectMap.find(SObject(rel.ulParentObjectId, 5 /* USEROBJECT_TYPE_NONACTIVE */));
  774. if (sObjectMapIter == sObjectMap.cend())
  775. continue;
  776. ulNewParentId = sObjectMapIter->second;
  777. break;
  778. case OBJECTRELATION_GROUP_MEMBER:
  779. sObjectMapIter = sObjectMap.find(SObject(rel.ulParentObjectId, 2 /* USEROBJECT_TYPE_GROUP */));
  780. if (sObjectMapIter == sObjectMap.cend())
  781. continue;
  782. ulNewParentId = sObjectMapIter->second;
  783. break;
  784. case OBJECTRELATION_COMPANY_VIEW:
  785. case OBJECTRELATION_COMPANY_ADMIN:
  786. case OBJECTRELATION_QUOTA_COMPANYRECIPIENT:
  787. sObjectMapIter = sObjectMap.find(SObject(rel.ulParentObjectId, 4 /* USEROBJECT_TYPE_COMPANY */));
  788. if (sObjectMapIter == sObjectMap.cend())
  789. continue;
  790. ulNewParentId = sObjectMapIter->second;
  791. break;
  792. case OBJECTRELATION_ADDRESSLIST_MEMBER:
  793. sObjectMapIter = sObjectMap.find(SObject(rel.ulParentObjectId, 6 /* USEROBJECT_TYPE_ADDRESSLIST */));
  794. if (sObjectMapIter == sObjectMap.cend())
  795. continue;
  796. ulNewParentId = sObjectMapIter->second;
  797. break;
  798. }
  799. // Find the new object id
  800. sObjectMapIter = sObjectMap.find(SObject(rel.ulObjectId, 1 /* USEROBJECT_TYPE_USER */));
  801. if (sObjectMapIter == sObjectMap.cend())
  802. sObjectMapIter = sObjectMap.find(SObject(rel.ulObjectId, 5)); // USEROBJECT_TYPE_NONACTIVE
  803. if (sObjectMapIter == sObjectMap.cend())
  804. continue;
  805. ulNewId = sObjectMapIter->second;
  806. // Update strQuery for this relation
  807. if (strQuery.empty())
  808. strQuery = "INSERT INTO objectrelation_temp (objectid,parentobjectid,relationtype) VALUES ";
  809. if (!bFirstResult)
  810. strQuery += ",";
  811. else
  812. bFirstResult = false;
  813. strQuery += "(" + stringify(ulNewId) + "," +
  814. stringify(ulNewParentId) + "," +
  815. stringify(rel.ulRelationType) + ")";
  816. }
  817. if (!strQuery.empty()) {
  818. er = lpDatabase->DoInsert(strQuery);
  819. if (er != erSuccess)
  820. goto exit;
  821. }
  822. // Now delete the old tables and rename the new ones
  823. er = lpDatabase->DoDelete("DROP TABLE object, objectproperty, objectrelation");
  824. if (er != erSuccess)
  825. goto exit;
  826. er = lpDatabase->DoUpdate("RENAME TABLE object_temp TO object, "
  827. "objectproperty_temp TO objectproperty, "
  828. "objectrelation_temp TO objectrelation");
  829. exit:
  830. // Delete the temporary tables if they exist at this point
  831. lpDatabase->DoDelete("DROP TABLE IF EXISTS object_temp, objectproperty_temp, objectrelation_temp");
  832. return er;
  833. }
  834. // 26
  835. ECRESULT UpdateDatabaseCreateReferences(ECDatabase *lpDatabase)
  836. {
  837. ECRESULT er = erSuccess;
  838. string strQuery;
  839. er = lpDatabase->DoInsert(Z_TABLEDEF_REFERENCES);
  840. if (er != erSuccess)
  841. return er;
  842. /*
  843. * Create all attachment references from hierarchy table, let
  844. * instanceid be equal to hierarchyid to minimize the impact
  845. * on the upgrade.
  846. */
  847. strQuery =
  848. "INSERT INTO `singleinstances` (`instanceid`, `hierarchyid`, `tag`) "
  849. "SELECT id, id, " + stringify(PROP_ID(PR_ATTACH_DATA_BIN)) + " "
  850. "FROM `hierarchy` "
  851. "WHERE type = " + stringify(MAPI_ATTACH);
  852. er = lpDatabase->DoInsert(strQuery);
  853. if (er != erSuccess)
  854. return er;
  855. /* We need to rename the column in `lob` */
  856. strQuery =
  857. "ALTER TABLE `lob` "
  858. "CHANGE COLUMN `hierarchyid` `instanceid` int(11) unsigned NOT NULL";
  859. return lpDatabase->DoUpdate(strQuery);
  860. }
  861. // 27
  862. ECRESULT UpdateDatabaseLockDistributed(ECDatabase *lpDatabase)
  863. {
  864. return lpDatabase->DoInsert("INSERT INTO settings VALUES ('lock_distributed_kopano', 'upgrade')");
  865. }
  866. // 28
  867. ECRESULT UpdateDatabaseCreateABChangesTable(ECDatabase *lpDatabase)
  868. {
  869. ECRESULT er = erSuccess;
  870. string strQuery;
  871. DB_RESULT lpResult;
  872. DB_ROW lpDBRow = NULL;
  873. DB_LENGTHS lpDBLen = NULL;
  874. int ulId = 0;
  875. list<int> syncIds;
  876. list<string> queries;
  877. bool fFirst = true;
  878. string strSyncId;
  879. er = lpDatabase->DoInsert(Z_TABLEDEF_ABCHANGES);
  880. if (er != erSuccess)
  881. goto exit;
  882. strQuery = "SELECT id, sourcekey, parentsourcekey, change_type FROM changes WHERE change_type & " + stringify(ICS_AB) + " AND parentsourcekey=0x00000000AC21A95040D3EE48B319FBA75330442500000000040000000100000000000000";
  883. er = lpDatabase->DoSelect(strQuery, &lpResult);
  884. if (er != erSuccess)
  885. goto exit;
  886. // Extract the AB changes from the changes table.
  887. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  888. lpDBLen = lpDatabase->FetchRowLengths(lpResult);
  889. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBLen[1] == 0 || lpDBRow[2] == NULL || lpDBLen[2] == 0) {
  890. er = KCERR_DATABASE_ERROR;
  891. ec_log_crit(" changes table contains invalid NULL records");
  892. goto exit;
  893. }
  894. ulId = atoi(lpDBRow[0]);
  895. syncIds.push_back(ulId);
  896. strQuery = "INSERT INTO abchanges (id, sourcekey, parentsourcekey, change_type";
  897. strQuery += (string)") VALUES (" + lpDBRow[0] + ", " +
  898. lpDatabase->EscapeBinary((unsigned char*)lpDBRow[1], lpDBLen[1]) + ", " +
  899. lpDatabase->EscapeBinary((unsigned char*)lpDBRow[2], lpDBLen[2]) + ", " +
  900. lpDBRow[3];
  901. strQuery += ")";
  902. queries.push_back(std::move(strQuery));
  903. }
  904. // Populate the abchanges table with the extracted data
  905. for (const auto &query : queries) {
  906. er = lpDatabase->DoInsert(query);
  907. if (er != erSuccess)
  908. goto exit;
  909. }
  910. // Remove the extracted changes from the changes table
  911. strQuery = "DELETE FROM changes WHERE id IN (";
  912. for (auto id : syncIds) {
  913. strSyncId = stringify(id, false);
  914. if (strQuery.length() + strSyncId.length() + 2 >= lpDatabase->GetMaxAllowedPacket()) { // we need to be able to add a ',' and a ')';
  915. strQuery += ")";
  916. er = lpDatabase->DoInsert(strQuery);
  917. if (er != erSuccess)
  918. goto exit;
  919. strQuery = "DELETE FROM changes WHERE id IN (";
  920. fFirst = true;
  921. }
  922. if (!fFirst)
  923. strQuery += ",";
  924. fFirst = false;
  925. strQuery += strSyncId;
  926. }
  927. if (!fFirst) {
  928. strQuery += ")";
  929. er = lpDatabase->DoInsert(strQuery);
  930. }
  931. exit:
  932. if (er != erSuccess)
  933. lpDatabase->DoDelete("DROP TABLE IF EXISTS abchanges");
  934. return er;
  935. }
  936. // 29
  937. ECRESULT UpdateDatabaseSetSingleinstanceTag(ECDatabase *lpDatabase)
  938. {
  939. // Force all tag values to PR_ATTACH_DATA_BIN. Up to now, no other values can be present in the table.
  940. return lpDatabase->DoUpdate("UPDATE `singleinstances` SET `tag` = " + stringify(PROP_ID(PR_ATTACH_DATA_BIN)));
  941. }
  942. // 30
  943. ECRESULT UpdateDatabaseCreateSyncedMessagesTable(ECDatabase *lpDatabase)
  944. {
  945. return lpDatabase->DoInsert(Z_TABLEDEFS_SYNCEDMESSAGES);
  946. }
  947. // 31
  948. ECRESULT UpdateDatabaseForceAbResync(ECDatabase *lpDatabase)
  949. {
  950. return KCERR_IGNORE_ME;
  951. }
  952. // 32
  953. ECRESULT UpdateDatabaseRenameObjectTypeToObjectClass(ECDatabase *lpDatabase)
  954. {
  955. ECRESULT er;
  956. std::string strQuery;
  957. // rename columns in users and object tables
  958. strQuery =
  959. "ALTER TABLE `users` "
  960. "CHANGE COLUMN `object_type` `objectclass` int(11) unsigned NOT NULL";
  961. er = lpDatabase->DoUpdate(strQuery);
  962. if (er != erSuccess)
  963. return er;
  964. // Note: type also changes from int to tinyint here
  965. strQuery =
  966. "ALTER TABLE `object` "
  967. "CHANGE COLUMN `objecttype` `objectclass` int(11) unsigned NOT NULL";
  968. return lpDatabase->DoUpdate(strQuery);
  969. }
  970. // 33
  971. ECRESULT UpdateDatabaseConvertObjectTypeToObjectClass(ECDatabase *lpDatabase)
  972. {
  973. ECRESULT er = erSuccess;
  974. DB_RESULT lpResult;
  975. DB_ROW lpDBRow = NULL;
  976. DB_LENGTHS lpDBLen = NULL;
  977. std::string strQuery, strUpdate;
  978. bool bFirst = true;
  979. std::map<unsigned int, unsigned int> mapTypes;
  980. std::list<std::string> lstUpdates;
  981. // make internal SYSTEM a objectclass_t user
  982. er = lpDatabase->DoUpdate("UPDATE `users` SET `objectclass` = "+stringify(ACTIVE_USER)+" WHERE `externid` is NULL AND `objectclass` = 1");
  983. if (er != erSuccess)
  984. return er;
  985. // make internal EVERYONE a objectclass_t security group
  986. er = lpDatabase->DoUpdate("UPDATE `users` SET `objectclass` = "+stringify(DISTLIST_SECURITY)+" WHERE `externid` is NULL AND `objectclass` = 2");
  987. if (er != erSuccess)
  988. return er;
  989. // database stored typed, convert to the new objectclass_t values
  990. mapTypes.insert(std::pair<unsigned int, unsigned int>(1, ACTIVE_USER)); // USEROBJECT_TYPE_USER
  991. mapTypes.insert(std::pair<unsigned int, unsigned int>(2, DISTLIST_GROUP)); // USEROBJECT_TYPE_GROUP
  992. mapTypes.insert(std::pair<unsigned int, unsigned int>(3, NONACTIVE_CONTACT)); // USEROBJECT_TYPE_CONTACT (unused, but who knows..)
  993. mapTypes.insert(std::pair<unsigned int, unsigned int>(4, CONTAINER_COMPANY)); // USEROBJECT_TYPE_COMPANY
  994. mapTypes.insert(std::pair<unsigned int, unsigned int>(5, NONACTIVE_USER)); // USEROBJECT_TYPE_NONACTIVE
  995. mapTypes.insert(std::pair<unsigned int, unsigned int>(6, CONTAINER_ADDRESSLIST)); // USEROBJECT_TYPE_ADDRESSLIST
  996. for (const auto &p : mapTypes) {
  997. // extern id, because it links to object table for DB plugin
  998. // on LDAP plugin, object table is empty.
  999. er = lpDatabase->DoSelect("SELECT `externid`, `objectclass` FROM `users` WHERE `externid` is not NULL AND `objectclass` = " + stringify(p.first), &lpResult);
  1000. if (er != erSuccess)
  1001. return er;
  1002. strUpdate = "(";
  1003. bFirst = true;
  1004. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  1005. lpDBLen = lpDatabase->FetchRowLengths(lpResult);
  1006. if (lpDBRow[0] == NULL || lpDBLen == NULL || lpDBLen[0] == 0) {
  1007. ec_log_crit(" users table contains invalid NULL records for type %d", p.first);
  1008. return KCERR_DATABASE_ERROR;
  1009. }
  1010. if (!bFirst)
  1011. strUpdate += ",";
  1012. strUpdate += lpDatabase->EscapeBinary((unsigned char*)lpDBRow[0], lpDBLen[0]);
  1013. bFirst = false;
  1014. }
  1015. strUpdate += ")";
  1016. if (bFirst)
  1017. continue; // we had no results for this type, continue with the next
  1018. // save all queries in a list, so we don't cross-update types
  1019. strQuery =
  1020. "UPDATE `users` SET `objectclass`=" + stringify(p.second) + " "
  1021. "WHERE `externid` IN " + strUpdate + " "
  1022. "AND `objectclass` = " + stringify(p.first);
  1023. lstUpdates.push_back(std::move(strQuery));
  1024. strQuery =
  1025. "UPDATE `object` SET `objectclass`=" + stringify(p.second) + " "
  1026. "WHERE `externid` IN " + strUpdate + " "
  1027. "AND `objectclass` = " + stringify(p.first);
  1028. lstUpdates.push_back(std::move(strQuery));
  1029. }
  1030. // process all type updates
  1031. for (const auto &q : lstUpdates) {
  1032. er = lpDatabase->DoUpdate(q);
  1033. if (er != erSuccess)
  1034. return er;
  1035. }
  1036. return erSuccess;
  1037. }
  1038. // 34
  1039. ECRESULT UpdateDatabaseAddMVPropertyTable(ECDatabase *lpDatabase)
  1040. {
  1041. return lpDatabase->DoInsert(Z_TABLEDEF_OBJECT_MVPROPERTY);
  1042. }
  1043. // 35
  1044. ECRESULT UpdateDatabaseCompanyNameToCompanyId(ECDatabase *lpDatabase)
  1045. {
  1046. ECRESULT er = erSuccess;
  1047. string strQuery;
  1048. map<string, string> mapIdToName;
  1049. DB_RESULT lpResult;
  1050. DB_ROW lpDBRow = NULL;
  1051. DB_LENGTHS lpDBLen = NULL;
  1052. // find all companies
  1053. strQuery = "SELECT object.externid, objectproperty.value FROM objectproperty JOIN object ON objectproperty.objectid=object.id WHERE objectproperty.propname = 'companyname'";
  1054. er = lpDatabase->DoSelect(strQuery, &lpResult);
  1055. if (er != erSuccess)
  1056. return er;
  1057. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  1058. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL)
  1059. continue;
  1060. lpDBLen = lpDatabase->FetchRowLengths(lpResult);
  1061. mapIdToName.insert(pair<string,string>(string(lpDBRow[0], lpDBLen[0]), string(lpDBRow[1], lpDBLen[1])));
  1062. }
  1063. // update objects to link via externid in companyid, not companyname anymore
  1064. for (const auto &p : mapIdToName) {
  1065. strQuery = "UPDATE objectproperty SET value = 0x" + bin2hex(p.first) +
  1066. " WHERE propname='companyid' AND value = '" + p.second + "'";
  1067. er = lpDatabase->DoUpdate(strQuery);
  1068. if (er != erSuccess)
  1069. return er;
  1070. }
  1071. return erSuccess;
  1072. }
  1073. // 36
  1074. ECRESULT UpdateDatabaseOutgoingQueuePrimarykey(ECDatabase *lpDatabase)
  1075. {
  1076. return lpDatabase->DoUpdate("ALTER TABLE outgoingqueue DROP PRIMARY KEY, ADD PRIMARY KEY (`hierarchy_id`,`flags`,`store_id`)");
  1077. }
  1078. // 37
  1079. ECRESULT UpdateDatabaseACLPrimarykey(ECDatabase *lpDatabase)
  1080. {
  1081. return lpDatabase->DoUpdate("ALTER TABLE acl DROP PRIMARY KEY, ADD PRIMARY KEY (`hierarchy_id`,`id`,`type`)");
  1082. }
  1083. // 38
  1084. ECRESULT UpdateDatabaseBlobExternId(ECDatabase *lpDatabase)
  1085. {
  1086. ECRESULT er;
  1087. std::string strQuery;
  1088. strQuery = "ALTER TABLE `object` "
  1089. "DROP KEY `externid`, "
  1090. "MODIFY `externid` blob, "
  1091. "ADD UNIQUE KEY `externid` (`externid`(255), `objectclass`)";
  1092. er = lpDatabase->DoUpdate(strQuery);
  1093. if (er != erSuccess)
  1094. return er;
  1095. strQuery = "ALTER TABLE `users` "
  1096. "DROP KEY `externid`, "
  1097. "MODIFY `externid` blob, "
  1098. "ADD UNIQUE KEY `externid` (`externid`(255), `objectclass`)";
  1099. return lpDatabase->DoUpdate(strQuery);
  1100. }
  1101. // 39
  1102. ECRESULT UpdateDatabaseKeysChanges2(ECDatabase *lpDatabase)
  1103. {
  1104. // Change index
  1105. return lpDatabase->DoUpdate("ALTER TABLE changes DROP PRIMARY KEY, ADD PRIMARY KEY(`parentsourcekey`,`sourcekey`,`change_type`)");
  1106. }
  1107. /**
  1108. * Update the primary key in mvproperties
  1109. *
  1110. * Change the primary key to get more performance in mysql because the mysql can not
  1111. * choose the right key we change the index into one primary key.
  1112. *
  1113. * @remarks We are checking extra for the 'hi' key because some upgrade issues
  1114. *
  1115. * @param[in] lpDatabase ECDatabase object pointer to update.
  1116. * @retval erSuccess
  1117. * Update is done.
  1118. * @retval KCERR_DATABASE_ERROR
  1119. * Update failed
  1120. */
  1121. // 40
  1122. ECRESULT UpdateDatabaseMVPropertiesPrimarykey(ECDatabase *lpDatabase)
  1123. {
  1124. ECRESULT er = erSuccess;
  1125. DB_RESULT lpResult;
  1126. DB_ROW lpDBRow = NULL;
  1127. bool bUpdate = false;
  1128. er = lpDatabase->DoSelect("SHOW KEYS FROM mvproperties", &lpResult);
  1129. if (er != erSuccess)
  1130. return er;
  1131. // Result: | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
  1132. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  1133. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL)
  1134. continue;
  1135. if(strcasecmp(lpDBRow[2], "hi") == 0) {
  1136. bUpdate = true;
  1137. break;
  1138. }
  1139. }
  1140. if (bUpdate) {
  1141. er = lpDatabase->DoUpdate("ALTER TABLE mvproperties DROP PRIMARY KEY, ADD PRIMARY KEY (`hierarchyid`,`tag`,`type`,`orderid`), DROP KEY `hi`");
  1142. if (er != erSuccess)
  1143. return er;
  1144. }
  1145. return erSuccess;
  1146. }
  1147. // 41
  1148. ECRESULT UpdateDatabaseFixDBPluginGroups(ECDatabase *lpDatabase)
  1149. {
  1150. return lpDatabase->DoUpdate("UPDATE object SET objectclass="+stringify(DISTLIST_SECURITY)+" WHERE objectclass="+stringify(DISTLIST_GROUP));
  1151. }
  1152. // 42
  1153. ECRESULT UpdateDatabaseFixDBPluginSendAs(ECDatabase *lpDatabase)
  1154. {
  1155. ECRESULT er = erSuccess;
  1156. DB_RESULT lpResult;
  1157. DB_ROW lpDBRow = NULL;
  1158. DB_LENGTHS lpDBLen = NULL;
  1159. list<std::pair<string, string> > lstRelations;
  1160. // relation 6 == OBJECTRELATION_USER_SENDAS
  1161. er = lpDatabase->DoSelect("SELECT objectid, parentobjectid FROM objectrelation WHERE relationtype=6", &lpResult);
  1162. if (er != erSuccess)
  1163. return er;
  1164. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  1165. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL)
  1166. continue;
  1167. lpDBLen = lpDatabase->FetchRowLengths(lpResult);
  1168. lstRelations.push_back(pair<string,string>(string(lpDBRow[0], lpDBLen[0]), string(lpDBRow[1], lpDBLen[1])));
  1169. }
  1170. er = lpDatabase->DoDelete("DELETE FROM objectrelation WHERE relationtype=6");
  1171. if (er != erSuccess)
  1172. return er;
  1173. for (const auto &p : lstRelations) {
  1174. er = lpDatabase->DoUpdate("INSERT INTO objectrelation (objectid, parentobjectid, relationtype) VALUES (" +
  1175. p.second + ", " + p.first + ", 6)");
  1176. if (er != erSuccess)
  1177. return er;
  1178. }
  1179. return erSuccess;
  1180. }
  1181. /**
  1182. * IMAP used to store subscriptions on the store. This gave problems
  1183. * when multi-threaded IMAP clients (Thunderbird) subscribed on
  1184. * folders in one thread, and requested the list on another
  1185. * thread. This would have returned the old subscribed list, since the
  1186. * store doesn't have an update notification system like normal
  1187. * folders do. Moved to the Inbox, since this folder is always
  1188. * present and easy to find on the server and client.
  1189. *
  1190. * @param[in] lpDatabase ECDatabase object pointer to update.
  1191. * @return ECRESULT erSuccess or KCERR_DATABASE_ERROR
  1192. */
  1193. // 43
  1194. ECRESULT UpdateDatabaseMoveSubscribedList(ECDatabase *lpDatabase)
  1195. {
  1196. ECRESULT er = erSuccess;
  1197. map<string, string> mapStoreInbox;
  1198. DB_RESULT lpResult;
  1199. DB_ROW lpDBRow = NULL;
  1200. DB_LENGTHS lpDBLen = NULL;
  1201. er = lpDatabase->DoSelect("SELECT storeid, objid FROM receivefolder WHERE messageclass='IPM'", &lpResult);
  1202. if (er != erSuccess)
  1203. return er;
  1204. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  1205. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL)
  1206. continue;
  1207. lpDBLen = lpDatabase->FetchRowLengths(lpResult);
  1208. mapStoreInbox.insert(pair<string,string>(string(lpDBRow[0], lpDBLen[0]), string(lpDBRow[1], lpDBLen[1])));
  1209. }
  1210. for (const auto &p : mapStoreInbox) {
  1211. // Remove property if it's already there (possible if you run new gateway against old server before upgrade)
  1212. er = lpDatabase->DoDelete("DELETE FROM properties WHERE storeid=" +
  1213. p.first + " AND hierarchyid=" + p.first +
  1214. " AND tag=0x6784 AND type=0x0102");
  1215. if (er != erSuccess)
  1216. return er;
  1217. // does not return an error if property was not in the database
  1218. er = lpDatabase->DoUpdate("UPDATE properties SET hierarchyid=" +
  1219. p.second + " WHERE storeid=" + p.first +
  1220. " AND hierarchyid=" + p.first +
  1221. " AND tag=0x6784 AND type=0x0102");
  1222. if (er != erSuccess)
  1223. return er;
  1224. }
  1225. return erSuccess;
  1226. }
  1227. // 44
  1228. ECRESULT UpdateDatabaseSyncTimeIndex(ECDatabase *lpDatabase)
  1229. {
  1230. ECRESULT er = erSuccess;
  1231. bool bHaveIndex;
  1232. // There are upgrade paths where the sync_time key already exists.
  1233. er = lpDatabase->CheckExistIndex("syncs", "sync_time", &bHaveIndex);
  1234. if (er == erSuccess && !bHaveIndex)
  1235. er = lpDatabase->DoUpdate("ALTER TABLE syncs ADD INDEX sync_time (`sync_time`)");
  1236. return er;
  1237. }
  1238. // 45
  1239. ECRESULT UpdateDatabaseAddStateKey(ECDatabase *lpDatabase)
  1240. {
  1241. ECRESULT er = erSuccess;
  1242. bool bHaveIndex;
  1243. // There are upgrade paths where the state key already exists.
  1244. er = lpDatabase->CheckExistIndex("changes", "state", &bHaveIndex);
  1245. if (er == erSuccess && !bHaveIndex)
  1246. er = lpDatabase->DoUpdate("ALTER TABLE changes ADD UNIQUE KEY `state` (`parentsourcekey`,`id`)");
  1247. return er;
  1248. }
  1249. // 46
  1250. ECRESULT UpdateDatabaseConvertToUnicode(ECDatabase *lpDatabase)
  1251. {
  1252. ECRESULT er = erSuccess;
  1253. std::string strQuery;
  1254. if (lpDatabase->m_bForceUpdate) {
  1255. // Admin requested a forced upgrade, converting known tables
  1256. /*
  1257. * Since we inserted the company guid into the objectproperty
  1258. * table, this convert may break, since the binary data won't
  1259. * be valid utf-8 data in mysql. So we convert the 'companyid'
  1260. * properties from this table into a hexed version, which is
  1261. * plain text and will not break.
  1262. *
  1263. * We need to do this first, since the begin/commit will work
  1264. * on this statement, and won't on the following alter table
  1265. * commands.
  1266. */
  1267. strQuery = "UPDATE objectproperty SET value = hex(value) WHERE propname = 'companyid'";
  1268. er = lpDatabase->DoUpdate(strQuery);
  1269. if (er != erSuccess)
  1270. return er;
  1271. // Convert tables to unicode
  1272. strQuery = "ALTER TABLE mvproperties MODIFY val_string longtext CHARSET utf8 COLLATE utf8_general_ci";
  1273. er = lpDatabase->DoUpdate(strQuery);
  1274. if (er != erSuccess)
  1275. return er;
  1276. // No need to convert the properties table as that will be done on the fly in update 50 (Z_UPDATE_CONVERT_PROPERTIES)
  1277. // db-plugin
  1278. strQuery = "ALTER TABLE objectproperty MODIFY propname VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci, MODIFY value TEXT CHARSET utf8 COLLATE utf8_general_ci";
  1279. er = lpDatabase->DoUpdate(strQuery);
  1280. if (er != erSuccess)
  1281. return er;
  1282. /*
  1283. * Another similar change is to the SYSADMIN property; it used
  1284. * to be 12345:XXXXXXXX with XXXXX being a binary externid. That
  1285. * has changed to be a hexed version, so, 12345:HHHHHHHHHH, with
  1286. * HHHH being the hexed version of XXXXX
  1287. */
  1288. strQuery = "UPDATE objectproperty SET value = concat(substr(value,1,instr(value,';')-1),';',hex(substr(value,instr(value,';')+1))) WHERE propname = 'companyadmin'";
  1289. er = lpDatabase->DoUpdate(strQuery);
  1290. if (er != erSuccess)
  1291. return er;
  1292. strQuery = "ALTER TABLE objectmvproperty MODIFY propname VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci, MODIFY value TEXT CHARSET utf8 COLLATE utf8_general_ci";
  1293. er = lpDatabase->DoUpdate(strQuery);
  1294. if (er != erSuccess)
  1295. return er;
  1296. /*
  1297. * Other tables containing varchar's are not converted, all data in those fields are us-ascii anyway:
  1298. * - receivefolder
  1299. * - stores (specially handled in next update
  1300. * - settings
  1301. */
  1302. } else {
  1303. ec_log_crit("Will not upgrade your database from Zarafa 6.40.x.");
  1304. ec_log_crit("The recommended upgrade procedure is to first upgrade by first upgrading to ZCP 7.2 and using the zarafa7-upgrade commandline tool.");
  1305. ec_log_crit("Please consult the Zarafa and Kopano administrator manual on how to correctly upgrade your database.");
  1306. ec_log_crit("Alternatively you may try to upgrade using --force-database-upgrade,");
  1307. ec_log_crit("but no progress and estimates within the updates will be available.");
  1308. return KCERR_USER_CANCEL;
  1309. }
  1310. return er;
  1311. }
  1312. // 47
  1313. ECRESULT UpdateDatabaseConvertStoreUsername(ECDatabase *lpDatabase)
  1314. {
  1315. ECRESULT er = erSuccess;
  1316. er = lpDatabase->DoUpdate("UPDATE stores SET user_name = CAST(CONVERT(user_name USING latin1) AS CHAR(255) CHARACTER SET utf8)");
  1317. if (er == erSuccess)
  1318. er = lpDatabase->DoUpdate("ALTER TABLE stores MODIFY user_name VARCHAR(255) CHARACTER SET utf8 NOT NULL DEFAULT ''");
  1319. return er;
  1320. }
  1321. // 48
  1322. ECRESULT UpdateDatabaseConvertRules(ECDatabase *lpDatabase)
  1323. {
  1324. ECRESULT er = erSuccess;
  1325. DB_RESULT lpResult;
  1326. DB_ROW lpDBRow = NULL;
  1327. convert_context converter;
  1328. er = lpDatabase->DoSelect("SELECT p.hierarchyid, p.storeid, p.val_binary FROM properties AS p JOIN receivefolder AS r ON p.hierarchyid=r.objid AND p.storeid=r.storeid JOIN stores AS s ON r.storeid=s.hierarchy_id WHERE p.tag=0x3fe1 AND p.type=0x102 AND r.messageclass='IPM'", &lpResult);
  1329. if (er != erSuccess)
  1330. return er;
  1331. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  1332. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL) {
  1333. ec_log_err("UpdateDatabaseConvertRules(): column NULL");
  1334. return KCERR_DATABASE_ERROR;
  1335. }
  1336. // Use WTF-1252 here since the pre-unicode rule serializer didn't pass the SOAP_C_UTFSTRING flag, causing
  1337. // gsoap to encode the data as UTF8, eventhough it was already encoded as WINDOWS-1252.
  1338. std::unique_ptr<char[]> lpszConverted(ECStringCompat::WTF1252_to_UTF8(nullptr, lpDBRow[2], &converter));
  1339. er = lpDatabase->DoUpdate("UPDATE properties SET val_binary='" + lpDatabase->Escape(lpszConverted.get()) + "' WHERE hierarchyid=" + lpDBRow[0] + " AND storeid=" + lpDBRow[1] + " AND tag=0x3fe1 AND type=0x102");
  1340. if (er != erSuccess)
  1341. return er;
  1342. }
  1343. return erSuccess;
  1344. }
  1345. // 49
  1346. ECRESULT UpdateDatabaseConvertSearchFolders(ECDatabase *lpDatabase)
  1347. {
  1348. ECRESULT er = erSuccess;
  1349. std::string strQuery;
  1350. DB_RESULT lpResult;
  1351. DB_ROW lpDBRow = NULL;
  1352. convert_context converter;
  1353. strQuery = "SELECT h.id, p.storeid, p.val_string FROM hierarchy AS h JOIN properties AS p ON p.hierarchyid=h.id AND p.tag=" + stringify(PROP_ID(PR_EC_SEARCHCRIT)) +" AND p.type=" + stringify(PROP_TYPE(PR_EC_SEARCHCRIT)) + " WHERE h.type=3 AND h.flags=2";
  1354. er = lpDatabase->DoSelect(strQuery, &lpResult);
  1355. if (er != erSuccess)
  1356. return er;
  1357. while ((lpDBRow = lpDatabase->FetchRow(lpResult))) {
  1358. if (lpDBRow[0] == NULL || lpDBRow[1] == NULL || lpDBRow[2] == NULL) {
  1359. ec_log_err("UpdateDatabaseConvertSearchFolders(): column NULL");
  1360. return KCERR_DATABASE_ERROR;
  1361. }
  1362. // Use WTF-1252 here since the pre-unicode rule serializer didn't pass the SOAP_C_UTFSTRING flag, causing
  1363. // gsoap to encode the data as UTF8, eventhough it was already encoded as WINDOWS-1252.
  1364. std::unique_ptr<char[]> lpszConverted(ECStringCompat::WTF1252_to_WINDOWS1252(nullptr, lpDBRow[2], &converter));
  1365. er = lpDatabase->DoUpdate("UPDATE properties SET val_string='" + lpDatabase->Escape(lpszConverted.get()) + "' WHERE hierarchyid=" + lpDBRow[0] + " AND storeid=" + lpDBRow[1] + " AND tag=" + stringify(PROP_ID(PR_EC_SEARCHCRIT)) +" AND type=" + stringify(PROP_TYPE(PR_EC_SEARCHCRIT)));
  1366. if (er != erSuccess)
  1367. return er;
  1368. }
  1369. return erSuccess;
  1370. }
  1371. // 50
  1372. ECRESULT UpdateDatabaseConvertProperties(ECDatabase *lpDatabase)
  1373. {
  1374. ECRESULT er = erSuccess;
  1375. std::string strQuery;
  1376. DB_RESULT lpResult;
  1377. DB_ROW lpDBRow = NULL;
  1378. // Create the temporary properties table
  1379. strQuery = Z_TABLEDEF_PROPERTIES;
  1380. strQuery.replace(strQuery.find("CREATE TABLE"), strlen("CREATE TABLE"), "CREATE TABLE IF NOT EXISTS");
  1381. strQuery.replace(strQuery.find("properties"), strlen("properties"), "properties_temp");
  1382. er = lpDatabase->DoInsert(strQuery);
  1383. if (er != erSuccess)
  1384. return er;
  1385. while (true) {
  1386. strQuery = "INSERT IGNORE INTO properties_temp (hierarchyid,tag,type,val_ulong,val_string,val_binary,val_double,val_longint,val_hi,val_lo) SELECT hierarchyid,tag,type,val_ulong,val_string,val_binary,val_double,val_longint,val_hi,val_lo FROM properties ORDER BY hierarchyid ASC LIMIT 10000";
  1387. er = lpDatabase->DoInsert(strQuery);
  1388. if (er != erSuccess)
  1389. return er;
  1390. strQuery = "DELETE FROM properties ORDER BY hierarchyid ASC LIMIT 10000";
  1391. er = lpDatabase->DoDelete(strQuery);
  1392. if (er != erSuccess)
  1393. return er;
  1394. er = lpDatabase->Commit();
  1395. if (er != erSuccess)
  1396. return er;
  1397. er = lpDatabase->Begin();
  1398. if (er != erSuccess)
  1399. return er;
  1400. strQuery = "SELECT MIN(hierarchyid) FROM properties";
  1401. er = lpDatabase->DoSelect(strQuery, &lpResult);
  1402. if (er != erSuccess)
  1403. return er;
  1404. lpDBRow = lpDatabase->FetchRow(lpResult);
  1405. if (lpDBRow == NULL || lpDBRow[0] == NULL)
  1406. break;
  1407. }
  1408. // update webaccess settings which were already utf8 in our latin1 table
  1409. strQuery = "UPDATE properties_temp JOIN hierarchy ON properties_temp.hierarchyid=hierarchy.id AND hierarchy.parent IS NULL SET val_string = CAST(CAST(CONVERT(val_string USING latin1) AS binary) AS CHAR CHARACTER SET utf8) WHERE properties_temp.type=0x1e AND properties_temp.tag=26480";
  1410. er = lpDatabase->DoUpdate(strQuery);
  1411. if (er != erSuccess)
  1412. return er;
  1413. er = lpDatabase->DoUpdate("RENAME TABLE properties TO properties_old, properties_temp TO properties");
  1414. if (er != erSuccess)
  1415. return er;
  1416. return lpDatabase->DoDelete("DROP TABLE properties_old");
  1417. }
  1418. // 51
  1419. ECRESULT UpdateDatabaseCreateCounters(ECDatabase *lpDatabase)
  1420. {
  1421. static const struct {
  1422. ULONG ulPropTag;
  1423. ULONG ulChildType;
  1424. ULONG ulChildFlagMask;
  1425. ULONG ulChildFlags;
  1426. const char* lpszValue;
  1427. } counter_info[] = {
  1428. { PR_CONTENT_COUNT, MAPI_MESSAGE, MAPI_ASSOCIATED|MSGFLAG_DELETED, 0, "COUNT(*)" },
  1429. { PR_CONTENT_UNREAD, MAPI_MESSAGE, MAPI_ASSOCIATED|MSGFLAG_DELETED|MSGFLAG_READ, 0, "SUM(IF(flags&1,0,1))" },
  1430. { PR_ASSOC_CONTENT_COUNT, MAPI_MESSAGE, MAPI_ASSOCIATED|MSGFLAG_DELETED, MAPI_ASSOCIATED, "0" },
  1431. { PR_DELETED_MSG_COUNT, MAPI_MESSAGE, MAPI_ASSOCIATED|MSGFLAG_DELETED, MSGFLAG_DELETED, "0" },
  1432. { PR_DELETED_ASSOC_MSG_COUNT, MAPI_MESSAGE, MAPI_ASSOCIATED|MSGFLAG_DELETED, MAPI_ASSOCIATED|MSGFLAG_DELETED, "0" },
  1433. { PR_SUBFOLDERS, MAPI_FOLDER, MSGFLAG_DELETED, 0, "0" },
  1434. { PR_FOLDER_CHILD_COUNT, MAPI_FOLDER, MSGFLAG_DELETED, 0, "0" },
  1435. { PR_DELETED_FOLDER_COUNT, MAPI_FOLDER, MSGFLAG_DELETED, MSGFLAG_DELETED, "0" }
  1436. };
  1437. ECRESULT er = erSuccess;
  1438. std::string strQuery;
  1439. for (unsigned i = 0; i < 8; ++i) {
  1440. strQuery = "REPLACE INTO properties(hierarchyid,tag,type,val_ulong) "
  1441. "SELECT parent.id,"+stringify(PROP_ID(counter_info[i].ulPropTag))+","+stringify(PROP_TYPE(counter_info[i].ulPropTag))+",count(child.id) "
  1442. "FROM hierarchy AS parent "
  1443. "LEFT JOIN hierarchy AS child ON parent.id=child.parent AND "
  1444. "parent.type=3 and child.type="+stringify(counter_info[i].ulChildType)+" AND "
  1445. "child.flags & "+stringify(counter_info[i].ulChildFlagMask)+"="+stringify(counter_info[i].ulChildFlags)+" "
  1446. "GROUP BY parent.id";
  1447. er = lpDatabase->DoInsert(strQuery);
  1448. if (er != erSuccess)
  1449. return er;
  1450. strQuery = "REPLACE INTO properties(hierarchyid,tag,type,val_ulong) "
  1451. "SELECT folderid,"+stringify(PROP_ID(counter_info[i].ulPropTag))+","+stringify(PROP_TYPE(counter_info[i].ulPropTag))+","+counter_info[i].lpszValue+" FROM searchresults GROUP BY folderid";
  1452. er = lpDatabase->DoInsert(strQuery);
  1453. if (er != erSuccess)
  1454. return er;
  1455. }
  1456. return hrSuccess;
  1457. }
  1458. // 52
  1459. ECRESULT UpdateDatabaseCreateCommonProps(ECDatabase *lpDatabase)
  1460. {
  1461. ECRESULT er = erSuccess;
  1462. std::string strQuery;
  1463. strQuery = "REPLACE INTO properties(hierarchyid,tag,type,val_hi,val_lo,val_ulong) "
  1464. "SELECT h.id,"+stringify(PROP_ID(PR_CREATION_TIME))+","+stringify(PROP_TYPE(PR_CREATION_TIME))+",(UNIX_TIMESTAMP(h.createtime) * 10000000 + 116444736000000000) >> 32,(UNIX_TIMESTAMP(h.createtime) * 10000000 + 116444736000000000) & 0xffffffff, NULL "
  1465. "FROM hierarchy AS h "
  1466. "WHERE h.type IN (3,5,7)";
  1467. er = lpDatabase->DoInsert(strQuery);
  1468. if (er != erSuccess)
  1469. return er;
  1470. strQuery = "REPLACE INTO properties(hierarchyid,tag,type,val_hi,val_lo,val_ulong) "
  1471. "SELECT h.id,"+stringify(PROP_ID(PR_LAST_MODIFICATION_TIME))+","+stringify(PROP_TYPE(PR_LAST_MODIFICATION_TIME))+",(UNIX_TIMESTAMP(h.modtime) * 10000000 + 116444736000000000) >> 32,(UNIX_TIMESTAMP(h.modtime) * 10000000 + 116444736000000000) & 0xffffffff, NULL "
  1472. "FROM hierarchy AS h "
  1473. "WHERE h.type IN (3,5,7)";
  1474. er = lpDatabase->DoInsert(strQuery);
  1475. if (er != erSuccess)
  1476. return er;
  1477. strQuery = "REPLACE INTO properties(hierarchyid,tag,type,val_hi,val_lo,val_ulong) "
  1478. "SELECT h.id,"+stringify(PROP_ID(PR_MESSAGE_FLAGS))+","+stringify(PROP_TYPE(PR_MESSAGE_FLAGS))+",NULL, NULL, h.flags "
  1479. "FROM hierarchy AS h "
  1480. "WHERE h.type IN (3,5,7)";
  1481. er = lpDatabase->DoInsert(strQuery);
  1482. if (er != erSuccess)
  1483. return er;
  1484. strQuery = "REPLACE INTO properties(hierarchyid,tag,type,val_hi,val_lo,val_ulong) "
  1485. "SELECT h.id,"+stringify(PROP_ID(PR_FOLDER_TYPE))+","+stringify(PROP_TYPE(PR_FOLDER_TYPE))+",NULL, NULL, h.flags & 0x3 "
  1486. "FROM hierarchy AS h "
  1487. "WHERE h.type=3";
  1488. return lpDatabase->DoInsert(strQuery);
  1489. }
  1490. // 53
  1491. ECRESULT UpdateDatabaseCheckAttachments(ECDatabase *lpDatabase)
  1492. {
  1493. ECRESULT er = erSuccess;
  1494. std::string strQuery;
  1495. strQuery = "REPLACE INTO properties(hierarchyid,tag,type,val_ulong) "
  1496. "SELECT h.id,"+stringify(PROP_ID(PR_HASATTACH))+","+stringify(PROP_TYPE(PR_HASATTACH))+",IF(att.id,1,0) "
  1497. "FROM hierarchy AS h "
  1498. "LEFT JOIN hierarchy AS att ON h.id=att.parent AND att.type=7 AND h.type=5 "
  1499. "GROUP BY h.id";
  1500. er = lpDatabase->DoInsert(strQuery);
  1501. if (er != erSuccess)
  1502. return er;
  1503. strQuery = "UPDATE properties AS p "
  1504. "JOIN hierarchy AS h ON p.hierarchyid=h.id AND h.type=5 "
  1505. "LEFT JOIN hierarchy AS c ON c.type=7 AND c.parent=p.hierarchyid "
  1506. "SET p.val_ulong = IF(c.id,p.val_ulong|"+stringify(MSGFLAG_DELETED)+", p.val_ulong & ~"+stringify(MSGFLAG_DELETED)+") "
  1507. "WHERE p.tag="+stringify(PROP_ID(PR_MESSAGE_FLAGS))+" AND p.type="+stringify(PROP_TYPE(PR_MESSAGE_FLAGS));
  1508. return lpDatabase->DoInsert(strQuery);
  1509. }
  1510. // 54
  1511. ECRESULT UpdateDatabaseCreateTProperties(ECDatabase *lpDatabase)
  1512. {
  1513. ECRESULT er = erSuccess;
  1514. std::string strQuery;
  1515. // Create the tproperties table
  1516. er = lpDatabase->DoInsert(Z_TABLEDEF_TPROPERTIES);
  1517. if (er != erSuccess)
  1518. return er;
  1519. strQuery = "INSERT IGNORE INTO tproperties (folderid,hierarchyid,tag,type,val_ulong,val_string,val_binary,val_double,val_longint,val_hi,val_lo) "
  1520. "SELECT h.id, p.hierarchyid, p.tag, p.type, p.val_ulong, LEFT(p.val_string,255), LEFT(p.val_binary,255), p.val_double, p.val_longint, p.val_hi, p.val_lo "
  1521. "FROM properties AS p "
  1522. "JOIN hierarchy AS tmp ON p.hierarchyid = tmp.id AND p.tag NOT IN (" + stringify(PROP_ID(PR_BODY_HTML)) + "," + stringify(PROP_ID(PR_RTF_COMPRESSED)) + ")"
  1523. "LEFT JOIN hierarchy AS h ON tmp.parent = h.id AND h.type = 3";
  1524. return lpDatabase->DoInsert(strQuery);
  1525. }
  1526. // 55
  1527. ECRESULT UpdateDatabaseConvertHierarchy(ECDatabase *lpDatabase)
  1528. {
  1529. ECRESULT er = erSuccess;
  1530. std::string strQuery;
  1531. // Create the temporary properties table
  1532. strQuery = Z_TABLEDEF_HIERARCHY;
  1533. strQuery.replace(strQuery.find("hierarchy"), strlen("hierarchy"), "hierarchy_temp");
  1534. er = lpDatabase->DoInsert(strQuery);
  1535. if (er != erSuccess)
  1536. goto exit;
  1537. // Folders can be 0, 1, 2 and 0x400 (Deleted)
  1538. // Messages can be 0x40 (associated) and Deleted
  1539. // Other can be Deleted
  1540. strQuery = "INSERT INTO hierarchy_temp (id, parent, type, flags, owner) SELECT id, parent, type, CASE type WHEN 3 THEN flags & 0x403 WHEN 5 THEN flags & 0x440 ELSE flags & 0x400 END, owner FROM hierarchy";
  1541. er = lpDatabase->DoInsert(strQuery);
  1542. if (er != erSuccess)
  1543. goto exit;
  1544. er = lpDatabase->DoUpdate("RENAME TABLE hierarchy TO hierarchy_old, hierarchy_temp TO hierarchy");
  1545. if (er != erSuccess)
  1546. goto exit;
  1547. er = lpDatabase->DoDelete("DROP TABLE hierarchy_old");
  1548. exit:
  1549. lpDatabase->DoDelete("DROP TABLE IF EXISTS hierarchy_temp");
  1550. return er;
  1551. }
  1552. // 56
  1553. ECRESULT UpdateDatabaseCreateDeferred(ECDatabase *lpDatabase)
  1554. {
  1555. // Create the deferred table
  1556. return lpDatabase->DoInsert(Z_TABLEDEF_DELAYEDUPDATE);
  1557. }
  1558. // 57
  1559. ECRESULT UpdateDatabaseConvertChanges(ECDatabase *lpDatabase)
  1560. {
  1561. ECRESULT er = erSuccess;
  1562. std::string strQuery;
  1563. bool bDropColumn;
  1564. // In some upgrade paths the moved_from column doesn't exist. We'll
  1565. // check so no error (which we could ignore) will be logged.
  1566. er = lpDatabase->CheckExistColumn("changes", "moved_from", &bDropColumn);
  1567. if (er == erSuccess && bDropColumn) {
  1568. strQuery = "ALTER TABLE changes DROP COLUMN moved_from, DROP key moved";
  1569. er = lpDatabase->DoDelete(strQuery);
  1570. }
  1571. return er;
  1572. }
  1573. // 58
  1574. ECRESULT UpdateDatabaseConvertNames(ECDatabase *lpDatabase)
  1575. {
  1576. ECRESULT er = erSuccess;
  1577. std::string strQuery;
  1578. // CharsetDetect(names)
  1579. // Create the temporary names table
  1580. strQuery = Z_TABLEDEF_NAMES;
  1581. strQuery.replace(strQuery.find("names"), strlen("names"), "names_temp");
  1582. er = lpDatabase->DoInsert(strQuery);
  1583. if (er != erSuccess)
  1584. goto exit;
  1585. strQuery = "INSERT INTO names_temp (id,nameid,namestring,guid) SELECT id,nameid,CAST(CAST(CONVERT(namestring USING latin1) AS binary) AS CHAR CHARACTER SET utf8),guid FROM names";
  1586. er = lpDatabase->DoInsert(strQuery);
  1587. if (er != erSuccess)
  1588. goto exit;
  1589. er = lpDatabase->DoUpdate("RENAME TABLE names TO names_old, names_temp TO names");
  1590. if (er != erSuccess)
  1591. goto exit;
  1592. er = lpDatabase->DoDelete("DROP TABLE names_old");
  1593. exit:
  1594. lpDatabase->DoDelete("DROP TABLE IF EXISTS names_temp");
  1595. return er;
  1596. }
  1597. // 59
  1598. ECRESULT UpdateDatabaseReceiveFolderToUnicode(ECDatabase *lpDatabase)
  1599. {
  1600. ECRESULT er = erSuccess;
  1601. std::string strQuery;
  1602. strQuery = "ALTER TABLE receivefolder MODIFY messageclass varchar(255) CHARSET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT''";
  1603. er = lpDatabase->DoUpdate(strQuery);
  1604. return er;
  1605. }
  1606. // 60
  1607. ECRESULT UpdateDatabaseClientUpdateStatus(ECDatabase *lpDatabase)
  1608. {
  1609. return lpDatabase->DoInsert(Z_TABLEDEF_CLIENTUPDATESTATUS);
  1610. }
  1611. // 61
  1612. ECRESULT UpdateDatabaseConvertStores(ECDatabase *lpDatabase)
  1613. {
  1614. ECRESULT er = erSuccess;
  1615. std::string strQuery;
  1616. // user_hierarchy_id does not exist on all servers, depends on upgrade path
  1617. strQuery = "ALTER TABLE stores "
  1618. "DROP KEY `user_hierarchy_id` ";
  1619. er = lpDatabase->DoUpdate(strQuery);
  1620. if (er != erSuccess) {
  1621. ec_log_err("Ignoring optional index error, and continuing database upgrade");
  1622. er = erSuccess;
  1623. }
  1624. strQuery = "ALTER TABLE stores "
  1625. "DROP PRIMARY KEY, "
  1626. "ADD COLUMN `type` smallint(6) unsigned NOT NULL default '0', "
  1627. "ADD PRIMARY KEY (`user_id`, `hierarchy_id`, `type`), "
  1628. "ADD UNIQUE KEY `id` (`id`)";
  1629. er = lpDatabase->DoUpdate(strQuery);
  1630. return er;
  1631. }
  1632. // 62
  1633. ECRESULT UpdateDatabaseUpdateStores(ECDatabase *lpDatabase)
  1634. {
  1635. ECRESULT er = erSuccess;
  1636. std::string strQuery;
  1637. strQuery = "UPDATE stores SET type="+stringify(ECSTORE_TYPE_PUBLIC)+" WHERE user_id=1 OR user_id IN (SELECT id FROM users where objectclass="+stringify(CONTAINER_COMPANY)+")";
  1638. er = lpDatabase->DoUpdate(strQuery);
  1639. return er;
  1640. }
  1641. // 63
  1642. ECRESULT UpdateWLinkRecordKeys(ECDatabase *lpDatabase)
  1643. {
  1644. ECRESULT er = erSuccess;
  1645. std::string strQuery;
  1646. strQuery = "update stores " // For each store
  1647. "join properties as p1 on p1.tag = 0x35E6 and p1.hierarchyid=stores.hierarchy_id " // Get PR_COMMON_VIEWS_ENTRYID
  1648. "join indexedproperties as i1 on i1.val_binary = p1.val_binary and i1.tag=0xfff " // Get hierarchy for common views
  1649. "join hierarchy as h2 on h2.parent=i1.hierarchyid " // Get children of common views
  1650. "join properties as p2 on p2.hierarchyid=h2.id and p2.tag=0x684d " // Get PR_WLINK_RECKEY for each child
  1651. "join properties as p3 on p3.hierarchyid=h2.id and p3.tag=0x684c " // Get PR_WLINK_ENTRYID for each child
  1652. "set p2.val_binary = p3.val_binary " // Set PR_WLINK_RECKEY = PR_WLINK_ENTRYID
  1653. "where length(p3.val_binary) = 48"; // Where entryid length is 48 (kopano)
  1654. er = lpDatabase->DoUpdate(strQuery);
  1655. return er;
  1656. }
  1657. /* Edit no. 64 */
  1658. ECRESULT UpdateVersionsTbl(ECDatabase *db)
  1659. {
  1660. return db->DoUpdate(
  1661. "alter table `versions` "
  1662. "add column `micro` int(11) unsigned not null default 0 after `minor`, "
  1663. "drop primary key, "
  1664. "add primary key (`major`, `minor`, `micro`, `revision`, `databaserevision`)");
  1665. }
  1666. /* Edit no. 65 */
  1667. ECRESULT UpdateChangesTbl(ECDatabase *db)
  1668. {
  1669. return db->DoUpdate(
  1670. "alter table `changes` "
  1671. "modify change_type int(11) unsigned not null default 0");
  1672. }
  1673. /* Edit no. 66 */
  1674. ECRESULT UpdateABChangesTbl(ECDatabase *db)
  1675. {
  1676. return db->DoUpdate(
  1677. "alter table `abchanges` "
  1678. "modify change_type int(11) unsigned not null default 0");
  1679. }
  1680. } /* namespace */