Commit | Line | Data |
---|---|---|
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 |
28 | TC_ID_MAP_ENTRY *DCTable::m_cache = NULL; |
29 | int DCTable::m_cacheSize = 0; | |
30 | int DCTable::m_cacheAllocated = 0; | |
31 | MUTEX DCTable::m_cacheMutex = MutexCreate(); | |
32 | ||
480e036b VK |
33 | /** |
34 | * Compare cache element's name to string key | |
35 | */ | |
ba89fed2 VK |
36 | static 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 |
44 | static 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 | 52 | INT32 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 |
124 | DCTable::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 |
134 | DCTable::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 | 148 | DCTable::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 | 165 | DCTable::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 | */ | |
216 | DCTable::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 |
256 | DCTable::~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 |
267 | void 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 |
285 | bool 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 | 305 | bool 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 | 361 | TCHAR query[256]; |
89e5f052 | 362 | _sntprintf(query, 256, _T("INSERT INTO tdata_%d (item_id,tdata_timestamp,tdata_value) 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); |
89e5f052 | 368 | DBBind(hStmt, 3, DB_SQLTYPE_TEXT, DB_CTYPE_UTF8_STRING, data->createPackedXML(), DB_BIND_DYNAMIC); |
a58454c9 VK |
369 | success = DBExecute(hStmt); |
370 | DBFreeStatement(hStmt); | |
22aaa779 | 371 | } |
22aaa779 | 372 | |
a58454c9 VK |
373 | if (success) |
374 | DBCommit(hdb); | |
375 | else | |
376 | DBRollback(hdb); | |
50633e41 | 377 | |
a58454c9 VK |
378 | DBConnectionPoolReleaseConnection(hdb); |
379 | } | |
f6456d80 | 380 | if ((g_offlineDataRelevanceTime <= 0) || (timestamp > (time(NULL) - g_offlineDataRelevanceTime))) |
7f418694 | 381 | checkThresholds((Table *)value); |
ea50bc33 VK |
382 | |
383 | if (g_flags & AF_PERFDATA_STORAGE_DRIVER_LOADED) | |
9664e8df | 384 | PerfDataStorageRequest(this, timestamp, (Table *)value); |
ea50bc33 | 385 | |
57c9050f | 386 | ((Table *)value)->decRefCount(); |
0156d6b2 | 387 | return true; |
533ce8c0 VK |
388 | } |
389 | ||
7de1151b VK |
390 | /** |
391 | * Transform received value | |
392 | */ | |
0156d6b2 | 393 | bool DCTable::transform(Table *value) |
7de1151b | 394 | { |
c2b7c9ae | 395 | if (m_transformationScript == NULL) |
0156d6b2 | 396 | return true; |
c2b7c9ae | 397 | |
4804be4e VK |
398 | bool success = false; |
399 | NXSL_VM *vm = new NXSL_VM(new NXSL_ServerEnv()); | |
400 | if (vm->load(m_transformationScript)) | |
7de1151b | 401 | { |
4804be4e VK |
402 | NXSL_Value *nxslValue = new NXSL_Value(new NXSL_Object(&g_nxslStaticTableClass, value)); |
403 | vm->setGlobalVariable(_T("$object"), m_owner->createNXSLObject()); | |
404 | if (m_owner->getObjectClass() == OBJECT_NODE) | |
b32b325d | 405 | { |
4804be4e | 406 | vm->setGlobalVariable(_T("$node"), m_owner->createNXSLObject()); |
b32b325d | 407 | } |
4804be4e VK |
408 | vm->setGlobalVariable(_T("$dci"), createNXSLObject()); |
409 | vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((m_owner->getObjectClass() == OBJECT_CLUSTER) ? 1 : 0)); | |
7de1151b | 410 | |
4804be4e VK |
411 | // remove lock from DCI for script execution to avoid deadlocks |
412 | unlock(); | |
413 | success = vm->run(1, &nxslValue); | |
414 | lock(); | |
415 | if (!success) | |
416 | { | |
417 | if (vm->getErrorCode() == NXSL_ERR_EXECUTION_ABORTED) | |
418 | { | |
419 | DbgPrintf(6, _T("Transformation script for DCI \"%s\" [%d] on node %s [%d] aborted"), | |
420 | m_description, m_id, getOwnerName(), getOwnerId()); | |
421 | } | |
422 | else | |
423 | { | |
424 | TCHAR buffer[1024]; | |
425 | _sntprintf(buffer, 1024, _T("DCI::%s::%d::TransformationScript"), getOwnerName(), m_id); | |
426 | PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, m_id, "ssd", buffer, vm->getErrorText(), m_id); | |
427 | nxlog_write(MSG_TRANSFORMATION_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "dsdss", | |
428 | getOwnerId(), getOwnerName(), m_id, m_name, vm->getErrorText()); | |
429 | } | |
b32b325d | 430 | } |
7de1151b | 431 | } |
4804be4e VK |
432 | else |
433 | { | |
434 | TCHAR buffer[1024]; | |
435 | _sntprintf(buffer, 1024, _T("DCI::%s::%d::TransformationScript"), getOwnerName(), m_id); | |
436 | PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, m_id, "ssd", buffer, vm->getErrorText(), m_id); | |
437 | nxlog_write(MSG_TRANSFORMATION_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "dsdss", | |
438 | getOwnerId(), getOwnerName(), m_id, m_name, vm->getErrorText()); | |
439 | } | |
440 | delete vm; | |
0156d6b2 | 441 | return success; |
7de1151b VK |
442 | } |
443 | ||
50633e41 VK |
444 | /** |
445 | * Check thresholds | |
446 | */ | |
447 | void DCTable::checkThresholds(Table *value) | |
448 | { | |
a0dc14f9 VK |
449 | static const TCHAR *paramNames[] = { _T("dciName"), _T("dciDescription"), _T("dciId"), _T("row"), _T("instance") }; |
450 | ||
50633e41 | 451 | lock(); |
a0dc14f9 | 452 | for(int row = 0; row < value->getNumRows(); row++) |
50633e41 | 453 | { |
a0dc14f9 VK |
454 | TCHAR instance[MAX_RESULT_LENGTH]; |
455 | value->buildInstanceString(row, instance, MAX_RESULT_LENGTH); | |
456 | for(int i = 0; i < m_thresholds->size(); i++) | |
457 | { | |
458 | DCTableThreshold *t = m_thresholds->get(i); | |
459 | ThresholdCheckResult result = t->check(value, row, instance); | |
460 | switch(result) | |
461 | { | |
462 | case ACTIVATED: | |
4804be4e | 463 | PostDciEventWithNames(t->getActivationEvent(), m_owner->getId(), m_id, "ssids", paramNames, m_name, m_description, m_id, row, instance); |
a0dc14f9 VK |
464 | if (!(m_flags & DCF_ALL_THRESHOLDS)) |
465 | i = m_thresholds->size(); // Stop processing (for current row) | |
466 | break; | |
467 | case DEACTIVATED: | |
4804be4e | 468 | PostDciEventWithNames(t->getDeactivationEvent(), m_owner->getId(), m_id, "ssids", paramNames, m_name, m_description, m_id, row, instance); |
a0dc14f9 VK |
469 | break; |
470 | case ALREADY_ACTIVE: | |
471 | i = m_thresholds->size(); // Threshold condition still true, stop processing | |
472 | break; | |
473 | default: | |
474 | break; | |
475 | } | |
476 | } | |
50633e41 VK |
477 | } |
478 | unlock(); | |
479 | } | |
480 | ||
480e036b VK |
481 | /** |
482 | * Process new data collection error | |
483 | */ | |
df94243f | 484 | void DCTable::processNewError(bool noInstance, time_t now) |
533ce8c0 | 485 | { |
c5c77583 | 486 | m_dwErrorCount++; |
533ce8c0 | 487 | } |
ba89fed2 | 488 | |
480e036b VK |
489 | /** |
490 | * Save to database | |
491 | */ | |
e7450f3b | 492 | bool DCTable::saveToDatabase(DB_HANDLE hdb) |
ba89fed2 VK |
493 | { |
494 | DB_STATEMENT hStmt; | |
c42b4551 | 495 | if (IsDatabaseRecordExist(hdb, _T("dc_tables"), _T("item_id"), m_id)) |
ba89fed2 VK |
496 | { |
497 | hStmt = DBPrepare(hdb, _T("UPDATE dc_tables SET node_id=?,template_id=?,template_item_id=?,name=?,") | |
22aaa779 | 498 | _T("description=?,flags=?,source=?,snmp_port=?,polling_interval=?,") |
ba89fed2 | 499 | _T("retention_time=?,status=?,system_tag=?,resource_id=?,proxy_node=?,") |
98ef8e4a | 500 | _T("perftab_settings=?,transformation_script=?,comments=?,guid=? WHERE item_id=?")); |
ba89fed2 VK |
501 | } |
502 | else | |
503 | { | |
504 | hStmt = DBPrepare(hdb, _T("INSERT INTO dc_tables (node_id,template_id,template_item_id,name,") | |
22aaa779 | 505 | _T("description,flags,source,snmp_port,polling_interval,") |
ba89fed2 | 506 | _T("retention_time,status,system_tag,resource_id,proxy_node,perftab_settings,") |
98ef8e4a VK |
507 | _T("transformation_script,comments,guid,item_id) ") |
508 | _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); | |
ba89fed2 VK |
509 | } |
510 | if (hStmt == NULL) | |
511 | return FALSE; | |
512 | ||
513 | lock(); | |
514 | ||
4804be4e | 515 | DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (m_owner == NULL) ? (UINT32)0 : m_owner->getId()); |
ba89fed2 VK |
516 | DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_dwTemplateId); |
517 | DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, m_dwTemplateItemId); | |
c42b4551 | 518 | DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, m_name, DB_BIND_STATIC); |
4804be4e | 519 | DBBind(hStmt, 5, DB_SQLTYPE_VARCHAR, m_description, DB_BIND_STATIC); |
22aaa779 VK |
520 | DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (UINT32)m_flags); |
521 | DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (INT32)m_source); | |
522 | DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (UINT32)m_snmpPort); | |
523 | DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (INT32)m_iPollingInterval); | |
524 | DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, (INT32)m_iRetentionTime); | |
525 | DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, (INT32)m_status); | |
526 | DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, m_systemTag, DB_BIND_STATIC); | |
527 | DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, m_dwResourceId); | |
191e4784 | 528 | DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, m_sourceNode); |
22aaa779 VK |
529 | DBBind(hStmt, 15, DB_SQLTYPE_TEXT, m_pszPerfTabSettings, DB_BIND_STATIC); |
530 | DBBind(hStmt, 16, DB_SQLTYPE_TEXT, m_transformationScriptSource, DB_BIND_STATIC); | |
4016c0df | 531 | DBBind(hStmt, 17, DB_SQLTYPE_TEXT, m_comments, DB_BIND_STATIC); |
98ef8e4a VK |
532 | DBBind(hStmt, 18, DB_SQLTYPE_VARCHAR, m_guid); |
533 | DBBind(hStmt, 19, DB_SQLTYPE_INTEGER, m_id); | |
ba89fed2 | 534 | |
e7450f3b | 535 | bool result = DBExecute(hStmt); |
ba89fed2 VK |
536 | DBFreeStatement(hStmt); |
537 | ||
538 | if (result) | |
539 | { | |
540 | // Save column configuration | |
541 | hStmt = DBPrepare(hdb, _T("DELETE FROM dc_table_columns WHERE table_id=?")); | |
542 | if (hStmt != NULL) | |
543 | { | |
c42b4551 | 544 | DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id); |
ba89fed2 VK |
545 | result = DBExecute(hStmt); |
546 | DBFreeStatement(hStmt); | |
547 | } | |
548 | else | |
549 | { | |
e7450f3b | 550 | result = false; |
ba89fed2 VK |
551 | } |
552 | ||
553 | if (result && (m_columns->size() > 0)) | |
554 | { | |
9387bc59 | 555 | hStmt = DBPrepare(hdb, _T("INSERT INTO dc_table_columns (table_id,sequence_number,column_name,snmp_oid,flags,display_name) VALUES (?,?,?,?,?,?)")); |
ba89fed2 VK |
556 | if (hStmt != NULL) |
557 | { | |
c42b4551 | 558 | DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id); |
ba89fed2 VK |
559 | for(int i = 0; i < m_columns->size(); i++) |
560 | { | |
561 | DCTableColumn *column = m_columns->get(i); | |
9387bc59 VK |
562 | DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (INT32)(i + 1)); |
563 | DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, column->getName(), DB_BIND_STATIC); | |
ba89fed2 | 564 | SNMP_ObjectId *oid = column->getSnmpOid(); |
9ceab287 | 565 | DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, (oid != NULL) ? (const TCHAR *)oid->toString() : NULL, DB_BIND_TRANSIENT); |
9387bc59 VK |
566 | DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (INT32)column->getFlags()); |
567 | DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, column->getDisplayName(), DB_BIND_STATIC); | |
ba89fed2 VK |
568 | |
569 | result = DBExecute(hStmt); | |
570 | if (!result) | |
571 | break; | |
572 | } | |
573 | DBFreeStatement(hStmt); | |
574 | } | |
575 | else | |
576 | { | |
e7450f3b | 577 | result = false; |
ba89fed2 VK |
578 | } |
579 | } | |
580 | } | |
581 | ||
9098ad59 VK |
582 | saveThresholds(hdb); |
583 | ||
ba89fed2 | 584 | unlock(); |
e7450f3b | 585 | return result ? DCObject::saveToDatabase(hdb) : false; |
ba89fed2 VK |
586 | } |
587 | ||
9098ad59 VK |
588 | /** |
589 | * Load thresholds from database | |
590 | */ | |
9bd1bace | 591 | bool DCTable::loadThresholds(DB_HANDLE hdb) |
9098ad59 | 592 | { |
9bd1bace | 593 | DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT id,activation_event,deactivation_event FROM dct_thresholds WHERE table_id=? ORDER BY sequence_number")); |
9098ad59 VK |
594 | if (hStmt == NULL) |
595 | return false; | |
596 | ||
c42b4551 | 597 | DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id); |
9098ad59 VK |
598 | DB_RESULT hResult = DBSelectPrepared(hStmt); |
599 | if (hResult != NULL) | |
600 | { | |
601 | int count = DBGetNumRows(hResult); | |
602 | for(int i = 0; i < count; i++) | |
603 | { | |
9bd1bace | 604 | DCTableThreshold *t = new DCTableThreshold(hdb, hResult, i); |
9098ad59 VK |
605 | m_thresholds->add(t); |
606 | } | |
607 | DBFreeResult(hResult); | |
608 | } | |
609 | DBFreeStatement(hStmt); | |
610 | return true; | |
611 | } | |
612 | ||
613 | /** | |
614 | * Save thresholds to database | |
615 | */ | |
616 | bool DCTable::saveThresholds(DB_HANDLE hdb) | |
617 | { | |
618 | DB_STATEMENT hStmt = DBPrepare(hdb, _T("DELETE FROM dct_threshold_conditions WHERE threshold_id=?")); | |
619 | if (hStmt == NULL) | |
620 | return false; | |
621 | ||
622 | for(int i = 0; i < m_thresholds->size(); i++) | |
623 | { | |
624 | DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_thresholds->get(i)->getId()); | |
625 | DBExecute(hStmt); | |
626 | } | |
627 | DBFreeStatement(hStmt); | |
628 | ||
629 | hStmt = DBPrepare(hdb, _T("DELETE FROM dct_thresholds WHERE table_id=?")); | |
630 | if (hStmt == NULL) | |
631 | return false; | |
c42b4551 | 632 | DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id); |
9098ad59 VK |
633 | DBExecute(hStmt); |
634 | DBFreeStatement(hStmt); | |
635 | ||
636 | for(int i = 0; i < m_thresholds->size(); i++) | |
c42b4551 | 637 | m_thresholds->get(i)->saveToDatabase(hdb, m_id, i); |
9098ad59 VK |
638 | return true; |
639 | } | |
640 | ||
480e036b VK |
641 | /** |
642 | * Delete table object and collected data from database | |
643 | */ | |
c42b4551 | 644 | void DCTable::deleteFromDatabase() |
ba89fed2 VK |
645 | { |
646 | TCHAR szQuery[256]; | |
647 | ||
c42b4551 | 648 | DCObject::deleteFromDatabase(); |
ba89fed2 | 649 | |
4804be4e | 650 | if(m_owner->getObjectClass() != OBJECT_TEMPLATE) |
59d9c840 | 651 | { |
4804be4e | 652 | _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM tdata_%d WHERE item_id=%d"), m_owner->getId(), (int)m_id); |
59d9c840 | 653 | QueueSQLRequest(szQuery); |
654 | } | |
22aaa779 | 655 | |
c42b4551 | 656 | _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM dc_tables WHERE item_id=%d"), (int)m_id); |
ba89fed2 | 657 | QueueSQLRequest(szQuery); |
c42b4551 | 658 | _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM dc_table_columns WHERE table_id=%d"), (int)m_id); |
ba89fed2 | 659 | QueueSQLRequest(szQuery); |
9098ad59 VK |
660 | |
661 | for(int i = 0; i < m_thresholds->size(); i++) | |
662 | { | |
663 | _sntprintf(szQuery, 256, _T("DELETE FROM dct_threshold_conditions WHERE threshold_id=%d"), (int)m_thresholds->get(i)->getId()); | |
664 | QueueSQLRequest(szQuery); | |
665 | } | |
666 | ||
c42b4551 | 667 | _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM dct_thresholds WHERE table_id=%d"), (int)m_id); |
9098ad59 | 668 | QueueSQLRequest(szQuery); |
ba89fed2 | 669 | } |
b4369830 | 670 | |
480e036b VK |
671 | /** |
672 | * Create NXCP message with item data | |
673 | */ | |
b368969c | 674 | void DCTable::createMessage(NXCPMessage *pMsg) |
b4369830 VK |
675 | { |
676 | DCObject::createMessage(pMsg); | |
677 | ||
678 | lock(); | |
b368969c | 679 | pMsg->setField(VID_NUM_COLUMNS, (UINT32)m_columns->size()); |
967893bb | 680 | UINT32 varId = VID_DCI_COLUMN_BASE; |
b4369830 VK |
681 | for(int i = 0; i < m_columns->size(); i++) |
682 | { | |
683 | DCTableColumn *column = m_columns->get(i); | |
b368969c VK |
684 | pMsg->setField(varId++, column->getName()); |
685 | pMsg->setField(varId++, column->getFlags()); | |
b4369830 VK |
686 | SNMP_ObjectId *oid = column->getSnmpOid(); |
687 | if (oid != NULL) | |
9ceab287 | 688 | pMsg->setFieldFromInt32Array(varId++, (UINT32)oid->length(), oid->value()); |
b4369830 VK |
689 | else |
690 | varId++; | |
b368969c | 691 | pMsg->setField(varId++, column->getDisplayName()); |
0b77b73e | 692 | varId += 6; |
b4369830 | 693 | } |
9098ad59 | 694 | |
b368969c | 695 | pMsg->setField(VID_NUM_THRESHOLDS, (UINT32)m_thresholds->size()); |
9098ad59 VK |
696 | varId = VID_DCI_THRESHOLD_BASE; |
697 | for(int i = 0; i < m_thresholds->size(); i++) | |
698 | { | |
699 | varId = m_thresholds->get(i)->fillMessage(pMsg, varId); | |
700 | } | |
701 | ||
b4369830 VK |
702 | unlock(); |
703 | } | |
704 | ||
480e036b VK |
705 | /** |
706 | * Update data collection object from NXCP message | |
707 | */ | |
b368969c | 708 | void DCTable::updateFromMessage(NXCPMessage *pMsg) |
b4369830 VK |
709 | { |
710 | DCObject::updateFromMessage(pMsg); | |
711 | ||
712 | lock(); | |
713 | ||
b4369830 | 714 | m_columns->clear(); |
b368969c | 715 | int count = (int)pMsg->getFieldAsUInt32(VID_NUM_COLUMNS); |
967893bb | 716 | UINT32 varId = VID_DCI_COLUMN_BASE; |
b4369830 VK |
717 | for(int i = 0; i < count; i++) |
718 | { | |
719 | m_columns->add(new DCTableColumn(pMsg, varId)); | |
720 | varId += 10; | |
721 | } | |
722 | ||
b368969c | 723 | count = (int)pMsg->getFieldAsUInt32(VID_NUM_THRESHOLDS); |
fa493140 | 724 | ObjectArray<DCTableThreshold> *newThresholds = new ObjectArray<DCTableThreshold>(count, 8, true); |
9098ad59 VK |
725 | varId = VID_DCI_THRESHOLD_BASE; |
726 | for(int i = 0; i < count; i++) | |
727 | { | |
fa493140 VK |
728 | DCTableThreshold *t = new DCTableThreshold(pMsg, &varId); |
729 | newThresholds->add(t); | |
730 | for(int j = 0; j < m_thresholds->size(); j++) | |
731 | { | |
732 | DCTableThreshold *old = m_thresholds->get(j); | |
733 | if (old->getId() == t->getId()) | |
734 | { | |
735 | t->copyState(old); | |
736 | break; | |
737 | } | |
738 | } | |
9098ad59 | 739 | } |
fa493140 VK |
740 | delete m_thresholds; |
741 | m_thresholds = newThresholds; | |
9098ad59 | 742 | |
b4369830 VK |
743 | unlock(); |
744 | } | |
b9a8e081 | 745 | |
480e036b VK |
746 | /** |
747 | * Get last collected value | |
748 | */ | |
b368969c | 749 | void DCTable::fillLastValueMessage(NXCPMessage *msg) |
b9a8e081 | 750 | { |
a567a02a | 751 | lock(); |
b9a8e081 VK |
752 | if (m_lastValue != NULL) |
753 | { | |
754 | m_lastValue->fillMessage(*msg, 0, -1); | |
b9a8e081 | 755 | } |
a567a02a | 756 | unlock(); |
b9a8e081 | 757 | } |
92c51b1d | 758 | |
480e036b VK |
759 | /** |
760 | * Get summary of last collected value (to show along simple DCI values) | |
761 | */ | |
b368969c | 762 | void DCTable::fillLastValueSummaryMessage(NXCPMessage *pMsg, UINT32 dwId) |
92c51b1d VK |
763 | { |
764 | lock(); | |
b368969c VK |
765 | pMsg->setField(dwId++, m_id); |
766 | pMsg->setField(dwId++, m_name); | |
4804be4e | 767 | pMsg->setField(dwId++, m_description); |
b368969c VK |
768 | pMsg->setField(dwId++, (WORD)m_source); |
769 | pMsg->setField(dwId++, (WORD)DCI_DT_NULL); // compatibility: data type | |
770 | pMsg->setField(dwId++, _T("")); // compatibility: value | |
771 | pMsg->setField(dwId++, (UINT32)m_tLastPoll); | |
772 | pMsg->setField(dwId++, (WORD)(matchClusterResource() ? m_status : ITEM_STATUS_DISABLED)); // show resource-bound DCIs as inactive if cluster resource is not on this node | |
773 | pMsg->setField(dwId++, (WORD)getType()); | |
774 | pMsg->setField(dwId++, m_dwErrorCount); | |
775 | pMsg->setField(dwId++, m_dwTemplateItemId); | |
776 | pMsg->setField(dwId++, (WORD)0); // compatibility: number of thresholds | |
92c51b1d VK |
777 | |
778 | unlock(); | |
779 | } | |
780 | ||
a567a02a VK |
781 | /** |
782 | * Get data type of given column | |
783 | */ | |
784 | int DCTable::getColumnDataType(const TCHAR *name) | |
785 | { | |
786 | int dt = DCI_DT_STRING; | |
787 | bool found = false; | |
4016c0df | 788 | |
a567a02a VK |
789 | lock(); |
790 | ||
791 | // look in column definition first | |
792 | for(int i = 0; i < m_columns->size(); i++) | |
793 | { | |
794 | DCTableColumn *column = m_columns->get(i); | |
795 | if (!_tcsicmp(column->getName(), name)) | |
796 | { | |
797 | dt = column->getDataType(); | |
798 | break; | |
799 | } | |
800 | } | |
801 | ||
802 | // use last values if not found in definitions | |
803 | if (!found && (m_lastValue != NULL)) | |
804 | { | |
805 | int index = m_lastValue->getColumnIndex(name); | |
806 | if (index != -1) | |
967893bb | 807 | dt = m_lastValue->getColumnDataType(index); |
a567a02a VK |
808 | } |
809 | ||
810 | unlock(); | |
811 | return dt; | |
812 | } | |
a0ddfb29 VK |
813 | |
814 | /** | |
815 | * Get last collected value | |
816 | */ | |
817 | Table *DCTable::getLastValue() | |
818 | { | |
819 | lock(); | |
820 | Table *value; | |
821 | if (m_lastValue != NULL) | |
822 | { | |
823 | value = m_lastValue; | |
824 | value->incRefCount(); | |
825 | } | |
826 | else | |
827 | { | |
828 | value = NULL; | |
829 | } | |
830 | unlock(); | |
831 | return value; | |
832 | } | |
833 | ||
834 | /** | |
835 | * Update destination value from source value | |
836 | */ | |
837 | #define RECALCULATE_VALUE(dst, src, func, count) \ | |
838 | { \ | |
839 | switch(func) \ | |
840 | { \ | |
841 | case DCF_FUNCTION_MIN: \ | |
842 | if (src < dst) dst = src; \ | |
843 | break; \ | |
844 | case DCF_FUNCTION_MAX: \ | |
845 | if (src > dst) dst = src; \ | |
846 | break; \ | |
847 | case DCF_FUNCTION_SUM: \ | |
848 | dst += src; \ | |
849 | break; \ | |
850 | case DCF_FUNCTION_AVG: \ | |
851 | dst = (dst * count + src) / (count + 1); \ | |
852 | break; \ | |
853 | } \ | |
854 | } | |
855 | ||
856 | /** | |
857 | * Merge values | |
858 | */ | |
859 | void DCTable::mergeValues(Table *dest, Table *src, int count) | |
860 | { | |
861 | for(int sRow = 0; sRow < src->getNumRows(); sRow++) | |
862 | { | |
863 | TCHAR instance[MAX_RESULT_LENGTH]; | |
864 | ||
865 | src->buildInstanceString(sRow, instance, MAX_RESULT_LENGTH); | |
866 | int dRow = dest->findRowByInstance(instance); | |
867 | if (dRow >= 0) | |
868 | { | |
869 | for(int j = 0; j < m_columns->size(); j++) | |
870 | { | |
871 | DCTableColumn *cd = m_columns->get(j); | |
872 | if ((cd == NULL) || cd->isInstanceColumn() || (cd->getDataType() == DCI_DT_STRING)) | |
873 | continue; | |
874 | int column = dest->getColumnIndex(cd->getName()); | |
875 | if (column == -1) | |
876 | continue; | |
877 | ||
878 | if (cd->getDataType() == DCI_DT_FLOAT) | |
879 | { | |
880 | double sval = src->getAsDouble(sRow, column); | |
881 | double dval = dest->getAsDouble(dRow, column); | |
882 | ||
883 | RECALCULATE_VALUE(dval, sval, cd->getAggregationFunction(), count); | |
884 | ||
885 | dest->setAt(dRow, column, dval); | |
886 | } | |
ae0e5359 | 887 | else if ((cd->getDataType() == DCI_DT_UINT) || (cd->getDataType() == DCI_DT_UINT64)) |
a0ddfb29 VK |
888 | { |
889 | UINT64 sval = src->getAsUInt64(sRow, column); | |
890 | UINT64 dval = dest->getAsUInt64(dRow, column); | |
891 | ||
892 | RECALCULATE_VALUE(dval, sval, cd->getAggregationFunction(), count); | |
893 | ||
894 | dest->setAt(dRow, column, dval); | |
895 | } | |
896 | else | |
897 | { | |
898 | INT64 sval = src->getAsInt64(sRow, column); | |
899 | INT64 dval = dest->getAsInt64(dRow, column); | |
900 | ||
901 | RECALCULATE_VALUE(dval, sval, cd->getAggregationFunction(), count); | |
902 | ||
903 | dest->setAt(dRow, column, dval); | |
904 | } | |
905 | } | |
906 | } | |
907 | else | |
908 | { | |
909 | // no such instance | |
910 | dest->copyRow(src, sRow); | |
911 | } | |
912 | } | |
913 | } | |
914 | ||
915 | /** | |
916 | * Update columns in resulting table according to definition | |
917 | */ | |
918 | void DCTable::updateResultColumns(Table *t) | |
919 | { | |
920 | lock(); | |
921 | for(int i = 0; i < m_columns->size(); i++) | |
922 | { | |
923 | DCTableColumn *col = m_columns->get(i); | |
924 | int index = t->getColumnIndex(col->getName()); | |
925 | if (index != -1) | |
926 | { | |
927 | TableColumnDefinition *cd = t->getColumnDefinitions()->get(index); | |
928 | if (cd != NULL) | |
929 | { | |
930 | cd->setDataType(col->getDataType()); | |
931 | cd->setInstanceColumn(col->isInstanceColumn()); | |
932 | cd->setDisplayName(col->getDisplayName()); | |
933 | } | |
934 | } | |
935 | } | |
936 | unlock(); | |
937 | } | |
938 | ||
939 | /** | |
940 | * Update from template item | |
941 | */ | |
942 | void DCTable::updateFromTemplate(DCObject *src) | |
943 | { | |
944 | DCObject::updateFromTemplate(src); | |
945 | ||
946 | if (src->getType() != DCO_TYPE_TABLE) | |
947 | { | |
c42b4551 | 948 | DbgPrintf(2, _T("INTERNAL ERROR: DCTable::updateFromTemplate(%d, %d): source type is %d"), (int)m_id, (int)src->getId(), src->getType()); |
a0ddfb29 VK |
949 | return; |
950 | } | |
951 | ||
952 | lock(); | |
953 | DCTable *table = (DCTable *)src; | |
954 | ||
955 | m_columns->clear(); | |
956 | for(int i = 0; i < table->m_columns->size(); i++) | |
957 | m_columns->add(new DCTableColumn(table->m_columns->get(i))); | |
9098ad59 VK |
958 | |
959 | m_thresholds->clear(); | |
960 | for(int i = 0; i < table->m_thresholds->size(); i++) | |
961 | m_thresholds->add(new DCTableThreshold(table->m_thresholds->get(i))); | |
962 | ||
a0ddfb29 VK |
963 | unlock(); |
964 | } | |
6e102d6e VK |
965 | |
966 | /** | |
967 | * Create management pack record | |
968 | */ | |
98ef8e4a | 969 | void DCTable::createExportRecord(String &str) |
6e102d6e | 970 | { |
6e102d6e | 971 | lock(); |
4016c0df | 972 | |
4e0e77e6 | 973 | str.appendFormattedString(_T("\t\t\t\t<dctable id=\"%d\">\n") |
98ef8e4a | 974 | _T("\t\t\t\t\t<guid>%s</guid>\n") |
6e102d6e VK |
975 | _T("\t\t\t\t\t<name>%s</name>\n") |
976 | _T("\t\t\t\t\t<description>%s</description>\n") | |
977 | _T("\t\t\t\t\t<origin>%d</origin>\n") | |
978 | _T("\t\t\t\t\t<interval>%d</interval>\n") | |
979 | _T("\t\t\t\t\t<retention>%d</retention>\n") | |
980 | _T("\t\t\t\t\t<systemTag>%s</systemTag>\n") | |
50ea73e3 | 981 | _T("\t\t\t\t\t<flags>%d</flags>\n") |
6e102d6e | 982 | _T("\t\t\t\t\t<snmpPort>%d</snmpPort>\n"), |
98ef8e4a VK |
983 | (int)m_id, (const TCHAR *)m_guid.toString(), |
984 | (const TCHAR *)EscapeStringForXML2(m_name), | |
4804be4e | 985 | (const TCHAR *)EscapeStringForXML2(m_description), |
6e102d6e VK |
986 | (int)m_source, m_iPollingInterval, m_iRetentionTime, |
987 | (const TCHAR *)EscapeStringForXML2(m_systemTag), | |
50ea73e3 | 988 | (int)m_flags, (int)m_snmpPort); |
6e102d6e VK |
989 | |
990 | if (m_transformationScriptSource != NULL) | |
991 | { | |
ef607e62 | 992 | str.append(_T("\t\t\t\t\t<transformation>")); |
4e0e77e6 | 993 | str.appendPreallocated(EscapeStringForXML(m_transformationScriptSource, -1)); |
ef607e62 | 994 | str.append(_T("</transformation>\n")); |
6e102d6e VK |
995 | } |
996 | ||
e7450f3b | 997 | if ((m_schedules != NULL) && (m_schedules->size() > 0)) |
6e102d6e | 998 | { |
ef607e62 VK |
999 | str.append(_T("\t\t\t\t\t<schedules>\n")); |
1000 | for(int i = 0; i < m_schedules->size(); i++) | |
1001 | { | |
1002 | str.append(_T("\t\t\t\t\t\t<schedule>")); | |
1003 | str.append(EscapeStringForXML2(m_schedules->get(i))); | |
1004 | str.append(_T("</schedule>\n")); | |
1005 | } | |
1006 | str.append(_T("\t\t\t\t\t</schedules>\n")); | |
6e102d6e VK |
1007 | } |
1008 | ||
1009 | if (m_columns != NULL) | |
1010 | { | |
1011 | str += _T("\t\t\t\t\t<columns>\n"); | |
ef607e62 | 1012 | for(int i = 0; i < m_columns->size(); i++) |
6e102d6e VK |
1013 | { |
1014 | m_columns->get(i)->createNXMPRecord(str, i + 1); | |
1015 | } | |
1016 | str += _T("\t\t\t\t\t</columns>\n"); | |
1017 | } | |
1018 | ||
1019 | if (m_thresholds != NULL) | |
1020 | { | |
1021 | str += _T("\t\t\t\t\t<thresholds>\n"); | |
ef607e62 | 1022 | for(int i = 0; i < m_thresholds->size(); i++) |
6e102d6e VK |
1023 | { |
1024 | m_thresholds->get(i)->createNXMPRecord(str, i + 1); | |
1025 | } | |
1026 | str += _T("\t\t\t\t\t</thresholds>\n"); | |
1027 | } | |
1028 | ||
1029 | if (m_pszPerfTabSettings != NULL) | |
1030 | { | |
ef607e62 | 1031 | str.append(_T("\t\t\t\t\t<perfTabSettings>")); |
4e0e77e6 | 1032 | str.appendPreallocated(EscapeStringForXML(m_pszPerfTabSettings, -1)); |
ef607e62 | 1033 | str.append(_T("</perfTabSettings>\n")); |
6e102d6e VK |
1034 | } |
1035 | ||
1036 | unlock(); | |
ef607e62 | 1037 | str.append(_T("\t\t\t\t</dctable>\n")); |
6e102d6e | 1038 | } |
e7450f3b VK |
1039 | |
1040 | /** | |
1041 | * Create DCObject from import file | |
1042 | */ | |
1043 | void DCTable::updateFromImport(ConfigEntry *config) | |
1044 | { | |
1045 | DCObject::updateFromImport(config); | |
1046 | ||
77b2c6de | 1047 | lock(); |
e7450f3b VK |
1048 | m_columns->clear(); |
1049 | ConfigEntry *columnsRoot = config->findEntry(_T("columns")); | |
1050 | if (columnsRoot != NULL) | |
1051 | { | |
1052 | ObjectArray<ConfigEntry> *columns = columnsRoot->getSubEntries(_T("column#*")); | |
1053 | for(int i = 0; i < columns->size(); i++) | |
1054 | { | |
1055 | m_columns->add(new DCTableColumn(columns->get(i))); | |
1056 | } | |
1057 | delete columns; | |
1058 | } | |
1059 | ||
1060 | m_thresholds->clear(); | |
1061 | ConfigEntry *thresholdsRoot = config->findEntry(_T("thresholds")); | |
1062 | if (thresholdsRoot != NULL) | |
1063 | { | |
1064 | ObjectArray<ConfigEntry> *thresholds = thresholdsRoot->getSubEntries(_T("threshold#*")); | |
1065 | for(int i = 0; i < thresholds->size(); i++) | |
1066 | { | |
1067 | m_thresholds->add(new DCTableThreshold(thresholds->get(i))); | |
1068 | } | |
1069 | delete thresholds; | |
1070 | } | |
77b2c6de | 1071 | unlock(); |
e7450f3b | 1072 | } |
faa89331 VK |
1073 | |
1074 | /** | |
1075 | * Should return true if object has (or can have) value | |
1076 | */ | |
1077 | bool DCTable::hasValue() | |
1078 | { | |
4804be4e | 1079 | if (m_owner->getObjectClass() == OBJECT_CLUSTER) |
faa89331 VK |
1080 | return isAggregateOnCluster(); |
1081 | return true; | |
1082 | } |