fixed compiler warnings
[public/netxms.git] / src / server / core / dcitem.cpp
CommitLineData
4671afeb 1/*
5039dede 2** NetXMS - Network Management System
a31a2d32 3** Copyright (C) 2003-2017 Victor Kirhenshtein
5039dede
AK
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: dcitem.cpp
20**
21**/
22
23#include "nxcore.h"
24
4ef60905
AK
25#ifdef WITH_ZMQ
26#include "zeromq.h"
27#endif
28
674164eb 29/**
3b21a646
VK
30 * Event parameter names
31 */
0984f0e7
VK
32static const TCHAR *s_paramNamesReach[] = { _T("dciName"), _T("dciDescription"), _T("thresholdValue"), _T("currentValue"), _T("dciId"), _T("instance"), _T("isRepeatedEvent"), _T("dciValue") };
33static const TCHAR *s_paramNamesRearm[] = { _T("dciName"), _T("dciDescription"), _T("dciId"), _T("instance"), _T("thresholdValue"), _T("currentValue"), _T("dciValue") };
3b21a646
VK
34
35/**
d140955e
VK
36 * DCI cache loader queue
37 */
38extern Queue g_dciCacheLoaderQueue;
39
40/**
3bdca1f8
VK
41 * Default constructor for DCItem
42 */
cc8ce218 43DCItem::DCItem() : DCObject()
5039dede 44{
6b8e9f96 45 m_thresholds = NULL;
ced80327 46 m_dataType = DCI_DT_INT;
ced80327 47 m_deltaCalculation = DCM_ORIGINAL_VALUE;
d02f6b92 48 m_sampleCount = 0;
d140955e 49 m_cacheSize = 0;
253ef939 50 m_requiredCacheSize = 0;
5039dede
AK
51 m_ppValueCache = NULL;
52 m_tPrevValueTimeStamp = 0;
cc8ce218 53 m_bCacheLoaded = false;
4d0c32f3
VK
54 m_nBaseUnits = DCI_BASEUNITS_OTHER;
55 m_nMultiplier = 1;
6b8e9f96 56 m_customUnitName = NULL;
e320f8ce 57 m_snmpRawValueType = SNMP_RAWTYPE_NONE;
288a0046 58 m_predictionEngine[0] = 0;
5039dede
AK
59}
60
3bdca1f8
VK
61/**
62 * Create DCItem from another DCItem
63 */
cc8ce218 64DCItem::DCItem(const DCItem *pSrc) : DCObject(pSrc)
5039dede 65{
ced80327 66 m_dataType = pSrc->m_dataType;
ced80327 67 m_deltaCalculation = pSrc->m_deltaCalculation;
d02f6b92 68 m_sampleCount = pSrc->m_sampleCount;
d140955e 69 m_cacheSize = 0;
253ef939 70 m_requiredCacheSize = 0;
5039dede
AK
71 m_ppValueCache = NULL;
72 m_tPrevValueTimeStamp = 0;
cc8ce218 73 m_bCacheLoaded = false;
4d0c32f3
VK
74 m_nBaseUnits = pSrc->m_nBaseUnits;
75 m_nMultiplier = pSrc->m_nMultiplier;
6b8e9f96 76 m_customUnitName = (pSrc->m_customUnitName != NULL) ? _tcsdup(pSrc->m_customUnitName) : NULL;
e320f8ce 77 m_snmpRawValueType = pSrc->m_snmpRawValueType;
288a0046 78 _tcscpy(m_predictionEngine, pSrc->m_predictionEngine);
5039dede
AK
79
80 // Copy thresholds
6b8e9f96
VK
81 if (pSrc->getThresholdCount() > 0)
82 {
83 m_thresholds = new ObjectArray<Threshold>(pSrc->m_thresholds->size(), 8, true);
84 for(int i = 0; i < pSrc->m_thresholds->size(); i++)
85 {
86 Threshold *t = new Threshold(pSrc->m_thresholds->get(i));
87 t->createId();
88 m_thresholds->add(t);
89 }
90 }
91 else
92 {
93 m_thresholds = NULL;
94 }
5039dede
AK
95}
96
3bdca1f8
VK
97/**
98 * Constructor for creating DCItem from database
99 * Assumes that fields in SELECT query are in following order:
100 * item_id,name,source,datatype,polling_interval,retention_time,status,
101 * delta_calculation,transformation,template_id,description,instance,
102 * template_item_id,flags,resource_id,proxy_node,base_units,unit_multiplier,
afbe5388 103 * custom_units_name,perftab_settings,system_tag,snmp_port,snmp_raw_value_type,
27c21485 104 * instd_method,instd_data,instd_filter,samples,comments,guid,npe_name,visibility_rights
3bdca1f8 105 */
9bd1bace 106DCItem::DCItem(DB_HANDLE hdb, DB_RESULT hResult, int iRow, Template *pNode) : DCObject()
5039dede 107{
c42b4551
VK
108 m_id = DBGetFieldULong(hResult, iRow, 0);
109 DBGetField(hResult, iRow, 1, m_name, MAX_ITEM_NAME);
ced80327
VK
110 m_source = (BYTE)DBGetFieldLong(hResult, iRow, 2);
111 m_dataType = (BYTE)DBGetFieldLong(hResult, iRow, 3);
5039dede
AK
112 m_iPollingInterval = DBGetFieldLong(hResult, iRow, 4);
113 m_iRetentionTime = DBGetFieldLong(hResult, iRow, 5);
ced80327
VK
114 m_status = (BYTE)DBGetFieldLong(hResult, iRow, 6);
115 m_deltaCalculation = (BYTE)DBGetFieldLong(hResult, iRow, 7);
ba89fed2 116 TCHAR *pszTmp = DBGetField(hResult, iRow, 8, NULL, 0);
fb05c05b 117 setTransformationScript(pszTmp);
5039dede
AK
118 free(pszTmp);
119 m_dwTemplateId = DBGetFieldULong(hResult, iRow, 9);
4804be4e 120 DBGetField(hResult, iRow, 10, m_description, MAX_DB_STRING);
6b8e9f96 121 DBGetField(hResult, iRow, 11, m_instance, MAX_DB_STRING);
5039dede 122 m_dwTemplateItemId = DBGetFieldULong(hResult, iRow, 12);
6b8e9f96 123 m_thresholds = NULL;
4804be4e 124 m_owner = pNode;
d140955e 125 m_cacheSize = 0;
253ef939 126 m_requiredCacheSize = 0;
5039dede
AK
127 m_ppValueCache = NULL;
128 m_tPrevValueTimeStamp = 0;
cc8ce218 129 m_bCacheLoaded = false;
e320f8ce
VK
130 m_flags = (WORD)DBGetFieldLong(hResult, iRow, 13);
131 m_dwResourceId = DBGetFieldULong(hResult, iRow, 14);
191e4784 132 m_sourceNode = DBGetFieldULong(hResult, iRow, 15);
e320f8ce
VK
133 m_nBaseUnits = DBGetFieldLong(hResult, iRow, 16);
134 m_nMultiplier = DBGetFieldLong(hResult, iRow, 17);
6b8e9f96 135 m_customUnitName = DBGetField(hResult, iRow, 18, NULL, 0);
e320f8ce 136 m_pszPerfTabSettings = DBGetField(hResult, iRow, 19, NULL, 0);
e320f8ce
VK
137 DBGetField(hResult, iRow, 20, m_systemTag, MAX_DB_STRING);
138 m_snmpPort = (WORD)DBGetFieldLong(hResult, iRow, 21);
139 m_snmpRawValueType = (WORD)DBGetFieldLong(hResult, iRow, 22);
afbe5388
VK
140 m_instanceDiscoveryMethod = (WORD)DBGetFieldLong(hResult, iRow, 23);
141 m_instanceDiscoveryData = DBGetField(hResult, iRow, 24, NULL, 0);
142 m_instanceFilterSource = NULL;
143 m_instanceFilter = NULL;
144 pszTmp = DBGetField(hResult, iRow, 25, NULL, 0);
145 setInstanceFilter(pszTmp);
146 free(pszTmp);
fb9441ee 147 m_sampleCount = DBGetFieldLong(hResult, iRow, 26);
4016c0df 148 m_comments = DBGetField(hResult, iRow, 27, NULL, 0);
98ef8e4a 149 m_guid = DBGetFieldGUID(hResult, iRow, 28);
288a0046 150 DBGetField(hResult, iRow, 29, m_predictionEngine, MAX_NPE_NAME_LEN);
27c21485 151 //set visibility rights
152 pszTmp = DBGetField(hResult, iRow, 30, NULL, 0);
153 StringList list;
154 list.splitAndAdd(pszTmp, _T(","));
155 for(int i = 0; i < list.size(); i++)
156 {
74f70b59
VK
157 if (*(list.get(i)) != 0)
158 m_visibilityRights->add(_tcstol(list.get(i), NULL, 0));
27c21485 159 }
160 free(pszTmp);
5039dede 161
5039dede 162 // Load last raw value from database
ba89fed2 163 TCHAR szQuery[256];
c42b4551 164 _sntprintf(szQuery, 256, _T("SELECT raw_value,last_poll_time FROM raw_dci_values WHERE item_id=%d"), m_id);
9bd1bace 165 DB_RESULT hTempResult = DBSelect(hdb, szQuery);
5039dede
AK
166 if (hTempResult != NULL)
167 {
168 if (DBGetNumRows(hTempResult) > 0)
169 {
ba89fed2 170 TCHAR szBuffer[MAX_DB_STRING];
5039dede
AK
171 m_prevRawValue = DBGetField(hTempResult, 0, 0, szBuffer, MAX_DB_STRING);
172 m_tPrevValueTimeStamp = DBGetFieldULong(hTempResult, 0, 1);
173 m_tLastPoll = m_tPrevValueTimeStamp;
174 }
175 DBFreeResult(hTempResult);
176 }
ba89fed2 177
9bd1bace 178 loadCustomSchedules(hdb);
5039dede
AK
179}
180
6b8e9f96
VK
181/**
182 * Constructor for creating new DCItem from scratch
183 */
4671afeb 184DCItem::DCItem(UINT32 dwId, const TCHAR *szName, int iSource, int iDataType,
5039dede 185 int iPollingInterval, int iRetentionTime, Template *pNode,
80d3565a 186 const TCHAR *pszDescription, const TCHAR *systemTag)
cc8ce218 187 : DCObject(dwId, szName, iSource, iPollingInterval, iRetentionTime, pNode, pszDescription, systemTag)
5039dede 188{
ced80327 189 m_dataType = iDataType;
ced80327 190 m_deltaCalculation = DCM_ORIGINAL_VALUE;
d02f6b92 191 m_sampleCount = 0;
6b8e9f96 192 m_thresholds = NULL;
d140955e 193 m_cacheSize = 0;
253ef939 194 m_requiredCacheSize = 0;
5039dede
AK
195 m_ppValueCache = NULL;
196 m_tPrevValueTimeStamp = 0;
cc8ce218 197 m_bCacheLoaded = false;
4d0c32f3
VK
198 m_nBaseUnits = DCI_BASEUNITS_OTHER;
199 m_nMultiplier = 1;
6b8e9f96 200 m_customUnitName = NULL;
e320f8ce 201 m_snmpRawValueType = SNMP_RAWTYPE_NONE;
288a0046 202 m_predictionEngine[0] = 0;
5039dede 203
822b5878 204 updateCacheSizeInternal(false);
5039dede
AK
205}
206
6b8e9f96
VK
207/**
208 * Create DCItem from import file
209 */
cc8ce218 210DCItem::DCItem(ConfigEntry *config, Template *owner) : DCObject(config, owner)
a65c1819 211{
31b0f68b
VK
212 m_dataType = (BYTE)config->getSubEntryValueAsInt(_T("dataType"));
213 m_deltaCalculation = (BYTE)config->getSubEntryValueAsInt(_T("delta"));
214 m_sampleCount = (BYTE)config->getSubEntryValueAsInt(_T("samples"));
d140955e 215 m_cacheSize = 0;
253ef939 216 m_requiredCacheSize = 0;
a65c1819
VK
217 m_ppValueCache = NULL;
218 m_tPrevValueTimeStamp = 0;
cc8ce218 219 m_bCacheLoaded = false;
a65c1819
VK
220 m_nBaseUnits = DCI_BASEUNITS_OTHER;
221 m_nMultiplier = 1;
6b8e9f96 222 m_customUnitName = NULL;
31b0f68b 223 m_snmpRawValueType = (WORD)config->getSubEntryValueAsInt(_T("snmpRawValueType"));
288a0046 224 nx_strncpy(m_predictionEngine, config->getSubEntryValue(_T("predictionEngine"), 0, _T("")), MAX_NPE_NAME_LEN);
e320f8ce 225
50ea73e3 226 // for compatibility with old format
31b0f68b 227 if (config->getSubEntryValueAsInt(_T("allThresholds")))
e320f8ce 228 m_flags |= DCF_ALL_THRESHOLDS;
31b0f68b 229 if (config->getSubEntryValueAsInt(_T("rawValueInOctetString")))
e320f8ce 230 m_flags |= DCF_RAW_VALUE_OCTET_STRING;
e320f8ce 231
a65c1819
VK
232 ConfigEntry *thresholdsRoot = config->findEntry(_T("thresholds"));
233 if (thresholdsRoot != NULL)
234 {
8b7ae7eb
VK
235 ObjectArray<ConfigEntry> *thresholds = thresholdsRoot->getSubEntries(_T("threshold#*"));
236 m_thresholds = new ObjectArray<Threshold>(thresholds->size(), 8, true);
237 for(int i = 0; i < thresholds->size(); i++)
a65c1819 238 {
8b7ae7eb 239 m_thresholds->add(new Threshold(thresholds->get(i), this));
a65c1819
VK
240 }
241 delete thresholds;
242 }
243 else
244 {
6b8e9f96 245 m_thresholds = NULL;
a65c1819
VK
246 }
247
822b5878 248 updateCacheSizeInternal(false);
a65c1819
VK
249}
250
6b8e9f96
VK
251/**
252 * Destructor
253 */
5039dede
AK
254DCItem::~DCItem()
255{
6b8e9f96 256 delete m_thresholds;
288a0046 257 free(m_customUnitName);
fb05c05b 258 clearCache();
5039dede
AK
259}
260
6b8e9f96
VK
261/**
262 * Delete all thresholds
263 */
fb05c05b
VK
264void DCItem::deleteAllThresholds()
265{
266 lock();
6b8e9f96 267 delete_and_null(m_thresholds);
fb05c05b
VK
268 unlock();
269}
270
6b8e9f96
VK
271/**
272 * Clear data cache
273 */
65e2005b 274void DCItem::clearCache()
5039dede 275{
288a0046 276 for(UINT32 i = 0; i < m_cacheSize; i++)
5039dede 277 delete m_ppValueCache[i];
288a0046 278 free(m_ppValueCache);
5039dede 279 m_ppValueCache = NULL;
d140955e 280 m_cacheSize = 0;
5039dede
AK
281}
282
6b8e9f96
VK
283/**
284 * Load data collection items thresholds from database
285 */
9bd1bace 286bool DCItem::loadThresholdsFromDB(DB_HANDLE hdb)
5039dede 287{
16d6f798 288 bool result = false;
5039dede 289
9bd1bace 290 DB_STATEMENT hStmt = DBPrepare(hdb,
35f836fe 291 _T("SELECT threshold_id,fire_value,rearm_value,check_function,")
1d34c533 292 _T("check_operation,sample_count,script,event_code,current_state,")
711e5e9a 293 _T("rearm_event_code,repeat_interval,current_severity,")
b2042b58 294 _T("last_event_timestamp,match_count FROM thresholds WHERE item_id=? ")
92c51b1d
VK
295 _T("ORDER BY sequence_number"));
296 if (hStmt != NULL)
297 {
c42b4551 298 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
92c51b1d
VK
299 DB_RESULT hResult = DBSelectPrepared(hStmt);
300 if (hResult != NULL)
301 {
6b8e9f96
VK
302 int count = DBGetNumRows(hResult);
303 if (count > 0)
92c51b1d 304 {
6b8e9f96
VK
305 m_thresholds = new ObjectArray<Threshold>(count, 8, true);
306 for(int i = 0; i < count; i++)
307 m_thresholds->add(new Threshold(hResult, i, this));
92c51b1d
VK
308 }
309 DBFreeResult(hResult);
310 result = true;
311 }
312 DBFreeStatement(hStmt);
313 }
16d6f798 314 return result;
5039dede
AK
315}
316
6b8e9f96
VK
317/**
318 * Save to database
319 */
e7450f3b 320bool DCItem::saveToDatabase(DB_HANDLE hdb)
5039dede 321{
5039dede 322 // Prepare and execute query
afbe5388 323 DB_STATEMENT hStmt;
c42b4551 324 if (IsDatabaseRecordExist(hdb, _T("items"), _T("item_id"), m_id))
65e2005b 325 {
4671afeb 326 hStmt = DBPrepare(hdb,
afbe5388
VK
327 _T("UPDATE items SET node_id=?,template_id=?,name=?,source=?,")
328 _T("datatype=?,polling_interval=?,retention_time=?,status=?,")
329 _T("delta_calculation=?,transformation=?,description=?,")
330 _T("instance=?,template_item_id=?,flags=?,")
331 _T("resource_id=?,proxy_node=?,base_units=?,")
332 _T("unit_multiplier=?,custom_units_name=?,perftab_settings=?,")
333 _T("system_tag=?,snmp_port=?,snmp_raw_value_type=?,")
98ef8e4a 334 _T("instd_method=?,instd_data=?,instd_filter=?,samples=?,")
27c21485 335 _T("comments=?,guid=?,npe_name=?,visibility_rights=? WHERE item_id=?"));
65e2005b 336 }
ba89fed2
VK
337 else
338 {
4671afeb 339 hStmt = DBPrepare(hdb,
afbe5388 340 _T("INSERT INTO items (node_id,template_id,name,source,")
ba89fed2 341 _T("datatype,polling_interval,retention_time,status,delta_calculation,")
afbe5388 342 _T("transformation,description,instance,template_item_id,flags,")
ba89fed2 343 _T("resource_id,proxy_node,base_units,unit_multiplier,")
afbe5388 344 _T("custom_units_name,perftab_settings,system_tag,snmp_port,snmp_raw_value_type,")
27c21485 345 _T("instd_method,instd_data,instd_filter,samples,comments,guid,npe_name,visibility_rights,item_id) VALUES ")
346 _T("(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
ba89fed2 347 }
afbe5388 348 if (hStmt == NULL)
8a57a85e 349 return false;
afbe5388
VK
350
351 lock();
352
4804be4e 353 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (m_owner == NULL) ? 0 : m_owner->getId());
afbe5388 354 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_dwTemplateId);
c42b4551 355 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_name, DB_BIND_STATIC);
967893bb
VK
356 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (INT32)m_source);
357 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (INT32)m_dataType);
358 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (INT32)m_iPollingInterval);
359 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (INT32)m_iRetentionTime);
360 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, (INT32)m_status);
361 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (INT32)m_deltaCalculation);
fe8e120d 362 DBBind(hStmt, 10, DB_SQLTYPE_TEXT, m_transformationScriptSource, DB_BIND_STATIC);
4804be4e 363 DBBind(hStmt, 11, DB_SQLTYPE_VARCHAR, m_description, DB_BIND_STATIC);
afbe5388
VK
364 DBBind(hStmt, 12, DB_SQLTYPE_VARCHAR, m_instance, DB_BIND_STATIC);
365 DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, m_dwTemplateItemId);
967893bb 366 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, (UINT32)m_flags);
afbe5388 367 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, m_dwResourceId);
191e4784 368 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, m_sourceNode);
967893bb
VK
369 DBBind(hStmt, 17, DB_SQLTYPE_INTEGER, (INT32)m_nBaseUnits);
370 DBBind(hStmt, 18, DB_SQLTYPE_INTEGER, (INT32)m_nMultiplier);
afbe5388
VK
371 DBBind(hStmt, 19, DB_SQLTYPE_VARCHAR, m_customUnitName, DB_BIND_STATIC);
372 DBBind(hStmt, 20, DB_SQLTYPE_VARCHAR, m_pszPerfTabSettings, DB_BIND_STATIC);
373 DBBind(hStmt, 21, DB_SQLTYPE_VARCHAR, m_systemTag, DB_BIND_STATIC);
967893bb
VK
374 DBBind(hStmt, 22, DB_SQLTYPE_INTEGER, (INT32)m_snmpPort);
375 DBBind(hStmt, 23, DB_SQLTYPE_INTEGER, (INT32)m_snmpRawValueType);
376 DBBind(hStmt, 24, DB_SQLTYPE_INTEGER, (INT32)m_instanceDiscoveryMethod);
afbe5388 377 DBBind(hStmt, 25, DB_SQLTYPE_VARCHAR, m_instanceDiscoveryData, DB_BIND_STATIC);
fe8e120d 378 DBBind(hStmt, 26, DB_SQLTYPE_TEXT, m_instanceFilterSource, DB_BIND_STATIC);
967893bb 379 DBBind(hStmt, 27, DB_SQLTYPE_INTEGER, (INT32)m_sampleCount);
fe8e120d 380 DBBind(hStmt, 28, DB_SQLTYPE_TEXT, m_comments, DB_BIND_STATIC);
98ef8e4a 381 DBBind(hStmt, 29, DB_SQLTYPE_VARCHAR, m_guid);
288a0046 382 DBBind(hStmt, 30, DB_SQLTYPE_VARCHAR, m_predictionEngine, DB_BIND_STATIC);
27c21485 383 String tmp;
384 int size = m_visibilityRights->size();
385 for(int i = 0; i < size; i++)
386 {
387 tmp.append(m_visibilityRights->get(i));
388 if(i != (size - 1))
389 tmp.append(_T(','));
390 }
391 DBBind(hStmt, 31, DB_SQLTYPE_VARCHAR, tmp, DB_BIND_STATIC);
392 DBBind(hStmt, 32, DB_SQLTYPE_INTEGER, m_id);
afbe5388 393
0df15d50 394 bool bResult = DBExecute(hStmt);
afbe5388 395 DBFreeStatement(hStmt);
5039dede
AK
396
397 // Save thresholds
6b8e9f96 398 if (bResult && (m_thresholds != NULL))
5039dede 399 {
6b8e9f96
VK
400 for(int i = 0; i < m_thresholds->size(); i++)
401 m_thresholds->get(i)->saveToDB(hdb, i);
5039dede
AK
402 }
403
404 // Delete non-existing thresholds
afbe5388 405 TCHAR query[256];
c42b4551 406 _sntprintf(query, 256, _T("SELECT threshold_id FROM thresholds WHERE item_id=%d"), m_id);
afbe5388 407 DB_RESULT hResult = DBSelect(hdb, query);
5039dede
AK
408 if (hResult != NULL)
409 {
6b8e9f96
VK
410 int iNumRows = DBGetNumRows(hResult);
411 for(int i = 0; i < iNumRows; i++)
5039dede 412 {
967893bb 413 UINT32 dwId = DBGetFieldULong(hResult, i, 0);
6b8e9f96
VK
414 int j;
415 for(j = 0; j < getThresholdCount(); j++)
416 if (m_thresholds->get(j)->getId() == dwId)
417 break;
418 if (j == getThresholdCount())
5039dede 419 {
afbe5388
VK
420 _sntprintf(query, 256, _T("DELETE FROM thresholds WHERE threshold_id=%d"), dwId);
421 DBQuery(hdb, query);
5039dede
AK
422 }
423 }
424 DBFreeResult(hResult);
425 }
426
427 // Create record in raw_dci_values if needed
8a57a85e 428 if (!IsDatabaseRecordExist(hdb, _T("raw_dci_values"), _T("item_id"), m_id))
5039dede 429 {
8a57a85e
VK
430 hStmt = DBPrepare(hdb, _T("INSERT INTO raw_dci_values (item_id,raw_value,last_poll_time) VALUES (?,?,?)"));
431 if (hStmt == NULL)
5039dede 432 {
8a57a85e
VK
433 unlock();
434 return false;
5039dede 435 }
8a57a85e
VK
436 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
437 DBBind(hStmt, 2, DB_SQLTYPE_TEXT, m_prevRawValue.getString(), DB_BIND_STATIC, 255);
438 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (INT64)m_tPrevValueTimeStamp);
439 bResult = DBExecute(hStmt);
440 DBFreeStatement(hStmt);
5039dede
AK
441 }
442
fb05c05b 443 unlock();
e7450f3b 444 return bResult ? DCObject::saveToDatabase(hdb) : false;
5039dede
AK
445}
446
6b8e9f96
VK
447/**
448 * Check last value for threshold violations
449 */
fb05c05b 450void DCItem::checkThresholds(ItemValue &value)
5039dede 451{
6b8e9f96
VK
452 if (m_thresholds == NULL)
453 return;
454
8db21082 455 bool thresholdDeactivated = false;
6b8e9f96 456 for(int i = 0; i < m_thresholds->size(); i++)
5039dede 457 {
a0dc14f9 458 Threshold *t = m_thresholds->get(i);
3b21a646 459 ItemValue checkValue;
4804be4e 460 ThresholdCheckResult result = t->check(value, m_ppValueCache, checkValue, m_owner, this);
a0dc14f9 461 switch(result)
5039dede 462 {
a0dc14f9 463 case ACTIVATED:
3b21a646 464 {
0984f0e7 465 PostDciEventWithNames(t->getEventCode(), m_owner->getId(), m_id, "ssssisds",
4804be4e 466 s_paramNamesReach, m_name, m_description, t->getStringValue(),
7e2cd182
VK
467 (const TCHAR *)checkValue, m_id, m_instance, 0, (const TCHAR *)value);
468 EventTemplate *evt = FindEventTemplateByCode(t->getEventCode());
3b21a646 469 if (evt != NULL)
50963ced
VK
470 {
471 t->markLastEvent(evt->getSeverity());
472 evt->decRefCount();
473 }
3b21a646
VK
474 if (!(m_flags & DCF_ALL_THRESHOLDS))
475 i = m_thresholds->size(); // Stop processing
476 }
5039dede 477 break;
a0dc14f9 478 case DEACTIVATED:
0984f0e7 479 PostDciEventWithNames(t->getRearmEventCode(), m_owner->getId(), m_id, "ssissss",
4804be4e 480 s_paramNamesRearm, m_name, m_description, m_id, m_instance,
0984f0e7 481 t->getStringValue(), (const TCHAR *)checkValue, (const TCHAR *)value);
8db21082
VK
482 if (!(m_flags & DCF_ALL_THRESHOLDS))
483 {
484 // this flag used to re-send activation event for next active threshold
485 thresholdDeactivated = true;
486 }
5039dede 487 break;
a0dc14f9 488 case ALREADY_ACTIVE:
3b21a646
VK
489 {
490 // Check if we need to re-sent threshold violation event
491 time_t now = time(NULL);
492 UINT32 repeatInterval = (t->getRepeatInterval() == -1) ? g_thresholdRepeatInterval : (UINT32)t->getRepeatInterval();
8db21082 493 if (thresholdDeactivated || ((repeatInterval != 0) && (t->getLastEventTimestamp() + (time_t)repeatInterval < now)))
3b21a646 494 {
be372638
EJ
495 PostDciEventWithNames(t->getEventCode(), m_owner->getId(), m_id, "ssssisds",
496 s_paramNamesReach, m_name, m_description, t->getStringValue(),
497 (const TCHAR *)checkValue, m_id, m_instance, 1, (const TCHAR *)value);
7e2cd182 498 EventTemplate *evt = FindEventTemplateByCode(t->getEventCode());
3b21a646 499 if (evt != NULL)
50963ced
VK
500 {
501 t->markLastEvent(evt->getSeverity());
502 evt->decRefCount();
503 }
3b21a646
VK
504 }
505 }
a0dc14f9 506 if (!(m_flags & DCF_ALL_THRESHOLDS))
5039dede 507 {
a0dc14f9 508 i = m_thresholds->size(); // Threshold condition still true, stop processing
5039dede 509 }
8db21082 510 thresholdDeactivated = false;
5039dede 511 break;
a0dc14f9
VK
512 default:
513 break;
5039dede
AK
514 }
515 }
516}
517
6b8e9f96
VK
518/**
519 * Create NXCP message with item data
520 */
b368969c 521void DCItem::createMessage(NXCPMessage *pMsg)
5039dede 522{
cc8ce218 523 DCObject::createMessage(pMsg);
5039dede 524
fb05c05b 525 lock();
b368969c
VK
526 pMsg->setField(VID_DCI_DATA_TYPE, (WORD)m_dataType);
527 pMsg->setField(VID_DCI_DELTA_CALCULATION, (WORD)m_deltaCalculation);
528 pMsg->setField(VID_SAMPLE_COUNT, (WORD)m_sampleCount);
529 pMsg->setField(VID_BASE_UNITS, (WORD)m_nBaseUnits);
530 pMsg->setField(VID_MULTIPLIER, (UINT32)m_nMultiplier);
531 pMsg->setField(VID_SNMP_RAW_VALUE_TYPE, m_snmpRawValueType);
288a0046 532 pMsg->setField(VID_NPE_NAME, m_predictionEngine);
6b8e9f96 533 if (m_customUnitName != NULL)
b368969c 534 pMsg->setField(VID_CUSTOM_UNITS_NAME, m_customUnitName);
6b8e9f96
VK
535 if (m_thresholds != NULL)
536 {
b368969c 537 pMsg->setField(VID_NUM_THRESHOLDS, (UINT32)m_thresholds->size());
967893bb 538 UINT32 dwId = VID_DCI_THRESHOLD_BASE;
6b8e9f96
VK
539 for(int i = 0; i < m_thresholds->size(); i++, dwId += 20)
540 m_thresholds->get(i)->createMessage(pMsg, dwId);
541 }
542 else
543 {
b368969c 544 pMsg->setField(VID_NUM_THRESHOLDS, (UINT32)0);
6b8e9f96 545 }
fb05c05b 546 unlock();
5039dede
AK
547}
548
6b8e9f96
VK
549/**
550 * Delete item and collected data from database
551 */
c42b4551 552void DCItem::deleteFromDatabase()
5039dede 553{
35f836fe 554 TCHAR szQuery[256];
5039dede 555
c42b4551 556 DCObject::deleteFromDatabase();
ba89fed2 557
c42b4551 558 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM items WHERE item_id=%d"), m_id);
5039dede 559 QueueSQLRequest(szQuery);
c42b4551 560 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM thresholds WHERE item_id=%d"), m_id);
5039dede 561 QueueSQLRequest(szQuery);
8a00fd4c
VK
562 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM raw_dci_values WHERE item_id=%d"), m_id);
563 QueueSQLRequest(szQuery);
b41a29fd
VK
564
565 if (m_owner->isDataCollectionTarget())
566 static_cast<DataCollectionTarget*>(m_owner)->scheduleItemDataCleanup(m_id);
5039dede
AK
567}
568
6b8e9f96
VK
569/**
570 * Update item from NXCP message
571 */
b368969c 572void DCItem::updateFromMessage(NXCPMessage *pMsg, UINT32 *pdwNumMaps, UINT32 **ppdwMapIndex, UINT32 **ppdwMapId)
5039dede 573{
cc8ce218 574 DCObject::updateFromMessage(pMsg);
5039dede 575
fb05c05b 576 lock();
5039dede 577
b368969c
VK
578 m_dataType = (BYTE)pMsg->getFieldAsUInt16(VID_DCI_DATA_TYPE);
579 m_deltaCalculation = (BYTE)pMsg->getFieldAsUInt16(VID_DCI_DELTA_CALCULATION);
580 m_sampleCount = (int)pMsg->getFieldAsUInt16(VID_SAMPLE_COUNT);
581 m_nBaseUnits = pMsg->getFieldAsUInt16(VID_BASE_UNITS);
582 m_nMultiplier = (int)pMsg->getFieldAsUInt32(VID_MULTIPLIER);
6b8e9f96 583 safe_free(m_customUnitName);
b368969c
VK
584 m_customUnitName = pMsg->getFieldAsString(VID_CUSTOM_UNITS_NAME);
585 m_snmpRawValueType = pMsg->getFieldAsUInt16(VID_SNMP_RAW_VALUE_TYPE);
288a0046 586 pMsg->getFieldAsString(VID_NPE_NAME, m_predictionEngine, MAX_NPE_NAME_LEN);
5039dede
AK
587
588 // Update thresholds
b368969c 589 UINT32 dwNum = pMsg->getFieldAsUInt32(VID_NUM_THRESHOLDS);
967893bb
VK
590 UINT32 *newThresholds = (UINT32 *)malloc(sizeof(UINT32) * dwNum);
591 *ppdwMapIndex = (UINT32 *)malloc(dwNum * sizeof(UINT32));
592 *ppdwMapId = (UINT32 *)malloc(dwNum * sizeof(UINT32));
5039dede
AK
593 *pdwNumMaps = 0;
594
d9ae1904 595 // Read all new threshold ids from message
967893bb 596 for(UINT32 i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < dwNum; i++, dwId += 10)
5039dede 597 {
b368969c 598 newThresholds[i] = pMsg->getFieldAsUInt32(dwId);
5039dede 599 }
4671afeb 600
5039dede 601 // Check if some thresholds was deleted, and reposition others if needed
cc8ce218 602 Threshold **ppNewList = (Threshold **)malloc(sizeof(Threshold *) * dwNum);
623a71c3 603 memset(ppNewList, 0, sizeof(Threshold *) * dwNum);
6b8e9f96 604 for(int i = 0; i < getThresholdCount(); i++)
5039dede 605 {
967893bb 606 UINT32 j;
5039dede 607 for(j = 0; j < dwNum; j++)
6b8e9f96 608 if (m_thresholds->get(i)->getId() == newThresholds[j])
5039dede
AK
609 break;
610 if (j == dwNum)
611 {
612 // No threshold with that id in new list, delete it
6b8e9f96 613 m_thresholds->remove(i);
5039dede
AK
614 i--;
615 }
616 else
617 {
618 // Move existing thresholds to appropriate positions in new list
6b8e9f96 619 ppNewList[j] = m_thresholds->get(i);
5039dede
AK
620 }
621 }
5039dede
AK
622
623 // Add or update thresholds
967893bb 624 for(UINT32 i = 0, dwId = VID_DCI_THRESHOLD_BASE; i < dwNum; i++, dwId += 10)
5039dede 625 {
d9ae1904 626 if (newThresholds[i] == 0) // New threshold?
5039dede 627 {
6b8e9f96
VK
628 ppNewList[i] = new Threshold(this);
629 ppNewList[i]->createId();
5039dede
AK
630
631 // Add index -> id mapping
632 (*ppdwMapIndex)[*pdwNumMaps] = i;
6b8e9f96 633 (*ppdwMapId)[*pdwNumMaps] = ppNewList[i]->getId();
5039dede
AK
634 (*pdwNumMaps)++;
635 }
623a71c3
VK
636 if (ppNewList[i] != NULL)
637 ppNewList[i]->updateFromMessage(pMsg, dwId);
5039dede 638 }
6b8e9f96
VK
639
640 if (dwNum > 0)
641 {
642 if (m_thresholds != NULL)
643 {
644 m_thresholds->setOwner(false);
645 m_thresholds->clear();
646 m_thresholds->setOwner(true);
647 }
648 else
649 {
650 m_thresholds = new ObjectArray<Threshold>((int)dwNum, 8, true);
651 }
967893bb 652 for(UINT32 i = 0; i < dwNum; i++)
623a71c3
VK
653 {
654 if (ppNewList[i] != NULL)
655 m_thresholds->add(ppNewList[i]);
656 }
6b8e9f96
VK
657 }
658 else
659 {
660 delete_and_null(m_thresholds);
661 }
662
6470750c
VK
663 // Update data type in thresholds
664 for(int i = 0; i < getThresholdCount(); i++)
665 m_thresholds->get(i)->setDataType(m_dataType);
666
822b5878
VK
667 free(ppNewList);
668 free(newThresholds);
669 updateCacheSizeInternal(true);
fb05c05b 670 unlock();
5039dede
AK
671}
672
6b8e9f96 673/**
0156d6b2
VK
674 * Process new collected value. Should return true on success.
675 * If returns false, current poll result will be converted into data collection error.
676 *
677 * @return true on success
6b8e9f96 678 */
b60584cf 679bool DCItem::processNewValue(time_t tmTimeStamp, const void *originalValue, bool *updateStatus)
5039dede 680{
5039dede
AK
681 ItemValue rawValue, *pValue;
682
fb05c05b 683 lock();
5039dede 684
4804be4e
VK
685 // Normally m_owner shouldn't be NULL for polled items, but who knows...
686 if (m_owner == NULL)
5039dede 687 {
fb05c05b 688 unlock();
0156d6b2 689 return false;
5039dede
AK
690 }
691
5039dede 692 // Create new ItemValue object and transform it as needed
3055d973 693 pValue = new ItemValue((const TCHAR *)originalValue, tmTimeStamp);
5039dede
AK
694 if (m_tPrevValueTimeStamp == 0)
695 m_prevRawValue = *pValue; // Delta should be zero for first poll
696 rawValue = *pValue;
f877ac05
VK
697
698 // Cluster can have only aggregated data, and transformation
699 // should not be used on aggregation
4804be4e 700 if ((m_owner->getObjectClass() != OBJECT_CLUSTER) || (m_flags & DCF_TRANSFORM_AGGREGATED))
0156d6b2 701 {
b60584cf 702 if (!transform(*pValue, (tmTimeStamp > m_tPrevValueTimeStamp) ? (tmTimeStamp - m_tPrevValueTimeStamp) : 0))
0156d6b2
VK
703 {
704 unlock();
705 return false;
706 }
707 }
708
709 m_dwErrorCount = 0;
f877ac05 710
b60584cf 711 if (isStatusDCO() && (tmTimeStamp > m_tPrevValueTimeStamp) && ((m_cacheSize == 0) || !m_bCacheLoaded || ((UINT32)*pValue != (UINT32)*m_ppValueCache[0])))
cd68963b 712 {
713 *updateStatus = true;
714 }
715 else
716 {
717 *updateStatus = false;
718 }
719
b60584cf
VK
720 if (tmTimeStamp > m_tPrevValueTimeStamp)
721 {
722 m_prevRawValue = rawValue;
723 m_tPrevValueTimeStamp = tmTimeStamp;
5039dede 724
b60584cf
VK
725 // Save raw value into database
726 QueueRawDciDataUpdate(tmTimeStamp, m_id, (const TCHAR *)originalValue, pValue->getString());
727 }
7dad92fb
VK
728
729 // Save transformed value to database
a58454c9 730 if ((m_flags & DCF_NO_STORAGE) == 0)
7cf72a57 731 QueueIDataInsert(tmTimeStamp, m_owner->getId(), m_id, (const TCHAR *)originalValue, pValue->getString());
ea50bc33
VK
732 if (g_flags & AF_PERFDATA_STORAGE_DRIVER_LOADED)
733 PerfDataStorageRequest(this, tmTimeStamp, pValue->getString());
5039dede 734
288a0046
VK
735 // Update prediction engine
736 if (m_predictionEngine[0] != 0)
737 {
738 PredictionEngine *engine = FindPredictionEngine(m_predictionEngine);
739 if (engine != NULL)
740 engine->update(m_id, tmTimeStamp, pValue->getDouble());
741 }
742
5039dede 743 // Check thresholds and add value to cache
f6456d80
VK
744 if (m_bCacheLoaded && (tmTimeStamp >= m_tPrevValueTimeStamp) &&
745 ((g_offlineDataRelevanceTime <= 0) || (tmTimeStamp > (time(NULL) - g_offlineDataRelevanceTime))))
717b277d
VK
746 {
747 checkThresholds(*pValue);
748 }
5039dede 749
b60584cf 750 if ((m_cacheSize > 0) && (tmTimeStamp >= m_tPrevValueTimeStamp))
5039dede 751 {
d140955e
VK
752 delete m_ppValueCache[m_cacheSize - 1];
753 memmove(&m_ppValueCache[1], m_ppValueCache, sizeof(ItemValue *) * (m_cacheSize - 1));
5039dede
AK
754 m_ppValueCache[0] = pValue;
755 }
756 else
757 {
758 delete pValue;
759 }
760
fb05c05b 761 unlock();
4ef60905 762
7ffb5590 763#ifdef WITH_ZMQ
4804be4e 764 ZmqPublishData(m_owner->getId(), m_id, m_name, pValue->getString());
7ffb5590 765#endif
4ef60905 766
0156d6b2 767 return true;
5039dede
AK
768}
769
6b8e9f96
VK
770/**
771 * Process new data collection error
772 */
df94243f 773void DCItem::processNewError(bool noInstance, time_t now)
5039dede 774{
fb05c05b 775 lock();
5039dede 776
4804be4e
VK
777 // Normally m_owner shouldn't be NULL for polled items, but who knows...
778 if (m_owner == NULL)
5039dede 779 {
fb05c05b 780 unlock();
5039dede
AK
781 return;
782 }
783
784 m_dwErrorCount++;
785
6b8e9f96 786 for(int i = 0; i < getThresholdCount(); i++)
5039dede 787 {
3b21a646
VK
788 Threshold *t = m_thresholds->get(i);
789 ThresholdCheckResult result = t->checkError(m_dwErrorCount);
a0dc14f9 790 switch(result)
5039dede 791 {
a0dc14f9 792 case ACTIVATED:
3b21a646 793 {
d10a4032 794 PostDciEventWithNames(t->getEventCode(), m_owner->getId(), m_id, "ssssisds",
4804be4e 795 s_paramNamesReach, m_name, m_description, _T(""), _T(""),
d10a4032
VK
796 m_id, m_instance, 0, _T(""));
797 EventTemplate *evt = FindEventTemplateByCode(t->getEventCode());
3b21a646 798 if (evt != NULL)
50963ced
VK
799 {
800 t->markLastEvent(evt->getSeverity());
801 evt->decRefCount();
802 }
3b21a646
VK
803 if (!(m_flags & DCF_ALL_THRESHOLDS))
804 {
805 i = m_thresholds->size(); // Stop processing
806 }
807 }
5039dede 808 break;
a0dc14f9 809 case DEACTIVATED:
d10a4032
VK
810 PostDciEventWithNames(t->getRearmEventCode(), m_owner->getId(), m_id, "ssissss",
811 s_paramNamesRearm, m_name, m_description, m_id, m_instance, _T(""), _T(""), _T(""));
5039dede 812 break;
a0dc14f9 813 case ALREADY_ACTIVE:
3b21a646
VK
814 {
815 // Check if we need to re-sent threshold violation event
3b21a646
VK
816 UINT32 repeatInterval = (t->getRepeatInterval() == -1) ? g_thresholdRepeatInterval : (UINT32)t->getRepeatInterval();
817 if ((repeatInterval != 0) && (t->getLastEventTimestamp() + (time_t)repeatInterval < now))
818 {
d10a4032 819 PostDciEventWithNames(t->getEventCode(), m_owner->getId(), m_id, "ssssisds",
4804be4e 820 s_paramNamesReach, m_name, m_description, _T(""), _T(""),
d10a4032
VK
821 m_id, m_instance, 1, _T(""));
822 EventTemplate *evt = FindEventTemplateByCode(t->getEventCode());
3b21a646 823 if (evt != NULL)
50963ced
VK
824 {
825 t->markLastEvent(evt->getSeverity());
826 evt->decRefCount();
827 }
3b21a646
VK
828 }
829 }
830 if (!(m_flags & DCF_ALL_THRESHOLDS))
831 {
832 i = m_thresholds->size(); // Threshold condition still true, stop processing
833 }
5039dede 834 break;
a0dc14f9
VK
835 default:
836 break;
5039dede
AK
837 }
838 }
839
fb05c05b 840 unlock();
5039dede
AK
841}
842
6b8e9f96
VK
843/**
844 * Transform received value
845 */
0156d6b2 846bool DCItem::transform(ItemValue &value, time_t nElapsedTime)
5039dede 847{
0156d6b2
VK
848 bool success = true;
849
ced80327 850 switch(m_deltaCalculation)
5039dede
AK
851 {
852 case DCM_SIMPLE:
ced80327 853 switch(m_dataType)
5039dede
AK
854 {
855 case DCI_DT_INT:
967893bb 856 value = (INT32)value - (INT32)m_prevRawValue;
5039dede
AK
857 break;
858 case DCI_DT_UINT:
967893bb 859 value = (UINT32)value - (UINT32)m_prevRawValue;
5039dede
AK
860 break;
861 case DCI_DT_INT64:
862 value = (INT64)value - (INT64)m_prevRawValue;
863 break;
864 case DCI_DT_UINT64:
967893bb 865 value = (UINT64)value - (UINT64)m_prevRawValue;
5039dede
AK
866 break;
867 case DCI_DT_FLOAT:
868 value = (double)value - (double)m_prevRawValue;
869 break;
870 case DCI_DT_STRING:
967893bb 871 value = (INT32)((_tcscmp((const TCHAR *)value, (const TCHAR *)m_prevRawValue) == 0) ? 0 : 1);
5039dede
AK
872 break;
873 default:
874 // Delta calculation is not supported for other types
875 break;
876 }
877 break;
878 case DCM_AVERAGE_PER_MINUTE:
879 nElapsedTime /= 60; // Convert to minutes
9ece2b31 880 /* no break */
5039dede
AK
881 case DCM_AVERAGE_PER_SECOND:
882 // Check elapsed time to prevent divide-by-zero exception
883 if (nElapsedTime == 0)
884 nElapsedTime++;
885
ced80327 886 switch(m_dataType)
5039dede
AK
887 {
888 case DCI_DT_INT:
967893bb 889 value = ((INT32)value - (INT32)m_prevRawValue) / (INT32)nElapsedTime;
5039dede
AK
890 break;
891 case DCI_DT_UINT:
967893bb 892 value = ((UINT32)value - (UINT32)m_prevRawValue) / (UINT32)nElapsedTime;
5039dede
AK
893 break;
894 case DCI_DT_INT64:
895 value = ((INT64)value - (INT64)m_prevRawValue) / (INT64)nElapsedTime;
896 break;
897 case DCI_DT_UINT64:
967893bb 898 value = ((UINT64)value - (UINT64)m_prevRawValue) / (UINT64)nElapsedTime;
5039dede
AK
899 break;
900 case DCI_DT_FLOAT:
901 value = ((double)value - (double)m_prevRawValue) / (double)nElapsedTime;
902 break;
903 case DCI_DT_STRING:
35f836fe 904 // I don't see any meaning in _T("average delta per second (minute)") for string
5039dede
AK
905 // values, so result will be 0 if there are no difference between
906 // current and previous values, and 1 otherwise
967893bb 907 value = (INT32)((_tcscmp((const TCHAR *)value, (const TCHAR *)m_prevRawValue) == 0) ? 0 : 1);
5039dede
AK
908 break;
909 default:
910 // Delta calculation is not supported for other types
911 break;
912 }
913 break;
914 default: // Default is no transformation
915 break;
916 }
917
55bdca5a 918 if (m_transformationScript != NULL)
5039dede 919 {
4804be4e
VK
920 NXSL_VM *vm = new NXSL_VM(new NXSL_ServerEnv());
921 if (vm->load(m_transformationScript))
9ad921e5 922 {
4804be4e
VK
923 NXSL_Value *pValue = new NXSL_Value((const TCHAR *)value);
924 vm->setGlobalVariable(_T("$object"), m_owner->createNXSLObject());
925 if (m_owner->getObjectClass() == OBJECT_NODE)
926 {
927 vm->setGlobalVariable(_T("$node"), m_owner->createNXSLObject());
928 }
929 vm->setGlobalVariable(_T("$dci"), createNXSLObject());
930 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((m_owner->getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
4671afeb 931
4804be4e
VK
932 // remove lock from DCI for script execution to avoid deadlocks
933 unlock();
934 success = vm->run(1, &pValue);
935 lock();
936 if (success)
5039dede 937 {
4804be4e
VK
938 pValue = vm->getResult();
939 if (pValue != NULL)
5039dede 940 {
4804be4e
VK
941 switch(m_dataType)
942 {
943 case DCI_DT_INT:
944 value = pValue->getValueAsInt32();
945 break;
946 case DCI_DT_UINT:
947 value = pValue->getValueAsUInt32();
948 break;
949 case DCI_DT_INT64:
950 value = pValue->getValueAsInt64();
951 break;
952 case DCI_DT_UINT64:
953 value = pValue->getValueAsUInt64();
954 break;
955 case DCI_DT_FLOAT:
956 value = pValue->getValueAsReal();
957 break;
958 case DCI_DT_STRING:
959 value = CHECK_NULL_EX(pValue->getValueAsCString());
960 break;
961 default:
962 break;
963 }
5039dede
AK
964 }
965 }
4804be4e
VK
966 else if (vm->getErrorCode() == NXSL_ERR_EXECUTION_ABORTED)
967 {
4804be4e
VK
968 DbgPrintf(6, _T("Transformation script for DCI \"%s\" [%d] on node %s [%d] aborted"),
969 m_description, m_id, getOwnerName(), getOwnerId());
970 }
971 else
972 {
4804be4e
VK
973 TCHAR buffer[1024];
974 _sntprintf(buffer, 1024, _T("DCI::%s::%d::TransformationScript"), getOwnerName(), m_id);
975 PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, m_id, "ssd", buffer, vm->getErrorText(), m_id);
976 nxlog_write(MSG_TRANSFORMATION_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "dsdss",
977 getOwnerId(), getOwnerName(), m_id, m_name, vm->getErrorText());
978 }
b32b325d 979 }
5039dede
AK
980 else
981 {
4804be4e
VK
982 TCHAR buffer[1024];
983 _sntprintf(buffer, 1024, _T("DCI::%s::%d::TransformationScript"), getOwnerName(), m_id);
984 PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, m_id, "ssd", buffer, vm->getErrorText(), m_id);
985 nxlog_write(MSG_TRANSFORMATION_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "dsdss",
986 getOwnerId(), getOwnerName(), m_id, m_name, vm->getErrorText());
0156d6b2 987 success = false;
5039dede 988 }
4804be4e 989 delete vm;
5039dede 990 }
0156d6b2 991 return success;
5039dede
AK
992}
993
6fd6de0a
VK
994/**
995 * Set new ID and node/template association
996 */
967893bb 997void DCItem::changeBinding(UINT32 dwNewId, Template *pNewNode, BOOL doMacroExpansion)
5039dede 998{
cc8ce218 999 DCObject::changeBinding(dwNewId, pNewNode, doMacroExpansion);
5039dede 1000
fb05c05b 1001 lock();
5039dede
AK
1002 if (dwNewId != 0)
1003 {
6b8e9f96 1004 for(int i = 0; i < getThresholdCount(); i++)
4804be4e 1005 m_thresholds->get(i)->bindToItem(m_id, m_owner->getId());
5039dede
AK
1006 }
1007
fb05c05b 1008 clearCache();
822b5878 1009 updateCacheSizeInternal(true);
fb05c05b 1010 unlock();
5039dede
AK
1011}
1012
6fd6de0a
VK
1013/**
1014 * Update required cache size depending on thresholds
1015 * dwCondId is an identifier of calling condition object id. If it is not 0,
1016 * GetCacheSizeForDCI should be called with bNoLock == TRUE for appropriate
1017 * condition object
1018 */
822b5878 1019void DCItem::updateCacheSizeInternal(bool allowLoad, UINT32 conditionId)
5039dede 1020{
5039dede 1021 // Sanity check
4804be4e 1022 if (m_owner == NULL)
5039dede 1023 {
1ea32b7e 1024 nxlog_debug(3, _T("DCItem::updateCacheSize() called for DCI %d when m_owner == NULL"), m_id);
5039dede
AK
1025 return;
1026 }
1027
1028 // Minimum cache size is 1 for nodes (so GetLastValue can work)
1029 // and it is always 0 for templates
46e2b370 1030 if (((m_owner->isDataCollectionTarget() && (m_owner->getObjectClass() != OBJECT_CLUSTER)) ||
4804be4e 1031 ((m_owner->getObjectClass() == OBJECT_CLUSTER) && isAggregateOnCluster())) &&
85ae39bc 1032 (m_instanceDiscoveryMethod == IDM_NONE))
5039dede 1033 {
822b5878 1034 UINT32 requiredSize = 1;
5039dede
AK
1035
1036 // Calculate required cache size
6b8e9f96 1037 for(int i = 0; i < getThresholdCount(); i++)
822b5878
VK
1038 if (requiredSize < m_thresholds->get(i)->getRequiredCacheSize())
1039 requiredSize = m_thresholds->get(i)->getRequiredCacheSize();
5039dede 1040
da9cf449 1041 ObjectArray<NetObj> *conditions = g_idxConditionById.getObjects(true);
6b8e9f96 1042 for(int i = 0; i < conditions->size(); i++)
5039dede 1043 {
9f06d008 1044 ConditionObject *c = (ConditionObject *)conditions->get(i);
822b5878
VK
1045 UINT32 size = c->getCacheSizeForDCI(m_id, conditionId == c->getId());
1046 if (size > requiredSize)
1047 requiredSize = size;
da9cf449 1048 c->decRefCount();
5039dede 1049 }
d5e19c61 1050 delete conditions;
822b5878
VK
1051
1052 m_requiredCacheSize = requiredSize;
5039dede
AK
1053 }
1054 else
1055 {
822b5878 1056 m_requiredCacheSize = 0;
5039dede
AK
1057 }
1058
822b5878
VK
1059 nxlog_debug_tag(_T("obj.dc.cache"), 8, _T("DCItem::updateCacheSizeInternal(dci=\"%s\", node=%s [%d]): requiredSize=%d cacheSize=%d"),
1060 m_name, m_owner->getName(), m_owner->getId(), m_requiredCacheSize, m_cacheSize);
1061
5039dede 1062 // Update cache if needed
822b5878 1063 if (m_requiredCacheSize < m_cacheSize)
5039dede
AK
1064 {
1065 // Destroy unneeded values
d140955e 1066 if (m_cacheSize > 0)
6b8e9f96 1067 {
822b5878 1068 for(UINT32 i = m_requiredCacheSize; i < m_cacheSize; i++)
5039dede 1069 delete m_ppValueCache[i];
6b8e9f96 1070 }
5039dede 1071
822b5878 1072 m_cacheSize = m_requiredCacheSize;
d140955e 1073 if (m_cacheSize > 0)
5039dede 1074 {
d140955e 1075 m_ppValueCache = (ItemValue **)realloc(m_ppValueCache, sizeof(ItemValue *) * m_cacheSize);
5039dede
AK
1076 }
1077 else
1078 {
1ea32b7e 1079 free(m_ppValueCache);
5039dede
AK
1080 m_ppValueCache = NULL;
1081 }
1082 }
822b5878 1083 else if (m_requiredCacheSize > m_cacheSize)
5039dede 1084 {
5039dede 1085 // Load missing values from database
48f47154
VK
1086 // Skip caching for DCIs where estimated time to fill the cache is less then 5 minutes
1087 // to reduce load on database at server startup
822b5878 1088 if (allowLoad && (m_owner != NULL) && (((m_requiredCacheSize - m_cacheSize) * m_iPollingInterval > 300) || (m_source == DS_PUSH_AGENT)))
5039dede 1089 {
d140955e 1090 m_bCacheLoaded = false;
5eecfc25 1091 g_dciCacheLoaderQueue.put(new DCObjectInfo(this));
d140955e
VK
1092 }
1093 else
1094 {
1095 // will not read data from database, fill cache with empty values
822b5878
VK
1096 m_ppValueCache = (ItemValue **)realloc(m_ppValueCache, sizeof(ItemValue *) * m_requiredCacheSize);
1097 for(UINT32 i = m_cacheSize; i < m_requiredCacheSize; i++)
d140955e
VK
1098 m_ppValueCache[i] = new ItemValue(_T(""), 1);
1099 DbgPrintf(7, _T("Cache load skipped for parameter %s [%d]"), m_name, (int)m_id);
822b5878 1100 m_cacheSize = m_requiredCacheSize;
717b277d 1101 m_bCacheLoaded = true;
d140955e 1102 }
d140955e 1103 }
d140955e 1104}
5039dede 1105
d140955e
VK
1106/**
1107 * Reload cache from database
1108 */
1109void DCItem::reloadCache()
1110{
1111 TCHAR szBuffer[MAX_DB_STRING];
5039dede 1112
d140955e
VK
1113 switch(g_dbSyntax)
1114 {
1115 case DB_SYNTAX_MSSQL:
1116 _sntprintf(szBuffer, MAX_DB_STRING, _T("SELECT TOP %d idata_value,idata_timestamp FROM idata_%d ")
1117 _T("WHERE item_id=%d ORDER BY idata_timestamp DESC"),
4804be4e 1118 m_requiredCacheSize, m_owner->getId(), m_id);
d140955e
VK
1119 break;
1120 case DB_SYNTAX_ORACLE:
1121 _sntprintf(szBuffer, MAX_DB_STRING, _T("SELECT * FROM (SELECT idata_value,idata_timestamp FROM idata_%d ")
1122 _T("WHERE item_id=%d ORDER BY idata_timestamp DESC) WHERE ROWNUM <= %d"),
4804be4e 1123 m_owner->getId(), m_id, m_requiredCacheSize);
d140955e
VK
1124 break;
1125 case DB_SYNTAX_MYSQL:
1126 case DB_SYNTAX_PGSQL:
1127 case DB_SYNTAX_SQLITE:
1128 _sntprintf(szBuffer, MAX_DB_STRING, _T("SELECT idata_value,idata_timestamp FROM idata_%d ")
1129 _T("WHERE item_id=%d ORDER BY idata_timestamp DESC LIMIT %d"),
4804be4e 1130 m_owner->getId(), m_id, m_requiredCacheSize);
d140955e
VK
1131 break;
1132 case DB_SYNTAX_DB2:
1133 _sntprintf(szBuffer, MAX_DB_STRING, _T("SELECT idata_value,idata_timestamp FROM idata_%d ")
1134 _T("WHERE item_id=%d ORDER BY idata_timestamp DESC FETCH FIRST %d ROWS ONLY"),
4804be4e 1135 m_owner->getId(), m_id, m_requiredCacheSize);
d140955e
VK
1136 break;
1137 default:
1138 _sntprintf(szBuffer, MAX_DB_STRING, _T("SELECT idata_value,idata_timestamp FROM idata_%d ")
1139 _T("WHERE item_id=%d ORDER BY idata_timestamp DESC"),
4804be4e 1140 m_owner->getId(), m_id);
d140955e
VK
1141 break;
1142 }
392f3205 1143
d140955e 1144 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
f17cf019 1145 DB_UNBUFFERED_RESULT hResult = DBSelectUnbuffered(hdb, szBuffer);
392f3205 1146
d140955e 1147 lock();
392f3205 1148
717b277d
VK
1149 UINT32 i;
1150 for(i = 0; i < m_cacheSize; i++)
1151 delete m_ppValueCache[i];
1152
1153 if (m_cacheSize != m_requiredCacheSize)
d140955e 1154 {
717b277d
VK
1155 m_ppValueCache = (ItemValue **)realloc(m_ppValueCache, sizeof(ItemValue *) * m_requiredCacheSize);
1156 }
5039dede 1157
822b5878
VK
1158 nxlog_debug_tag(_T("obj.dc.cache"), 8, _T("DCItem::reloadCache(dci=\"%s\", node=%s [%d]): requiredSize=%d cacheSize=%d"),
1159 m_name, m_owner->getName(), m_owner->getId(), m_requiredCacheSize, m_cacheSize);
717b277d
VK
1160 if (hResult != NULL)
1161 {
1162 // Create cache entries
1163 bool moreData = true;
1164 for(i = 0; (i < m_requiredCacheSize) && moreData; i++)
d140955e 1165 {
717b277d
VK
1166 moreData = DBFetch(hResult);
1167 if (moreData)
d140955e 1168 {
f17cf019
VK
1169 DBGetField(hResult, 0, szBuffer, MAX_DB_STRING);
1170 m_ppValueCache[i] = new ItemValue(szBuffer, DBGetFieldULong(hResult, 1));
5039dede
AK
1171 }
1172 else
1173 {
d140955e 1174 m_ppValueCache[i] = new ItemValue(_T(""), 1); // Empty value
5039dede 1175 }
48f47154 1176 }
d140955e
VK
1177
1178 // Fill up cache with empty values if we don't have enough values in database
822b5878
VK
1179 if (i < m_requiredCacheSize)
1180 {
1181 nxlog_debug_tag(_T("obj.dc.cache"), 8, _T("DCItem::reloadCache(dci=\"%s\", node=%s [%d]): %d values missing in DB"),
1182 m_name, m_owner->getName(), m_owner->getId(), m_requiredCacheSize - i);
1183 for(; i < m_requiredCacheSize; i++)
1184 m_ppValueCache[i] = new ItemValue(_T(""), 1);
1185 }
f17cf019 1186 DBFreeResult(hResult);
5039dede 1187 }
d140955e
VK
1188 else
1189 {
1190 // Error reading data from database, fill cache with empty values
717b277d 1191 for(i = 0; i < m_requiredCacheSize; i++)
d140955e
VK
1192 m_ppValueCache[i] = new ItemValue(_T(""), 1);
1193 }
392f3205 1194
717b277d 1195 m_cacheSize = m_requiredCacheSize;
cc8ce218 1196 m_bCacheLoaded = true;
d140955e 1197 unlock();
392f3205 1198
d140955e 1199 DBConnectionPoolReleaseConnection(hdb);
5039dede
AK
1200}
1201
6fd6de0a
VK
1202/**
1203 * Put last value into CSCP message
1204 */
b368969c 1205void DCItem::fillLastValueMessage(NXCPMessage *pMsg, UINT32 dwId)
5039dede 1206{
0506004f 1207 lock();
b368969c
VK
1208 pMsg->setField(dwId++, m_id);
1209 pMsg->setField(dwId++, m_name);
4804be4e 1210 pMsg->setField(dwId++, m_description);
b60584cf 1211 pMsg->setField(dwId++, (UINT16)m_source);
d140955e 1212 if (m_cacheSize > 0)
5039dede 1213 {
b60584cf
VK
1214 pMsg->setField(dwId++, (UINT16)m_dataType);
1215 pMsg->setField(dwId++, m_ppValueCache[0]->getString());
3055d973 1216 pMsg->setFieldFromTime(dwId++, m_ppValueCache[0]->getTimeStamp());
5039dede
AK
1217 }
1218 else
1219 {
b60584cf 1220 pMsg->setField(dwId++, (UINT16)DCI_DT_NULL);
b368969c
VK
1221 pMsg->setField(dwId++, _T(""));
1222 pMsg->setField(dwId++, (UINT32)0);
5039dede 1223 }
b368969c
VK
1224 pMsg->setField(dwId++, (WORD)(matchClusterResource() ? m_status : ITEM_STATUS_DISABLED)); // show resource-bound DCIs as inactive if cluster resource is not on this node
1225 pMsg->setField(dwId++, (WORD)getType());
1226 pMsg->setField(dwId++, m_dwErrorCount);
1227 pMsg->setField(dwId++, m_dwTemplateItemId);
941409ee 1228
6b8e9f96
VK
1229 int i;
1230 for(i = 0; i < getThresholdCount(); i++)
941409ee 1231 {
6b8e9f96 1232 if (m_thresholds->get(i)->isReached())
941409ee
VK
1233 break;
1234 }
6b8e9f96 1235 if (i < getThresholdCount())
941409ee 1236 {
b368969c 1237 pMsg->setField(dwId++, (WORD)1);
6b8e9f96 1238 m_thresholds->get(i)->createMessage(pMsg, dwId);
941409ee
VK
1239 }
1240 else
1241 {
b368969c 1242 pMsg->setField(dwId++, (WORD)0);
941409ee
VK
1243 }
1244
0506004f 1245 unlock();
5039dede
AK
1246}
1247
6fd6de0a
VK
1248/**
1249 * Get item's last value for use in NXSL
1250 */
42c782b1
VK
1251NXSL_Value *DCItem::getRawValueForNXSL()
1252{
1253 lock();
1254 NXSL_Value *value = new NXSL_Value(m_prevRawValue.getString());
1255 unlock();
1256 return value;
1257}
1258
1259/**
1260 * Get item's last value for use in NXSL
1261 */
fb05c05b 1262NXSL_Value *DCItem::getValueForNXSL(int nFunction, int nPolls)
5039dede
AK
1263{
1264 NXSL_Value *pValue;
1265
0506004f 1266 lock();
5039dede
AK
1267 switch(nFunction)
1268 {
1269 case F_LAST:
3f229efb 1270 // cache placeholders will have timestamp 1
77b2c6de 1271 pValue = (m_bCacheLoaded && (m_cacheSize > 0) && (m_ppValueCache[0]->getTimeStamp() != 1)) ? new NXSL_Value(m_ppValueCache[0]->getString()) : new NXSL_Value;
5039dede
AK
1272 break;
1273 case F_DIFF:
77b2c6de 1274 if (m_bCacheLoaded && (m_cacheSize >= 2))
5039dede
AK
1275 {
1276 ItemValue result;
ced80327 1277 CalculateItemValueDiff(result, m_dataType, *m_ppValueCache[0], *m_ppValueCache[1]);
df94e0ce 1278 pValue = new NXSL_Value(result.getString());
5039dede
AK
1279 }
1280 else
1281 {
1282 pValue = new NXSL_Value;
1283 }
1284 break;
1285 case F_AVERAGE:
77b2c6de 1286 if (m_bCacheLoaded && (m_cacheSize > 0))
5039dede
AK
1287 {
1288 ItemValue result;
78032263 1289 CalculateItemValueAverage(result, m_dataType, std::min(m_cacheSize, (UINT32)nPolls), m_ppValueCache);
df94e0ce 1290 pValue = new NXSL_Value(result.getString());
5039dede
AK
1291 }
1292 else
1293 {
1294 pValue = new NXSL_Value;
1295 }
1296 break;
1297 case F_DEVIATION:
77b2c6de 1298 if (m_bCacheLoaded && (m_cacheSize > 0))
5039dede
AK
1299 {
1300 ItemValue result;
78032263 1301 CalculateItemValueMD(result, m_dataType, std::min(m_cacheSize, (UINT32)nPolls), m_ppValueCache);
df94e0ce 1302 pValue = new NXSL_Value(result.getString());
5039dede
AK
1303 }
1304 else
1305 {
1306 pValue = new NXSL_Value;
1307 }
1308 break;
1309 case F_ERROR:
967893bb 1310 pValue = new NXSL_Value((INT32)((m_dwErrorCount >= (UINT32)nPolls) ? 1 : 0));
5039dede
AK
1311 break;
1312 default:
1313 pValue = new NXSL_Value;
1314 break;
1315 }
0506004f 1316 unlock();
5039dede
AK
1317 return pValue;
1318}
1319
4a435beb
VK
1320/**
1321 * Get last value
1322 */
1323const TCHAR *DCItem::getLastValue()
1324{
1325 lock();
d140955e 1326 const TCHAR *v = (m_cacheSize > 0) ? (const TCHAR *)m_ppValueCache[0]->getString() : NULL;
4a435beb
VK
1327 unlock();
1328 return v;
1329}
5039dede 1330
4a435beb 1331/**
85ae39bc
VK
1332 * Get copy of internal last value object. Caller is responsible for destroying returned object.
1333 */
1334ItemValue *DCItem::getInternalLastValue()
1335{
1336 lock();
d140955e 1337 ItemValue *v = (m_cacheSize > 0) ? new ItemValue(m_ppValueCache[0]) : NULL;
85ae39bc
VK
1338 unlock();
1339 return v;
1340}
1341
1342/**
2852ef09
VK
1343 * Get aggregate value. Returned value must be deallocated by caller.
1344 *
1345 * @return dynamically allocated value or NULL on error
1346 */
1347TCHAR *DCItem::getAggregateValue(AggregationFunction func, time_t periodStart, time_t periodEnd)
1348{
1349 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1350 TCHAR query[1024];
1351 TCHAR *result = NULL;
392f3205 1352
2852ef09
VK
1353 static const TCHAR *functions[] = { _T(""), _T("min"), _T("max"), _T("avg"), _T("sum") };
1354
1355 if (g_dbSyntax == DB_SYNTAX_ORACLE)
1356 {
1357 _sntprintf(query, 1024, _T("SELECT %s(coalesce(to_number(idata_value),0)) FROM idata_%u ")
392f3205 1358 _T("WHERE item_id=? AND idata_timestamp BETWEEN ? AND ?"),
4804be4e 1359 functions[func], m_owner->getId());
2852ef09
VK
1360 }
1361 else if (g_dbSyntax == DB_SYNTAX_MSSQL)
1362 {
1363 _sntprintf(query, 1024, _T("SELECT %s(coalesce(cast(idata_value as float),0)) FROM idata_%u ")
392f3205 1364 _T("WHERE item_id=? AND (idata_timestamp BETWEEN ? AND ?) AND isnumeric(idata_value)=1"),
4804be4e 1365 functions[func], m_owner->getId());
2852ef09
VK
1366 }
1367 else if (g_dbSyntax == DB_SYNTAX_PGSQL)
1368 {
dc9ba563
VK
1369 _sntprintf(query, 1024, _T("SELECT %s(idata_value::double precision) FROM idata_%u ")
1370 _T("WHERE item_id=? AND idata_timestamp BETWEEN ? AND ? AND idata_value~E'^\\\\d+(\\\\.\\\\d+)*$'"),
4804be4e 1371 functions[func], m_owner->getId());
2852ef09
VK
1372 }
1373 else
1374 {
1375 _sntprintf(query, 1024, _T("SELECT %s(coalesce(idata_value,0)) FROM idata_%u ")
392f3205 1376 _T("WHERE item_id=? and idata_timestamp between ? and ?"),
4804be4e 1377 functions[func], m_owner->getId());
2852ef09
VK
1378 }
1379
1380 DB_STATEMENT hStmt = DBPrepare(hdb, query);
1381 if (hStmt != NULL)
1382 {
1383 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
1384 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (INT32)periodStart);
1385 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (INT32)periodEnd);
1386 DB_RESULT hResult = DBSelectPrepared(hStmt);
1387 if (hResult != NULL)
1388 {
1389 if (DBGetNumRows(hResult) == 1)
1390 {
1391 result = DBGetField(hResult, 0, 0, NULL, 0);
1392 }
1393 DBFreeResult(hResult);
1394 }
1395 DBFreeStatement(hStmt);
1396 }
1397
1398 DBConnectionPoolReleaseConnection(hdb);
1399 return result;
5039dede
AK
1400}
1401
a294a36f
VK
1402/**
1403 * Delete all collected data
1404 */
cc8ce218 1405bool DCItem::deleteAllData()
5039dede
AK
1406{
1407 TCHAR szQuery[256];
cc8ce218 1408 bool success;
5039dede 1409
fb05c05b 1410 lock();
035745fc 1411 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
4804be4e 1412 _sntprintf(szQuery, 256, _T("DELETE FROM idata_%d WHERE item_id=%d"), m_owner->getId(), m_id);
035745fc
VK
1413 success = DBQuery(hdb, szQuery) ? true : false;
1414 DBConnectionPoolReleaseConnection(hdb);
fb05c05b 1415 clearCache();
822b5878 1416 updateCacheSizeInternal(true);
fb05c05b 1417 unlock();
5039dede
AK
1418 return success;
1419}
1420
6b8e9f96
VK
1421/**
1422 * Update from template item
1423 */
16d6f798 1424void DCItem::updateFromTemplate(DCObject *src)
5039dede 1425{
16d6f798
VK
1426 DCObject::updateFromTemplate(src);
1427
1428 if (src->getType() != DCO_TYPE_ITEM)
1429 {
c42b4551 1430 DbgPrintf(2, _T("INTERNAL ERROR: DCItem::updateFromTemplate(%d, %d): source type is %d"), (int)m_id, (int)src->getId(), src->getType());
16d6f798
VK
1431 return;
1432 }
5039dede 1433
fb05c05b 1434 lock();
16d6f798 1435 DCItem *item = (DCItem *)src;
5039dede 1436
16d6f798
VK
1437 m_dataType = item->m_dataType;
1438 m_deltaCalculation = item->m_deltaCalculation;
05865506 1439 m_sampleCount = item->m_sampleCount;
b97a7955 1440 m_snmpRawValueType = item->m_snmpRawValueType;
ccddd54c 1441
16d6f798
VK
1442 m_nBaseUnits = item->m_nBaseUnits;
1443 m_nMultiplier = item->m_nMultiplier;
6b8e9f96
VK
1444 safe_free(m_customUnitName);
1445 m_customUnitName = (item->m_customUnitName != NULL) ? _tcsdup(item->m_customUnitName) : NULL;
5039dede
AK
1446
1447 // Copy thresholds
1448 // ***************************
1449 // First, skip matching thresholds
78032263 1450 int count = std::min(getThresholdCount(), item->getThresholdCount());
6b8e9f96
VK
1451 int i;
1452 for(i = 0; i < count; i++)
1453 if (!m_thresholds->get(i)->compare(item->m_thresholds->get(i)))
5039dede 1454 break;
6b8e9f96 1455 count = i; // First unmatched threshold's position
5039dede
AK
1456
1457 // Delete all original thresholds starting from first unmatched
6b8e9f96
VK
1458 while(count < getThresholdCount())
1459 m_thresholds->remove(count);
5039dede
AK
1460
1461 // (Re)create thresholds starting from first unmatched
6b8e9f96
VK
1462 if ((m_thresholds == NULL) && (item->getThresholdCount() > 0))
1463 m_thresholds = new ObjectArray<Threshold>(item->getThresholdCount(), 8, true);
1464 for(i = count; i < item->getThresholdCount(); i++)
5039dede 1465 {
6b8e9f96
VK
1466 Threshold *t = new Threshold(item->m_thresholds->get(i));
1467 t->createId();
4804be4e 1468 t->bindToItem(m_id, m_owner->getId());
6b8e9f96 1469 m_thresholds->add(t);
5039dede
AK
1470 }
1471
6470750c
VK
1472 // Update data type in thresholds
1473 for(i = 0; i < getThresholdCount(); i++)
1474 m_thresholds->get(i)->setDataType(m_dataType);
1475
822b5878 1476 updateCacheSizeInternal(true);
fb05c05b 1477 unlock();
5039dede
AK
1478}
1479
6b8e9f96 1480/**
6b8e9f96
VK
1481 * Get list of used events
1482 */
47282713 1483void DCItem::getEventList(IntegerArray<UINT32> *eventList)
5039dede 1484{
fb05c05b 1485 lock();
47282713 1486 if (m_thresholds != NULL)
5039dede 1487 {
6b8e9f96 1488 for(int i = 0; i < m_thresholds->size(); i++)
5039dede 1489 {
47282713
VK
1490 eventList->add(m_thresholds->get(i)->getEventCode());
1491 eventList->add(m_thresholds->get(i)->getRearmEventCode());
5039dede
AK
1492 }
1493 }
fb05c05b 1494 unlock();
5039dede
AK
1495}
1496
6b8e9f96
VK
1497/**
1498 * Create management pack record
1499 */
98ef8e4a 1500void DCItem::createExportRecord(String &str)
5039dede 1501{
fb05c05b 1502 lock();
4671afeb 1503
4e0e77e6 1504 str.appendFormattedString(_T("\t\t\t\t<dci id=\"%d\">\n")
98ef8e4a 1505 _T("\t\t\t\t\t<guid>%s</guid>\n")
a7ff20a5
VK
1506 _T("\t\t\t\t\t<name>%s</name>\n")
1507 _T("\t\t\t\t\t<description>%s</description>\n")
1508 _T("\t\t\t\t\t<dataType>%d</dataType>\n")
d02f6b92 1509 _T("\t\t\t\t\t<samples>%d</samples>\n")
a7ff20a5
VK
1510 _T("\t\t\t\t\t<origin>%d</origin>\n")
1511 _T("\t\t\t\t\t<interval>%d</interval>\n")
1512 _T("\t\t\t\t\t<retention>%d</retention>\n")
1513 _T("\t\t\t\t\t<instance>%s</instance>\n")
a65c1819 1514 _T("\t\t\t\t\t<systemTag>%s</systemTag>\n")
a7ff20a5 1515 _T("\t\t\t\t\t<delta>%d</delta>\n")
50ea73e3 1516 _T("\t\t\t\t\t<flags>%d</flags>\n")
e320f8ce 1517 _T("\t\t\t\t\t<snmpRawValueType>%d</snmpRawValueType>\n")
a294a36f
VK
1518 _T("\t\t\t\t\t<snmpPort>%d</snmpPort>\n")
1519 _T("\t\t\t\t\t<instanceDiscoveryMethod>%d</instanceDiscoveryMethod>\n"),
98ef8e4a
VK
1520 (int)m_id, (const TCHAR *)m_guid.toString(),
1521 (const TCHAR *)EscapeStringForXML2(m_name),
4804be4e 1522 (const TCHAR *)EscapeStringForXML2(m_description),
d02f6b92 1523 m_dataType, m_sampleCount, (int)m_source, m_iPollingInterval, m_iRetentionTime,
6b8e9f96 1524 (const TCHAR *)EscapeStringForXML2(m_instance),
a65c1819 1525 (const TCHAR *)EscapeStringForXML2(m_systemTag),
50ea73e3 1526 (int)m_deltaCalculation, (int)m_flags,
a294a36f 1527 (int)m_snmpRawValueType, (int)m_snmpPort, (int)m_instanceDiscoveryMethod);
5039dede 1528
55bdca5a 1529 if (m_transformationScriptSource != NULL)
5039dede 1530 {
a7ff20a5 1531 str += _T("\t\t\t\t\t<transformation>");
4e0e77e6 1532 str.appendPreallocated(EscapeStringForXML(m_transformationScriptSource, -1));
a7ff20a5 1533 str += _T("</transformation>\n");
5039dede
AK
1534 }
1535
e7450f3b 1536 if ((m_schedules != NULL) && (m_schedules->size() > 0))
5039dede 1537 {
a7ff20a5 1538 str += _T("\t\t\t\t\t<schedules>\n");
a01c2a20 1539 for(int i = 0; i < m_schedules->size(); i++)
e7450f3b 1540 str.appendFormattedString(_T("\t\t\t\t\t\t<schedule>%s</schedule>\n"), (const TCHAR *)EscapeStringForXML2(m_schedules->get(i)));
a7ff20a5 1541 str += _T("\t\t\t\t\t</schedules>\n");
5039dede
AK
1542 }
1543
6b8e9f96
VK
1544 if (m_thresholds != NULL)
1545 {
1546 str += _T("\t\t\t\t\t<thresholds>\n");
a01c2a20 1547 for(int i = 0; i < m_thresholds->size(); i++)
6b8e9f96
VK
1548 {
1549 m_thresholds->get(i)->createNXMPRecord(str, i + 1);
1550 }
1551 str += _T("\t\t\t\t\t</thresholds>\n");
1552 }
5039dede 1553
a294a36f
VK
1554 if (m_pszPerfTabSettings != NULL)
1555 {
1556 str += _T("\t\t\t\t\t<perfTabSettings>");
4e0e77e6 1557 str.appendPreallocated(EscapeStringForXML(m_pszPerfTabSettings, -1));
a294a36f
VK
1558 str += _T("</perfTabSettings>\n");
1559 }
1560
1561 if (m_instanceDiscoveryData != NULL)
1562 {
1563 str += _T("\t\t\t\t\t<instanceDiscoveryData>");
4e0e77e6 1564 str.appendPreallocated(EscapeStringForXML(m_instanceDiscoveryData, -1));
a294a36f
VK
1565 str += _T("</instanceDiscoveryData>\n");
1566 }
1567
1568 if (m_instanceFilterSource != NULL)
1569 {
1570 str += _T("\t\t\t\t\t<instanceFilter>");
4e0e77e6 1571 str.appendPreallocated(EscapeStringForXML(m_instanceFilterSource, -1));
a294a36f
VK
1572 str += _T("</instanceFilter>\n");
1573 }
1574
fb05c05b 1575 unlock();
a7ff20a5 1576 str += _T("\t\t\t\t</dci>\n");
5039dede
AK
1577}
1578
6b8e9f96
VK
1579/**
1580 * Add threshold to the list
1581 */
fb05c05b 1582void DCItem::addThreshold(Threshold *pThreshold)
5039dede 1583{
6b8e9f96
VK
1584 if (m_thresholds == NULL)
1585 m_thresholds = new ObjectArray<Threshold>(8, 8, true);
1586 m_thresholds->add(pThreshold);
5039dede
AK
1587}
1588
6b8e9f96
VK
1589/**
1590 * Enumerate all thresholds
1591 */
967893bb 1592BOOL DCItem::enumThresholds(BOOL (* pfCallback)(Threshold *, UINT32, void *), void *pArg)
5039dede 1593{
5039dede
AK
1594 BOOL bRet = TRUE;
1595
fb05c05b 1596 lock();
6b8e9f96 1597 if (m_thresholds != NULL)
5039dede 1598 {
6b8e9f96 1599 for(int i = 0; i < m_thresholds->size(); i++)
5039dede 1600 {
6b8e9f96
VK
1601 if (!pfCallback(m_thresholds->get(i), i, pArg))
1602 {
1603 bRet = FALSE;
1604 break;
1605 }
5039dede
AK
1606 }
1607 }
fb05c05b 1608 unlock();
5039dede
AK
1609 return bRet;
1610}
1611
6b8e9f96
VK
1612/**
1613 * Test DCI's transformation script
1614 */
75f78aef 1615bool DCItem::testTransformation(DataCollectionTarget *object, const TCHAR *script, const TCHAR *value, TCHAR *buffer, size_t bufSize)
4d0c32f3 1616{
fca44b96 1617 bool success = false;
6b29839d
VK
1618 NXSL_VM *vm = NXSLCompileAndCreateVM(script, buffer, (int)bufSize, new NXSL_ServerEnv);
1619 if (vm != NULL)
4d0c32f3 1620 {
6b29839d 1621 NXSL_Value *pValue = new NXSL_Value(value);
297a88eb 1622 vm->setGlobalVariable(_T("$object"), object->createNXSLObject());
c42b4551 1623 if (object->getObjectClass() == OBJECT_NODE)
75f78aef 1624 {
4804be4e 1625 vm->setGlobalVariable(_T("$node"), object->createNXSLObject());
75f78aef 1626 }
4804be4e 1627 //FIXME: vm->setGlobalVariable(_T("$dci"), new NXSL_Value(new NXSL_Object(&g_nxslDciClass, this)));
c42b4551 1628 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((object->getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
4671afeb 1629
6b29839d 1630 if (vm->run(1, &pValue))
4d0c32f3 1631 {
6b29839d 1632 pValue = vm->getResult();
4d0c32f3
VK
1633 if (pValue != NULL)
1634 {
bb5365ed 1635 if (pValue->isNull())
17a9c342
VK
1636 {
1637 nx_strncpy(buffer, _T("(null)"), bufSize);
1638 }
bb5365ed 1639 else if (pValue->isObject())
4d0c32f3
VK
1640 {
1641 nx_strncpy(buffer, _T("(object)"), bufSize);
1642 }
bb5365ed 1643 else if (pValue->isArray())
4d0c32f3
VK
1644 {
1645 nx_strncpy(buffer, _T("(array)"), bufSize);
1646 }
1647 else
1648 {
bb5365ed 1649 const TCHAR *strval;
4d0c32f3 1650
bb5365ed 1651 strval = pValue->getValueAsCString();
4d0c32f3
VK
1652 nx_strncpy(buffer, CHECK_NULL(strval), bufSize);
1653 }
1654 }
1655 else
1656 {
1657 nx_strncpy(buffer, _T("(null)"), bufSize);
1658 }
fca44b96 1659 success = true;
4d0c32f3
VK
1660 }
1661 else
1662 {
6b29839d 1663 nx_strncpy(buffer, vm->getErrorText(), bufSize);
4d0c32f3 1664 }
4d0c32f3 1665 }
dfb95f8f 1666 delete vm;
4d0c32f3
VK
1667 return success;
1668}
071fd171 1669
6b8e9f96
VK
1670/**
1671 * Fill NXCP message with thresholds
1672 */
b368969c 1673void DCItem::fillMessageWithThresholds(NXCPMessage *msg)
071fd171 1674{
071fd171
VK
1675 lock();
1676
b368969c 1677 msg->setField(VID_NUM_THRESHOLDS, (UINT32)getThresholdCount());
967893bb 1678 UINT32 id = VID_DCI_THRESHOLD_BASE;
6b8e9f96 1679 for(int i = 0; i < getThresholdCount(); i++, id += 20)
071fd171 1680 {
6b8e9f96 1681 m_thresholds->get(i)->createMessage(msg, id);
071fd171
VK
1682 }
1683
1684 unlock();
1685}
cc8ce218 1686
6b8e9f96
VK
1687/**
1688 * Check if DCI has active threshold
1689 */
711e5e9a
VK
1690bool DCItem::hasActiveThreshold()
1691{
1692 bool result = false;
1693 lock();
6b8e9f96 1694 for(int i = 0; i < getThresholdCount(); i++)
711e5e9a 1695 {
6b8e9f96 1696 if (m_thresholds->get(i)->isReached())
711e5e9a
VK
1697 {
1698 result = true;
1699 break;
1700 }
1701 }
1702 unlock();
1703 return result;
1704}
1705
6b8e9f96 1706/**
3f4c195f
VK
1707 * Get severity of active threshold. If no active threshold exist, returns SEVERITY_NORMAL.
1708 */
1709int DCItem::getThresholdSeverity()
1710{
1711 int result = SEVERITY_NORMAL;
1712 lock();
1713 for(int i = 0; i < getThresholdCount(); i++)
1714 {
1715 Threshold *t = m_thresholds->get(i);
1716 if (t->isReached())
1717 {
1718 result = t->getCurrentSeverity();
1719 break;
1720 }
1721 }
1722 unlock();
1723 return result;
1724}
1725
1726/**
6b8e9f96
VK
1727 * Returns true if internal cache is loaded. If data collection object
1728 * does not have cache should return true
1729 */
cc8ce218
VK
1730bool DCItem::isCacheLoaded()
1731{
1732 return m_bCacheLoaded;
1733}
d51f2182
VK
1734
1735/**
e9c75749 1736 * Create DCI from import file
e7450f3b
VK
1737 */
1738void DCItem::updateFromImport(ConfigEntry *config)
1739{
1740 DCObject::updateFromImport(config);
1741
77b2c6de 1742 lock();
e7450f3b
VK
1743 m_dataType = (BYTE)config->getSubEntryValueAsInt(_T("dataType"));
1744 m_deltaCalculation = (BYTE)config->getSubEntryValueAsInt(_T("delta"));
1745 m_sampleCount = (BYTE)config->getSubEntryValueAsInt(_T("samples"));
1746 m_snmpRawValueType = (WORD)config->getSubEntryValueAsInt(_T("snmpRawValueType"));
e7450f3b
VK
1747
1748 ConfigEntry *thresholdsRoot = config->findEntry(_T("thresholds"));
1749 if (thresholdsRoot != NULL)
1750 {
1751 ObjectArray<ConfigEntry> *thresholds = thresholdsRoot->getSubEntries(_T("threshold#*"));
1752 if (m_thresholds != NULL)
1753 m_thresholds->clear();
1754 else
1755 m_thresholds = new ObjectArray<Threshold>(thresholds->size(), 8, true);
1756 for(int i = 0; i < thresholds->size(); i++)
1757 {
1758 m_thresholds->add(new Threshold(thresholds->get(i), this));
1759 }
1760 delete thresholds;
1761 }
1762 else
1763 {
1764 delete_and_null(m_thresholds);
1765 }
1766
822b5878 1767 updateCacheSizeInternal(true);
77b2c6de 1768 unlock();
e7450f3b 1769}
e9c75749
EJ
1770
1771/*
1772 * Clone DCI
1773 */
1774DCObject *DCItem::clone()
1775{
1776 return new DCItem(this);
1777}
a31a2d32
VK
1778
1779/**
1780 * Serialize object to JSON
1781 */
1782json_t *DCItem::toJson()
1783{
1784 json_t *root = DCObject::toJson();
1785 json_object_set_new(root, "deltaCalculation", json_integer(m_deltaCalculation));
1786 json_object_set_new(root, "dataType", json_integer(m_dataType));
1787 json_object_set_new(root, "sampleCount", json_integer(m_sampleCount));
1788 json_object_set_new(root, "thresholds", json_object_array(m_thresholds));
1789 json_object_set_new(root, "prevRawValue", json_string_t(m_prevRawValue));
1790 json_object_set_new(root, "prevValueTimeStamp", json_integer(m_tPrevValueTimeStamp));
1791 json_object_set_new(root, "baseUnits", json_integer(m_nBaseUnits));
1792 json_object_set_new(root, "multiplier", json_integer(m_nMultiplier));
1793 json_object_set_new(root, "customUnitName", json_string_t(m_customUnitName));
1794 json_object_set_new(root, "snmpRawValueType", json_integer(m_snmpRawValueType));
1795 json_object_set_new(root, "predictionEngine", json_string_t(m_predictionEngine));
1796 return root;
1797}
822b5878
VK
1798
1799/**
1800 * Prepare DCI object for recalculation (should be executed on DCI copy)
1801 */
1802void DCItem::prepareForRecalc()
1803{
1804 m_tPrevValueTimeStamp = 0;
1805 m_tLastPoll = 0;
1806 updateCacheSizeInternal(false);
1807}
1808
1809/**
1810 * Recalculate old value (should be executed on DCI copy)
1811 */
1812void DCItem::recalculateValue(ItemValue &value)
1813{
1814 if (m_tPrevValueTimeStamp == 0)
1815 m_prevRawValue = value; // Delta should be zero for first poll
1816 ItemValue rawValue = value;
1817
1818 // Cluster can have only aggregated data, and transformation
1819 // should not be used on aggregation
1820 if ((m_owner->getObjectClass() != OBJECT_CLUSTER) || (m_flags & DCF_TRANSFORM_AGGREGATED))
1821 {
1822 if (!transform(value, (value.getTimeStamp() > m_tPrevValueTimeStamp) ? (value.getTimeStamp() - m_tPrevValueTimeStamp) : 0))
1823 {
1824 return;
1825 }
1826 }
1827
1828 if (value.getTimeStamp() > m_tPrevValueTimeStamp)
1829 {
1830 m_prevRawValue = rawValue;
1831 m_tPrevValueTimeStamp = value.getTimeStamp();
1832 }
1833
1834 if ((m_cacheSize > 0) && (value.getTimeStamp() >= m_tPrevValueTimeStamp))
1835 {
1836 delete m_ppValueCache[m_cacheSize - 1];
1837 memmove(&m_ppValueCache[1], m_ppValueCache, sizeof(ItemValue *) * (m_cacheSize - 1));
1838 m_ppValueCache[0] = new ItemValue(&value);
1839 }
1840
1841 m_tLastPoll = value.getTimeStamp();
1842}