fixed issue 286; code sync between RCP and RAP
[public/netxms.git] / src / server / core / dc_nxsl.cpp
CommitLineData
d02f6b92
VK
1/*
2** NetXMS - Network Management System
3** Copyright (C) 2003-2013 Victor Kirhenshtein
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: dc_nxsl.cpp
20**
21**/
22
23#include "nxcore.h"
24
25/**
26 * NXSL function: Get DCI object
27 * First argument is a node object (usually passed to script via $node variable),
28 * and second is DCI ID
29 */
30static int F_GetDCIObject(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
31{
32 if (!argv[0]->isObject())
33 return NXSL_ERR_NOT_OBJECT;
34
35 if (!argv[1]->isInteger())
36 return NXSL_ERR_NOT_INTEGER;
37
38 NXSL_Object *object = argv[0]->getValueAsObject();
39 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
40 return NXSL_ERR_BAD_CLASS;
41
42 Node *node = (Node *)object->getData();
43 DCObject *dci = node->getDCObjectById(argv[1]->getValueAsUInt32());
44 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
45 {
46 *ppResult = new NXSL_Value(new NXSL_Object(&g_nxslDciClass, dci));
47 }
48 else
49 {
50 *ppResult = new NXSL_Value; // Return NULL if DCI not found
51 }
52
53 return 0;
54}
55
56/**
57 * NXSL function: Get DCI value from within transformation script
58 * First argument is a node object (passed to script via $node variable),
59 * and second is DCI ID
60 */
61static int F_GetDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
62{
63 if (!argv[0]->isObject())
64 return NXSL_ERR_NOT_OBJECT;
65
66 if (!argv[1]->isInteger())
67 return NXSL_ERR_NOT_INTEGER;
68
69 NXSL_Object *object = argv[0]->getValueAsObject();
70 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
71 return NXSL_ERR_BAD_CLASS;
72
73 Node *node = (Node *)object->getData();
74 DCObject *dci = node->getDCObjectById(argv[1]->getValueAsUInt32());
75 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
76 {
77 *ppResult = ((DCItem *)dci)->getValueForNXSL(F_LAST, 1);
78 }
79 else
80 {
81 *ppResult = new NXSL_Value; // Return NULL if DCI not found
82 }
83
84 return 0;
85}
86
87/**
88 * Internal implementation of GetDCIValueByName and GetDCIValueByDescription
89 */
90static int GetDciValueExImpl(bool byName, int argc, NXSL_Value **argv, NXSL_Value **ppResult)
91{
92 if (!argv[0]->isObject())
93 return NXSL_ERR_NOT_OBJECT;
94
95 if (!argv[1]->isString())
96 return NXSL_ERR_NOT_STRING;
97
98 NXSL_Object *object = argv[0]->getValueAsObject();
99 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
100 return NXSL_ERR_BAD_CLASS;
101
102 Node *node = (Node *)object->getData();
103 DCObject *dci = byName ? node->getDCObjectByName(argv[1]->getValueAsCString()) : node->getDCObjectByDescription(argv[1]->getValueAsCString());
104 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
105 {
106 *ppResult = ((DCItem *)dci)->getValueForNXSL(F_LAST, 1);
107 }
108 else
109 {
110 *ppResult = new NXSL_Value; // Return NULL if DCI not found
111 }
112
113 return 0;
114}
115
116/**
117 * NXSL function: Get DCI value from within transformation script
118 * First argument is a node object (passed to script via $node variable),
119 * and second is DCI name
120 */
121static int F_GetDCIValueByName(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
122{
123 return GetDciValueExImpl(true, argc, argv, ppResult);
124}
125
126/**
127 * NXSL function: Get DCI value from within transformation script
128 * First argument is a node object (passed to script via $node variable),
129 * and second is DCI description
130 */
131static int F_GetDCIValueByDescription(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
132{
133 return GetDciValueExImpl(false, argc, argv, ppResult);
134}
135
136/**
137 * NXSL function: Find DCI by name
138 */
139static int F_FindDCIByName(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
140{
141 if (!argv[0]->isObject())
142 return NXSL_ERR_NOT_OBJECT;
143
144 if (!argv[1]->isString())
145 return NXSL_ERR_NOT_STRING;
146
147 NXSL_Object *object = argv[0]->getValueAsObject();
148 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
149 return NXSL_ERR_BAD_CLASS;
150
151 Node *node = (Node *)object->getData();
152 DCObject *dci = node->getDCObjectByName(argv[1]->getValueAsCString());
967893bb 153 *ppResult = ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM)) ? new NXSL_Value(dci->getId()) : new NXSL_Value((UINT32)0);
d02f6b92
VK
154 return 0;
155}
156
157/**
158 * NXSL function: Find DCI by description
159 */
160static int F_FindDCIByDescription(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
161{
162 if (!argv[0]->isObject())
163 return NXSL_ERR_NOT_OBJECT;
164
165 if (!argv[1]->isString())
166 return NXSL_ERR_NOT_STRING;
167
168 NXSL_Object *object = argv[0]->getValueAsObject();
169 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
170 return NXSL_ERR_BAD_CLASS;
171
172 Node *node = (Node *)object->getData();
173 DCObject *dci = node->getDCObjectByDescription(argv[1]->getValueAsCString());
967893bb 174 *ppResult = ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM)) ? new NXSL_Value(dci->getId()) : new NXSL_Value((UINT32)0);
d02f6b92
VK
175 return 0;
176}
177
178/**
179 * Get min, max or average of DCI values for a period
180 */
215637cc 181typedef enum { DCI_MIN = 0, DCI_MAX = 1, DCI_AVG = 2, DCI_SUM = 3 } DciSqlFunc_t;
d02f6b92
VK
182
183static int F_GetDCIValueStat(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program, DciSqlFunc_t sqlFunc)
184{
185 if (!argv[0]->isObject())
186 return NXSL_ERR_NOT_OBJECT;
187
188 if (!argv[1]->isInteger() || !argv[2]->isInteger() || !argv[3]->isInteger())
189 return NXSL_ERR_NOT_INTEGER;
190
191 NXSL_Object *object = argv[0]->getValueAsObject();
192 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
193 return NXSL_ERR_BAD_CLASS;
194
195 Node *node = (Node *)object->getData();
967893bb 196 UINT32 nodeId = node->Id();
d02f6b92
VK
197 DCObject *dci = node->getDCObjectById(argv[1]->getValueAsUInt32());
198 if (dci == NULL || dci->getType() != DCO_TYPE_ITEM)
199 {
200 *ppResult = new NXSL_Value; // Return NULL if DCI not found
201 }
202 else
203 {
204 *ppResult = NULL;
205
206 double result = 0.;
207 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
208 TCHAR query[1024];
e8e76b4f 209 static const TCHAR *functions[] = { _T("min"), _T("max"), _T("avg"), _T("sum") };
d02f6b92
VK
210
211 if (g_nDBSyntax == DB_SYNTAX_ORACLE)
212 {
213 _sntprintf(query, 1024, _T("SELECT %s(coalesce(to_number(idata_value),0)) FROM idata_%u ")
214 _T("WHERE item_id=? and idata_timestamp between ? and ?"),
215637cc 215 functions[sqlFunc], node->Id());
d02f6b92
VK
216 }
217 else if (g_nDBSyntax == DB_SYNTAX_PGSQL)
218 {
219 _sntprintf(query, 1024, _T("SELECT %s(coalesce(idata_value::double precision,0)) FROM idata_%u ")
220 _T("WHERE item_id=? and idata_timestamp between ? and ?"),
215637cc 221 functions[sqlFunc], node->Id());
d02f6b92
VK
222 }
223 else
224 {
225 _sntprintf(query, 1024, _T("SELECT %s(coalesce(idata_value,0)) FROM idata_%u ")
226 _T("WHERE item_id=? and idata_timestamp between ? and ?"),
215637cc 227 functions[sqlFunc], node->Id());
d02f6b92
VK
228 }
229
230 DB_STATEMENT hStmt = DBPrepare(hdb, query);
231 if (hStmt != NULL)
232 {
233 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, argv[1]->getValueAsUInt32());
234 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, argv[2]->getValueAsInt32());
235 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, argv[3]->getValueAsInt32());
236 DB_RESULT hResult = DBSelectPrepared(hStmt);
237 if (hResult != NULL)
238 {
239 if (DBGetNumRows(hResult) == 1)
240 {
241 result = DBGetFieldDouble(hResult, 0, 0);
242 }
243 *ppResult = new NXSL_Value(result);
244 DBFreeResult(hResult);
245 }
246 else
247 {
248 *ppResult = new NXSL_Value; // Return NULL if prepared select failed
249 }
250 DBFreeStatement(hStmt);
251 }
252 else
253 {
254 *ppResult = new NXSL_Value; // Return NULL if prepare failed
255 }
256
257 DBConnectionPoolReleaseConnection(hdb);
258 }
259
260 return 0;
261}
262
263/**
264 * Get min of DCI values for a period
265 */
266static int F_GetMinDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
267{
268 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_MIN);
269}
270
271/**
272 * Get max of DCI values for a period
273 */
274static int F_GetMaxDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
275{
276 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_MAX);
277}
278
279/**
280 * Get average of DCI values for a period
281 */
282static int F_GetAvgDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
283{
284 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_AVG);
285}
286
215637cc
VK
287/**
288 * Get average of DCI values for a period
289 */
290static int F_GetSumDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
291{
292 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_SUM);
293}
294
d02f6b92
VK
295/**
296 * NXSL function: create new DCI
297 * Format: CreateDCI(node, origin, name, description, dataType, pollingInterval, retentionTime)
298 * Possible origin values: "agent", "snmp", "internal", "push"
299 * Possible dataType values: "int32", "uint32", "int64", "uint64", "float", "string"
300 * Returns DCI object on success and NULL of failure
301 */
302static int F_CreateDCI(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
303{
304 if (!argv[0]->isObject())
305 return NXSL_ERR_NOT_OBJECT;
306
307 if (!argv[1]->isString() || !argv[2]->isString() || !argv[3]->isString() || !argv[4]->isString())
308 return NXSL_ERR_NOT_STRING;
309
310 if (!argv[5]->isInteger() || !argv[6]->isInteger())
311 return NXSL_ERR_NOT_INTEGER;
312
313 NXSL_Object *object = argv[0]->getValueAsObject();
314 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
315 return NXSL_ERR_BAD_CLASS;
316 Node *node = (Node *)object->getData();
317
318 // Origin
319 static const TCHAR *originNames[] = { _T("internal"), _T("agent"), _T("snmp"), _T("cpsnmp"), _T("push"), NULL };
320 int origin = -1;
321 const TCHAR *name = argv[1]->getValueAsCString();
322 for(int i = 0; originNames[i] != NULL; i++)
323 if (!_tcsicmp(originNames[i], name))
324 {
325 origin = i;
326 break;
327 }
328
329 // Data types
330 static const TCHAR *dtNames[] = { _T("int32"), _T("uint32"), _T("int64"), _T("uint64"), _T("string"), _T("float"), NULL };
331 int dataType = -1;
332 name = argv[4]->getValueAsCString();
333 for(int i = 0; dtNames[i] != NULL; i++)
334 if (!_tcsicmp(dtNames[i], name))
335 {
336 dataType = i;
337 break;
338 }
339
340 int pollingInterval = argv[5]->getValueAsInt32();
341 int retentionTime = argv[6]->getValueAsInt32();
342
343 if ((origin != -1) && (dataType != -1) && (pollingInterval > 0) && (retentionTime > 0))
344 {
345 DCItem *dci = new DCItem(CreateUniqueId(IDG_ITEM), argv[2]->getValueAsCString(),
346 origin, dataType, pollingInterval, retentionTime, node, argv[3]->getValueAsCString());
347 node->addDCObject(dci);
348 *ppResult = new NXSL_Value(new NXSL_Object(&g_nxslDciClass, dci));
349 }
350 else
351 {
352 *ppResult = new NXSL_Value;
353 }
354 return 0;
355}
356
357/**
358 * Additional NXSL functions for DCI manipulation
359 */
360static NXSL_ExtFunction m_nxslDCIFunctions[] =
361{
362 { _T("CreateDCI"), F_CreateDCI, 7 },
363 { _T("FindDCIByName"), F_FindDCIByName, 2 },
364 { _T("FindDCIByDescription"), F_FindDCIByDescription, 2 },
215637cc 365 { _T("GetAvgDCIValue"), F_GetAvgDCIValue, 4 },
d02f6b92
VK
366 { _T("GetDCIObject"), F_GetDCIObject, 2 },
367 { _T("GetDCIValue"), F_GetDCIValue, 2 },
d02f6b92 368 { _T("GetDCIValueByDescription"), F_GetDCIValueByDescription, 2 },
215637cc 369 { _T("GetDCIValueByName"), F_GetDCIValueByName, 2 },
d02f6b92
VK
370 { _T("GetMaxDCIValue"), F_GetMaxDCIValue, 4 },
371 { _T("GetMinDCIValue"), F_GetMinDCIValue, 4 },
215637cc 372 { _T("GetSumDCIValue"), F_GetSumDCIValue, 4 }
d02f6b92
VK
373};
374
375/**
376 * Register DCI-related functions in NXSL environment
377 */
378void RegisterDCIFunctions(NXSL_Environment *pEnv)
379{
380 pEnv->registerFunctionSet(sizeof(m_nxslDCIFunctions) / sizeof(NXSL_ExtFunction), m_nxslDCIFunctions);
381}