2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
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.
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.
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.
26 * Modify DCI summary table. Will create new table if id is 0.
28 * @return RCC ready to be sent to client
30 UINT32
ModifySummaryTable(NXCPMessage
*msg
, LONG
*newId
)
32 LONG id
= msg
->getFieldAsUInt32(VID_SUMMARY_TABLE_ID
);
35 id
= CreateUniqueId(IDG_DCI_SUMMARY_TABLE
);
39 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
41 bool isNew
= !IsDatabaseRecordExist(hdb
, _T("dci_summary_tables"), _T("id"), (UINT32
)id
);
45 hStmt
= DBPrepare(hdb
, _T("INSERT INTO dci_summary_tables (menu_path,title,node_filter,flags,columns,table_dci_name,id,guid) VALUES (?,?,?,?,?,?,?,?)"));
49 hStmt
= DBPrepare(hdb
, _T("UPDATE dci_summary_tables SET menu_path=?,title=?,node_filter=?,flags=?,columns=?,table_dci_name=? WHERE id=?"));
55 DBBind(hStmt
, 1, DB_SQLTYPE_VARCHAR
, msg
->getFieldAsString(VID_MENU_PATH
), DB_BIND_DYNAMIC
);
56 DBBind(hStmt
, 2, DB_SQLTYPE_VARCHAR
, msg
->getFieldAsString(VID_TITLE
), DB_BIND_DYNAMIC
);
57 DBBind(hStmt
, 3, DB_SQLTYPE_TEXT
, msg
->getFieldAsString(VID_FILTER
), DB_BIND_DYNAMIC
);
58 DBBind(hStmt
, 4, DB_SQLTYPE_INTEGER
, msg
->getFieldAsUInt32(VID_FLAGS
));
59 DBBind(hStmt
, 5, DB_SQLTYPE_TEXT
, msg
->getFieldAsString(VID_COLUMNS
), DB_BIND_DYNAMIC
);
60 DBBind(hStmt
, 6, DB_SQLTYPE_VARCHAR
, msg
->getFieldAsString(VID_DCI_NAME
), DB_BIND_DYNAMIC
);
61 DBBind(hStmt
, 7, DB_SQLTYPE_INTEGER
, id
);
65 DBBind(hStmt
, 8, DB_SQLTYPE_VARCHAR
, uuid
::generate());
68 rcc
= DBExecute(hStmt
) ? RCC_SUCCESS
: RCC_DB_FAILURE
;
69 if (rcc
== RCC_SUCCESS
)
70 NotifyClientSessions(NX_NOTIFY_DCISUMTBL_CHANGED
, (UINT32
)id
);
72 DBFreeStatement(hStmt
);
79 DBConnectionPoolReleaseConnection(hdb
);
84 * Delete DCI summary table
86 UINT32
DeleteSummaryTable(LONG tableId
)
88 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
89 UINT32 rcc
= RCC_DB_FAILURE
;
90 DB_STATEMENT hStmt
= DBPrepare(hdb
, _T("DELETE FROM dci_summary_tables WHERE id=?"));
93 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, tableId
);
97 NotifyClientSessions(NX_NOTIFY_DCISUMTBL_DELETED
, (UINT32
)tableId
);
99 DBFreeStatement(hStmt
);
101 DBConnectionPoolReleaseConnection(hdb
);
106 * Create column definition from NXCP message
108 SummaryTableColumn
::SummaryTableColumn(NXCPMessage
*msg
, UINT32 baseId
)
110 msg
->getFieldAsString(baseId
, m_name
, MAX_DB_STRING
);
111 msg
->getFieldAsString(baseId
+ 1, m_dciName
, MAX_PARAM_NAME
);
112 m_flags
= msg
->getFieldAsUInt32(baseId
+ 2);
113 if (msg
->isFieldExist(baseId
+ 3))
114 msg
->getFieldAsString(baseId
+ 3, m_separator
, 16);
116 _tcscpy(m_separator
, _T(";"));
120 * Create export record for column
122 void SummaryTableColumn
::createExportRecord(String
&xml
, int id
)
124 xml
.append(_T("\t\t\t\t<column id=\""));
126 xml
.append(_T("\">\n\t\t\t\t\t<name>"));
127 xml
.appendPreallocated(EscapeStringForXML(m_name
, -1));
128 xml
.append(_T("</name>\n\t\t\t\t\t<dci>"));
129 xml
.appendPreallocated(EscapeStringForXML(m_dciName
, -1));
130 xml
.append(_T("</dci>\n\t\t\t\t\t<flags>"));
132 xml
.append(_T("</flags>\n\t\t\t\t\t<separator>\n"));
133 xml
.append(m_separator
);
134 xml
.append(_T("</separator>\n\t\t\t\t</column>\n"));
138 * Create column definition from configuration string
140 SummaryTableColumn
::SummaryTableColumn(TCHAR
*configStr
)
142 TCHAR
*ptr
= _tcsstr(configStr
, _T("^#^"));
147 TCHAR
*opt
= _tcsstr(ptr
, _T("^#^"));
152 TCHAR
*sep
= _tcsstr(opt
, _T("^#^"));
157 nx_strncpy(m_separator
, sep
, 16);
161 _tcscpy(m_separator
, _T(";"));
163 m_flags
= _tcstoul(opt
, NULL
, 10);
169 nx_strncpy(m_dciName
, ptr
, MAX_PARAM_NAME
);
173 nx_strncpy(m_dciName
, configStr
, MAX_PARAM_NAME
);
176 nx_strncpy(m_name
, configStr
, MAX_DB_STRING
);
180 * Create ad-hoc summary table definition from NXCP message
182 SummaryTable
::SummaryTable(NXCPMessage
*msg
)
185 m_guid
= uuid
::generate();
188 m_flags
= msg
->getFieldAsUInt32(VID_FLAGS
);
189 m_filterSource
= NULL
;
191 m_aggregationFunction
= (AggregationFunction
)msg
->getFieldAsInt16(VID_FUNCTION
);
192 m_periodStart
= msg
->getFieldAsTime(VID_TIME_FROM
);
193 m_periodEnd
= msg
->getFieldAsTime(VID_TIME_TO
);
195 int count
= msg
->getFieldAsInt32(VID_NUM_COLUMNS
);
196 m_columns
= new ObjectArray
<SummaryTableColumn
>(count
, 16, true);
198 UINT32 id
= VID_COLUMN_INFO_BASE
;
199 for(int i
= 0; i
< count
; i
++)
201 m_columns
->add(new SummaryTableColumn(msg
, id
));
204 msg
->getFieldAsString(VID_DCI_NAME
, m_tableDciName
, MAX_PARAM_NAME
);
208 * Create summary table definition from DB data
210 SummaryTable
::SummaryTable(INT32 id
, DB_RESULT hResult
)
214 DBGetField(hResult
, 0, 0, m_title
, MAX_DB_STRING
);
215 m_flags
= DBGetFieldULong(hResult
, 0, 1);
216 m_guid
= DBGetFieldGUID(hResult
, 0, 2);
217 DBGetField(hResult
, 0, 3, m_menuPath
, MAX_DB_STRING
);
219 m_aggregationFunction
= DCI_AGG_LAST
;
224 m_filterSource
= DBGetField(hResult
, 0, 4, NULL
, 0);
225 if (m_filterSource
!= NULL
)
227 StrStrip(m_filterSource
);
228 if (*m_filterSource
!= 0)
230 TCHAR errorText
[1024];
231 m_filter
= NXSLCompileAndCreateVM(m_filterSource
, errorText
, 1024, new NXSL_ServerEnv
);
232 if (m_filter
== NULL
)
234 nxlog_debug(4, _T("Error compiling filter script for DCI summary table: %s"), errorText
);
248 m_columns
= new ObjectArray
<SummaryTableColumn
>(16, 16, true);
249 TCHAR
*config
= DBGetField(hResult
, 0, 5, NULL
, 0);
250 if ((config
!= NULL
) && (*config
!= 0))
252 TCHAR
*curr
= config
;
255 TCHAR
*next
= _tcsstr(curr
, _T("^~^"));
261 m_columns
->add(new SummaryTableColumn(curr
));
266 DBGetField(hResult
, 0, 6, m_tableDciName
, MAX_PARAM_NAME
);
270 * Load summary table object from database
272 SummaryTable
*SummaryTable
::loadFromDB(INT32 id
, UINT32
*rcc
)
274 nxlog_debug(4, _T("Loading configuration for DCI summary table %d"), id
);
275 SummaryTable
*table
= NULL
;
276 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
277 DB_STATEMENT hStmt
= DBPrepare(hdb
, _T("SELECT title,flags,guid,menu_path,node_filter,columns,table_dci_name FROM dci_summary_tables WHERE id=?"));
280 DBBind(hStmt
, 1, DB_SQLTYPE_INTEGER
, id
);
281 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
284 if (DBGetNumRows(hResult
) > 0)
286 table
= new SummaryTable(id
, hResult
);
291 *rcc
= RCC_INVALID_SUMMARY_TABLE_ID
;
293 DBFreeResult(hResult
);
297 *rcc
= RCC_DB_FAILURE
;
299 DBFreeStatement(hStmt
);
303 *rcc
= RCC_DB_FAILURE
;
305 DBConnectionPoolReleaseConnection(hdb
);
306 nxlog_debug(4, _T("SummaryTable::loadFromDB(%d): object=%p, rcc=%d"), id
, table
, (int)*rcc
);
313 SummaryTable
::~SummaryTable()
317 free(m_filterSource
);
321 * Pass node through filter
323 bool SummaryTable
::filter(DataCollectionTarget
*object
)
325 if (m_filter
== NULL
)
326 return true; // no filtering
329 m_filter
->setGlobalVariable(_T("$object"), object
->createNXSLObject());
330 if (object
->getObjectClass() == OBJECT_NODE
)
331 m_filter
->setGlobalVariable(_T("$node"), object
->createNXSLObject());
334 NXSL_Value
*value
= m_filter
->getResult();
337 result
= value
->getValueAsInt32() ?
true : false;
342 nxlog_debug(4, _T("Error executing filter script for DCI summary table: %s"), m_filter
->getErrorText());
348 * Create empty result table
350 Table
*SummaryTable
::createEmptyResultTable()
352 Table
*result
= new Table();
353 result
->setTitle(m_title
);
354 result
->setExtendedFormat(true);
355 result
->addColumn(_T("Node"), DCI_DT_STRING
);
356 if (m_flags
& SUMMARY_TABLE_MULTI_INSTANCE
)
357 result
->addColumn(_T("Instance"), DCI_DT_STRING
);
359 if (!(m_flags
& SUMMARY_TABLE_TABLE_DCI_SOURCE
))
361 for(int i
= 0; i
< m_columns
->size(); i
++)
363 result
->addColumn(m_columns
->get(i
)->m_name
, DCI_DT_STRING
);
370 * Create export record
372 void SummaryTable
::createExportRecord(String
&xml
) const
376 xml
.append(_T("\t\t<table id=\""));
378 xml
.append(_T("\">\n\t\t\t<guid>"));
379 xml
.append(m_guid
.toString(buffer
));
380 xml
.append(_T("</guid>\n\t\t\t<title>"));
381 xml
.appendPreallocated(EscapeStringForXML(m_title
, -1));
382 xml
.append(_T("</title>\n\t\t\t<flags>"));
384 xml
.append(_T("</flags>\n\t\t\t<path>"));
385 xml
.appendPreallocated(EscapeStringForXML(m_menuPath
, -1));
386 xml
.append(_T("</path>\n\t\t\t<filter>"));
387 xml
.appendPreallocated(EscapeStringForXML(m_filterSource
, -1));
388 xml
.append(_T("</filter>\n\t\t\t<tableDci>\n"));
389 xml
.appendPreallocated(EscapeStringForXML(m_tableDciName
, -1));
390 xml
.append(_T("</tableDci>\n\t\t\t<columns>\n"));
391 for(int i
= 0; i
< m_columns
->size(); i
++)
393 m_columns
->get(i
)->createExportRecord(xml
, i
+ 1);
395 xml
.append(_T("\t\t\t</columns>\n\t\t</table>\n"));
399 * Query summary table
401 Table
*QuerySummaryTable(LONG tableId
, SummaryTable
*adHocDefinition
, UINT32 baseObjectId
, UINT32 userId
, UINT32
*rcc
)
403 NetObj
*object
= FindObjectById(baseObjectId
);
406 *rcc
= RCC_INVALID_OBJECT_ID
;
409 if (!object
->checkAccessRights(userId
, OBJECT_ACCESS_READ
))
411 *rcc
= RCC_ACCESS_DENIED
;
414 if ((object
->getObjectClass() != OBJECT_CONTAINER
) && (object
->getObjectClass() != OBJECT_CLUSTER
) &&
415 (object
->getObjectClass() != OBJECT_SERVICEROOT
) && (object
->getObjectClass() != OBJECT_SUBNET
) &&
416 (object
->getObjectClass() != OBJECT_ZONE
) && (object
->getObjectClass() != OBJECT_NETWORK
))
418 *rcc
= RCC_INCOMPATIBLE_OPERATION
;
422 SummaryTable
*tableDefinition
= (adHocDefinition
!= NULL
) ? adHocDefinition
: SummaryTable
::loadFromDB(tableId
, rcc
);
423 if (tableDefinition
== NULL
)
426 ObjectArray
<NetObj
> *childObjects
= object
->getFullChildList(true, true);
427 Table
*tableData
= tableDefinition
->createEmptyResultTable();
428 for(int i
= 0; i
< childObjects
->size(); i
++)
430 NetObj
*obj
= childObjects
->get(i
);
431 if (!obj
->isDataCollectionTarget() || !obj
->checkAccessRights(userId
, OBJECT_ACCESS_READ
))
437 if (tableDefinition
->filter((DataCollectionTarget
*)obj
))
439 ((DataCollectionTarget
*)obj
)->getDciValuesSummary(tableDefinition
, tableData
);
445 delete tableDefinition
;
451 * Create export record for summary table
453 bool CreateSummaryTableExportRecord(INT32 id
, String
&xml
)
456 SummaryTable
*t
= SummaryTable
::loadFromDB(id
, &rcc
);
459 t
->createExportRecord(xml
);
467 static TCHAR
*BuildColumnList(ConfigEntry
*root
)
470 return _tcsdup(_T(""));
473 ObjectArray
<ConfigEntry
> *columns
= root
->getOrderedSubEntries(_T("column#*"));
474 for(int i
= 0; i
< columns
->size(); i
++)
479 ConfigEntry
*c
= columns
->get(i
);
480 s
.append(c
->getSubEntryValue(_T("name")));
482 s
.append(c
->getSubEntryValue(_T("dci")));
484 s
.append(c
->getSubEntryValueAsUInt(_T("flags")));
486 s
.append(c
->getSubEntryValue(_T("separator")));
489 return _tcsdup((const TCHAR
*)s
);
493 * Import failure exit
495 static bool ImportFailure(DB_HANDLE hdb
, DB_STATEMENT hStmt
)
498 DBFreeStatement(hStmt
);
500 DBConnectionPoolReleaseConnection(hdb
);
501 DbgPrintf(4, _T("ImportObjectTool: database failure"));
506 * Import summary table
508 bool ImportSummaryTable(ConfigEntry
*config
)
510 const TCHAR
*guid
= config
->getSubEntryValue(_T("guid"));
513 DbgPrintf(4, _T("ImportSummaryTable: missing GUID"));
518 if (_uuid_parse(guid
, temp
) == -1)
520 DbgPrintf(4, _T("ImportSummaryTable: GUID (%s) is invalid"), guid
);
524 DB_HANDLE hdb
= DBConnectionPoolAcquireConnection();
526 // Step 1: find existing tool ID by GUID
527 DB_STATEMENT hStmt
= DBPrepare(hdb
, _T("SELECT id FROM dci_summary_tables WHERE guid=?"));
530 return ImportFailure(hdb
, NULL
);
533 DBBind(hStmt
, 1, DB_SQLTYPE_VARCHAR
, guid
, DB_BIND_STATIC
);
534 DB_RESULT hResult
= DBSelectPrepared(hStmt
);
537 return ImportFailure(hdb
, hStmt
);
541 if (DBGetNumRows(hResult
) > 0)
543 id
= DBGetFieldULong(hResult
, 0, 0);
549 DBFreeResult(hResult
);
550 DBFreeStatement(hStmt
);
552 // Step 2: create or update summary table configuration record
555 id
= CreateUniqueId(IDG_DCI_SUMMARY_TABLE
);
556 hStmt
= DBPrepare(hdb
, _T("INSERT INTO dci_summary_tables (menu_path,title,node_filter,flags,columns,guid,id) VALUES (?,?,?,?,?,?,?)"));
560 hStmt
= DBPrepare(hdb
, _T("UPDATE dci_summary_tables SET menu_path=?,title=?,node_filter=?,flags=?,columns=?,guid=? WHERE id=?"));
564 return ImportFailure(hdb
, NULL
);
567 DBBind(hStmt
, 1, DB_SQLTYPE_VARCHAR
, config
->getSubEntryValue(_T("path")), DB_BIND_STATIC
);
568 DBBind(hStmt
, 2, DB_SQLTYPE_VARCHAR
, config
->getSubEntryValue(_T("title")), DB_BIND_STATIC
);
569 DBBind(hStmt
, 3, DB_SQLTYPE_TEXT
, config
->getSubEntryValue(_T("filter")), DB_BIND_STATIC
);
570 DBBind(hStmt
, 4, DB_SQLTYPE_INTEGER
, config
->getSubEntryValueAsUInt(_T("flags")));
571 DBBind(hStmt
, 5, DB_SQLTYPE_TEXT
, BuildColumnList(config
->findEntry(_T("columns"))), DB_BIND_DYNAMIC
);
572 DBBind(hStmt
, 6, DB_SQLTYPE_VARCHAR
, guid
, DB_BIND_STATIC
);
573 DBBind(hStmt
, 7, DB_SQLTYPE_INTEGER
, id
);
575 if (!DBExecute(hStmt
))
577 return ImportFailure(hdb
, hStmt
);
580 NotifyClientSessions(NX_NOTIFY_DCISUMTBL_CHANGED
, (UINT32
)id
);
582 DBFreeStatement(hStmt
);
583 DBConnectionPoolReleaseConnection(hdb
);