fixed server crash when reconciling table DCI data with agent
[public/netxms.git] / src / server / core / dctable.cpp
CommitLineData
4016c0df 1/*
16d6f798 2** NetXMS - Network Management System
4804be4e 3** Copyright (C) 2003-2016 Victor Kirhenshtein
16d6f798
VK
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: dctable.cpp
20**
21**/
22
23#include "nxcore.h"
24
480e036b
VK
25/**
26 * Column ID cache
27 */
ba89fed2
VK
28TC_ID_MAP_ENTRY *DCTable::m_cache = NULL;
29int DCTable::m_cacheSize = 0;
30int DCTable::m_cacheAllocated = 0;
31MUTEX DCTable::m_cacheMutex = MutexCreate();
32
480e036b
VK
33/**
34 * Compare cache element's name to string key
35 */
ba89fed2
VK
36static int CompareCacheElements(const void *key, const void *element)
37{
38 return _tcsicmp((const TCHAR *)key, ((TC_ID_MAP_ENTRY *)element)->name);
39}
40
480e036b
VK
41/**
42 * Compare names of two cache elements
43 */
ba89fed2
VK
44static int CompareCacheElements2(const void *e1, const void *e2)
45{
46 return _tcsicmp(((TC_ID_MAP_ENTRY *)e1)->name, ((TC_ID_MAP_ENTRY *)e2)->name);
47}
48
480e036b
VK
49/**
50 * Get column ID from column name
51 */
967893bb 52INT32 DCTable::columnIdFromName(const TCHAR *name)
ba89fed2
VK
53{
54 TC_ID_MAP_ENTRY buffer;
55
56 // check that column name is valid
57 if ((name == NULL) || (*name == 0))
58 return 0;
59
60 MutexLock(m_cacheMutex);
61
62 TC_ID_MAP_ENTRY *entry = (TC_ID_MAP_ENTRY *)bsearch(name, m_cache, m_cacheSize, sizeof(TC_ID_MAP_ENTRY), CompareCacheElements);
63 if (entry == NULL)
64 {
65 // Not in cache, go to database
66 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
67
68 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT column_id FROM dct_column_names WHERE column_name=?"));
69 if (hStmt != NULL)
70 {
71 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, name, DB_BIND_STATIC);
72 DB_RESULT hResult = DBSelectPrepared(hStmt);
73 if (hResult != NULL)
74 {
75 entry = &buffer;
76 nx_strncpy(entry->name, name, MAX_COLUMN_NAME);
77 if (DBGetNumRows(hResult) > 0)
78 {
79 // found in database
80 entry->id = DBGetFieldLong(hResult, 0, 0);
81 }
82 else
83 {
84 // no such column name in database
85 entry->id = CreateUniqueId(IDG_DCT_COLUMN);
86
87 // update database
88 DB_STATEMENT hStmt2 = DBPrepare(hdb, _T("INSERT INTO dct_column_names (column_id,column_name) VALUES (?,?)"));
89 if (hStmt2 != NULL)
90 {
91 DBBind(hStmt2, 1, DB_SQLTYPE_INTEGER, entry->id);
92 DBBind(hStmt2, 2, DB_SQLTYPE_VARCHAR, name, DB_BIND_STATIC);
93 DBExecute(hStmt2);
94 DBFreeStatement(hStmt2);
95 }
96 }
4016c0df 97
ba89fed2
VK
98 DBFreeResult(hResult);
99
100 // Add to cache
101 if (m_cacheSize == m_cacheAllocated)
102 {
103 m_cacheAllocated += 16;
104 m_cache = (TC_ID_MAP_ENTRY *)realloc(m_cache, sizeof(TC_ID_MAP_ENTRY) * m_cacheAllocated);
105 }
106 memcpy(&m_cache[m_cacheSize++], entry, sizeof(TC_ID_MAP_ENTRY));
107 qsort(m_cache, m_cacheSize, sizeof(TC_ID_MAP_ENTRY), CompareCacheElements2);
108
109 DbgPrintf(6, _T("DCTable::columnIdFromName(): column name %s added to cache, ID=%d"), name, (int)entry->id);
110 }
111 DBFreeStatement(hStmt);
112 }
113
114 DBConnectionPoolReleaseConnection(hdb);
115 }
116
117 MutexUnlock(m_cacheMutex);
118 return (entry != NULL) ? entry->id : 0;
119}
120
480e036b
VK
121/**
122 * Default constructor
123 */
16d6f798
VK
124DCTable::DCTable() : DCObject()
125{
df94e0ce 126 m_columns = new ObjectArray<DCTableColumn>(8, 8, true);
9098ad59 127 m_thresholds = new ObjectArray<DCTableThreshold>(0, 4, true);
b9a8e081 128 m_lastValue = NULL;
16d6f798
VK
129}
130
480e036b
VK
131/**
132 * Copy constructor
133 */
16d6f798
VK
134DCTable::DCTable(const DCTable *src) : DCObject(src)
135{
df94e0ce
VK
136 m_columns = new ObjectArray<DCTableColumn>(src->m_columns->size(), 8, true);
137 for(int i = 0; i < src->m_columns->size(); i++)
138 m_columns->add(new DCTableColumn(src->m_columns->get(i)));
9098ad59
VK
139 m_thresholds = new ObjectArray<DCTableThreshold>(src->m_thresholds->size(), 4, true);
140 for(int i = 0; i < src->m_thresholds->size(); i++)
141 m_thresholds->add(new DCTableThreshold(src->m_thresholds->get(i)));
b9a8e081 142 m_lastValue = NULL;
16d6f798
VK
143}
144
480e036b
VK
145/**
146 * Constructor for creating new DCTable from scratch
147 */
967893bb 148DCTable::DCTable(UINT32 id, const TCHAR *name, int source, int pollingInterval, int retentionTime,
22aaa779 149 Template *node, const TCHAR *description, const TCHAR *systemTag)
ba89fed2
VK
150 : DCObject(id, name, source, pollingInterval, retentionTime, node, description, systemTag)
151{
ba89fed2 152 m_columns = new ObjectArray<DCTableColumn>(8, 8, true);
9098ad59 153 m_thresholds = new ObjectArray<DCTableThreshold>(0, 4, true);
b9a8e081 154 m_lastValue = NULL;
ba89fed2
VK
155}
156
480e036b
VK
157/**
158 * Constructor for creating DCTable from database
159 * Assumes that fields in SELECT query are in following order:
22aaa779 160 * item_id,template_id,template_item_id,name,
480e036b 161 * description,flags,source,snmp_port,polling_interval,retention_time,
55bdca5a 162 * status,system_tag,resource_id,proxy_node,perftab_settings,
98ef8e4a 163 * transformation_script,comments,guid
480e036b 164 */
9bd1bace 165DCTable::DCTable(DB_HANDLE hdb, DB_RESULT hResult, int iRow, Template *pNode) : DCObject()
ba89fed2 166{
c42b4551 167 m_id = DBGetFieldULong(hResult, iRow, 0);
ba89fed2
VK
168 m_dwTemplateId = DBGetFieldULong(hResult, iRow, 1);
169 m_dwTemplateItemId = DBGetFieldULong(hResult, iRow, 2);
c42b4551 170 DBGetField(hResult, iRow, 3, m_name, MAX_ITEM_NAME);
4804be4e 171 DBGetField(hResult, iRow, 4, m_description, MAX_DB_STRING);
22aaa779
VK
172 m_flags = (WORD)DBGetFieldLong(hResult, iRow, 5);
173 m_source = (BYTE)DBGetFieldLong(hResult, iRow, 6);
174 m_snmpPort = (WORD)DBGetFieldLong(hResult, iRow, 7);
175 m_iPollingInterval = DBGetFieldLong(hResult, iRow, 8);
176 m_iRetentionTime = DBGetFieldLong(hResult, iRow, 9);
177 m_status = (BYTE)DBGetFieldLong(hResult, iRow, 10);
178 DBGetField(hResult, iRow, 11, m_systemTag, MAX_DB_STRING);
179 m_dwResourceId = DBGetFieldULong(hResult, iRow, 12);
191e4784 180 m_sourceNode = DBGetFieldULong(hResult, iRow, 13);
22aaa779
VK
181 m_pszPerfTabSettings = DBGetField(hResult, iRow, 14, NULL, 0);
182 TCHAR *pszTmp = DBGetField(hResult, iRow, 15, NULL, 0);
4016c0df 183 m_comments = DBGetField(hResult, iRow, 16, NULL, 0);
98ef8e4a 184 m_guid = DBGetFieldGUID(hResult, iRow, 17);
55bdca5a
VK
185 setTransformationScript(pszTmp);
186 free(pszTmp);
ba89fed2 187
4804be4e 188 m_owner = pNode;
b4369830 189 m_columns = new ObjectArray<DCTableColumn>(8, 8, true);
b9a8e081 190 m_lastValue = NULL;
b4369830 191
9bd1bace 192 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT column_name,flags,snmp_oid,display_name FROM dc_table_columns WHERE table_id=? ORDER BY sequence_number"));
b4369830
VK
193 if (hStmt != NULL)
194 {
c42b4551 195 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
b4369830
VK
196 DB_RESULT hColumnList = DBSelectPrepared(hStmt);
197 if (hColumnList != NULL)
198 {
199 int count = DBGetNumRows(hColumnList);
200 for(int i = 0; i < count; i++)
201 m_columns->add(new DCTableColumn(hColumnList, i));
202 DBFreeResult(hColumnList);
203 }
204 DBFreeStatement(hStmt);
205 }
ba89fed2 206
9bd1bace 207 loadCustomSchedules(hdb);
c16e83db
VK
208
209 m_thresholds = new ObjectArray<DCTableThreshold>(0, 4, true);
9bd1bace 210 loadThresholds(hdb);
ba89fed2
VK
211}
212
9387bc59
VK
213/**
214 * Create DCTable from import file
215 */
216DCTable::DCTable(ConfigEntry *config, Template *owner) : DCObject(config, owner)
217{
218 ConfigEntry *columnsRoot = config->findEntry(_T("columns"));
219 if (columnsRoot != NULL)
220 {
8b7ae7eb
VK
221 ObjectArray<ConfigEntry> *columns = columnsRoot->getSubEntries(_T("column#*"));
222 m_columns = new ObjectArray<DCTableColumn>(columns->size(), 8, true);
223 for(int i = 0; i < columns->size(); i++)
9387bc59 224 {
8b7ae7eb 225 m_columns->add(new DCTableColumn(columns->get(i)));
9387bc59
VK
226 }
227 delete columns;
228 }
229 else
230 {
231 m_columns = new ObjectArray<DCTableColumn>(8, 8, true);
232 }
233
234 ConfigEntry *thresholdsRoot = config->findEntry(_T("thresholds"));
235 if (thresholdsRoot != NULL)
236 {
8b7ae7eb
VK
237 ObjectArray<ConfigEntry> *thresholds = thresholdsRoot->getSubEntries(_T("threshold#*"));
238 m_thresholds = new ObjectArray<DCTableThreshold>(thresholds->size(), 8, true);
239 for(int i = 0; i < thresholds->size(); i++)
9387bc59 240 {
8b7ae7eb 241 m_thresholds->add(new DCTableThreshold(thresholds->get(i)));
9387bc59
VK
242 }
243 delete thresholds;
244 }
245 else
246 {
247 m_thresholds = new ObjectArray<DCTableThreshold>(0, 4, true);
248 }
249
250 m_lastValue = NULL;
251}
252
480e036b
VK
253/**
254 * Destructor
255 */
16d6f798
VK
256DCTable::~DCTable()
257{
df94e0ce 258 delete m_columns;
9098ad59 259 delete m_thresholds;
a0ddfb29
VK
260 if (m_lastValue != NULL)
261 m_lastValue->decRefCount();
16d6f798 262}
533ce8c0 263
480e036b
VK
264/**
265 * Clean expired data
266 */
ba89fed2
VK
267void DCTable::deleteExpiredData()
268{
1d4f7890 269 TCHAR query[256];
ba89fed2
VK
270 time_t now;
271
272 now = time(NULL);
1d4f7890 273
ba89fed2 274 lock();
1d4f7890 275 _sntprintf(query, 256, _T("DELETE FROM tdata_%d WHERE (item_id=%d) AND (tdata_timestamp<%ld)"),
4804be4e 276 (int)m_owner->getId(), (int)m_id, (long)(now - (time_t)m_iRetentionTime * 86400));
ba89fed2 277 unlock();
1d4f7890
VK
278
279 QueueSQLRequest(query);
ba89fed2
VK
280}
281
480e036b
VK
282/**
283 * Delete all collected data
284 */
ba89fed2
VK
285bool DCTable::deleteAllData()
286{
287 TCHAR szQuery[256];
288 bool success;
289
290 lock();
035745fc 291 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
4804be4e 292 _sntprintf(szQuery, 256, _T("DELETE FROM tdata_%d WHERE item_id=%d"), m_owner->getId(), (int)m_id);
035745fc
VK
293 success = DBQuery(hdb, szQuery) ? true : false;
294 DBConnectionPoolReleaseConnection(hdb);
ba89fed2
VK
295 unlock();
296 return success;
297}
298
480e036b 299/**
0156d6b2
VK
300 * Process new collected value. Should return true on success.
301 * If returns false, current poll result will be converted into data collection error.
302 *
303 * @return true on success
480e036b 304 */
9664e8df 305bool DCTable::processNewValue(time_t timestamp, const void *value, bool *updateStatus)
533ce8c0 306{
cd68963b 307 *updateStatus = false;
ba89fed2
VK
308 lock();
309
4804be4e
VK
310 // Normally m_owner shouldn't be NULL for polled items, but who knows...
311 if (m_owner == NULL)
ba89fed2
VK
312 {
313 unlock();
0156d6b2 314 return false;
ba89fed2
VK
315 }
316
7de1151b 317 // Transform input value
f877ac05
VK
318 // Cluster can have only aggregated data, and transformation
319 // should not be used on aggregation
4804be4e 320 if ((m_owner->getObjectClass() != OBJECT_CLUSTER) || (m_flags & DCF_TRANSFORM_AGGREGATED))
0156d6b2
VK
321 {
322 if (!transform((Table *)value))
323 {
324 unlock();
1693f955 325 ((Table *)value)->decRefCount();
0156d6b2
VK
326 return false;
327 }
328 }
7de1151b 329
ba89fed2 330 m_dwErrorCount = 0;
a0ddfb29
VK
331 if (m_lastValue != NULL)
332 m_lastValue->decRefCount();
b9a8e081 333 m_lastValue = (Table *)value;
4804be4e 334 m_lastValue->setTitle(m_description);
5891329f 335 m_lastValue->setSource(m_source);
ba89fed2
VK
336
337 // Copy required fields into local variables
c42b4551 338 UINT32 tableId = m_id;
4804be4e 339 UINT32 nodeId = m_owner->getId();
a58454c9 340 bool save = (m_flags & DCF_NO_STORAGE) == 0;
ba89fed2 341
57c9050f
VK
342 ((Table *)value)->incRefCount();
343
ba89fed2
VK
344 unlock();
345
346 // Save data to database
347 // Object is unlocked, so only local variables can be used
a58454c9 348 if (save)
22aaa779 349 {
a58454c9
VK
350 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
351 if (!DBBegin(hdb))
352 {
353 DBConnectionPoolReleaseConnection(hdb);
0156d6b2 354 return true;
a58454c9 355 }
22aaa779 356
9664e8df 357 INT64 recordId = ((INT64)timestamp << 30) | (((INT64)tableId & 0xFFFF) << 14);
a58454c9
VK
358 BOOL success = FALSE;
359 Table *data = (Table *)value;
ba89fed2 360
a58454c9
VK
361 TCHAR query[256];
362 _sntprintf(query, 256, _T("INSERT INTO tdata_%d (item_id,tdata_timestamp,record_id) VALUES (?,?,?)"), (int)nodeId);
22aaa779
VK
363 DB_STATEMENT hStmt = DBPrepare(hdb, query);
364 if (hStmt != NULL)
365 {
a58454c9 366 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, tableId);
9664e8df 367 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (INT32)timestamp);
a58454c9
VK
368 DBBind(hStmt, 3, DB_SQLTYPE_BIGINT, recordId);
369 success = DBExecute(hStmt);
370 DBFreeStatement(hStmt);
22aaa779 371 }
22aaa779 372
a58454c9
VK
373 if (success)
374 {
375 _sntprintf(query, 256, _T("INSERT INTO tdata_records_%d (record_id,row_id,instance) VALUES (?,?,?)"), (int)nodeId);
376 DB_STATEMENT hStmt = DBPrepare(hdb, query);
377 if (hStmt != NULL)
378 {
379 DBBind(hStmt, 1, DB_SQLTYPE_BIGINT, recordId);
380 for(int row = 0; row < data->getNumRows(); row++)
381 {
382 TCHAR instance[MAX_RESULT_LENGTH];
383 data->buildInstanceString(row, instance, MAX_RESULT_LENGTH);
384 DBBind(hStmt, 2, DB_SQLTYPE_BIGINT, recordId | (INT64)row);
385 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, instance, DB_BIND_STATIC);
386 success = DBExecute(hStmt);
22aaa779
VK
387 if (!success)
388 break;
a58454c9
VK
389 }
390 DBFreeStatement(hStmt);
391 }
22aaa779 392 }
22aaa779 393
a58454c9
VK
394 if (success)
395 {
396 _sntprintf(query, 256, _T("INSERT INTO tdata_rows_%d (row_id,column_id,value) VALUES (?,?,?)"), (int)nodeId);
397 DB_STATEMENT hStmt = DBPrepare(hdb, query);
398 if (hStmt != NULL)
399 {
400 for(int col = 0; col < data->getNumColumns(); col++)
401 {
402 INT32 colId = columnIdFromName(data->getColumnName(col));
403 if (colId == 0)
404 continue; // cannot get column ID
405
406 for(int row = 0; row < data->getNumRows(); row++)
407 {
408 DBBind(hStmt, 1, DB_SQLTYPE_BIGINT, recordId | (INT64)row);
409 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, colId);
410 const TCHAR *s = data->getAsString(row, col);
411 if ((s == NULL) || (_tcslen(s) < MAX_DB_STRING))
412 {
413 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, s, DB_BIND_STATIC);
414 }
415 else
416 {
417 TCHAR *sp = (TCHAR *)nx_memdup(s, MAX_DB_STRING * sizeof(TCHAR));
418 sp[MAX_DB_STRING - 1] = 0;
419 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, sp, DB_BIND_DYNAMIC);
420 }
421 success = DBExecute(hStmt);
422 if (!success)
423 break;
424 }
425 }
426 DBFreeStatement(hStmt);
427 }
428 }
22aaa779 429
a58454c9
VK
430 if (success)
431 DBCommit(hdb);
432 else
433 DBRollback(hdb);
50633e41 434
a58454c9
VK
435 DBConnectionPoolReleaseConnection(hdb);
436 }
f6456d80 437 if ((g_offlineDataRelevanceTime <= 0) || (timestamp > (time(NULL) - g_offlineDataRelevanceTime)))
7f418694 438 checkThresholds((Table *)value);
ea50bc33
VK
439
440 if (g_flags & AF_PERFDATA_STORAGE_DRIVER_LOADED)
9664e8df 441 PerfDataStorageRequest(this, timestamp, (Table *)value);
ea50bc33 442
57c9050f 443 ((Table *)value)->decRefCount();
0156d6b2 444 return true;
533ce8c0
VK
445}
446
7de1151b
VK
447/**
448 * Transform received value
449 */
0156d6b2 450bool DCTable::transform(Table *value)
7de1151b 451{
c2b7c9ae 452 if (m_transformationScript == NULL)
0156d6b2 453 return true;
c2b7c9ae 454
4804be4e
VK
455 bool success = false;
456 NXSL_VM *vm = new NXSL_VM(new NXSL_ServerEnv());
457 if (vm->load(m_transformationScript))
7de1151b 458 {
4804be4e
VK
459 NXSL_Value *nxslValue = new NXSL_Value(new NXSL_Object(&g_nxslStaticTableClass, value));
460 vm->setGlobalVariable(_T("$object"), m_owner->createNXSLObject());
461 if (m_owner->getObjectClass() == OBJECT_NODE)
b32b325d 462 {
4804be4e 463 vm->setGlobalVariable(_T("$node"), m_owner->createNXSLObject());
b32b325d 464 }
4804be4e
VK
465 vm->setGlobalVariable(_T("$dci"), createNXSLObject());
466 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((m_owner->getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
7de1151b 467
4804be4e
VK
468 // remove lock from DCI for script execution to avoid deadlocks
469 unlock();
470 success = vm->run(1, &nxslValue);
471 lock();
472 if (!success)
473 {
474 if (vm->getErrorCode() == NXSL_ERR_EXECUTION_ABORTED)
475 {
476 DbgPrintf(6, _T("Transformation script for DCI \"%s\" [%d] on node %s [%d] aborted"),
477 m_description, m_id, getOwnerName(), getOwnerId());
478 }
479 else
480 {
481 TCHAR buffer[1024];
482 _sntprintf(buffer, 1024, _T("DCI::%s::%d::TransformationScript"), getOwnerName(), m_id);
483 PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, m_id, "ssd", buffer, vm->getErrorText(), m_id);
484 nxlog_write(MSG_TRANSFORMATION_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "dsdss",
485 getOwnerId(), getOwnerName(), m_id, m_name, vm->getErrorText());
486 }
b32b325d 487 }
7de1151b 488 }
4804be4e
VK
489 else
490 {
491 TCHAR buffer[1024];
492 _sntprintf(buffer, 1024, _T("DCI::%s::%d::TransformationScript"), getOwnerName(), m_id);
493 PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, m_id, "ssd", buffer, vm->getErrorText(), m_id);
494 nxlog_write(MSG_TRANSFORMATION_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "dsdss",
495 getOwnerId(), getOwnerName(), m_id, m_name, vm->getErrorText());
496 }
497 delete vm;
0156d6b2 498 return success;
7de1151b
VK
499}
500
50633e41
VK
501/**
502 * Check thresholds
503 */
504void DCTable::checkThresholds(Table *value)
505{
a0dc14f9
VK
506 static const TCHAR *paramNames[] = { _T("dciName"), _T("dciDescription"), _T("dciId"), _T("row"), _T("instance") };
507
50633e41 508 lock();
a0dc14f9 509 for(int row = 0; row < value->getNumRows(); row++)
50633e41 510 {
a0dc14f9
VK
511 TCHAR instance[MAX_RESULT_LENGTH];
512 value->buildInstanceString(row, instance, MAX_RESULT_LENGTH);
513 for(int i = 0; i < m_thresholds->size(); i++)
514 {
515 DCTableThreshold *t = m_thresholds->get(i);
516 ThresholdCheckResult result = t->check(value, row, instance);
517 switch(result)
518 {
519 case ACTIVATED:
4804be4e 520 PostDciEventWithNames(t->getActivationEvent(), m_owner->getId(), m_id, "ssids", paramNames, m_name, m_description, m_id, row, instance);
a0dc14f9
VK
521 if (!(m_flags & DCF_ALL_THRESHOLDS))
522 i = m_thresholds->size(); // Stop processing (for current row)
523 break;
524 case DEACTIVATED:
4804be4e 525 PostDciEventWithNames(t->getDeactivationEvent(), m_owner->getId(), m_id, "ssids", paramNames, m_name, m_description, m_id, row, instance);
a0dc14f9
VK
526 break;
527 case ALREADY_ACTIVE:
528 i = m_thresholds->size(); // Threshold condition still true, stop processing
529 break;
530 default:
531 break;
532 }
533 }
50633e41
VK
534 }
535 unlock();
536}
537
480e036b
VK
538/**
539 * Process new data collection error
540 */
82493366 541void DCTable::processNewError(bool noInstance)
533ce8c0 542{
c5c77583 543 m_dwErrorCount++;
533ce8c0 544}
ba89fed2 545
480e036b
VK
546/**
547 * Save to database
548 */
e7450f3b 549bool DCTable::saveToDatabase(DB_HANDLE hdb)
ba89fed2
VK
550{
551 DB_STATEMENT hStmt;
c42b4551 552 if (IsDatabaseRecordExist(hdb, _T("dc_tables"), _T("item_id"), m_id))
ba89fed2
VK
553 {
554 hStmt = DBPrepare(hdb, _T("UPDATE dc_tables SET node_id=?,template_id=?,template_item_id=?,name=?,")
22aaa779 555 _T("description=?,flags=?,source=?,snmp_port=?,polling_interval=?,")
ba89fed2 556 _T("retention_time=?,status=?,system_tag=?,resource_id=?,proxy_node=?,")
98ef8e4a 557 _T("perftab_settings=?,transformation_script=?,comments=?,guid=? WHERE item_id=?"));
ba89fed2
VK
558 }
559 else
560 {
561 hStmt = DBPrepare(hdb, _T("INSERT INTO dc_tables (node_id,template_id,template_item_id,name,")
22aaa779 562 _T("description,flags,source,snmp_port,polling_interval,")
ba89fed2 563 _T("retention_time,status,system_tag,resource_id,proxy_node,perftab_settings,")
98ef8e4a
VK
564 _T("transformation_script,comments,guid,item_id) ")
565 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
ba89fed2
VK
566 }
567 if (hStmt == NULL)
568 return FALSE;
569
570 lock();
571
4804be4e 572 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (m_owner == NULL) ? (UINT32)0 : m_owner->getId());
ba89fed2
VK
573 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_dwTemplateId);
574 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, m_dwTemplateItemId);
c42b4551 575 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, m_name, DB_BIND_STATIC);
4804be4e 576 DBBind(hStmt, 5, DB_SQLTYPE_VARCHAR, m_description, DB_BIND_STATIC);
22aaa779
VK
577 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (UINT32)m_flags);
578 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (INT32)m_source);
579 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (UINT32)m_snmpPort);
580 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (INT32)m_iPollingInterval);
581 DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, (INT32)m_iRetentionTime);
582 DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, (INT32)m_status);
583 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, m_systemTag, DB_BIND_STATIC);
584 DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, m_dwResourceId);
191e4784 585 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, m_sourceNode);
22aaa779
VK
586 DBBind(hStmt, 15, DB_SQLTYPE_TEXT, m_pszPerfTabSettings, DB_BIND_STATIC);
587 DBBind(hStmt, 16, DB_SQLTYPE_TEXT, m_transformationScriptSource, DB_BIND_STATIC);
4016c0df 588 DBBind(hStmt, 17, DB_SQLTYPE_TEXT, m_comments, DB_BIND_STATIC);
98ef8e4a
VK
589 DBBind(hStmt, 18, DB_SQLTYPE_VARCHAR, m_guid);
590 DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, m_id);
ba89fed2 591
e7450f3b 592 bool result = DBExecute(hStmt);
ba89fed2
VK
593 DBFreeStatement(hStmt);
594
595 if (result)
596 {
597 // Save column configuration
598 hStmt = DBPrepare(hdb, _T("DELETE FROM dc_table_columns WHERE table_id=?"));
599 if (hStmt != NULL)
600 {
c42b4551 601 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
ba89fed2
VK
602 result = DBExecute(hStmt);
603 DBFreeStatement(hStmt);
604 }
605 else
606 {
e7450f3b 607 result = false;
ba89fed2
VK
608 }
609
610 if (result && (m_columns->size() > 0))
611 {
9387bc59 612 hStmt = DBPrepare(hdb, _T("INSERT INTO dc_table_columns (table_id,sequence_number,column_name,snmp_oid,flags,display_name) VALUES (?,?,?,?,?,?)"));
ba89fed2
VK
613 if (hStmt != NULL)
614 {
c42b4551 615 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
ba89fed2
VK
616 for(int i = 0; i < m_columns->size(); i++)
617 {
618 DCTableColumn *column = m_columns->get(i);
9387bc59
VK
619 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (INT32)(i + 1));
620 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, column->getName(), DB_BIND_STATIC);
ba89fed2 621 SNMP_ObjectId *oid = column->getSnmpOid();
9ceab287 622 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, (oid != NULL) ? (const TCHAR *)oid->toString() : NULL, DB_BIND_TRANSIENT);
9387bc59
VK
623 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (INT32)column->getFlags());
624 DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, column->getDisplayName(), DB_BIND_STATIC);
ba89fed2
VK
625
626 result = DBExecute(hStmt);
627 if (!result)
628 break;
629 }
630 DBFreeStatement(hStmt);
631 }
632 else
633 {
e7450f3b 634 result = false;
ba89fed2
VK
635 }
636 }
637 }
638
9098ad59
VK
639 saveThresholds(hdb);
640
ba89fed2 641 unlock();
e7450f3b 642 return result ? DCObject::saveToDatabase(hdb) : false;
ba89fed2
VK
643}
644
9098ad59
VK
645/**
646 * Load thresholds from database
647 */
9bd1bace 648bool DCTable::loadThresholds(DB_HANDLE hdb)
9098ad59 649{
9bd1bace 650 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT id,activation_event,deactivation_event FROM dct_thresholds WHERE table_id=? ORDER BY sequence_number"));
9098ad59
VK
651 if (hStmt == NULL)
652 return false;
653
c42b4551 654 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
9098ad59
VK
655 DB_RESULT hResult = DBSelectPrepared(hStmt);
656 if (hResult != NULL)
657 {
658 int count = DBGetNumRows(hResult);
659 for(int i = 0; i < count; i++)
660 {
9bd1bace 661 DCTableThreshold *t = new DCTableThreshold(hdb, hResult, i);
9098ad59
VK
662 m_thresholds->add(t);
663 }
664 DBFreeResult(hResult);
665 }
666 DBFreeStatement(hStmt);
667 return true;
668}
669
670/**
671 * Save thresholds to database
672 */
673bool DCTable::saveThresholds(DB_HANDLE hdb)
674{
675 DB_STATEMENT hStmt = DBPrepare(hdb, _T("DELETE FROM dct_threshold_conditions WHERE threshold_id=?"));
676 if (hStmt == NULL)
677 return false;
678
679 for(int i = 0; i < m_thresholds->size(); i++)
680 {
681 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_thresholds->get(i)->getId());
682 DBExecute(hStmt);
683 }
684 DBFreeStatement(hStmt);
685
686 hStmt = DBPrepare(hdb, _T("DELETE FROM dct_thresholds WHERE table_id=?"));
687 if (hStmt == NULL)
688 return false;
c42b4551 689 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
9098ad59
VK
690 DBExecute(hStmt);
691 DBFreeStatement(hStmt);
692
693 for(int i = 0; i < m_thresholds->size(); i++)
c42b4551 694 m_thresholds->get(i)->saveToDatabase(hdb, m_id, i);
9098ad59
VK
695 return true;
696}
697
480e036b
VK
698/**
699 * Delete table object and collected data from database
700 */
c42b4551 701void DCTable::deleteFromDatabase()
ba89fed2
VK
702{
703 TCHAR szQuery[256];
704
c42b4551 705 DCObject::deleteFromDatabase();
ba89fed2 706
4804be4e 707 if(m_owner->getObjectClass() != OBJECT_TEMPLATE)
59d9c840 708 {
4804be4e 709 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM tdata_%d WHERE item_id=%d"), m_owner->getId(), (int)m_id);
59d9c840 710 QueueSQLRequest(szQuery);
711 }
22aaa779 712
c42b4551 713 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM dc_tables WHERE item_id=%d"), (int)m_id);
ba89fed2 714 QueueSQLRequest(szQuery);
c42b4551 715 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM dc_table_columns WHERE table_id=%d"), (int)m_id);
ba89fed2 716 QueueSQLRequest(szQuery);
9098ad59
VK
717
718 for(int i = 0; i < m_thresholds->size(); i++)
719 {
720 _sntprintf(szQuery, 256, _T("DELETE FROM dct_threshold_conditions WHERE threshold_id=%d"), (int)m_thresholds->get(i)->getId());
721 QueueSQLRequest(szQuery);
722 }
723
c42b4551 724 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM dct_thresholds WHERE table_id=%d"), (int)m_id);
9098ad59 725 QueueSQLRequest(szQuery);
ba89fed2 726}
b4369830 727
480e036b
VK
728/**
729 * Create NXCP message with item data
730 */
b368969c 731void DCTable::createMessage(NXCPMessage *pMsg)
b4369830
VK
732{
733 DCObject::createMessage(pMsg);
734
735 lock();
b368969c 736 pMsg->setField(VID_NUM_COLUMNS, (UINT32)m_columns->size());
967893bb 737 UINT32 varId = VID_DCI_COLUMN_BASE;
b4369830
VK
738 for(int i = 0; i < m_columns->size(); i++)
739 {
740 DCTableColumn *column = m_columns->get(i);
b368969c
VK
741 pMsg->setField(varId++, column->getName());
742 pMsg->setField(varId++, column->getFlags());
b4369830
VK
743 SNMP_ObjectId *oid = column->getSnmpOid();
744 if (oid != NULL)
9ceab287 745 pMsg->setFieldFromInt32Array(varId++, (UINT32)oid->length(), oid->value());
b4369830
VK
746 else
747 varId++;
b368969c 748 pMsg->setField(varId++, column->getDisplayName());
0b77b73e 749 varId += 6;
b4369830 750 }
9098ad59 751
b368969c 752 pMsg->setField(VID_NUM_THRESHOLDS, (UINT32)m_thresholds->size());
9098ad59
VK
753 varId = VID_DCI_THRESHOLD_BASE;
754 for(int i = 0; i < m_thresholds->size(); i++)
755 {
756 varId = m_thresholds->get(i)->fillMessage(pMsg, varId);
757 }
758
b4369830
VK
759 unlock();
760}
761
480e036b
VK
762/**
763 * Update data collection object from NXCP message
764 */
b368969c 765void DCTable::updateFromMessage(NXCPMessage *pMsg)
b4369830
VK
766{
767 DCObject::updateFromMessage(pMsg);
768
769 lock();
770
b4369830 771 m_columns->clear();
b368969c 772 int count = (int)pMsg->getFieldAsUInt32(VID_NUM_COLUMNS);
967893bb 773 UINT32 varId = VID_DCI_COLUMN_BASE;
b4369830
VK
774 for(int i = 0; i < count; i++)
775 {
776 m_columns->add(new DCTableColumn(pMsg, varId));
777 varId += 10;
778 }
779
b368969c 780 count = (int)pMsg->getFieldAsUInt32(VID_NUM_THRESHOLDS);
fa493140 781 ObjectArray<DCTableThreshold> *newThresholds = new ObjectArray<DCTableThreshold>(count, 8, true);
9098ad59
VK
782 varId = VID_DCI_THRESHOLD_BASE;
783 for(int i = 0; i < count; i++)
784 {
fa493140
VK
785 DCTableThreshold *t = new DCTableThreshold(pMsg, &varId);
786 newThresholds->add(t);
787 for(int j = 0; j < m_thresholds->size(); j++)
788 {
789 DCTableThreshold *old = m_thresholds->get(j);
790 if (old->getId() == t->getId())
791 {
792 t->copyState(old);
793 break;
794 }
795 }
9098ad59 796 }
fa493140
VK
797 delete m_thresholds;
798 m_thresholds = newThresholds;
9098ad59 799
b4369830
VK
800 unlock();
801}
b9a8e081 802
480e036b
VK
803/**
804 * Get last collected value
805 */
b368969c 806void DCTable::fillLastValueMessage(NXCPMessage *msg)
b9a8e081 807{
a567a02a 808 lock();
b9a8e081
VK
809 if (m_lastValue != NULL)
810 {
811 m_lastValue->fillMessage(*msg, 0, -1);
b9a8e081 812 }
a567a02a 813 unlock();
b9a8e081 814}
92c51b1d 815
480e036b
VK
816/**
817 * Get summary of last collected value (to show along simple DCI values)
818 */
b368969c 819void DCTable::fillLastValueSummaryMessage(NXCPMessage *pMsg, UINT32 dwId)
92c51b1d
VK
820{
821 lock();
b368969c
VK
822 pMsg->setField(dwId++, m_id);
823 pMsg->setField(dwId++, m_name);
4804be4e 824 pMsg->setField(dwId++, m_description);
b368969c
VK
825 pMsg->setField(dwId++, (WORD)m_source);
826 pMsg->setField(dwId++, (WORD)DCI_DT_NULL); // compatibility: data type
827 pMsg->setField(dwId++, _T("")); // compatibility: value
828 pMsg->setField(dwId++, (UINT32)m_tLastPoll);
829 pMsg->setField(dwId++, (WORD)(matchClusterResource() ? m_status : ITEM_STATUS_DISABLED)); // show resource-bound DCIs as inactive if cluster resource is not on this node
830 pMsg->setField(dwId++, (WORD)getType());
831 pMsg->setField(dwId++, m_dwErrorCount);
832 pMsg->setField(dwId++, m_dwTemplateItemId);
833 pMsg->setField(dwId++, (WORD)0); // compatibility: number of thresholds
92c51b1d
VK
834
835 unlock();
836}
837
a567a02a
VK
838/**
839 * Get data type of given column
840 */
841int DCTable::getColumnDataType(const TCHAR *name)
842{
843 int dt = DCI_DT_STRING;
844 bool found = false;
4016c0df 845
a567a02a
VK
846 lock();
847
848 // look in column definition first
849 for(int i = 0; i < m_columns->size(); i++)
850 {
851 DCTableColumn *column = m_columns->get(i);
852 if (!_tcsicmp(column->getName(), name))
853 {
854 dt = column->getDataType();
855 break;
856 }
857 }
858
859 // use last values if not found in definitions
860 if (!found && (m_lastValue != NULL))
861 {
862 int index = m_lastValue->getColumnIndex(name);
863 if (index != -1)
967893bb 864 dt = m_lastValue->getColumnDataType(index);
a567a02a
VK
865 }
866
867 unlock();
868 return dt;
869}
a0ddfb29
VK
870
871/**
872 * Get last collected value
873 */
874Table *DCTable::getLastValue()
875{
876 lock();
877 Table *value;
878 if (m_lastValue != NULL)
879 {
880 value = m_lastValue;
881 value->incRefCount();
882 }
883 else
884 {
885 value = NULL;
886 }
887 unlock();
888 return value;
889}
890
891/**
892 * Update destination value from source value
893 */
894#define RECALCULATE_VALUE(dst, src, func, count) \
895 { \
896 switch(func) \
897 { \
898 case DCF_FUNCTION_MIN: \
899 if (src < dst) dst = src; \
900 break; \
901 case DCF_FUNCTION_MAX: \
902 if (src > dst) dst = src; \
903 break; \
904 case DCF_FUNCTION_SUM: \
905 dst += src; \
906 break; \
907 case DCF_FUNCTION_AVG: \
908 dst = (dst * count + src) / (count + 1); \
909 break; \
910 } \
911 }
912
913/**
914 * Merge values
915 */
916void DCTable::mergeValues(Table *dest, Table *src, int count)
917{
918 for(int sRow = 0; sRow < src->getNumRows(); sRow++)
919 {
920 TCHAR instance[MAX_RESULT_LENGTH];
921
922 src->buildInstanceString(sRow, instance, MAX_RESULT_LENGTH);
923 int dRow = dest->findRowByInstance(instance);
924 if (dRow >= 0)
925 {
926 for(int j = 0; j < m_columns->size(); j++)
927 {
928 DCTableColumn *cd = m_columns->get(j);
929 if ((cd == NULL) || cd->isInstanceColumn() || (cd->getDataType() == DCI_DT_STRING))
930 continue;
931 int column = dest->getColumnIndex(cd->getName());
932 if (column == -1)
933 continue;
934
935 if (cd->getDataType() == DCI_DT_FLOAT)
936 {
937 double sval = src->getAsDouble(sRow, column);
938 double dval = dest->getAsDouble(dRow, column);
939
940 RECALCULATE_VALUE(dval, sval, cd->getAggregationFunction(), count);
941
942 dest->setAt(dRow, column, dval);
943 }
ae0e5359 944 else if ((cd->getDataType() == DCI_DT_UINT) || (cd->getDataType() == DCI_DT_UINT64))
a0ddfb29
VK
945 {
946 UINT64 sval = src->getAsUInt64(sRow, column);
947 UINT64 dval = dest->getAsUInt64(dRow, column);
948
949 RECALCULATE_VALUE(dval, sval, cd->getAggregationFunction(), count);
950
951 dest->setAt(dRow, column, dval);
952 }
953 else
954 {
955 INT64 sval = src->getAsInt64(sRow, column);
956 INT64 dval = dest->getAsInt64(dRow, column);
957
958 RECALCULATE_VALUE(dval, sval, cd->getAggregationFunction(), count);
959
960 dest->setAt(dRow, column, dval);
961 }
962 }
963 }
964 else
965 {
966 // no such instance
967 dest->copyRow(src, sRow);
968 }
969 }
970}
971
972/**
973 * Update columns in resulting table according to definition
974 */
975void DCTable::updateResultColumns(Table *t)
976{
977 lock();
978 for(int i = 0; i < m_columns->size(); i++)
979 {
980 DCTableColumn *col = m_columns->get(i);
981 int index = t->getColumnIndex(col->getName());
982 if (index != -1)
983 {
984 TableColumnDefinition *cd = t->getColumnDefinitions()->get(index);
985 if (cd != NULL)
986 {
987 cd->setDataType(col->getDataType());
988 cd->setInstanceColumn(col->isInstanceColumn());
989 cd->setDisplayName(col->getDisplayName());
990 }
991 }
992 }
993 unlock();
994}
995
996/**
997 * Update from template item
998 */
999void DCTable::updateFromTemplate(DCObject *src)
1000{
1001 DCObject::updateFromTemplate(src);
1002
1003 if (src->getType() != DCO_TYPE_TABLE)
1004 {
c42b4551 1005 DbgPrintf(2, _T("INTERNAL ERROR: DCTable::updateFromTemplate(%d, %d): source type is %d"), (int)m_id, (int)src->getId(), src->getType());
a0ddfb29
VK
1006 return;
1007 }
1008
1009 lock();
1010 DCTable *table = (DCTable *)src;
1011
1012 m_columns->clear();
1013 for(int i = 0; i < table->m_columns->size(); i++)
1014 m_columns->add(new DCTableColumn(table->m_columns->get(i)));
9098ad59
VK
1015
1016 m_thresholds->clear();
1017 for(int i = 0; i < table->m_thresholds->size(); i++)
1018 m_thresholds->add(new DCTableThreshold(table->m_thresholds->get(i)));
1019
a0ddfb29
VK
1020 unlock();
1021}
6e102d6e
VK
1022
1023/**
1024 * Create management pack record
1025 */
98ef8e4a 1026void DCTable::createExportRecord(String &str)
6e102d6e 1027{
6e102d6e 1028 lock();
4016c0df 1029
4e0e77e6 1030 str.appendFormattedString(_T("\t\t\t\t<dctable id=\"%d\">\n")
98ef8e4a 1031 _T("\t\t\t\t\t<guid>%s</guid>\n")
6e102d6e
VK
1032 _T("\t\t\t\t\t<name>%s</name>\n")
1033 _T("\t\t\t\t\t<description>%s</description>\n")
1034 _T("\t\t\t\t\t<origin>%d</origin>\n")
1035 _T("\t\t\t\t\t<interval>%d</interval>\n")
1036 _T("\t\t\t\t\t<retention>%d</retention>\n")
1037 _T("\t\t\t\t\t<systemTag>%s</systemTag>\n")
50ea73e3 1038 _T("\t\t\t\t\t<flags>%d</flags>\n")
6e102d6e 1039 _T("\t\t\t\t\t<snmpPort>%d</snmpPort>\n"),
98ef8e4a
VK
1040 (int)m_id, (const TCHAR *)m_guid.toString(),
1041 (const TCHAR *)EscapeStringForXML2(m_name),
4804be4e 1042 (const TCHAR *)EscapeStringForXML2(m_description),
6e102d6e
VK
1043 (int)m_source, m_iPollingInterval, m_iRetentionTime,
1044 (const TCHAR *)EscapeStringForXML2(m_systemTag),
50ea73e3 1045 (int)m_flags, (int)m_snmpPort);
6e102d6e
VK
1046
1047 if (m_transformationScriptSource != NULL)
1048 {
ef607e62 1049 str.append(_T("\t\t\t\t\t<transformation>"));
4e0e77e6 1050 str.appendPreallocated(EscapeStringForXML(m_transformationScriptSource, -1));
ef607e62 1051 str.append(_T("</transformation>\n"));
6e102d6e
VK
1052 }
1053
e7450f3b 1054 if ((m_schedules != NULL) && (m_schedules->size() > 0))
6e102d6e 1055 {
ef607e62
VK
1056 str.append(_T("\t\t\t\t\t<schedules>\n"));
1057 for(int i = 0; i < m_schedules->size(); i++)
1058 {
1059 str.append(_T("\t\t\t\t\t\t<schedule>"));
1060 str.append(EscapeStringForXML2(m_schedules->get(i)));
1061 str.append(_T("</schedule>\n"));
1062 }
1063 str.append(_T("\t\t\t\t\t</schedules>\n"));
6e102d6e
VK
1064 }
1065
1066 if (m_columns != NULL)
1067 {
1068 str += _T("\t\t\t\t\t<columns>\n");
ef607e62 1069 for(int i = 0; i < m_columns->size(); i++)
6e102d6e
VK
1070 {
1071 m_columns->get(i)->createNXMPRecord(str, i + 1);
1072 }
1073 str += _T("\t\t\t\t\t</columns>\n");
1074 }
1075
1076 if (m_thresholds != NULL)
1077 {
1078 str += _T("\t\t\t\t\t<thresholds>\n");
ef607e62 1079 for(int i = 0; i < m_thresholds->size(); i++)
6e102d6e
VK
1080 {
1081 m_thresholds->get(i)->createNXMPRecord(str, i + 1);
1082 }
1083 str += _T("\t\t\t\t\t</thresholds>\n");
1084 }
1085
1086 if (m_pszPerfTabSettings != NULL)
1087 {
ef607e62 1088 str.append(_T("\t\t\t\t\t<perfTabSettings>"));
4e0e77e6 1089 str.appendPreallocated(EscapeStringForXML(m_pszPerfTabSettings, -1));
ef607e62 1090 str.append(_T("</perfTabSettings>\n"));
6e102d6e
VK
1091 }
1092
1093 unlock();
ef607e62 1094 str.append(_T("\t\t\t\t</dctable>\n"));
6e102d6e 1095}
e7450f3b
VK
1096
1097/**
1098 * Create DCObject from import file
1099 */
1100void DCTable::updateFromImport(ConfigEntry *config)
1101{
1102 DCObject::updateFromImport(config);
1103
77b2c6de 1104 lock();
e7450f3b
VK
1105 m_columns->clear();
1106 ConfigEntry *columnsRoot = config->findEntry(_T("columns"));
1107 if (columnsRoot != NULL)
1108 {
1109 ObjectArray<ConfigEntry> *columns = columnsRoot->getSubEntries(_T("column#*"));
1110 for(int i = 0; i < columns->size(); i++)
1111 {
1112 m_columns->add(new DCTableColumn(columns->get(i)));
1113 }
1114 delete columns;
1115 }
1116
1117 m_thresholds->clear();
1118 ConfigEntry *thresholdsRoot = config->findEntry(_T("thresholds"));
1119 if (thresholdsRoot != NULL)
1120 {
1121 ObjectArray<ConfigEntry> *thresholds = thresholdsRoot->getSubEntries(_T("threshold#*"));
1122 for(int i = 0; i < thresholds->size(); i++)
1123 {
1124 m_thresholds->add(new DCTableThreshold(thresholds->get(i)));
1125 }
1126 delete thresholds;
1127 }
77b2c6de 1128 unlock();
e7450f3b 1129}
faa89331
VK
1130
1131/**
1132 * Should return true if object has (or can have) value
1133 */
1134bool DCTable::hasValue()
1135{
4804be4e 1136 if (m_owner->getObjectClass() == OBJECT_CLUSTER)
faa89331
VK
1137 return isAggregateOnCluster();
1138 return true;
1139}