6a31050c86eec433934e22219e6030eedd845d4e
[public/netxms.git] / src / server / tools / nxdbmgr / check.cpp
1 /*
2 ** nxdbmgr - NetXMS database manager
3 ** Copyright (C) 2004-2016 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: check.cpp
20 **
21 **/
22
23 #include "nxdbmgr.h"
24
25
26 //
27 // Static data
28 //
29
30 static int m_iNumErrors = 0;
31 static int m_iNumFixes = 0;
32 static int m_iStageErrors;
33 static int s_stageErrorsUpdate;
34 static int m_iStageFixes;
35 static TCHAR *m_pszStageMsg = NULL;
36 static int s_stageWorkTotal = 0;
37 static int s_stageWorkDone = 0;
38
39 /**
40 * Start stage
41 */
42 static void StartStage(const TCHAR *pszMsg, int workTotal = 1)
43 {
44 if (pszMsg != NULL)
45 {
46 free(m_pszStageMsg);
47 m_pszStageMsg = _tcsdup(pszMsg);
48 m_iStageErrors = m_iNumErrors;
49 s_stageErrorsUpdate = m_iNumErrors;
50 m_iStageFixes = m_iNumFixes;
51 s_stageWorkTotal = workTotal;
52 s_stageWorkDone = 0;
53 }
54 WriteToTerminalEx(_T("\x1b[1m*\x1b[0m %-67s \x1b[37;1m[\x1b[0m 0%% \x1b[37;1m]\x1b[0m\b\b\b"), m_pszStageMsg);
55 #ifndef _WIN32
56 fflush(stdout);
57 #endif
58 SetOperationInProgress(true);
59 }
60
61 /**
62 * Set total work for stage
63 */
64 static void SetStageWorkTotal(int workTotal)
65 {
66 s_stageWorkTotal = workTotal;
67 if (s_stageWorkDone > s_stageWorkTotal)
68 s_stageWorkDone = s_stageWorkTotal;
69 }
70
71 /**
72 * Update stage progress
73 */
74 static void UpdateStageProgress(int installment)
75 {
76 if (m_iNumErrors - s_stageErrorsUpdate > 0)
77 {
78 StartStage(NULL); // redisplay stage message
79 s_stageErrorsUpdate = m_iNumErrors;
80 }
81
82 s_stageWorkDone += installment;
83 if (s_stageWorkDone > s_stageWorkTotal)
84 s_stageWorkDone = s_stageWorkTotal;
85 WriteToTerminalEx(_T("\b\b\b%3d"), s_stageWorkDone * 100 / s_stageWorkTotal);
86 #ifndef _WIN32
87 fflush(stdout);
88 #endif
89 }
90
91 /**
92 * End stage
93 */
94 static void EndStage()
95 {
96 static const TCHAR *pszStatus[] = { _T("PASSED"), _T("FIXED "), _T("ERROR ") };
97 static int nColor[] = { 32, 33, 31 };
98 int nCode, nErrors;
99
100 nErrors = m_iNumErrors - m_iStageErrors;
101 if (nErrors > 0)
102 {
103 nCode = (m_iNumFixes - m_iStageFixes == nErrors) ? 1 : 2;
104 if (m_iNumErrors - s_stageErrorsUpdate > 0)
105 StartStage(NULL); // redisplay stage message
106 }
107 else
108 {
109 nCode = 0;
110 }
111 WriteToTerminalEx(_T("\b\b\b\b\b\x1b[37;1m[\x1b[%d;1m%s\x1b[37;1m]\x1b[0m\n"), nColor[nCode], pszStatus[nCode]);
112 SetOperationInProgress(false);
113 }
114
115 /**
116 * Get object name from object_properties table
117 */
118 static TCHAR *GetObjectName(DWORD dwId, TCHAR *pszBuffer)
119 {
120 TCHAR szQuery[256];
121 DB_RESULT hResult;
122
123 _sntprintf(szQuery, 256, _T("SELECT name FROM object_properties WHERE object_id=%d"), dwId);
124 hResult = SQLSelect(szQuery);
125 if (hResult != NULL)
126 {
127 if (DBGetNumRows(hResult) > 0)
128 {
129 DBGetField(hResult, 0, 0, pszBuffer, MAX_OBJECT_NAME);
130 }
131 else
132 {
133 _tcscpy(pszBuffer, _T("<unknown>"));
134 }
135 }
136 else
137 {
138 _tcscpy(pszBuffer, _T("<unknown>"));
139 }
140 return pszBuffer;
141 }
142
143 /**
144 * Check that given node is inside at least one container or cluster
145 */
146 static bool NodeInContainer(DWORD id)
147 {
148 TCHAR query[256];
149 DB_RESULT hResult;
150 bool result = false;
151
152 _sntprintf(query, 256, _T("SELECT container_id FROM container_members WHERE object_id=%d"), id);
153 hResult = SQLSelect(query);
154 if (hResult != NULL)
155 {
156 result = (DBGetNumRows(hResult) > 0);
157 DBFreeResult(hResult);
158 }
159
160 if (!result)
161 {
162 _sntprintf(query, 256, _T("SELECT cluster_id FROM cluster_members WHERE node_id=%d"), id);
163 hResult = SQLSelect(query);
164 if (hResult != NULL)
165 {
166 result = (DBGetNumRows(hResult) > 0);
167 DBFreeResult(hResult);
168 }
169 }
170
171 return result;
172 }
173
174 /**
175 * Find subnet for unlinked node
176 */
177 static BOOL FindSubnetForNode(DWORD id, const TCHAR *name)
178 {
179 DB_RESULT hResult, hResult2;
180 TCHAR query[256], buffer[32];
181 int i, count;
182 BOOL success = FALSE;
183
184 // Read list of interfaces of given node
185 _sntprintf(query, 256, _T("SELECT l.ip_addr,l.ip_netmask FROM interfaces i INNER JOIN interface_address_list l ON l.iface_id = i.id WHERE node_id=%d"), id);
186 hResult = SQLSelect(query);
187 if (hResult != NULL)
188 {
189 count = DBGetNumRows(hResult);
190 for(i = 0; i < count; i++)
191 {
192 InetAddress addr = DBGetFieldInetAddr(hResult, i, 0);
193 addr.setMaskBits(DBGetFieldLong(hResult, i, 1));
194 InetAddress subnet = addr.getSubnetAddress();
195
196 _sntprintf(query, 256, _T("SELECT id FROM subnets WHERE ip_addr='%s'"), subnet.toString(buffer));
197 hResult2 = SQLSelect(query);
198 if (hResult2 != NULL)
199 {
200 if (DBGetNumRows(hResult2) > 0)
201 {
202 UINT32 subnetId = DBGetFieldULong(hResult2, 0, 0);
203 m_iNumErrors++;
204 if (GetYesNo(_T("Unlinked node object %d (\"%s\") can be linked to subnet %d (%s). Link?"), id, name, subnetId, buffer))
205 {
206 _sntprintf(query, 256, _T("INSERT INTO nsmap (subnet_id,node_id) VALUES (%d,%d)"), subnetId, id);
207 if (SQLQuery(query))
208 {
209 success = TRUE;
210 m_iNumFixes++;
211 break;
212 }
213 else
214 {
215 // Node remains unlinked, so error count will be
216 // incremented again by node deletion code or next iteration
217 m_iNumErrors--;
218 }
219 }
220 else
221 {
222 // Node remains unlinked, so error count will be
223 // incremented again by node deletion code
224 m_iNumErrors--;
225 }
226 }
227 DBFreeResult(hResult2);
228 }
229 }
230 DBFreeResult(hResult);
231 }
232 return success;
233 }
234
235 /**
236 * Check zone objects
237 */
238 static void CheckZones()
239 {
240 DB_RESULT hResult, hResult2;
241 DWORD i, dwNumObjects, dwId;
242 TCHAR szQuery[1024];
243
244 StartStage(_T("Checking zone objects"));
245 hResult = SQLSelect(_T("SELECT id FROM zones"));
246 if (hResult != NULL)
247 {
248 dwNumObjects = DBGetNumRows(hResult);
249 for(i = 0; i < dwNumObjects; i++)
250 {
251 dwId = DBGetFieldULong(hResult, i, 0);
252
253 // Check appropriate record in object_properties table
254 _sntprintf(szQuery, 256, _T("SELECT name,is_deleted FROM object_properties WHERE object_id=%d"), (int)dwId);
255 hResult2 = SQLSelect(szQuery);
256 if (hResult2 != NULL)
257 {
258 if ((DBGetNumRows(hResult2) == 0) && (dwId != 4)) // Properties for built-in zone can be missing
259 {
260 m_iNumErrors++;
261 if (GetYesNo(_T("Missing zone object %d properties. Create?"), dwId))
262 {
263 uuid_t guid;
264 TCHAR guidText[128];
265
266 _uuid_generate(guid);
267 _sntprintf(szQuery, 1024,
268 _T("INSERT INTO object_properties (object_id,guid,name,")
269 _T("status,is_deleted,is_system,inherit_access_rights,")
270 _T("last_modified,status_calc_alg,status_prop_alg,")
271 _T("status_fixed_val,status_shift,status_translation,")
272 _T("status_single_threshold,status_thresholds,location_type,")
273 _T("latitude,longitude,location_accuracy,location_timestamp,image,submap_id,maint_mode,maint_event_id) VALUES ")
274 _T("(%d,'%s','lost_zone_%d',5,0,0,1,") TIME_T_FMT _T(",0,0,0,0,0,0,'00000000',0,")
275 _T("'0.000000','0.000000',0,0,'00000000-0000-0000-0000-000000000000',0,'0',0)"),
276 (int)dwId, _uuid_to_string(guid, guidText), (int)dwId, TIME_T_FCAST(time(NULL)));
277 if (SQLQuery(szQuery))
278 m_iNumFixes++;
279 }
280 }
281 DBFreeResult(hResult2);
282 }
283 }
284 DBFreeResult(hResult);
285 }
286 EndStage();
287 }
288
289 /**
290 * Check node objects
291 */
292 static void CheckNodes()
293 {
294 DB_RESULT hResult, hResult2;
295 DWORD i, dwNumObjects, dwId;
296 TCHAR szQuery[1024], szName[MAX_OBJECT_NAME];
297 BOOL bResult, bIsDeleted = FALSE;
298
299 StartStage(_T("Checking node objects"));
300 hResult = SQLSelect(_T("SELECT id,primary_ip FROM nodes"));
301 if (hResult != NULL)
302 {
303 dwNumObjects = DBGetNumRows(hResult);
304 SetStageWorkTotal(dwNumObjects);
305 for(i = 0; i < dwNumObjects; i++)
306 {
307 dwId = DBGetFieldULong(hResult, i, 0);
308
309 // Check appropriate record in object_properties table
310 _sntprintf(szQuery, 256, _T("SELECT name,is_deleted FROM object_properties WHERE object_id=%d"), dwId);
311 hResult2 = SQLSelect(szQuery);
312 if (hResult2 != NULL)
313 {
314 if (DBGetNumRows(hResult2) == 0)
315 {
316 m_iNumErrors++;
317 if (GetYesNo(_T("Missing node object %d properties. Create?"), dwId))
318 {
319 uuid_t guid;
320 TCHAR guidText[128];
321
322 _uuid_generate(guid);
323 _sntprintf(szQuery, 1024,
324 _T("INSERT INTO object_properties (object_id,guid,name,")
325 _T("status,is_deleted,is_system,inherit_access_rights,")
326 _T("last_modified,status_calc_alg,status_prop_alg,")
327 _T("status_fixed_val,status_shift,status_translation,")
328 _T("status_single_threshold,status_thresholds,location_type,")
329 _T("latitude,longitude,location_accuracy,location_timestamp,")
330 _T("image,submap_id,maint_mode,maint_event_id) VALUES ")
331 _T("(%d,'%s','lost_node_%d',5,0,0,1,") TIME_T_FMT _T(",0,0,0,0,0,0,'00000000',0,")
332 _T("'0.000000','0.000000',0,0,'00000000-0000-0000-0000-000000000000',0,'0',0)"),
333 (int)dwId, _uuid_to_string(guid, guidText), (int)dwId, TIME_T_FCAST(time(NULL)));
334 if (SQLQuery(szQuery))
335 m_iNumFixes++;
336 }
337 }
338 else
339 {
340 DBGetField(hResult2, 0, 0, szName, MAX_OBJECT_NAME);
341 bIsDeleted = DBGetFieldLong(hResult2, 0, 1) ? TRUE : FALSE;
342 }
343 DBFreeResult(hResult2);
344 }
345
346 if (!bIsDeleted)
347 {
348 _sntprintf(szQuery, 1024, _T("SELECT subnet_id FROM nsmap WHERE node_id=%d"), dwId);
349 hResult2 = SQLSelect(szQuery);
350 if (hResult2 != NULL)
351 {
352 if ((DBGetNumRows(hResult2) == 0) && (!NodeInContainer(dwId)))
353 {
354 if ((DBGetFieldIPAddr(hResult, i, 1) == 0) || (!FindSubnetForNode(dwId, szName)))
355 {
356 m_iNumErrors++;
357 if (GetYesNo(_T("Unlinked node object %d (\"%s\"). Delete it?"), dwId, szName))
358 {
359 _sntprintf(szQuery, 1024, _T("DELETE FROM nodes WHERE id=%d"), dwId);
360 bResult = SQLQuery(szQuery);
361 _sntprintf(szQuery, 1024, _T("DELETE FROM acl WHERE object_id=%d"), dwId);
362 bResult = bResult && SQLQuery(szQuery);
363 _sntprintf(szQuery, 1024, _T("DELETE FROM object_properties WHERE object_id=%d"), dwId);
364 if (SQLQuery(szQuery) && bResult)
365 m_iNumFixes++;
366 }
367 }
368 }
369 DBFreeResult(hResult2);
370 }
371 }
372 UpdateStageProgress(1);
373 }
374 DBFreeResult(hResult);
375 }
376 EndStage();
377 }
378
379 /**
380 * Check node component objects
381 */
382 static void CheckComponents(const TCHAR *pszDisplayName, const TCHAR *pszTable)
383 {
384 DB_RESULT hResult, hResult2;
385 DWORD i, dwNumObjects, dwId;
386 TCHAR szQuery[1024], szName[MAX_OBJECT_NAME];
387
388 _sntprintf(szQuery, 1024, _T("Checking %s objects"), pszDisplayName);
389 StartStage(szQuery);
390
391 _sntprintf(szQuery, 1024, _T("SELECT id,node_id FROM %s"), pszTable);
392 hResult = SQLSelect(szQuery);
393 if (hResult != NULL)
394 {
395 dwNumObjects = DBGetNumRows(hResult);
396 for(i = 0; i < dwNumObjects; i++)
397 {
398 dwId = DBGetFieldULong(hResult, i, 0);
399
400 // Check appropriate record in object_properties table
401 _sntprintf(szQuery, 1024, _T("SELECT name,is_deleted FROM object_properties WHERE object_id=%d"), dwId);
402 hResult2 = SQLSelect(szQuery);
403 if (hResult2 != NULL)
404 {
405 if (DBGetNumRows(hResult2) == 0)
406 {
407 m_iNumErrors++;
408 if (GetYesNo(_T("Missing %s object %d properties. Create?"), pszDisplayName, dwId))
409 {
410 uuid_t guid;
411 TCHAR guidText[128];
412
413 _uuid_generate(guid);
414 _sntprintf(szQuery, 1024,
415 _T("INSERT INTO object_properties (object_id,guid,name,")
416 _T("status,is_deleted,is_system,inherit_access_rights,")
417 _T("last_modified,status_calc_alg,status_prop_alg,")
418 _T("status_fixed_val,status_shift,status_translation,")
419 _T("status_single_threshold,status_thresholds,location_type,")
420 _T("latitude,longitude,location_accuracy,location_timestamp,submap_id,image,maint_mode,maint_event_id) VALUES ")
421 _T("(%d,'%s','lost_%s_%d',5,0,0,1,") TIME_T_FMT _T(",0,0,0,0,0,0,'00000000',0,")
422 _T("'0.000000','0.000000',0,0,0,'00000000-0000-0000-0000-000000000000','0',0)"),
423 (int)dwId, _uuid_to_string(guid, guidText), pszDisplayName, (int)dwId, TIME_T_FCAST(time(NULL)));
424 if (SQLQuery(szQuery))
425 m_iNumFixes++;
426 szName[0] = 0;
427 }
428 }
429 else
430 {
431 DBGetField(hResult2, 0, 0, szName, MAX_OBJECT_NAME);
432 }
433 DBFreeResult(hResult2);
434 }
435 else
436 {
437 szName[0] = 0;
438 }
439
440 // Check if referred node exists
441 _sntprintf(szQuery, 256, _T("SELECT name FROM object_properties WHERE object_id=%d AND is_deleted=0"),
442 DBGetFieldULong(hResult, i, 1));
443 hResult2 = SQLSelect(szQuery);
444 if (hResult2 != NULL)
445 {
446 if (DBGetNumRows(hResult2) == 0)
447 {
448 m_iNumErrors++;
449 dwId = DBGetFieldULong(hResult, i, 0);
450 if (GetYesNo(_T("Unlinked %s object %d (\"%s\"). Delete it?"), pszDisplayName, dwId, szName))
451 {
452 _sntprintf(szQuery, 256, _T("DELETE FROM %s WHERE id=%d"), pszTable, dwId);
453 if (SQLQuery(szQuery))
454 {
455 _sntprintf(szQuery, 256, _T("DELETE FROM object_properties WHERE object_id=%d"), dwId);
456 SQLQuery(szQuery);
457 m_iNumFixes++;
458 }
459 }
460 }
461 DBFreeResult(hResult2);
462 }
463 }
464 DBFreeResult(hResult);
465 }
466 EndStage();
467 }
468
469 /**
470 * Check common object properties
471 */
472 static void CheckObjectProperties()
473 {
474 DB_RESULT hResult;
475 TCHAR szQuery[1024];
476 DWORD i, dwNumRows, dwObjectId;
477
478 StartStage(_T("Checking object properties"));
479 hResult = SQLSelect(_T("SELECT object_id,name,last_modified FROM object_properties"));
480 if (hResult != NULL)
481 {
482 dwNumRows = DBGetNumRows(hResult);
483 for(i = 0; i < dwNumRows; i++)
484 {
485 dwObjectId = DBGetFieldULong(hResult, i, 0);
486
487 // Check last change time
488 if (DBGetFieldULong(hResult, i, 2) == 0)
489 {
490 m_iNumErrors++;
491 if (GetYesNo(_T("Object %d [%s] has invalid timestamp. Fix it?"),
492 dwObjectId, DBGetField(hResult, i, 1, szQuery, 1024)))
493 {
494 _sntprintf(szQuery, 1024, _T("UPDATE object_properties SET last_modified=") TIME_T_FMT _T(" WHERE object_id=%d"),
495 TIME_T_FCAST(time(NULL)), (int)dwObjectId);
496 if (SQLQuery(szQuery))
497 m_iNumFixes++;
498 }
499 }
500 }
501 DBFreeResult(hResult);
502 }
503 EndStage();
504 }
505
506 static void CheckContainerMembership()
507 {
508 StartStage(_T("Checking container membership"));
509 DB_RESULT containerList = SQLSelect(_T("SELECT object_id,container_id FROM container_members"));
510 DB_RESULT objectList = SQLSelect(_T("SELECT object_id FROM object_properties"));
511 if (containerList != NULL && objectList != NULL)
512 {
513 int numContainers = DBGetNumRows(containerList);
514 int numObjects = DBGetNumRows(objectList);
515 bool match = false;
516 TCHAR szQuery[1024];
517
518 SetStageWorkTotal(numContainers);
519 for(int i = 0; i < numContainers; i++)
520 {
521 for(int n = 0; n < numObjects; n++)
522 {
523 if (DBGetFieldULong(containerList, i, 0) == DBGetFieldULong(objectList, n, 0))
524 {
525 match = true;
526 break;
527 }
528 }
529 if (!match)
530 {
531 m_iNumErrors++;
532 if (GetYesNo(_T("Container %d contains non-existing child %d. Fix it?"),
533 DBGetFieldULong(containerList, i, 1), DBGetFieldULong(containerList, i, 0)))
534 {
535 _sntprintf(szQuery, 1024, _T("DELETE FROM container_members WHERE object_id=%d AND container_id=%d"),
536 DBGetFieldULong(containerList, i, 0), DBGetFieldULong(containerList, i, 1));
537 if (SQLQuery(szQuery))
538 m_iNumFixes++;
539 }
540 }
541 match = false;
542 UpdateStageProgress(1);
543 }
544 DBFreeResult(containerList);
545 DBFreeResult(objectList);
546 }
547 EndStage();
548 }
549
550 /**
551 * Check cluster objects
552 */
553 static void CheckClusters()
554 {
555 DB_RESULT hResult;
556 TCHAR szQuery[256], szName[MAX_OBJECT_NAME];
557 DWORD i, dwNumRows, dwObjectId, dwId;
558
559 StartStage(_T("Checking cluster objects"));
560 hResult = SQLSelect(_T("SELECT cluster_id,node_id FROM cluster_members"));
561 if (hResult != NULL)
562 {
563 dwNumRows = DBGetNumRows(hResult);
564 for(i = 0; i < dwNumRows; i++)
565 {
566 dwObjectId = DBGetFieldULong(hResult, i, 1);
567 if (!IsDatabaseRecordExist(_T("nodes"), _T("id"), dwObjectId))
568 {
569 m_iNumErrors++;
570 dwId = DBGetFieldULong(hResult, i, 0);
571 if (GetYesNo(_T("Cluster object %s [%d] refers to non-existing node %d. Dereference?"),
572 GetObjectName(dwId, szName), dwId, dwObjectId))
573 {
574 _sntprintf(szQuery, 256, _T("DELETE FROM cluster_members WHERE cluster_id=%d AND node_id=%d"),dwId, dwObjectId);
575 if (SQLQuery(szQuery))
576 {
577 m_iNumFixes++;
578 }
579 }
580 }
581 }
582 DBFreeResult(hResult);
583 }
584 EndStage();
585 }
586
587 /**
588 * Returns TRUE if SELECT returns non-empty set
589 */
590 static BOOL CheckResultSet(TCHAR *pszQuery)
591 {
592 DB_RESULT hResult;
593 BOOL bResult = FALSE;
594
595 hResult = SQLSelect(pszQuery);
596 if (hResult != NULL)
597 {
598 bResult = (DBGetNumRows(hResult) > 0);
599 DBFreeResult(hResult);
600 }
601 return bResult;
602 }
603
604 /**
605 * Check event processing policy
606 */
607 static void CheckEPP()
608 {
609 DB_RESULT hResult;
610 TCHAR szQuery[1024];
611 int i, iNumRows;
612 DWORD dwId;
613
614 StartStage(_T("Checking event processing policy"));
615
616 // Check source object ID's
617 hResult = SQLSelect(_T("SELECT object_id FROM policy_source_list"));
618 if (hResult != NULL)
619 {
620 iNumRows = DBGetNumRows(hResult);
621 for(i = 0; i < iNumRows; i++)
622 {
623 dwId = DBGetFieldULong(hResult, i, 0);
624 _sntprintf(szQuery, 1024, _T("SELECT object_id FROM object_properties WHERE object_id=%d"), dwId);
625 if (!CheckResultSet(szQuery))
626 {
627 m_iNumErrors++;
628 if (GetYesNo(_T("Invalid object ID %d used in policy. Delete it from policy?"), dwId))
629 {
630 _sntprintf(szQuery, 1024, _T("DELETE FROM policy_source_list WHERE object_id=%d"), dwId);
631 if (SQLQuery(szQuery))
632 m_iNumFixes++;
633 }
634 }
635 }
636 DBFreeResult(hResult);
637 }
638
639 // Check event ID's
640 hResult = SQLSelect(_T("SELECT event_code FROM policy_event_list"));
641 if (hResult != NULL)
642 {
643 iNumRows = DBGetNumRows(hResult);
644 for(i = 0; i < iNumRows; i++)
645 {
646 dwId = DBGetFieldULong(hResult, i, 0);
647 if (dwId & GROUP_FLAG)
648 _sntprintf(szQuery, 1024, _T("SELECT id FROM event_groups WHERE id=%d"), dwId);
649 else
650 _sntprintf(szQuery, 1024, _T("SELECT event_code FROM event_cfg WHERE event_code=%d"), dwId);
651 if (!CheckResultSet(szQuery))
652 {
653 m_iNumErrors++;
654 if (GetYesNo(_T("Invalid event%s ID 0x%08X referenced in policy. Delete this reference?"), (dwId & GROUP_FLAG) ? _T(" group") : _T(""), dwId))
655 {
656 _sntprintf(szQuery, 1024, _T("DELETE FROM policy_event_list WHERE event_code=%d"), dwId);
657 if (SQLQuery(szQuery))
658 m_iNumFixes++;
659 }
660 }
661 }
662 DBFreeResult(hResult);
663 }
664
665 // Check action ID's
666 hResult = SQLSelect(_T("SELECT action_id FROM policy_action_list"));
667 if (hResult != NULL)
668 {
669 iNumRows = DBGetNumRows(hResult);
670 for(i = 0; i < iNumRows; i++)
671 {
672 dwId = DBGetFieldULong(hResult, i, 0);
673 _sntprintf(szQuery, 1024, _T("SELECT action_id FROM actions WHERE action_id=%d"), dwId);
674 if (!CheckResultSet(szQuery))
675 {
676 m_iNumErrors++;
677 if (GetYesNo(_T("Invalid action ID %d referenced in policy. Delete this reference?"), dwId))
678 {
679 _sntprintf(szQuery, 1024, _T("DELETE FROM policy_action_list WHERE action_id=%d"), dwId);
680 if (SQLQuery(szQuery))
681 m_iNumFixes++;
682 }
683 }
684 }
685 DBFreeResult(hResult);
686 }
687
688 EndStage();
689 }
690
691 /**
692 * Check data tables for given object class
693 */
694 static void CollectObjectIdentifiers(const TCHAR *className, IntegerArray<UINT32> *list)
695 {
696 TCHAR query[1024];
697 _sntprintf(query, 256, _T("SELECT id FROM %s"), className);
698 DB_RESULT hResult = SQLSelect(query);
699 if (hResult != NULL)
700 {
701 int count = DBGetNumRows(hResult);
702 for(int i = 0; i < count; i++)
703 {
704 list->add(DBGetFieldULong(hResult, i, 0));
705 }
706 DBFreeResult(hResult);
707 }
708 }
709
710 /**
711 * Get all data collection targets
712 */
713 static IntegerArray<UINT32> *GetDataCollectionTargets()
714 {
715 IntegerArray<UINT32> *list = new IntegerArray<UINT32>(128, 128);
716 CollectObjectIdentifiers(_T("nodes"), list);
717 CollectObjectIdentifiers(_T("clusters"), list);
718 CollectObjectIdentifiers(_T("mobile_devices"), list);
719 CollectObjectIdentifiers(_T("access_points"), list);
720 CollectObjectIdentifiers(_T("chassis"), list);
721 CollectObjectIdentifiers(_T("sensors"), list);
722 return list;
723 }
724
725 /**
726 * Create idata_xx table
727 */
728 BOOL CreateIDataTable(DWORD nodeId)
729 {
730 TCHAR szQuery[256], szQueryTemplate[256];
731 DWORD i;
732
733 MetaDataReadStr(_T("IDataTableCreationCommand"), szQueryTemplate, 255, _T(""));
734 _sntprintf(szQuery, 256, szQueryTemplate, nodeId);
735 if (!SQLQuery(szQuery))
736 return FALSE;
737
738 for(i = 0; i < 10; i++)
739 {
740 _sntprintf(szQuery, 256, _T("IDataIndexCreationCommand_%d"), i);
741 MetaDataReadStr(szQuery, szQueryTemplate, 255, _T(""));
742 if (szQueryTemplate[0] != 0)
743 {
744 _sntprintf(szQuery, 256, szQueryTemplate, nodeId, nodeId);
745 if (!SQLQuery(szQuery))
746 return FALSE;
747 }
748 }
749
750 return TRUE;
751 }
752
753 /**
754 * Create tdata_xx table - pre V281 version
755 */
756 BOOL CreateTDataTable_preV281(DWORD nodeId)
757 {
758 TCHAR szQuery[256], szQueryTemplate[256];
759 DWORD i;
760
761 MetaDataReadStr(_T("TDataTableCreationCommand"), szQueryTemplate, 255, _T(""));
762 _sntprintf(szQuery, 256, szQueryTemplate, nodeId);
763 if (!SQLQuery(szQuery))
764 return FALSE;
765
766 for(i = 0; i < 10; i++)
767 {
768 _sntprintf(szQuery, 256, _T("TDataIndexCreationCommand_%d"), i);
769 MetaDataReadStr(szQuery, szQueryTemplate, 255, _T(""));
770 if (szQueryTemplate[0] != 0)
771 {
772 _sntprintf(szQuery, 256, szQueryTemplate, nodeId, nodeId);
773 if (!SQLQuery(szQuery))
774 return FALSE;
775 }
776 }
777
778 return TRUE;
779 }
780
781 /**
782 * Create tdata_xx table
783 */
784 BOOL CreateTDataTable(DWORD nodeId)
785 {
786 TCHAR szQuery[256], szQueryTemplate[256];
787 DWORD i;
788
789 for(i = 0; i < 10; i++)
790 {
791 _sntprintf(szQuery, 256, _T("TDataTableCreationCommand_%d"), i);
792 MetaDataReadStr(szQuery, szQueryTemplate, 255, _T(""));
793 if (szQueryTemplate[0] != 0)
794 {
795 _sntprintf(szQuery, 256, szQueryTemplate, nodeId, nodeId);
796 if (!SQLQuery(szQuery))
797 return FALSE;
798 }
799 }
800
801 for(i = 0; i < 10; i++)
802 {
803 _sntprintf(szQuery, 256, _T("TDataIndexCreationCommand_%d"), i);
804 MetaDataReadStr(szQuery, szQueryTemplate, 255, _T(""));
805 if (szQueryTemplate[0] != 0)
806 {
807 _sntprintf(szQuery, 256, szQueryTemplate, nodeId, nodeId);
808 if (!SQLQuery(szQuery))
809 return FALSE;
810 }
811 }
812
813 return TRUE;
814 }
815
816 /**
817 * Check if DCI exists
818 */
819 static bool IsDciExists(UINT32 dciId, UINT32 nodeId, bool isTable)
820 {
821 TCHAR query[256];
822 if (nodeId != 0)
823 _sntprintf(query, 256, _T("SELECT count(*) FROM %s WHERE item_id=%d AND node_id=%d"), isTable ? _T("dc_tables") : _T("items"), dciId, nodeId);
824 else
825 _sntprintf(query, 256, _T("SELECT count(*) FROM %s WHERE item_id=%d"), isTable ? _T("dc_tables") : _T("items"), dciId);
826 DB_RESULT hResult = SQLSelect(query);
827 if (hResult == NULL)
828 return false;
829
830 int count = DBGetFieldLong(hResult, 0, 0);
831 DBFreeResult(hResult);
832 return count != 0;
833 }
834
835 /**
836 * Check collected data
837 */
838 static void CheckCollectedData(bool isTable)
839 {
840 StartStage(isTable ? _T("Checking table DCI history records") : _T("Checking DCI history records"));
841
842 time_t now = time(NULL);
843 IntegerArray<UINT32> *targets = GetDataCollectionTargets();
844 SetStageWorkTotal(targets->size());
845 for(int i = 0; i < targets->size(); i++)
846 {
847 UINT32 objectId = targets->get(i);
848 TCHAR query[1024];
849 _sntprintf(query, 1024, _T("SELECT count(*) FROM %s_%d WHERE %s_timestamp>") TIME_T_FMT,
850 isTable ? _T("tdata") : _T("idata"), objectId, isTable ? _T("tdata") : _T("idata"), TIME_T_FCAST(now));
851 DB_RESULT hResult = SQLSelect(query);
852 if (hResult != NULL)
853 {
854 if (DBGetFieldLong(hResult, 0, 0) > 0)
855 {
856 m_iNumErrors++;
857 if (GetYesNo(_T("Found collected data for node [%d] with timestamp in the future. Delete invalid records?"), objectId))
858 {
859 _sntprintf(query, 1024, _T("DELETE FROM %s_%d WHERE %s_timestamp>") TIME_T_FMT,
860 isTable ? _T("tdata") : _T("idata"), objectId, isTable ? _T("tdata") : _T("idata"), TIME_T_FCAST(now));
861 if (SQLQuery(query))
862 m_iNumFixes++;
863 }
864 }
865 DBFreeResult(hResult);
866 }
867
868 _sntprintf(query, 1024, _T("SELECT distinct(item_id) FROM %s_%d"), isTable ? _T("tdata") : _T("idata"), objectId);
869 hResult = SQLSelect(query);
870 if (hResult != NULL)
871 {
872 int count = DBGetNumRows(hResult);
873 for(int i = 0; i < count; i++)
874 {
875 UINT32 id = DBGetFieldLong(hResult, i, 0);
876 if (!IsDciExists(id, objectId, isTable))
877 {
878 m_iNumErrors++;
879 if (GetYesNo(_T("Found collected data for non-existing DCI [%d] on node [%d]. Delete invalid records?"), id, objectId))
880 {
881 _sntprintf(query, 1024, _T("DELETE FROM %s_%d WHERE item_id=%d"), isTable ? _T("tdata") : _T("idata"), objectId, id);
882 if (SQLQuery(query))
883 m_iNumFixes++;
884 }
885 }
886 }
887 DBFreeResult(hResult);
888 }
889
890 UpdateStageProgress(1);
891 }
892 delete targets;
893
894 EndStage();
895 }
896
897 /**
898 * Check raw DCI values
899 */
900 static void CheckRawDciValues()
901 {
902 StartStage(_T("Checking raw DCI values table"));
903
904 time_t now = time(NULL);
905
906 DB_RESULT hResult = SQLSelect(_T("SELECT item_id FROM raw_dci_values"));
907 if (hResult != NULL)
908 {
909 int count = DBGetNumRows(hResult);
910 SetStageWorkTotal(count + 1);
911 for(int i = 0; i < count; i++)
912 {
913 UINT32 id = DBGetFieldLong(hResult, i, 0);
914 if (!IsDciExists(id, 0, false))
915 {
916 m_iNumErrors++;
917 if (GetYesNo(_T("Found raw value record for non-existing DCI [%d]. Delete it?"), id))
918 {
919 TCHAR query[256];
920 _sntprintf(query, 256, _T("DELETE FROM raw_dci_values WHERE item_id=%d"), id);
921 if (SQLQuery(query))
922 m_iNumFixes++;
923 }
924 }
925 UpdateStageProgress(1);
926 }
927 DBFreeResult(hResult);
928 }
929
930 TCHAR query[1024];
931 _sntprintf(query, 1024, _T("SELECT count(*) FROM raw_dci_values WHERE last_poll_time>") TIME_T_FMT, TIME_T_FCAST(now));
932 hResult = SQLSelect(query);
933 if (hResult != NULL)
934 {
935 if (DBGetFieldLong(hResult, 0, 0) > 0)
936 {
937 m_iNumErrors++;
938 if (GetYesNo(_T("Found DCIs with last poll timestamp in the future. Fix it?")))
939 {
940 _sntprintf(query, 1024, _T("UPDATE raw_dci_values SET last_poll_time=") TIME_T_FMT _T(" WHERE last_poll_time>") TIME_T_FMT, TIME_T_FCAST(now), TIME_T_FCAST(now));
941 if (SQLQuery(query))
942 m_iNumFixes++;
943 }
944 }
945 DBFreeResult(hResult);
946 }
947 UpdateStageProgress(1);
948
949 EndStage();
950 }
951
952 /**
953 * Check thresholds
954 */
955 static void CheckThresholds()
956 {
957 StartStage(_T("Checking DCI thresholds"));
958
959 DB_RESULT hResult = SQLSelect(_T("SELECT threshold_id,item_id FROM thresholds"));
960 if (hResult != NULL)
961 {
962 int count = DBGetNumRows(hResult);
963 SetStageWorkTotal(count);
964 for(int i = 0; i < count; i++)
965 {
966 UINT32 dciId = DBGetFieldULong(hResult, i, 1);
967 if (!IsDciExists(dciId, 0, false))
968 {
969 m_iNumErrors++;
970 if (GetYesNo(_T("Found threshold configuration for non-existing DCI [%d]. Delete?"), dciId))
971 {
972 TCHAR query[256];
973 _sntprintf(query, 256, _T("DELETE FROM thresholds WHERE threshold_id=%d AND item_id=%d"), DBGetFieldLong(hResult, i, 0), dciId);
974 if (SQLQuery(query))
975 m_iNumFixes++;
976 }
977 }
978 UpdateStageProgress(1);
979 }
980 DBFreeResult(hResult);
981 }
982
983 EndStage();
984 }
985
986 /**
987 * Check thresholds
988 */
989 static void CheckTableThresholds()
990 {
991 StartStage(_T("Checking table DCI thresholds"));
992
993 DB_RESULT hResult = SQLSelect(_T("SELECT id,table_id FROM dct_thresholds"));
994 if (hResult != NULL)
995 {
996 int count = DBGetNumRows(hResult);
997 SetStageWorkTotal(count);
998 for(int i = 0; i < count; i++)
999 {
1000 UINT32 dciId = DBGetFieldULong(hResult, i, 1);
1001 if (!IsDciExists(dciId, 0, true))
1002 {
1003 m_iNumErrors++;
1004 if (GetYesNo(_T("Found threshold configuration for non-existing table DCI [%d]. Delete?"), dciId))
1005 {
1006 UINT32 id = DBGetFieldLong(hResult, i, 0);
1007
1008 TCHAR query[256];
1009 _sntprintf(query, 256, _T("DELETE FROM dct_threshold_instances WHERE threshold_id=%d"), id);
1010 if (SQLQuery(query))
1011 {
1012 _sntprintf(query, 256, _T("DELETE FROM dct_threshold_conditions WHERE threshold_id=%d"), id);
1013 if (SQLQuery(query))
1014 {
1015 _sntprintf(query, 256, _T("DELETE FROM dct_thresholds WHERE id=%d"), id);
1016 if (SQLQuery(query))
1017 m_iNumFixes++;
1018 }
1019 }
1020 }
1021 }
1022 UpdateStageProgress(1);
1023 }
1024 DBFreeResult(hResult);
1025 }
1026
1027 EndStage();
1028 }
1029
1030 /**
1031 * Check if given data table exist
1032 */
1033 bool IsDataTableExist(const TCHAR *format, UINT32 id)
1034 {
1035 TCHAR table[256];
1036 _sntprintf(table, 256, format, id);
1037 int rc = DBIsTableExist(g_hCoreDB, table);
1038 if (rc == DBIsTableExist_Failure)
1039 {
1040 _tprintf(_T("WARNING: call to DBIsTableExist(\"%s\") failed\n"), table);
1041 }
1042 return rc != DBIsTableExist_NotFound;
1043 }
1044
1045 /**
1046 * Check data tables
1047 */
1048 static void CheckDataTables()
1049 {
1050 StartStage(_T("Checking data tables"));
1051
1052 IntegerArray<UINT32> *targets = GetDataCollectionTargets();
1053 SetStageWorkTotal(targets->size());
1054 for(int i = 0; i < targets->size(); i++)
1055 {
1056 UINT32 objectId = targets->get(i);
1057
1058 // IDATA
1059 if (!IsDataTableExist(_T("idata_%d"), objectId))
1060 {
1061 m_iNumErrors++;
1062
1063 TCHAR objectName[MAX_OBJECT_NAME];
1064 GetObjectName(objectId, objectName);
1065 if (GetYesNo(_T("Data collection table (IDATA) for object %s [%d] not found. Create? (Y/N) "), objectName, objectId))
1066 {
1067 if (CreateIDataTable(objectId))
1068 m_iNumFixes++;
1069 }
1070 }
1071
1072 // TDATA
1073 if (!IsDataTableExist(_T("tdata_%d"), objectId))
1074 {
1075 m_iNumErrors++;
1076
1077 TCHAR objectName[MAX_OBJECT_NAME];
1078 GetObjectName(objectId, objectName);
1079 if (GetYesNo(_T("Data collection table (TDATA) for %s [%d] not found. Create? (Y/N) "), objectName, objectId))
1080 {
1081 if (CreateTDataTable(objectId))
1082 m_iNumFixes++;
1083 }
1084 }
1085
1086 UpdateStageProgress(1);
1087 }
1088
1089 delete targets;
1090 EndStage();
1091 }
1092
1093 /**
1094 * Check template to node mapping
1095 */
1096 static void CheckTemplateNodeMapping()
1097 {
1098 DB_RESULT hResult;
1099 TCHAR name[256], query[256];
1100 DWORD i, dwNumRows, dwTemplateId, dwNodeId;
1101
1102 StartStage(_T("Checking template to node mapping"));
1103 hResult = SQLSelect(_T("SELECT template_id,node_id FROM dct_node_map ORDER BY template_id"));
1104 if (hResult != NULL)
1105 {
1106 dwNumRows = DBGetNumRows(hResult);
1107 SetStageWorkTotal(dwNumRows);
1108 for(i = 0; i < dwNumRows; i++)
1109 {
1110 dwTemplateId = DBGetFieldULong(hResult, i, 0);
1111 dwNodeId = DBGetFieldULong(hResult, i, 1);
1112
1113 // Check node existence
1114 if (!IsDatabaseRecordExist(_T("nodes"), _T("id"), dwNodeId) &&
1115 !IsDatabaseRecordExist(_T("clusters"), _T("id"), dwNodeId) &&
1116 !IsDatabaseRecordExist(_T("mobile_devices"), _T("id"), dwNodeId))
1117 {
1118 m_iNumErrors++;
1119 GetObjectName(dwTemplateId, name);
1120 if (GetYesNo(_T("Template %d [%s] mapped to non-existent node %d. Delete this mapping?"), dwTemplateId, name, dwNodeId))
1121 {
1122 _sntprintf(query, 256, _T("DELETE FROM dct_node_map WHERE template_id=%d AND node_id=%d"),
1123 dwTemplateId, dwNodeId);
1124 if (SQLQuery(query))
1125 m_iNumFixes++;
1126 }
1127 }
1128 UpdateStageProgress(1);
1129 }
1130 DBFreeResult(hResult);
1131 }
1132 EndStage();
1133 }
1134
1135 /**
1136 * Check network map links
1137 */
1138 static void CheckMapLinks()
1139 {
1140 StartStage(_T("Checking network map links"));
1141
1142 for(int pass = 1; pass <= 2; pass++)
1143 {
1144 TCHAR query[1024];
1145 _sntprintf(query, 1024,
1146 _T("SELECT network_map_links.map_id,network_map_links.element1,network_map_links.element2 ")
1147 _T("FROM network_map_links ")
1148 _T("LEFT OUTER JOIN network_map_elements ON ")
1149 _T(" network_map_links.map_id = network_map_elements.map_id AND ")
1150 _T(" network_map_links.element%d = network_map_elements.element_id ")
1151 _T("WHERE network_map_elements.element_id IS NULL"), pass);
1152
1153 DB_RESULT hResult = SQLSelect(query);
1154 if (hResult != NULL)
1155 {
1156 int count = DBGetNumRows(hResult);
1157 for(int i = 0; i < count; i++)
1158 {
1159 m_iNumErrors++;
1160 DWORD mapId = DBGetFieldULong(hResult, i, 0);
1161 TCHAR name[MAX_OBJECT_NAME];
1162 GetObjectName(mapId, name);
1163 if (GetYesNo(_T("Invalid link on network map %s [%d]. Delete?"), name, mapId))
1164 {
1165 _sntprintf(query, 256, _T("DELETE FROM network_map_links WHERE map_id=%d AND element1=%d AND element2=%d"),
1166 mapId, DBGetFieldLong(hResult, i, 1), DBGetFieldLong(hResult, i, 2));
1167 if (SQLQuery(query))
1168 m_iNumFixes++;
1169 }
1170 }
1171 DBFreeResult(hResult);
1172 }
1173 }
1174 EndStage();
1175 }
1176
1177 /**
1178 * Check database for errors
1179 */
1180 void CheckDatabase()
1181 {
1182 DB_RESULT hResult;
1183 LONG iVersion = 0;
1184 BOOL bCompleted = FALSE;
1185
1186 if (g_checkDataTablesOnly)
1187 _tprintf(_T("Checking database (data tables only):\n"));
1188 else
1189 _tprintf(_T("Checking database (%s collected data):\n"), g_checkData ? _T("including") : _T("excluding"));
1190
1191 // Get database format version
1192 iVersion = DBGetSchemaVersion(g_hCoreDB);
1193 if ((iVersion < DB_FORMAT_VERSION) && !g_checkDataTablesOnly)
1194 {
1195 _tprintf(_T("Your database has format version %d, this tool is compiled for version %d.\nUse \"upgrade\" command to upgrade your database first.\n"),
1196 iVersion, DB_FORMAT_VERSION);
1197 }
1198 else if (iVersion > DB_FORMAT_VERSION)
1199 {
1200 _tprintf(_T("Your database has format version %d, this tool is compiled for version %d.\n")
1201 _T("You need to upgrade your server before using this database.\n"),
1202 iVersion, DB_FORMAT_VERSION);
1203
1204 }
1205 else
1206 {
1207 TCHAR szLockStatus[MAX_DB_STRING], szLockInfo[MAX_DB_STRING];
1208 BOOL bLocked = FALSE;
1209
1210 // Check if database is locked
1211 hResult = DBSelect(g_hCoreDB, _T("SELECT var_value FROM config WHERE var_name='DBLockStatus'"));
1212 if (hResult != NULL)
1213 {
1214 if (DBGetNumRows(hResult) > 0)
1215 {
1216 DBGetField(hResult, 0, 0, szLockStatus, MAX_DB_STRING);
1217 DecodeSQLString(szLockStatus);
1218 bLocked = _tcscmp(szLockStatus, _T("UNLOCKED"));
1219 }
1220 DBFreeResult(hResult);
1221
1222 if (bLocked)
1223 {
1224 hResult = DBSelect(g_hCoreDB, _T("SELECT var_value FROM config WHERE var_name='DBLockInfo'"));
1225 if (hResult != NULL)
1226 {
1227 if (DBGetNumRows(hResult) > 0)
1228 {
1229 DBGetField(hResult, 0, 0, szLockInfo, MAX_DB_STRING);
1230 DecodeSQLString(szLockInfo);
1231 }
1232 DBFreeResult(hResult);
1233 }
1234 }
1235
1236 if (bLocked)
1237 {
1238 if (GetYesNo(_T("Database is locked by server %s [%s]\nDo you wish to force database unlock?"), szLockStatus, szLockInfo))
1239 {
1240 if (SQLQuery(_T("UPDATE config SET var_value='UNLOCKED' where var_name='DBLockStatus'")))
1241 {
1242 bLocked = FALSE;
1243 _tprintf(_T("Database lock removed\n"));
1244 }
1245 }
1246 }
1247
1248 if (!bLocked)
1249 {
1250 DBBegin(g_hCoreDB);
1251
1252 if (g_checkDataTablesOnly)
1253 {
1254 CheckDataTables();
1255 }
1256 else
1257 {
1258 CheckZones();
1259 CheckNodes();
1260 CheckComponents(_T("interface"), _T("interfaces"));
1261 CheckComponents(_T("network service"), _T("network_services"));
1262 CheckClusters();
1263 CheckTemplateNodeMapping();
1264 CheckObjectProperties();
1265 CheckContainerMembership();
1266 CheckEPP();
1267 CheckMapLinks();
1268 CheckDataTables();
1269 CheckRawDciValues();
1270 CheckThresholds();
1271 CheckTableThresholds();
1272 if (g_checkData)
1273 {
1274 CheckCollectedData(false);
1275 CheckCollectedData(true);
1276 }
1277 }
1278
1279 if (m_iNumErrors == 0)
1280 {
1281 _tprintf(_T("Database doesn't contain any errors\n"));
1282 DBCommit(g_hCoreDB);
1283 }
1284 else
1285 {
1286 _tprintf(_T("%d errors was found, %d errors was corrected\n"), m_iNumErrors, m_iNumFixes);
1287 if (m_iNumFixes == m_iNumErrors)
1288 _tprintf(_T("All errors in database was fixed\n"));
1289 else
1290 _tprintf(_T("Database still contain errors\n"));
1291 if (m_iNumFixes > 0)
1292 {
1293 if (GetYesNo(_T("Commit changes?")))
1294 {
1295 _tprintf(_T("Committing changes...\n"));
1296 if (DBCommit(g_hCoreDB))
1297 _tprintf(_T("Changes was successfully committed to database\n"));
1298 }
1299 else
1300 {
1301 _tprintf(_T("Rolling back changes...\n"));
1302 if (DBRollback(g_hCoreDB))
1303 _tprintf(_T("All changes made to database was cancelled\n"));
1304 }
1305 }
1306 else
1307 {
1308 DBRollback(g_hCoreDB);
1309 }
1310 }
1311 bCompleted = TRUE;
1312 }
1313 }
1314 else
1315 {
1316 _tprintf(_T("Unable to get database lock status\n"));
1317 }
1318 }
1319
1320 _tprintf(_T("Database check %s\n"), bCompleted ? _T("completed") : _T("aborted"));
1321 }