Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndris Zeila <andris.zeila@zabbix.com>2022-11-10 10:48:49 +0300
committerAndris Zeila <andris.zeila@zabbix.com>2022-11-10 10:48:49 +0300
commit3385fecdb61d2899a9dd50b05c5f6d76180538e1 (patch)
treef49b3828905179a9828cf34adcf2b9378e9df9f8
parenta75008b2130733f32f2ba8b1100da2b9773e7773 (diff)
parenta776758776e65ec288b9dffa688e296980fcff33 (diff)
.......PS. [ZBXNEXT-8040] added object based json parsing and jsonpath optimizations
Merge in ZBX/zabbix from feature/ZBXNEXT-8040-6.0 to release/6.0 * commit 'a776758776e65ec288b9dffa688e296980fcff33': .......PS. [ZBXNEXT-8040] fixed warnings ...G...... [ZBXNEXT-8040] fixed windows agent builds .......PS. [ZBXNEXT-8040] added object based json parsing and jsonpath indexing for simple expressions
-rw-r--r--.gitignore3
-rw-r--r--ChangeLog.d/feature/ZBXNEXT-80401
-rw-r--r--build/mingw/Makefile11
-rw-r--r--build/win32/project/Makefile_agent2
-rw-r--r--build/win32/project/Makefile_get2
-rw-r--r--build/win32/project/Makefile_sender2
-rw-r--r--build/win32/project/Makefile_sender_dll2
-rw-r--r--include/zbxjson.h51
-rw-r--r--src/go/pkg/zbxlib/globals_windows.go2
-rw-r--r--src/libs/zbxjson/Makefile.am4
-rw-r--r--src/libs/zbxjson/json.c14
-rw-r--r--src/libs/zbxjson/json.h2
-rw-r--r--src/libs/zbxjson/json_parser.c127
-rw-r--r--src/libs/zbxjson/json_parser.h8
-rw-r--r--src/libs/zbxjson/jsonobj.c366
-rw-r--r--src/libs/zbxjson/jsonobj.h56
-rw-r--r--src/libs/zbxjson/jsonpath.c1219
-rw-r--r--src/libs/zbxjson/jsonpath.h17
-rw-r--r--src/zabbix_agent/Makefile.am2
-rw-r--r--src/zabbix_server/Makefile.am4
-rw-r--r--src/zabbix_server/preprocessor/item_preproc.c73
-rw-r--r--src/zabbix_server/preprocessor/preproc_cache.c5
-rw-r--r--tests/libs/zbxcommon/Makefile.am2
-rw-r--r--tests/libs/zbxjson/Makefile.am20
-rw-r--r--tests/libs/zbxjson/zbx_jsonobj_query.c (renamed from tests/libs/zbxjson/zbx_jsonpath_query.c)46
-rw-r--r--tests/libs/zbxjson/zbx_jsonobj_query.inc.yaml (renamed from tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml)0
-rw-r--r--tests/libs/zbxjson/zbx_jsonobj_query.yaml (renamed from tests/libs/zbxjson/zbx_jsonpath_query.yaml)182
-rw-r--r--tests/libs/zbxsysinfo/Makefile.am5
-rw-r--r--tests/libs/zbxsysinfo/common/Makefile.am2
-rw-r--r--tests/libs/zbxsysinfo/linux/Makefile.am2
-rw-r--r--tests/zabbix_server/poller/Makefile.am61
-rw-r--r--tests/zabbix_server/preprocessor/zbx_item_preproc.yaml6
32 files changed, 1706 insertions, 593 deletions
diff --git a/.gitignore b/.gitignore
index b47bd411822..a26a06af5c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -195,8 +195,8 @@ tests/libs/zbxhistory/zbx_history_get_values
tests/libs/zbxjson/zbx_json_decodevalue
tests/libs/zbxjson/zbx_json_decodevalue_dyn
tests/libs/zbxjson/zbx_json_open_path
+tests/libs/zbxjson/zbx_jsonobj_query
tests/libs/zbxjson/zbx_jsonpath_compile
-tests/libs/zbxjson/zbx_jsonpath_query
tests/libs/zbxprometheus/prometheus_filter_init
tests/libs/zbxprometheus/prometheus_parse_row
tests/libs/zbxprometheus/zbx_prometheus_pattern
@@ -230,6 +230,7 @@ tests/libs/zbxcommon/zbx_tm_add
tests/libs/zbxcommon/zbx_tm_sub
tests/libs/zbxcommon/zbx_tm_round_up
tests/libs/zbxcommon/zbx_tm_round_down
+tests/libs/zbxtime/zbx_iso8601_utc
tests/libs/zbxtrends/zbx_baseline_get_data
tests/libs/zbxtrends/zbx_trends_parse_range
tests/libs/zbxsysinfo/process_http
diff --git a/ChangeLog.d/feature/ZBXNEXT-8040 b/ChangeLog.d/feature/ZBXNEXT-8040
new file mode 100644
index 00000000000..15238ae2c93
--- /dev/null
+++ b/ChangeLog.d/feature/ZBXNEXT-8040
@@ -0,0 +1 @@
+.......PS. [ZBXNEXT-8040] added object based json parsing and jsonpath optimizations (wiper)
diff --git a/build/mingw/Makefile b/build/mingw/Makefile
index 863565b4e8a..8cdf11d4a57 100644
--- a/build/mingw/Makefile
+++ b/build/mingw/Makefile
@@ -23,6 +23,7 @@ OBJS = \
$(OUTPUTDIR)\md5.o \
$(OUTPUTDIR)\sysinfo.o \
$(OUTPUTDIR)\vector.o \
+ $(OUTPUTDIR)\hashset.o \
$(OUTPUTDIR)\zbxregexp.o \
$(OUTPUTDIR)\persistent_state.o \
$(OUTPUTDIR)\logfiles.o \
@@ -32,6 +33,7 @@ OBJS = \
$(OUTPUTDIR)\json.o \
$(OUTPUTDIR)\json_parser.o \
$(OUTPUTDIR)\jsonpath.o \
+ $(OUTPUTDIR)\jsonobj.o \
$(OUTPUTDIR)\sha256crypt.o \
$(OUTPUTDIR)\variant.o \
$(OUTPUTDIR)\sysinfo_system.o \
@@ -138,6 +140,9 @@ $(OUTPUTDIR)\json_parser.o: $(TOPDIR)\src\libs\zbxjson\json_parser.c
$(OUTPUTDIR)\jsonpath.o: $(TOPDIR)\src\libs\zbxjson\jsonpath.c
$(CC) $(CFLAGS) -DUNICODE -DWITH_COMMON_METRICS -c $^ -o $@
+$(OUTPUTDIR)\jsonobj.o: $(TOPDIR)\src\libs\zbxjson\jsonobj.c
+ $(CC) $(CFLAGS) -DUNICODE -DWITH_COMMON_METRICS -c $^ -o $@
+
$(OUTPUTDIR)\sha256crypt.o: $(TOPDIR)\src\libs\zbxcrypto\sha256crypt.c
$(CC) $(CFLAGS) -DUNICODE -DWITH_COMMON_METRICS -c $^ -o $@
@@ -165,6 +170,12 @@ $(OUTPUTDIR)\sysinfo_dir.o: $(TOPDIR)\src\libs\zbxsysinfo\common\dir.c
$(OUTPUTDIR)\vector.o: $(TOPDIR)\src\libs\zbxalgo\vector.c
$(CC) $(CFLAGS) -DUNICODE -c $^ -o $@
+$(OUTPUTDIR)\hashset.o: $(TOPDIR)\src\libs\zbxalgo\hashset.c
+ $(CC) $(CFLAGS) -DUNICODE -c $^ -o $@
+
+$(OUTPUTDIR)\version.o: $(TOPDIR)\src\libs\zbxversion\version.c
+ $(CC) $(CFLAGS) -DUNICODE -c $^ -o $@
+
$(OUTPUTDIR)\algodefs.o: $(TOPDIR)\src\libs\zbxalgo\algodefs.c
$(CC) $(CFLAGS) -DUNICODE -c $^ -o $@
diff --git a/build/win32/project/Makefile_agent b/build/win32/project/Makefile_agent
index 54c7c5bf354..fc3f5177626 100644
--- a/build/win32/project/Makefile_agent
+++ b/build/win32/project/Makefile_agent
@@ -38,6 +38,7 @@ OBJS = \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
..\..\..\src\libs\zbxcommon\alias.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxcommon\iprange.o \
..\..\..\src\libs\zbxcommon\misc.o \
@@ -58,6 +59,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxsys\mutexs.o \
..\..\..\src\libs\zbxsys\symbols.o \
diff --git a/build/win32/project/Makefile_get b/build/win32/project/Makefile_get
index 9c69d1562e3..b29a11251c8 100644
--- a/build/win32/project/Makefile_get
+++ b/build/win32/project/Makefile_get
@@ -29,6 +29,7 @@ ADD_RFLAGS = /d "ZABBIX_GET"
OBJS = \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxcommon\iprange.o \
..\..\..\src\libs\zbxcommon\misc.o \
@@ -46,6 +47,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxsys\mutexs.o \
..\..\..\src\libs\zbxsys\symbols.o \
diff --git a/build/win32/project/Makefile_sender b/build/win32/project/Makefile_sender
index 544d68941fb..1500aa3afce 100644
--- a/build/win32/project/Makefile_sender
+++ b/build/win32/project/Makefile_sender
@@ -45,6 +45,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxsys\mutexs.o \
..\..\..\src\libs\zbxsys\symbols.o \
@@ -52,6 +53,7 @@ OBJS = \
..\..\..\src\libs\zbxwin32\fatal.o \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxregexp\zbxregexp.o \
..\..\..\src\zabbix_sender\zabbix_sender.o
diff --git a/build/win32/project/Makefile_sender_dll b/build/win32/project/Makefile_sender_dll
index dc9db4547cc..20cbc0d71b6 100644
--- a/build/win32/project/Makefile_sender_dll
+++ b/build/win32/project/Makefile_sender_dll
@@ -51,6 +51,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxsys\mutexs.o \
..\..\..\src\libs\zbxsys\symbols.o \
@@ -58,6 +59,7 @@ OBJS = \
..\..\..\src\libs\zbxwin32\fatal.o \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxregexp\zbxregexp.o \
..\..\..\src\zabbix_sender\win32\zabbix_sender.o
diff --git a/include/zbxjson.h b/include/zbxjson.h
index 8e2d929a01a..0299a219d2f 100644
--- a/include/zbxjson.h
+++ b/include/zbxjson.h
@@ -21,6 +21,7 @@
#define ZABBIX_ZJSON_H
#include "zbxtypes.h"
+#include "zbxalgo.h"
#define ZBX_PROTO_TAG_CLOCK "clock"
#define ZBX_PROTO_TAG_NS "ns"
@@ -234,7 +235,8 @@ typedef enum
ZBX_JSON_TYPE_OBJECT,
ZBX_JSON_TYPE_NULL,
ZBX_JSON_TYPE_TRUE,
- ZBX_JSON_TYPE_FALSE
+ ZBX_JSON_TYPE_FALSE,
+ ZBX_JSON_TYPE_NUMBER
}
zbx_json_type_t;
@@ -312,15 +314,52 @@ typedef struct
int segments_num;
int segments_alloc;
- /* set to 1 when jsonpath points at single location */
- unsigned char definite;
-
- unsigned char first_match;
+ unsigned char definite; /* set to 1 when jsonpath points at single location */
+ unsigned char first_match; /* set to 1 if first match must be returned */
}
zbx_jsonpath_t;
-void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath);
+typedef struct zbx_jsonobj zbx_jsonobj_t;
+
+ZBX_PTR_VECTOR_DECL(jsonobj_ptr, zbx_jsonobj_t *)
+
+typedef union
+{
+ char *string;
+ double number;
+ zbx_hashset_t object;
+ zbx_vector_jsonobj_ptr_t array;
+}
+zbx_jsonobj_data_t;
+
+typedef struct
+{
+ char *path; /* the path that was indexed - for example @.a.b.c */
+ zbx_hashset_t objects;
+}
+zbx_jsonobj_index_t;
+
+struct zbx_jsonobj
+{
+ zbx_json_type_t type;
+ zbx_jsonobj_data_t data;
+ zbx_jsonobj_index_t *index;
+};
+
+typedef struct
+{
+ char *name;
+ zbx_jsonobj_t value;
+}
+zbx_jsonobj_el_t;
+
int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath);
int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output);
+void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath);
+
+int zbx_jsonobj_open(const char *data, zbx_jsonobj_t *obj);
+void zbx_jsonobj_clear(zbx_jsonobj_t *obj);
+int zbx_jsonobj_query(zbx_jsonobj_t *obj, const char *path, char **output);
+int zbx_jsonobj_to_string(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj);
#endif /* ZABBIX_ZJSON_H */
diff --git a/src/go/pkg/zbxlib/globals_windows.go b/src/go/pkg/zbxlib/globals_windows.go
index 17cbe67a30b..c3138979244 100644
--- a/src/go/pkg/zbxlib/globals_windows.go
+++ b/src/go/pkg/zbxlib/globals_windows.go
@@ -39,6 +39,7 @@ package zbxlib
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/md5.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sysinfo.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/vector.o
+#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/hashset.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/zbxregexp.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/algodefs.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/persistent_state.o
@@ -46,6 +47,7 @@ package zbxlib
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/json.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/json_parser.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/jsonpath.o
+#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/jsonobj.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sha256crypt.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/variant.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sysinfo_system.o
diff --git a/src/libs/zbxjson/Makefile.am b/src/libs/zbxjson/Makefile.am
index ad27f80c98e..f7981730a30 100644
--- a/src/libs/zbxjson/Makefile.am
+++ b/src/libs/zbxjson/Makefile.am
@@ -8,4 +8,6 @@ libzbxjson_a_SOURCES = \
json_parser.c \
json_parser.h \
jsonpath.c \
- jsonpath.h
+ jsonpath.h \
+ jsonobj.c \
+ jsonobj.h
diff --git a/src/libs/zbxjson/json.c b/src/libs/zbxjson/json.c
index 4960eca4466..412dcc098cf 100644
--- a/src/libs/zbxjson/json.c
+++ b/src/libs/zbxjson/json.c
@@ -840,7 +840,7 @@ static unsigned int zbx_json_decode_character(const char **p, unsigned char *byt
* string copying failed. *
* *
******************************************************************************/
-static const char *zbx_json_copy_string(const char *p, char *out, size_t size)
+const char *json_copy_string(const char *p, char *out, size_t size)
{
char *start = out;
@@ -919,7 +919,7 @@ const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_j
/* only primitive values are decoded */
return NULL;
default:
- if (0 == (len = json_parse_value(p, NULL)))
+ if (0 == (len = json_parse_value(p, NULL, NULL)))
return NULL;
}
@@ -929,7 +929,7 @@ const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_j
switch (type_local)
{
case ZBX_JSON_TYPE_STRING:
- return zbx_json_copy_string(p, string, size);
+ return json_copy_string(p, string, size);
case ZBX_JSON_TYPE_NULL:
if (0 == size)
return NULL;
@@ -953,7 +953,7 @@ const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *strin
/* only primitive values are decoded */
return NULL;
default:
- if (0 == (len = json_parse_value(p, NULL)))
+ if (0 == (len = json_parse_value(p, NULL, NULL)))
return NULL;
}
@@ -969,7 +969,7 @@ const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *strin
switch (type_local)
{
case ZBX_JSON_TYPE_STRING:
- return zbx_json_copy_string(p, *string, *string_alloc);
+ return json_copy_string(p, *string, *string_alloc);
case ZBX_JSON_TYPE_NULL:
**string = '\0';
return p + len;
@@ -986,7 +986,7 @@ const char *zbx_json_pair_next(const struct zbx_json_parse *jp, const char *p, c
if (ZBX_JSON_TYPE_STRING != __zbx_json_type(p))
return NULL;
- if (NULL == (p = zbx_json_copy_string(p, name, len)))
+ if (NULL == (p = json_copy_string(p, name, len)))
return NULL;
SKIP_WHITESPACE(p);
@@ -1214,7 +1214,7 @@ int json_open_path(const struct zbx_json_parse *jp, const zbx_jsonpath_t *jsonpa
object.start = p;
if (NULL == (object.end = __zbx_json_rbracket(p)))
- object.end = p + json_parse_value(p, NULL) - 1;
+ object.end = p + json_parse_value(p, NULL, NULL) - 1;
}
*out = object;
diff --git a/src/libs/zbxjson/json.h b/src/libs/zbxjson/json.h
index a9b7a4f5f29..2a53f0ec687 100644
--- a/src/libs/zbxjson/json.h
+++ b/src/libs/zbxjson/json.h
@@ -35,4 +35,6 @@ void zbx_set_json_strerror(const char *fmt, ...) __zbx_attr_format_printf(1, 2);
int json_open_path(const struct zbx_json_parse *jp, const zbx_jsonpath_t *jsonpath, struct zbx_json_parse *out);
+const char *json_copy_string(const char *p, char *out, size_t size);
+
#endif
diff --git a/src/libs/zbxjson/json_parser.c b/src/libs/zbxjson/json_parser.c
index 20ce1098437..7f64f4164f2 100644
--- a/src/libs/zbxjson/json_parser.c
+++ b/src/libs/zbxjson/json_parser.c
@@ -21,27 +21,31 @@
#include "common.h"
#include "json.h"
-
-static zbx_int64_t json_parse_object(const char *start, char **error);
+#include "jsonobj.h"
/******************************************************************************
* *
* Purpose: Prepares JSON parsing error message *
* *
- * Parameters: message - [IN] the error message *
- * json_buffer - [IN] the failing data fragment *
- * error - [OUT] the parsing error message (can be NULL) *
+ * Parameters: message - [IN] the error message *
+ * ptr - [IN] the failing data fragment *
+ * error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: 0 - the json_error() function always returns 0 value *
* so it can be used to return from failed parses *
* *
******************************************************************************/
-static zbx_int64_t json_error(const char *message, const char *json_buffer, char **error)
+zbx_int64_t json_error(const char *message, const char *ptr, char **error)
{
if (NULL != error)
{
- if (NULL != json_buffer)
- *error = zbx_dsprintf(*error, "%s at: '%s'", message, json_buffer);
+ if (NULL != ptr)
+ {
+ if (128 < strlen(ptr))
+ *error = zbx_dsprintf(*error, "%s at: '%128s...'", message, ptr);
+ else
+ *error = zbx_dsprintf(*error, "%s at: '%s'", message, ptr);
+ }
else
*error = zbx_strdup(*error, message);
}
@@ -54,6 +58,7 @@ static zbx_int64_t json_error(const char *message, const char *json_buffer, char
* Purpose: Parses JSON string value or object name *
* *
* Parameters: start - [IN] the JSON data without leading whitespace *
+ * str - [OUT] the parsed unquoted string (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -61,7 +66,7 @@ static zbx_int64_t json_error(const char *message, const char *json_buffer, char
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_string(const char *start, char **error)
+static zbx_int64_t json_parse_string(const char *start, char **str, char **error)
{
const char *ptr = start;
@@ -119,6 +124,12 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
ptr++;
}
+ if (NULL != str)
+ {
+ *str = (char *)zbx_malloc(NULL, (size_t)(ptr - start));
+ json_copy_string(start, *str, (size_t)(ptr - start));
+ }
+
return ptr - start + 1;
}
@@ -127,6 +138,7 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
* Purpose: Parses JSON array value *
* *
* Parameters: start - [IN] the JSON data without leading whitespace *
+ * obj - [IN/OUT] the JSON object (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -134,11 +146,14 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_array(const char *start, char **error)
+zbx_int64_t json_parse_array(const char *start, zbx_jsonobj_t *obj, char **error)
{
const char *ptr = start;
zbx_int64_t len;
+ if (NULL != obj)
+ jsonobj_init(obj, ZBX_JSON_TYPE_ARRAY);
+
ptr++;
SKIP_WHITESPACE(ptr);
@@ -146,9 +161,29 @@ static zbx_int64_t json_parse_array(const char *start, char **error)
{
while (1)
{
+ zbx_jsonobj_t *value;
+
+ if (NULL != obj)
+ {
+ value = zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+ jsonobj_init(value, ZBX_JSON_TYPE_UNKNOWN);
+ }
+ else
+ value = NULL;
+
/* json_parse_value strips leading whitespace, so we don't have to do it here */
- if (0 == (len = json_parse_value(ptr, error)))
+ if (0 == (len = json_parse_value(ptr, value, error)))
+ {
+ if (NULL != obj)
+ {
+ zbx_jsonobj_clear(value);
+ zbx_free(value);
+ }
return 0;
+ }
+
+ if (NULL != obj)
+ zbx_vector_jsonobj_ptr_append(&obj->data.array, value);
ptr += len;
SKIP_WHITESPACE(ptr);
@@ -171,15 +206,16 @@ static zbx_int64_t json_parse_array(const char *start, char **error)
* *
* Purpose: Parses JSON number value *
* *
- * Parameters: start - [IN] the JSON data without leading whitespace *
- * error - [OUT] the parsing error message (can be NULL) *
+ * Parameters: start - [IN] the JSON data without leading whitespace *
+ * number - [OUT] the parsed number (can be NULL) *
+ * error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
* error parameter (if not NULL) contains allocated error *
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_number(const char *start, char **error)
+static zbx_int64_t json_parse_number(const char *start, double *number, char **error)
{
const char *ptr = start;
char first_digit;
@@ -235,6 +271,9 @@ static zbx_int64_t json_parse_number(const char *start, char **error)
}
}
+ if (NULL != number)
+ *number = atof(start);
+
return ptr - start;
}
@@ -281,10 +320,12 @@ static zbx_int64_t json_parse_literal(const char *start, const char *text, char
* message. *
* *
******************************************************************************/
-zbx_int64_t json_parse_value(const char *start, char **error)
+zbx_int64_t json_parse_value(const char *start, zbx_jsonobj_t *obj, char **error)
{
const char *ptr = start;
zbx_int64_t len;
+ char *str = NULL;
+ double number;
SKIP_WHITESPACE(ptr);
@@ -293,28 +334,40 @@ zbx_int64_t json_parse_value(const char *start, char **error)
case '\0':
return json_error("unexpected end of object value", NULL, error);
case '"':
- if (0 == (len = json_parse_string(ptr, error)))
+ if (0 == (len = json_parse_string(ptr, (NULL != obj ? &str : NULL), error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_string(obj, str);
break;
case '{':
- if (0 == (len = json_parse_object(ptr, error)))
+ if (0 == (len = json_parse_object(ptr, obj, error)))
return 0;
break;
case '[':
- if (0 == (len = json_parse_array(ptr, error)))
+ if (0 == (len = json_parse_array(ptr, obj, error)))
return 0;
break;
case 't':
if (0 == (len = json_parse_literal(ptr, "true", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_true(obj);
break;
case 'f':
if (0 == (len = json_parse_literal(ptr, "false", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_false(obj);
break;
case 'n':
if (0 == (len = json_parse_literal(ptr, "null", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_null(obj);
break;
case '0':
case '1':
@@ -327,8 +380,12 @@ zbx_int64_t json_parse_value(const char *start, char **error)
case '8':
case '9':
case '-':
- if (0 == (len = json_parse_number(ptr, error)))
+ if (0 == (len = json_parse_number(ptr, (NULL != obj ? &number : NULL), error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_number(obj, number);
+
break;
default:
return json_error("invalid JSON object value starting character", ptr, error);
@@ -342,6 +399,7 @@ zbx_int64_t json_parse_value(const char *start, char **error)
* Purpose: Parses JSON object *
* *
* Parameters: start - [IN] the JSON data *
+ * obj - [IN/OUT] the JSON object (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -349,10 +407,13 @@ zbx_int64_t json_parse_value(const char *start, char **error)
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_object(const char *start, char **error)
+zbx_int64_t json_parse_object(const char *start, zbx_jsonobj_t *obj, char **error)
{
- const char *ptr = start;
- zbx_int64_t len;
+ const char *ptr = start;
+ zbx_int64_t len;
+
+ if (NULL != obj)
+ jsonobj_init(obj, ZBX_JSON_TYPE_OBJECT);
/* parse object name */
SKIP_WHITESPACE(ptr);
@@ -364,11 +425,15 @@ static zbx_int64_t json_parse_object(const char *start, char **error)
{
while (1)
{
+ zbx_jsonobj_el_t el;
+
if ('"' != *ptr)
return json_error("invalid object name", ptr, error);
+ jsonobj_el_init(&el);
+
/* cannot parse object name, failing */
- if (0 == (len = json_parse_string(ptr, error)))
+ if (0 == (len = json_parse_string(ptr, (NULL != obj ? &el.name : NULL), error)))
return 0;
ptr += len;
@@ -377,11 +442,21 @@ static zbx_int64_t json_parse_object(const char *start, char **error)
SKIP_WHITESPACE(ptr);
if (':' != *ptr)
+ {
+ jsonobj_el_clear(&el);
return json_error("invalid object name/value separator", ptr, error);
+ }
+
ptr++;
- if (0 == (len = json_parse_value(ptr, error)))
+ if (0 == (len = json_parse_value(ptr, (NULL != obj ? &el.value : NULL), error)))
+ {
+ jsonobj_el_clear(&el);
return 0;
+ }
+
+ if (NULL != obj)
+ zbx_hashset_insert(&obj->data.object, &el, sizeof(el));
ptr += len;
@@ -426,11 +501,11 @@ zbx_int64_t zbx_json_validate(const char *start, char **error)
switch (*start)
{
case '{':
- if (0 == (len = json_parse_object(start, error)))
+ if (0 == (len = json_parse_object(start, NULL, error)))
return 0;
break;
case '[':
- if (0 == (len = json_parse_array(start, error)))
+ if (0 == (len = json_parse_array(start, NULL, error)))
return 0;
break;
default:
diff --git a/src/libs/zbxjson/json_parser.h b/src/libs/zbxjson/json_parser.h
index f9fb3bb8cf5..cd54939eb7d 100644
--- a/src/libs/zbxjson/json_parser.h
+++ b/src/libs/zbxjson/json_parser.h
@@ -21,9 +21,15 @@
#define ZABBIX_JSON_PARSER_H
#include "zbxtypes.h"
+#include "jsonobj.h"
zbx_int64_t zbx_json_validate(const char *start, char **error);
-zbx_int64_t json_parse_value(const char *start, char **error);
+zbx_int64_t json_parse_value(const char *start, zbx_jsonobj_t *obj, char **error);
+
+zbx_int64_t json_error(const char *message, const char *ptr, char **error);
+
+zbx_int64_t json_parse_object(const char *start, zbx_jsonobj_t *obj, char **error);
+zbx_int64_t json_parse_array(const char *start, zbx_jsonobj_t *obj, char **error);
#endif
diff --git a/src/libs/zbxjson/jsonobj.c b/src/libs/zbxjson/jsonobj.c
new file mode 100644
index 00000000000..c343e4e896a
--- /dev/null
+++ b/src/libs/zbxjson/jsonobj.c
@@ -0,0 +1,366 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "jsonobj.h"
+
+#include "json_parser.h"
+#include "json.h"
+#include "../zbxalgo/vectorimpl.h"
+
+ZBX_PTR_VECTOR_IMPL(jsonobj_ptr, zbx_jsonobj_t *)
+ZBX_VECTOR_IMPL(jsonobj_ref, zbx_jsonobj_ref_t)
+
+/* jsonobject index hashset support */
+
+static zbx_hash_t jsonobj_index_el_hash(const void *v)
+{
+ const zbx_jsonobj_index_el_t *el = (const zbx_jsonobj_index_el_t *)v;
+
+ return ZBX_DEFAULT_STRING_HASH_FUNC(el->value);
+}
+
+static int jsonobj_index_el_compare(const void *v1, const void *v2)
+{
+ const zbx_jsonobj_index_el_t *el1 = (const zbx_jsonobj_index_el_t *)v1;
+ const zbx_jsonobj_index_el_t *el2 = (const zbx_jsonobj_index_el_t *)v2;
+
+ return strcmp(el1->value, el2->value);
+}
+
+/* jsonobject values hashset support */
+
+static zbx_hash_t jsonobj_el_hash(const void *v)
+{
+ const zbx_jsonobj_el_t *el = (const zbx_jsonobj_el_t *)v;
+
+ return ZBX_DEFAULT_STRING_HASH_FUNC(el->name);
+}
+
+static int jsonobj_el_compare(const void *v1, const void *v2)
+{
+ const zbx_jsonobj_el_t *el1 = (const zbx_jsonobj_el_t *)v1;
+ const zbx_jsonobj_el_t *el2 = (const zbx_jsonobj_el_t *)v2;
+
+ return strcmp(el1->name, el2->name);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object structure *
+ * *
+ * Parameters: obj - [IN/OUT] the json object to initialize *
+ * type - [IN] the json object type *
+ * *
+ ******************************************************************************/
+void jsonobj_init(zbx_jsonobj_t *obj, zbx_json_type_t type)
+{
+ obj->type = type;
+
+ switch (type)
+ {
+ case ZBX_JSON_TYPE_ARRAY:
+ zbx_vector_jsonobj_ptr_create(&obj->data.array);
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ zbx_hashset_create(&obj->data.object, 0, jsonobj_el_hash, jsonobj_el_compare);
+ break;
+ default:
+ memset(&obj->data, 0, sizeof(obj->data));
+ break;
+ }
+
+ obj->index = NULL;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object index element *
+ * *
+ * Parameters: v - [IN] the json index element *
+ * *
+ ******************************************************************************/
+static void jsonobj_index_el_clear(void *v)
+{
+ zbx_jsonobj_index_el_t *el = (zbx_jsonobj_index_el_t *)v;
+ int i;
+
+ zbx_free(el->value);
+ for (i = 0; i < el->objects.values_num; i++)
+ {
+ zbx_free(el->objects.values[i].name);
+
+ if (0 != el->objects.values[i].external)
+ {
+ zbx_jsonobj_clear(el->objects.values[i].value);
+ zbx_free(el->objects.values[i].value);
+ }
+ }
+
+ zbx_vector_jsonobj_ref_destroy(&el->objects);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object index *
+ * *
+ * Parameters: obj - [IN/OUT] the json object *
+ * path - [IN] the indexed relative path *
+ * *
+ ******************************************************************************/
+void jsonobj_init_index(zbx_jsonobj_t *obj, const char *path)
+{
+ obj->index = (zbx_jsonobj_index_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_index_t));
+ obj->index->path = zbx_strdup(NULL, path);
+ zbx_hashset_create_ext(&obj->index->objects, 0, jsonobj_index_el_hash, jsonobj_index_el_compare,
+ jsonobj_index_el_clear, ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC,
+ ZBX_DEFAULT_MEM_FREE_FUNC);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set string value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_string(zbx_jsonobj_t *obj, char *str)
+{
+ obj->type = ZBX_JSON_TYPE_STRING;
+ obj->data.string = str;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set numeric value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_number(zbx_jsonobj_t *obj, double number)
+{
+ obj->type = ZBX_JSON_TYPE_NUMBER;
+ obj->data.number = number;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set true value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_true(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_TRUE;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set false value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_false(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_FALSE;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set null value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_null(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_NULL;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object element *
+ * *
+ ******************************************************************************/
+void jsonobj_el_init(zbx_jsonobj_el_t *el)
+{
+ el->name = NULL;
+ jsonobj_init(&el->value, ZBX_JSON_TYPE_UNKNOWN);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object element *
+ * *
+ ******************************************************************************/
+void jsonobj_el_clear(zbx_jsonobj_el_t *el)
+{
+ zbx_free(el->name);
+ zbx_jsonobj_clear(&el->value);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free json object *
+ * *
+ ******************************************************************************/
+static void jsonobj_free(zbx_jsonobj_t *obj)
+{
+ zbx_jsonobj_clear(obj);
+ zbx_free(obj);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object *
+ * *
+ ******************************************************************************/
+void zbx_jsonobj_clear(zbx_jsonobj_t *obj)
+{
+ zbx_jsonobj_el_t *el;
+ zbx_hashset_iter_t iter;
+
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_STRING:
+ zbx_free(obj->data.string);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ zbx_vector_jsonobj_ptr_clear_ext(&obj->data.array, jsonobj_free);
+ zbx_vector_jsonobj_ptr_destroy(&obj->data.array);
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ zbx_free(el->name);
+ zbx_jsonobj_clear(&el->value);
+ }
+ zbx_hashset_destroy(&obj->data.object);
+ break;
+ default:
+ break;
+ }
+
+ if (NULL != obj->index)
+ {
+ zbx_free(obj->index->path);
+ zbx_hashset_destroy(&obj->index->objects);
+ zbx_free(obj->index);
+ }
+}
+
+/******************************************************************************
+ * *
+ * Purpose: convert json object to text format *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_to_string(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj)
+{
+ char *tmp, buf[32], delim;
+ int i;
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_TRUE:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "true");
+ break;
+ case ZBX_JSON_TYPE_FALSE:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "false");
+ break;
+ case ZBX_JSON_TYPE_NULL:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "null");
+ break;
+ case ZBX_JSON_TYPE_STRING:
+ tmp = zbx_strdup(NULL, obj->data.string);
+ zbx_json_escape(&tmp);
+ zbx_snprintf_alloc(str, str_alloc, str_offset, "\"%s\"", tmp);
+ zbx_free(tmp);
+ break;
+ case ZBX_JSON_TYPE_NUMBER:
+ zbx_print_double(buf, sizeof(buf), obj->data.number);
+ zbx_strcpy_alloc(str, str_alloc, str_offset, buf);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ delim = '[';
+ for (i = 0; i < obj->data.array.values_num; i++)
+ {
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, delim);
+ delim = ',';
+ zbx_jsonobj_to_string(str, str_alloc, str_offset, obj->data.array.values[i]);
+ }
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, ']');
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ delim = '{';
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, delim);
+ delim = ',';
+
+ tmp = zbx_strdup(NULL, el->name);
+ zbx_json_escape(&tmp);
+ zbx_snprintf_alloc(str, str_alloc, str_offset, "\"%s\"", tmp);
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, ':');
+ zbx_free(tmp);
+
+ zbx_jsonobj_to_string(str, str_alloc, str_offset, &el->value);
+ }
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, '}');
+ break;
+ default:
+ zbx_set_json_strerror("unknown json object with type: %u", obj->type);
+ return FAIL;
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: parses json formatted data into json object structure *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_open(const char *data, zbx_jsonobj_t *obj)
+{
+ int ret = FAIL;
+ char *error = NULL;
+
+ switch (*data)
+ {
+ case '{':
+ if (0 == json_parse_object(data, obj, &error))
+ goto out;
+ break;
+ case '[':
+ if (0 == json_parse_array(data, obj, &error))
+ goto out;
+ break;
+ default:
+ /* not json data, failing */
+ jsonobj_init(obj, ZBX_JSON_TYPE_UNKNOWN);
+ (void)json_error("invalid object format, expected opening character '{' or '['", data, &error);
+ goto out;
+ }
+
+ ret = SUCCEED;
+out:
+ if (FAIL == ret)
+ {
+ zbx_jsonobj_clear(obj);
+ zbx_set_json_strerror("%s", error);
+ zbx_free(error);
+ }
+
+ return ret;
+}
diff --git a/src/libs/zbxjson/jsonobj.h b/src/libs/zbxjson/jsonobj.h
new file mode 100644
index 00000000000..dfd12df6b9b
--- /dev/null
+++ b/src/libs/zbxjson/jsonobj.h
@@ -0,0 +1,56 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#ifndef ZABBIX_JSONOBJ_H
+#define ZABBIX_JSONOBJ_H
+
+#include "zbxjson.h"
+
+typedef struct
+{
+ char *name;
+ zbx_jsonobj_t *value;
+ unsigned char external; /* 1 - the reference is to an external object. */
+ /* 0 - the reference is to a local object which must be freed */
+ /* when reference is destroyed */
+}
+zbx_jsonobj_ref_t;
+
+ZBX_VECTOR_DECL(jsonobj_ref, zbx_jsonobj_ref_t)
+
+typedef struct
+{
+ char *value; /* the value found at indexed path */
+ zbx_vector_jsonobj_ref_t objects; /* the objects matching value at indexed path */
+}
+zbx_jsonobj_index_el_t;
+
+void jsonobj_init(zbx_jsonobj_t *obj, zbx_json_type_t type);
+
+void jsonobj_el_init(zbx_jsonobj_el_t *el);
+void jsonobj_init_index(zbx_jsonobj_t *obj, const char *path);
+void jsonobj_el_clear(zbx_jsonobj_el_t *el);
+
+void jsonobj_set_string(zbx_jsonobj_t *obj, char *str);
+void jsonobj_set_number(zbx_jsonobj_t *obj, double number);
+void jsonobj_set_true(zbx_jsonobj_t *obj);
+void jsonobj_set_false(zbx_jsonobj_t *obj);
+void jsonobj_set_null(zbx_jsonobj_t *obj);
+
+#endif
diff --git a/src/libs/zbxjson/jsonpath.c b/src/libs/zbxjson/jsonpath.c
index 7944e2b88e0..0cce389e9b2 100644
--- a/src/libs/zbxjson/jsonpath.c
+++ b/src/libs/zbxjson/jsonpath.c
@@ -19,28 +19,22 @@
#include "jsonpath.h"
-#include "common.h"
#include "zbxregexp.h"
-#include "zbxjson.h"
+#include "zbxvariant.h"
#include "json.h"
#include "json_parser.h"
-#include "zbxvariant.h"
+#include "jsonobj.h"
#include "../zbxalgo/vectorimpl.h"
typedef struct
{
- char *name;
- const char *value;
+ zbx_jsonobj_t *root; /* the root object */
+ zbx_jsonpath_t *path;
+ unsigned char found; /* set to 1 when one object was matched and */
+ /* no more matches are required */
+ zbx_vector_jsonobj_ref_t objects; /* the matched objects */
}
-zbx_json_element_t;
-
-ZBX_VECTOR_DECL(json, zbx_json_element_t)
-ZBX_VECTOR_IMPL(json, zbx_json_element_t)
-
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects);
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects);
+zbx_jsonpath_context_t;
typedef struct
{
@@ -49,6 +43,10 @@ typedef struct
}
zbx_jsonpath_token_def_t;
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth);
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth);
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj);
+
/* define token groups and precedence */
static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{0, 0},
@@ -74,6 +72,7 @@ static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 7} /* ZBX_JSONPATH_TOKEN_OP_REGEXP */
};
+
static int jsonpath_token_precedence(int type)
{
return jsonpath_tokens[type].precedence;
@@ -84,31 +83,118 @@ static int jsonpath_token_group(int type)
return jsonpath_tokens[type].group;
}
-/* json element vector support */
-static void zbx_vector_json_add_element(zbx_vector_json_t *elements, const char *name, const char *value)
+/******************************************************************************
+ * *
+ * Purpose: add external json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * value - [IN] the json object *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_object(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ zbx_jsonobj_t *value)
+{
+ zbx_jsonobj_ref_t ref;
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 1;
+
+ ref.value = value;
+ zbx_vector_jsonobj_ref_append(refs, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: add internal json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * str - [IN] the string value of the object *
+ * *
+ * Comments: This function will create json object and add internal reference,*
+ * meaning the object will be destroyed together with its reference.*
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_string(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ const char *str)
{
- zbx_json_element_t el;
+ zbx_jsonobj_ref_t ref;
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 0;
+
+ ref.value = (zbx_jsonobj_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+ jsonobj_init(ref.value, ZBX_JSON_TYPE_STRING);
+ jsonobj_set_string(ref.value, zbx_strdup(NULL, str));
- el.name = zbx_strdup(NULL, name);
- el.value = value;
- zbx_vector_json_append(elements, el);
+ zbx_vector_jsonobj_ref_append(refs, ref);
}
-static void zbx_vector_json_copy(zbx_vector_json_t *dst, const zbx_vector_json_t *src)
+/******************************************************************************
+ * *
+ * Purpose: add a copy of json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * ref - [IN] the json object reference *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add(zbx_vector_jsonobj_ref_t *refs, zbx_jsonobj_ref_t *ref)
+{
+ if (0 != ref->external)
+ zbx_vector_jsonobj_ref_add_object(refs, ref->name, ref->value);
+ else
+ zbx_vector_jsonobj_ref_add_string(refs, ref->name, ref->value->data.string);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: copy json object references from one vector to other *
+ * *
+ * Parameters: dst - [IN/OUT] the destination json object reference vector *
+ * src - [IN] the source json object reference vector *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_copy(zbx_vector_jsonobj_ref_t *dst, const zbx_vector_jsonobj_ref_t *src)
{
int i;
for (i = 0; i < src->values_num; i++)
- zbx_vector_json_add_element(dst, src->values[i].name, src->values[i].value);
+ {
+ if (0 != src->values[i].external)
+ zbx_vector_jsonobj_ref_add_object(dst, src->values[i].name, src->values[i].value);
+ else
+ zbx_vector_jsonobj_ref_add_string(dst, src->values[i].name, src->values[i].value->data.string);
+ }
}
-static void zbx_vector_json_clear_ext(zbx_vector_json_t *elements)
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object reference *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_clear_ext(zbx_vector_jsonobj_ref_t *refs)
{
int i;
- for (i = 0; i < elements->values_num; i++)
- zbx_free(elements->values[i].name);
- zbx_vector_json_clear(elements);
+ for (i = 0; i < refs->values_num; i++)
+ {
+ zbx_jsonobj_ref_t *ref = &refs->values[i];
+
+ zbx_free(ref->name);
+ if (0 == ref->external)
+ {
+ zbx_jsonobj_clear(ref->value);
+ zbx_free(ref->value);
+ }
+ }
+ zbx_vector_jsonobj_ref_clear(refs);
}
/******************************************************************************
@@ -215,7 +301,62 @@ static void jsonpath_list_free(zbx_jsonpath_list_node_t *list)
/******************************************************************************
* *
- * Purpose: create jsonpath and compile json path *
+ * Purpose: append array index to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_index(zbx_jsonpath_list_node_t *head, int index,
+ int check_duplicate)
+{
+ zbx_jsonpath_list_node_t *node;
+
+ if (0 != check_duplicate)
+ {
+ for (node = head; NULL != node; node = node->next)
+ {
+ int query_index;
+
+ memcpy(&query_index, node->data, sizeof(query_index));
+ if (query_index == index)
+ return head;
+ }
+ }
+
+ node = jsonpath_list_create_node(sizeof(int));
+ node->next = head;
+ memcpy(node->data, &index, sizeof(int));
+
+ return node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: append name to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_name(zbx_jsonpath_list_node_t *head, const char *name, size_t len)
+{
+ zbx_jsonpath_list_node_t *node, *new_node;
+
+ new_node = jsonpath_list_create_node(len + 1);
+ jsonpath_unquote(new_node->data, name, len + 1);
+
+ for (node = head; NULL != node; node = node->next)
+ {
+ if (0 == strcmp((char *)new_node->data, (char *)node->data))
+ {
+ zbx_free(new_node);
+ return head;
+ }
+ }
+
+ new_node->next = head;
+
+ return new_node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: create jsonpath structure and compile json path *
* *
******************************************************************************/
static zbx_jsonpath_t *jsonpath_create_token_jsonpath(const char *text, size_t len)
@@ -258,18 +399,18 @@ out:
/******************************************************************************
* *
- * Function: jsonpath_create_token *
- * *
* Purpose: create jsonpath expression token *
* *
* Parameters: type - [IN] the token type *
* expression - [IN] the expression *
* loc - [IN] the token location in the expression *
* *
- * Return value: The created token (must be freed by the caller). *
+ * Return value: The created token (must be freed by the caller) or *
+ * NULL in the case of error. *
* *
******************************************************************************/
-static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *expression, const zbx_strloc_t *loc)
+static zbx_jsonpath_token_t *jsonpath_create_token(unsigned char type, const char *expression,
+ const zbx_strloc_t *loc)
{
zbx_jsonpath_token_t *token;
@@ -304,6 +445,11 @@ static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *express
return token;
}
+/******************************************************************************
+ * *
+ * Purpose: free jsonpath expression token *
+ * *
+ ******************************************************************************/
static void jsonpath_token_free(zbx_jsonpath_token_t *token)
{
zbx_free(token->text);
@@ -337,16 +483,21 @@ static void jsonpath_reserve(zbx_jsonpath_t *jsonpath, int num)
jsonpath->segments_alloc *= 2;
jsonpath->segments = (zbx_jsonpath_segment_t *)zbx_realloc(jsonpath->segments,
- sizeof(zbx_jsonpath_segment_t) * jsonpath->segments_alloc);
+ sizeof(zbx_jsonpath_segment_t) * (size_t)jsonpath->segments_alloc);
/* Initialize the memory allocated for new segments, as parser can set */
/* detached flag for the next segment, so the memory cannot be initialized */
/* when creating a segment. */
memset(jsonpath->segments + old_alloc, 0,
- (jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
+ (size_t)(jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
}
}
+/******************************************************************************
+ * *
+ * Purpose: free resource allocated by jsonpath segment *
+ * *
+ ******************************************************************************/
static void jsonpath_segment_clear(zbx_jsonpath_segment_t *segment)
{
switch (segment->type)
@@ -454,7 +605,7 @@ static int jsonpath_next(const char **pnext)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_substring(const char *start, int *len)
+static int jsonpath_parse_substring(const char *start, size_t *len)
{
const char *ptr;
char quotes;
@@ -463,7 +614,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
{
if (*ptr == quotes)
{
- *len = ptr - start + 1;
+ *len = (size_t)(ptr - start + 1);
return SUCCEED;
}
@@ -492,7 +643,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
* jsonpath filter expressions. *
* *
******************************************************************************/
-static int jsonpath_parse_path(const char *start, int *len)
+static int jsonpath_parse_path(const char *start, size_t *len)
{
const char *ptr = start + 1;
@@ -502,7 +653,7 @@ static int jsonpath_parse_path(const char *start, int *len)
return FAIL;
}
- *len = ptr - start;
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -517,7 +668,7 @@ static int jsonpath_parse_path(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_number(const char *start, int *len)
+static int jsonpath_parse_number(const char *start, size_t *len)
{
const char *ptr = start;
char *end;
@@ -537,7 +688,7 @@ static int jsonpath_parse_number(const char *start, int *len)
if (ptr != end || HUGE_VAL == tmp || -HUGE_VAL == tmp || EDOM == errno)
return FAIL;
- *len = (int)(ptr - start);
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -557,14 +708,14 @@ static int jsonpath_parse_number(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_expression_next_token(const char *expression, int pos, int prev_group,
+static int jsonpath_expression_next_token(const char *expression, size_t pos, int prev_group,
zbx_jsonpath_token_type_t *type, zbx_strloc_t *loc)
{
- int len;
+ size_t len;
const char *ptr = expression + pos;
SKIP_WHITESPACE(ptr);
- loc->l = ptr - expression;
+ loc->l = (size_t)(ptr - expression);
switch (*ptr)
{
@@ -696,6 +847,139 @@ out:
return zbx_jsonpath_error(ptr);
}
+/* value types on index stack */
+typedef enum
+{
+ ZBX_JSONPATH_CONST = 1, /* constant value - string or number */
+ ZBX_JSONPATH_VALUE, /* result of an operation after which cannot be used in index */
+ ZBX_JSONPATH_PATH, /* relative jsonpath - @.a.b.c */
+ ZBX_JSONPATH_PATH_OP /* result of an operation with jsonpath which still can be used in index */
+}
+zbx_jsonpath_index_value_type_t;
+
+typedef struct
+{
+ zbx_jsonpath_index_value_type_t type;
+ zbx_jsonpath_token_t *index_token;
+ zbx_jsonpath_token_t *value_token;
+}
+zbx_jsonpath_index_value_t;
+
+ZBX_VECTOR_DECL(jpi_value, zbx_jsonpath_index_value_t)
+ZBX_VECTOR_IMPL(jpi_value, zbx_jsonpath_index_value_t)
+
+/******************************************************************************
+ * *
+ * Purpose: analyze expression and set indexing fields if possible *
+ * *
+ * Comments: Expression can be indexed if it contains relative json path *
+ * comparison with constant that is used in and operations. *
+ * This is tested by doing a pseudo evaluation by operand types *
+ * and checking the result type. *
+ * *
+ * So expressions like ?(@.a.b == 1), ?(@.a == "A" and @.b == "B") *
+ * can be indexed (by @.a.b and by @.a) while expressions like *
+ * ?(@.a == @.b), ?(@.a == "A" or @.b == "B") cannot. *
+ * *
+ ******************************************************************************/
+static void jsonpath_expression_prepare_index(zbx_jsonpath_expression_t *exp)
+{
+ int i;
+ zbx_vector_jpi_value_t stack;
+ zbx_jsonpath_index_value_t *left, *right;
+
+ zbx_vector_jpi_value_create(&stack);
+
+ for (i = 0; i < exp->tokens.values_num; i++)
+ {
+ zbx_jsonpath_token_t *token = (zbx_jsonpath_token_t *)exp->tokens.values[i];
+ zbx_jsonpath_index_value_t jpi = {0};
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_NOT:
+ if (1 > stack.values_num)
+ goto out;
+ stack.values[stack.values_num - 1].type = ZBX_JSONPATH_VALUE;
+ stack.values[stack.values_num - 1].index_token = NULL;
+ stack.values[stack.values_num - 1].value_token = NULL;
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ jpi.index_token = token;
+ jpi.type = ZBX_JSONPATH_PATH;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ jpi.type = ZBX_JSONPATH_VALUE;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ jpi.value_token = token;
+ jpi.type = ZBX_JSONPATH_CONST;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ }
+
+ if (2 > stack.values_num)
+ goto out;
+
+ left = &stack.values[stack.values_num - 2];
+ right = &stack.values[stack.values_num - 1];
+ stack.values_num--;
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_EQ:
+ if ((ZBX_JSONPATH_PATH == left->type || ZBX_JSONPATH_PATH == right->type) &&
+ (ZBX_JSONPATH_CONST == left->type || ZBX_JSONPATH_CONST == right->type))
+ {
+ left->type = ZBX_JSONPATH_PATH_OP;
+
+ if (ZBX_JSONPATH_CONST == right->type)
+ left->value_token = right->value_token;
+ else
+ left->index_token = right->index_token;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ case ZBX_JSONPATH_TOKEN_OP_AND:
+ if (ZBX_JSONPATH_PATH == left->type)
+ left->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH == right->type)
+ right->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH_OP == left->type && ZBX_JSONPATH_PATH_OP == right->type)
+ continue;
+
+ if ((ZBX_JSONPATH_PATH_OP == left->type || ZBX_JSONPATH_PATH_OP == right->type) &&
+ (ZBX_JSONPATH_VALUE == left->type || ZBX_JSONPATH_VALUE == right->type))
+ {
+ if (ZBX_JSONPATH_PATH_OP != left->type)
+ *left = *right;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ default:
+ left->type = ZBX_JSONPATH_VALUE;
+ left->index_token = NULL;
+ left->value_token = NULL;
+ break;
+ }
+ }
+
+ if (1 == stack.values_num && ZBX_JSONPATH_PATH_OP == stack.values[0].type)
+ {
+ exp->index_token = stack.values[0].index_token;
+ exp->value_token = stack.values[0].value_token;
+ }
+out:
+ zbx_vector_jpi_value_destroy(&stack);
+}
+
/******************************************************************************
* *
* Purpose: parse jsonpath filter expression in format *
@@ -888,6 +1172,10 @@ out:
zbx_vector_ptr_create(&segment->data.expression.tokens);
zbx_vector_ptr_append_array(&segment->data.expression.tokens, output.values, output.values_num);
+ /* index only json path that has been definite until this point */
+ if (0 != jsonpath->definite)
+ jsonpath_expression_prepare_index(&segment->data.expression);
+
jsonpath->definite = 0;
}
cleanup:
@@ -941,18 +1229,13 @@ static int jsonpath_parse_names(const char *list, zbx_jsonpath_t *jsonpath, cons
}
else if (*start == *end)
{
- zbx_jsonpath_list_node_t *node;
-
if (start + 1 == end)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(end - start + 1);
- jsonpath_unquote(node->data, start, end - start + 1);
- node->next = head;
- head = node;
+ head = jsonpath_list_append_name(head, start, (size_t)(end - start));
parsed_name = 1;
start = NULL;
}
@@ -1059,19 +1342,13 @@ static int jsonpath_parse_indexes(const char *list, zbx_jsonpath_t *jsonpath, co
if (NULL != start)
{
- int value;
-
if ('-' == *start && end == start + 1)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(sizeof(int));
- node->next = head;
- head = node;
- value = atoi(start);
- memcpy(node->data, &value, sizeof(int));
+ head = jsonpath_list_append_index(head, atoi(start), type == ZBX_JSONPATH_SEGMENT_MATCH_LIST);
start = NULL;
parsed_index = 1;
}
@@ -1235,7 +1512,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
{
zbx_jsonpath_segment_t *segment;
const char *ptr;
- int len;
+ size_t len;
segment = &jsonpath->segments[jsonpath->segments_num];
jsonpath->segments_num++;
@@ -1251,6 +1528,8 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
for (ptr = start; 0 != isalnum((unsigned char)*ptr) || '_' == *ptr;)
ptr++;
+ len = (size_t)(ptr - start);
+
if ('(' == *ptr)
{
const char *end = ptr + 1;
@@ -1258,28 +1537,28 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
SKIP_WHITESPACE(end);
if (')' == *end)
{
- if (ZBX_CONST_STRLEN("min") == ptr - start && 0 == strncmp(start, "min", ptr - start))
+ if (ZBX_CONST_STRLEN("min") == len && 0 == strncmp(start, "min", len))
{
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MIN;
}
- else if (ZBX_CONST_STRLEN("max") == ptr - start && 0 == strncmp(start, "max", ptr - start))
+ else if (ZBX_CONST_STRLEN("max") == len && 0 == strncmp(start, "max", len))
{
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MAX;
}
- else if (ZBX_CONST_STRLEN("avg") == ptr - start && 0 == strncmp(start, "avg", ptr - start))
+ else if (ZBX_CONST_STRLEN("avg") == len && 0 == strncmp(start, "avg", len))
{
segment->data.function.type = ZBX_JSONPATH_FUNCTION_AVG;
}
- else if (ZBX_CONST_STRLEN("length") == ptr - start && 0 == strncmp(start, "length", ptr - start))
+ else if (ZBX_CONST_STRLEN("length") == len && 0 == strncmp(start, "length", len))
{
segment->data.function.type = ZBX_JSONPATH_FUNCTION_LENGTH;
}
- else if (ZBX_CONST_STRLEN("first") == ptr - start && 0 == strncmp(start, "first", ptr - start))
+ else if (ZBX_CONST_STRLEN("first") == len && 0 == strncmp(start, "first", len))
{
segment->data.function.type = ZBX_JSONPATH_FUNCTION_FIRST;
jsonpath->first_match = 1;
}
- else if (ZBX_CONST_STRLEN("sum") == ptr - start && 0 == strncmp(start, "sum", ptr - start))
+ else if (ZBX_CONST_STRLEN("sum") == len && 0 == strncmp(start, "sum", len))
{
segment->data.function.type = ZBX_JSONPATH_FUNCTION_SUM;
}
@@ -1292,7 +1571,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
}
}
- if (0 < (len = ptr - start))
+ if (0 < len)
{
segment->type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
segment->data.list.type = ZBX_JSONPATH_LIST_NAME;
@@ -1332,123 +1611,84 @@ static int jsonpath_parse_name_reference(const char *start, zbx_jsonpath_t *json
/******************************************************************************
* *
- * Purpose: convert a pointer to an object/array/value in json data to *
- * json parse structure *
- * *
- * Parameters: pnext - [IN] a pointer to object/array/value data *
- * jp - [OUT] json parse data with start/end set *
- * *
- * Return value: SUCCEED - pointer was converted successfully *
- * FAIL - otherwise *
- * *
- ******************************************************************************/
-static int jsonpath_pointer_to_jp(const char *pnext, struct zbx_json_parse *jp)
-{
- if ('[' == *pnext || '{' == *pnext)
- {
- return zbx_json_brackets_open(pnext, jp);
- }
- else
- {
- jp->start = pnext;
- jp->end = pnext + json_parse_value(pnext, NULL) - 1;
- return SUCCEED;
- }
-}
-
-/******************************************************************************
- * *
* Purpose: perform the rest of jsonpath query on json data *
* *
- * Parameters: jp_root - [IN] the document root *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object *
* path_depth - [IN] the jsonpath segment to match *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the data were queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_contents(const struct zbx_json_parse *jp_root, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects)
+static int jsonpath_query_contents(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- struct zbx_json_parse jp_child;
+ int ret;
- switch (*pnext)
+ switch (obj->type)
{
- case '{':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_object(jp_root, &jp_child, jsonpath, path_depth, done, objects);
- case '[':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_array(jp_root, &jp_child, jsonpath, path_depth, done, objects);
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(ctx, obj, path_depth);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(ctx, obj, path_depth);
+ break;
+ default:
+ ret = SUCCEED;
}
- return SUCCEED;
+
+ return ret;
}
/******************************************************************************
* *
* Purpose: query next segment *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the current json object *
* path_depth - [IN] the jsonpath segment to match *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the segment was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_next_segment(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects)
+static int jsonpath_query_next_segment(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
/* check if jsonpath end has been reached, so we have found matching data */
/* (functions are processed afterwards) */
- if (++path_depth == jsonpath->segments_num ||
- ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath->segments[path_depth].type)
+ if (++path_depth == ctx->path->segments_num ||
+ ZBX_JSONPATH_SEGMENT_FUNCTION == ctx->path->segments[path_depth].type)
{
- if (1 == jsonpath->first_match)
- *done = 1;
+ if (1 == ctx->path->first_match)
+ ctx->found = 1;
- zbx_vector_json_add_element(objects, name, pnext);
+ zbx_vector_jsonobj_ref_add_object(&ctx->objects, name, obj);
return SUCCEED;
}
- /* continue by matching found data against the rest of jsonpath segments */
- return jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, done, objects);
+ /* continue by matching found object against the rest of jsonpath segments */
+ return jsonpath_query_contents(ctx, obj, path_depth);
}
/******************************************************************************
* *
- * Purpose: match object value name against jsonpath segment name list *
+ * Purpose: match object contents against jsonpath segment name list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object value with the specified *
- * name *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] parent json object *
* path_depth - [IN] the jsonpath segment to match *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects)
+static int jsonpath_match_name(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
+ zbx_jsonobj_el_t el_local, *el;
/* object contents can match only name list */
if (ZBX_JSONPATH_LIST_NAME != segment->data.list.type)
@@ -1456,14 +1696,11 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
for (node = segment->data.list.values; NULL != node; node = node->next)
{
- if (0 == strcmp(name, node->data))
+ el_local.name = (char *)node->data;
+ if (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_search(&parent->data.object, &el_local)))
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, done,
- objects))
- {
+ if (FAIL == jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth))
return FAIL;
- }
- break;
}
}
@@ -1474,8 +1711,8 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* *
* Purpose: extract value from json data by the specified path *
* *
- * Parameters: jp - [IN] the parent object *
- * path - [IN] the jsonpath (definite) *
+ * Parameters: obj - [IN] the parent object *
+ * path - [IN] the jsonpath *
* value - [OUT] the extracted value *
* *
* Return value: SUCCEED - the value was extracted successfully *
@@ -1483,28 +1720,29 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* extract *
* *
******************************************************************************/
-static int jsonpath_extract_value(const struct zbx_json_parse *jp, const zbx_jsonpath_t *path,
- zbx_variant_t *value)
+static int jsonpath_extract_value(zbx_jsonobj_t *obj, zbx_jsonpath_t *path, zbx_variant_t *value)
{
- struct zbx_json_parse jp_child;
- char *data = NULL;
- size_t data_alloc = 0;
- int ret = FAIL;
+ int ret = FAIL;
+ zbx_jsonpath_context_t ctx;
- if (FAIL == json_open_path(jp, path, &jp_child))
- goto out;
+ ctx.path = path;
+ ctx.found = 0;
+ ctx.root = obj;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if (NULL == zbx_json_decodevalue_dyn(jp_child.start, &data, &data_alloc, NULL))
+ if (SUCCEED == jsonpath_query_contents(&ctx, obj, 0) && 0 != ctx.objects.values_num)
{
- size_t len = jp_child.end - jp_child.start + 2;
+ char *str = NULL;
+ size_t str_alloc = 0, str_offset = 0;
- data = (char *)zbx_malloc(NULL, len);
- zbx_strlcpy(data, jp_child.start, len);
+ jsonpath_str_copy_value(&str, &str_alloc, &str_offset, ctx.objects.values[0].value);
+ zbx_variant_set_str(value, str);
+ ret = SUCCEED;
}
- zbx_variant_set_str(value, data);
- ret = SUCCEED;
-out:
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
+
return ret;
}
@@ -1521,15 +1759,9 @@ out:
******************************************************************************/
static char *jsonpath_expression_to_str(zbx_jsonpath_expression_t *expression)
{
- int i;
- char *str = NULL;
- size_t str_alloc = 0, str_offset = 0;
-
- if (0 == expression->tokens.values_num)
- {
- THIS_SHOULD_NEVER_HAPPEN;
- return zbx_strdup(NULL, "?");
- }
+ int i;
+ char *str = NULL;
+ size_t str_alloc = 0, str_offset = 0;
for (i = 0; i < expression->tokens.values_num; i++)
{
@@ -1696,36 +1928,123 @@ static int jsonpath_regexp_match(const char *text, const char *pattern, double *
/******************************************************************************
* *
+ * Purpose: add matched object to the index *
+ * *
+ * Parameters: index - [IN] the parent object index *
+ * name - [IN] the name of objec to add to index *
+ * obj - [IN] the object to add to index *
+ * value - [IN] the object matched by index path *
+ * *
+ ******************************************************************************/
+static void jsonpath_index_append_result(zbx_hashset_t *index, const char *name, zbx_jsonobj_t *obj,
+ zbx_jsonobj_t *value)
+{
+ zbx_jsonobj_index_el_t el_local = {.value = NULL}, *el;
+ size_t value_alloc = 0, value_offset = 0;
+ zbx_jsonobj_ref_t ref;
+
+ jsonpath_str_copy_value(&el_local.value, &value_alloc, &value_offset, value);
+
+ if (NULL == (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(index, &el_local)))
+ {
+ el = (zbx_jsonobj_index_el_t *)zbx_hashset_insert(index, &el_local, sizeof(el_local));
+ zbx_vector_jsonobj_ref_create(&el->objects);
+ }
+ else
+ zbx_free(el_local.value);
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.value = obj;
+ ref.external = 0;
+ zbx_vector_jsonobj_ref_append(&el->objects, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: index json object using the expression token index path *
+ * *
+ * Parameters: obj - [IN] the object to index *
+ * index_token - [IN] the expression index token (relative path) *
+ * *
+ ******************************************************************************/
+static void jsonpath_create_index(zbx_jsonobj_t *obj, zbx_jsonpath_token_t *index_token)
+{
+ zbx_jsonpath_context_t ctx;
+
+ jsonobj_init_index(obj, index_token->text);
+
+ ctx.root = obj;
+ ctx.path = index_token->path;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
+
+ if (ZBX_JSON_TYPE_OBJECT == obj->type)
+ {
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, &el->value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, el->name, &el->value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < obj->data.array.values_num; i++)
+ {
+ char name[MAX_ID_LEN + 1];
+ zbx_jsonobj_t *value = obj->data.array.values[i];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, name, value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
+}
+
+/******************************************************************************
+ * *
* Purpose: match json array element/object value against jsonpath expression *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to array element/object value *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the jsonobject to match *
* path_depth - [IN] the jsonpath segment to match *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects)
+static int jsonpath_match_expression(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
- struct zbx_json_parse jp;
zbx_vector_var_t stack;
int i, ret = SUCCEED;
zbx_jsonpath_segment_t *segment;
zbx_variant_t value, *right;
double res;
- if (SUCCEED != jsonpath_pointer_to_jp(pnext, &jp))
- return FAIL;
-
zbx_vector_var_create(&stack);
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
for (i = 0; i < segment->data.expression.tokens.values_num; i++)
{
@@ -1872,16 +2191,16 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
switch (token->type)
{
case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
- if (FAIL == jsonpath_extract_value(jp_root, token->path, &value))
+ if (FAIL == jsonpath_extract_value(ctx->root, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
/* relative path can be applied only to array or object */
- if ('[' != *jp.start && '{' != *jp.start)
+ if (ZBX_JSON_TYPE_ARRAY != obj->type && ZBX_JSON_TYPE_OBJECT != obj->type)
goto out;
- if (FAIL == jsonpath_extract_value(&jp, token->path, &value))
+ if (FAIL == jsonpath_extract_value(obj, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
@@ -1917,7 +2236,7 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
jsonpath_variant_to_boolean(&stack.values[0]);
if (SUCCEED != zbx_double_compare(stack.values[0].data.dbl, 0.0))
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, done, objects);
+ ret = jsonpath_query_next_segment(ctx, name, obj, path_depth);
out:
for (i = 0; i < stack.values_num; i++)
zbx_variant_clear(&stack.values[i]);
@@ -1928,50 +2247,91 @@ out:
/******************************************************************************
* *
+ * Purpose: query indexed object fields for jsonpath segment match *
+ * *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
+ * path_depth - [IN] the jsonpath segment to match *
+ * *
+ * Return value: SUCCEED - the object was queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_indexed_expression(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
+{
+ zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ zbx_jsonobj_index_el_t index_local, *el;
+
+ index_local.value = segment->data.expression.value_token->text;
+
+ if (NULL != (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(&obj->index->objects, &index_local)))
+ {
+ int i;
+
+ for (i = 0; i < el->objects.values_num; i++)
+ {
+ jsonpath_match_expression(ctx, el->objects.values[i].name, el->objects.values[i].value,
+ path_depth);
+ }
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
* Purpose: query object fields for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json object to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
* path_depth - [IN] the jsonpath segment to match *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the object was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects)
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- const char *pnext = NULL;
- char name[MAX_STRING_LEN];
const zbx_jsonpath_segment_t *segment;
int ret = SUCCEED;
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
- while (NULL != (pnext = zbx_json_pair_next(jp, pnext, name, sizeof(name))) && SUCCEED == ret && 0 == *done)
+ if (ZBX_JSONPATH_SEGMENT_MATCH_LIST == segment->type)
+ {
+ ret = jsonpath_match_name(ctx, obj, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ }
+ else if (ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION == segment->type && NULL != segment->data.expression.index_token)
+ {
+ if (NULL == obj->index)
+ jsonpath_create_index(obj, segment->data.expression.index_token);
+
+ if (0 == strcmp(obj->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, obj, path_depth);
+ }
+
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)) && SUCCEED == ret &&
+ 0 == ctx->found)
{
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, done,
- objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_name(jp_root, name, pnext, jsonpath, path_depth, done, objects);
+ ret = jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, done,
- objects);
+ ret = jsonpath_match_expression(ctx, el->name, &el->value, path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, done, objects);
+ ret = jsonpath_query_contents(ctx, &el->value, path_depth);
}
return ret;
@@ -1979,27 +2339,19 @@ static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const str
/******************************************************************************
* *
- * Purpose: match array element against segment index list *
+ * Purpose: array elements against segment index list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
* path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, unsigned char *done,
- zbx_vector_json_t *objects)
+static int jsonpath_match_index(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
/* array contents can match only index list */
@@ -2012,14 +2364,20 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
memcpy(&query_index, node->data, sizeof(query_index));
- if ((query_index >= 0 && index == query_index) || index == elements_num + query_index)
+ if (0 > query_index)
+ query_index += parent->data.array.values_num;
+
+ if (query_index >= 0 && query_index < parent->data.array.values_num)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, done,
- objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", query_index);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[query_index],
+ path_depth))
{
return FAIL;
}
- break;
}
}
@@ -2028,40 +2386,37 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: match array element against segment index range *
+ * Purpose: match array elements against segment index range *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
+ * path_depth - [IN] the jsonpath segment to match *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, unsigned char *done,
- zbx_vector_json_t *objects)
+static int jsonpath_match_range(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- int start_index, end_index;
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ int i, start_index, end_index, values_num;
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ values_num = parent->data.array.values_num;
start_index = (0 != (segment->data.range.flags & 0x01) ? segment->data.range.start : 0);
- end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : elements_num);
+ end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : values_num);
if (0 > start_index)
- start_index += elements_num;
+ start_index += values_num;
if (0 > end_index)
- end_index += elements_num;
+ end_index += values_num;
- if (start_index <= index && end_index > index)
+ for (i = start_index; i < end_index; i++)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, done, objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[i], path_depth))
return FAIL;
}
@@ -2070,62 +2425,69 @@ static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: query array elements for jsonpath segment match *
+ * Purpose: query json array for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json array to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * array - [IN] the json array to query *
* path_depth - [IN] the jsonpath segment to match *
- * done - [OUT] set to 1 when the query is finished *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the array was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, unsigned char *done, zbx_vector_json_t *objects)
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth)
{
- const char *pnext = NULL;
- int index = 0, elements_num = 0, ret = SUCCEED;
+ int ret = SUCCEED, i;
zbx_jsonpath_segment_t *segment;
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
- while (NULL != (pnext = zbx_json_next(jp, pnext)))
- elements_num++;
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ ret = jsonpath_match_index(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
+ ret = jsonpath_match_range(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ if (NULL != segment->data.expression.index_token)
+ {
+ if (NULL == array->index)
+ jsonpath_create_index(array, segment->data.expression.index_token);
- while (NULL != (pnext = zbx_json_next(jp, pnext)) && SUCCEED == ret && 0 == *done)
+ if (0 == strcmp(array->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, array, path_depth);
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < array->data.array.values_num && SUCCEED == ret && 0 == ctx->found; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, done,
- objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_index(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, done, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
- ret = jsonpath_match_range(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, done, objects);
+ ret = jsonpath_query_next_segment(ctx, name, array->data.array.values[i], path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, done,
- objects);
+ ret = jsonpath_match_expression(ctx, name, array->data.array.values[i], path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, done, objects);
-
- index++;
+ ret = jsonpath_query_contents(ctx, array->data.array.values[i], path_depth);
}
return ret;
@@ -2133,123 +2495,99 @@ static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const stru
/******************************************************************************
* *
- * Purpose: extract JSON element value from data *
- * *
- * Parameters: ptr - [IN] pointer to the element to extract *
- * element - [OUT] the extracted element *
+ * Purpose: get numeric value from json data *
* *
- * Return value: SUCCEED - the element was extracted successfully *
- * FAIL - the pointer was not pointing to a JSON element *
+ * Parameters: obj - [IN] json object *
+ * value - [OUT] the extracted value *
* *
- * Comments: String value element is unquoted, other elements are copied as *
- * is. *
+ * Return value: SUCCEED - the value was extracted successfully *
+ * FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_element(const char *ptr, char **element)
+static int jsonpath_get_numeric_value(const zbx_jsonobj_t *obj, double *value)
{
- size_t element_size = 0;
-
- if (NULL == zbx_json_decodevalue_dyn(ptr, element, &element_size, NULL))
+ switch (obj->type)
{
- struct zbx_json_parse jp;
-
- if (SUCCEED != zbx_json_brackets_open(ptr, &jp))
+ case ZBX_JSON_TYPE_NUMBER:
+ *value = obj->data.number;
+ return SUCCEED;
+ case ZBX_JSON_TYPE_STRING:
+ if (SUCCEED == is_double(obj->data.string, value))
+ return SUCCEED;
+ zbx_set_json_strerror("array value is not a number or out of range: %s", obj->data.string);
+ return FAIL;
+ default:
+ zbx_set_json_strerror("array value type is not a number or string");
return FAIL;
-
- *element = jsonpath_strndup(jp.start, jp.end - jp.start + 1);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
- * Purpose: extract numeric value from json data *
- * *
- * Parameters: ptr - [IN] pointer to the value to extract *
- * value - [OUT] the extracted value *
+ * Purpose: get value from json data *
* *
* Return value: SUCCEED - the value was extracted successfully *
* FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_numeric_value(const char *ptr, double *value)
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj)
{
- char buffer[MAX_STRING_LEN];
-
- if (NULL == zbx_json_decodevalue(ptr, buffer, sizeof(buffer), NULL) ||
- SUCCEED != is_double(buffer, value))
+ switch (obj->type)
{
- zbx_set_json_strerror("array value is not a number or out of range starting with: %s", ptr);
- return FAIL;
+ case ZBX_JSON_TYPE_STRING:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, obj->data.string);
+ return SUCCEED;
+ break;
+ default:
+ return zbx_jsonobj_to_string(str, str_alloc, str_offset, obj);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
+ * Parameters: in - [IN] the matched objects *
* type - [IN] the function type *
- * definite_path - [IN] 1 - if the path is definite (pointing at *
- * single object) *
- * 0 - otherwise *
- * output - [OUT] the output value *
+ * definite_path - [IN/OUT] 1 - if the path is definite (pointing *
+ * at single object) *
+ * 0 - otherwise *
+ * out - [OUT] the result objects *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpath_function_type_t type,
- int definite_path, char **output)
+static int jsonpath_apply_function(const zbx_vector_jsonobj_ref_t *in, zbx_jsonpath_function_type_t type,
+ int *definite_path, zbx_vector_jsonobj_ref_t *out)
{
- int i, ret = FAIL;
- zbx_vector_json_t objects_tmp;
- double result;
+ int i, ret = FAIL;
+ double result;
+ zbx_vector_jsonobj_ref_t tmp;
+ char buffer[64];
- zbx_vector_json_create(&objects_tmp);
+ zbx_vector_jsonobj_ref_create(&tmp);
if (ZBX_JSONPATH_FUNCTION_NAME == type)
{
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot extract name from empty result");
goto out;
}
- /* For definite paths we have single output value, so return its name. */
- /* Otherwise return array of all output element names. */
- if (0 == definite_path)
- {
- struct zbx_json j;
-
- /* reserve some space for output json, 1k being large enough to satisfy most queries */
- zbx_json_initarray(&j, 1024);
- for (i = 0; i < objects->values_num; i++)
- zbx_json_addstring(&j, NULL, objects->values[i].name, ZBX_JSON_TYPE_STRING);
-
- zbx_json_close(&j);
- *output = zbx_strdup(NULL, j.buffer);
- zbx_json_clean(&j);
- }
- else
- *output = zbx_strdup(NULL, objects->values[0].name);
+ for (i = 0; i < in->values_num; i++)
+ zbx_vector_jsonobj_ref_add_string(out, "", in->values[i].name);
ret = SUCCEED;
goto out;
}
/* convert definite path result to object array if possible */
- if (0 != definite_path)
+ if (0 != *definite_path)
{
- const char *pnext;
- struct zbx_json_parse jp;
- int index = 0;
-
- if (0 == objects->values_num || '[' != *objects->values[0].value)
+ if (0 == in->values_num || ZBX_JSON_TYPE_ARRAY != in->values[0].value->type)
{
/* all functions can be applied only to arrays */
/* attempt to apply a function to non-array will fail */
@@ -2257,51 +2595,51 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
goto out;
}
- if (FAIL == zbx_json_brackets_open(objects->values[0].value, &jp))
- goto out;
-
- for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp, pnext));)
+ for (i = 0; i < in->values[0].value->data.array.values_num; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index++);
- zbx_vector_json_add_element(&objects_tmp, name, pnext);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+ zbx_vector_jsonobj_ref_add_object(&tmp, name, in->values[0].value->data.array.values[i]);
}
- objects = &objects_tmp;
+ in = &tmp;
+ *definite_path = 0;
}
if (ZBX_JSONPATH_FUNCTION_LENGTH == type)
{
- *output = zbx_dsprintf(NULL, "%d", objects->values_num);
+ zbx_snprintf(buffer, sizeof(buffer), "%d", in->values_num);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
goto out;
}
if (ZBX_JSONPATH_FUNCTION_FIRST == type)
{
- if (0 < objects->values_num)
- ret = jsonpath_extract_element(objects->values[0].value, output);
- else
- ret = SUCCEED;
+ if (0 < in->values_num)
+ zbx_vector_jsonobj_ref_add(out, &in->values[0]);
+ *definite_path = 1;
+ ret = SUCCEED;
goto out;
}
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot apply aggregation function to empty array");
goto out;
}
- if (FAIL == jsonpath_extract_numeric_value(objects->values[0].value, &result))
+ if (FAIL == jsonpath_get_numeric_value(in->values[0].value, &result))
goto out;
- for (i = 1; i < objects->values_num; i++)
+ for (i = 1; i < in->values_num; i++)
{
double value;
- if (FAIL == jsonpath_extract_numeric_value(objects->values[i].value, &value))
+ if (FAIL == jsonpath_get_numeric_value(in->values[i].value, &value))
goto out;
switch (type)
@@ -2324,19 +2662,22 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
}
if (ZBX_JSONPATH_FUNCTION_AVG == type)
- result /= objects->values_num;
+ result /= in->values_num;
- *output = zbx_dsprintf(NULL, ZBX_FS_DBL, result);
- if (SUCCEED != is_double(*output, NULL))
+ zbx_print_double(buffer, sizeof(buffer), result);
+ if (SUCCEED != is_double(buffer, NULL))
{
- zbx_set_json_strerror("invalid function result: %s", *output);
+ zbx_set_json_strerror("invalid function result: %s", buffer);
goto out;
}
- del_zeros(*output);
+
+ del_zeros(buffer);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
out:
- zbx_vector_json_clear_ext(&objects_tmp);
- zbx_vector_json_destroy(&objects_tmp);
+ zbx_vector_jsonobj_ref_clear_ext(&tmp);
+ zbx_vector_jsonobj_ref_destroy(&tmp);
return ret;
}
@@ -2345,58 +2686,47 @@ out:
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: jp_root - [IN] the document root *
- * objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * output - [OUT] the output value *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * path_depth - [IN] the jsonpath segment to match *
+ * definite_path - [IN/OUT] *
+ * out - [OUT] the result object *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const zbx_vector_json_t *objects,
- const zbx_jsonpath_t *jsonpath, int path_depth, char **output)
+static int jsonpath_apply_functions(zbx_jsonpath_context_t *ctx, int path_depth, int *definite_path,
+ zbx_vector_jsonobj_ref_t *out)
{
- int ret, definite_path;
- zbx_vector_json_t input;
- char *input_json = NULL;
+ int ret;
+ zbx_vector_jsonobj_ref_t in;
- zbx_vector_json_create(&input);
+ zbx_vector_jsonobj_ref_create(&in);
/* when functions are applied directly to the json document (at the start of the jsonpath ) */
/* it makes all document as input object */
if (0 == path_depth)
- zbx_vector_json_add_element(&input, "", jp_root->start);
+ zbx_vector_jsonobj_ref_add_object(&in, "", ctx->root);
else
- zbx_vector_json_copy(&input, objects);
-
- definite_path = jsonpath->definite;
+ zbx_vector_jsonobj_ref_copy(&in, &ctx->objects);
for (;;)
{
- ret = jsonpath_apply_function(&input, jsonpath->segments[path_depth++].data.function.type,
- definite_path, output);
+ ret = jsonpath_apply_function(&in, ctx->path->segments[path_depth++].data.function.type,
+ definite_path, out);
- zbx_vector_json_clear_ext(&input);
- zbx_free(input_json);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
- if (SUCCEED != ret || path_depth == jsonpath->segments_num)
+ if (SUCCEED != ret || path_depth == ctx->path->segments_num)
break;
- if (NULL != *output)
- {
- zbx_vector_json_add_element(&input, "", *output);
- input_json = *output;
- *output = NULL;
- }
-
- /* functions return single value, so for the next functions path becomes definite */
- definite_path = 1;
+ zbx_vector_jsonobj_ref_copy(&in, out);
+ zbx_vector_jsonobj_ref_clear_ext(out);
}
- zbx_vector_json_destroy(&input);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
+ zbx_vector_jsonobj_ref_destroy(&in);
return ret;
}
@@ -2405,49 +2735,37 @@ static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const
* *
* Purpose: format query result, depending on jsonpath type *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath used to acquire result *
- * output - [OUT] the output value *
+ * Parameters: objects - [IN] the matched json refs (name, value) *
+ * definite_path - [IN] the jsonpath definite flag *
+ * output - [OUT] the output value *
* *
* Return value: SUCCEED - the result was formatted successfully *
* FAIL - invalid result data (internal json error) *
* *
******************************************************************************/
-static int jsonpath_format_query_result(const zbx_vector_json_t *objects, zbx_jsonpath_t *jsonpath, char **output)
+static int jsonpath_format_query_result(const zbx_vector_jsonobj_ref_t *objects, int definite_path, char **output)
{
size_t output_offset = 0, output_alloc;
int i;
+ char delim;
if (0 == objects->values_num)
return SUCCEED;
- if (1 == jsonpath->definite)
- {
- return jsonpath_extract_element(objects->values[0].value, output);
- }
+ if (1 == definite_path)
+ return jsonpath_str_copy_value(output, &output_alloc, &output_offset, objects->values[0].value);
/* reserve 32 bytes per returned object plus array start/end [] and terminating zero */
- output_alloc = objects->values_num * 32 + 3;
+ output_alloc = (size_t)objects->values_num * 32 + 3;
*output = (char *)zbx_malloc(NULL, output_alloc);
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, '[');
+ delim = '[';
for (i = 0; i < objects->values_num; i++)
{
- struct zbx_json_parse jp;
-
- if (FAIL == jsonpath_pointer_to_jp(objects->values[i].value, &jp))
- {
- zbx_set_json_strerror("cannot format query result, unrecognized json part starting with: %s",
- objects->values[i].value);
- zbx_free(*output);
- return FAIL;
- }
-
- if (0 != i)
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ',');
-
- zbx_strncpy_alloc(output, &output_alloc, &output_offset, jp.start, jp.end - jp.start + 1);
+ zbx_chrcpy_alloc(output, &output_alloc, &output_offset, delim);
+ zbx_jsonobj_to_string(output, &output_alloc, &output_offset, objects->values[i].value);
+ delim = ',';
}
zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ']');
@@ -2470,7 +2788,7 @@ void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath)
* Purpose: compile jsonpath to be used in queries *
* *
* Parameters: path - [IN] the path to parse *
- * jsonpath - [IN/OUT] the compiled jsonpath *
+ * jsonpath - [IN/OUT] the compiled jsonpath *
* *
* Return value: SUCCEED - the segment was parsed successfully *
* FAIL - otherwise *
@@ -2582,38 +2900,89 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
* being counted as successful query) *
* FAIL - otherwise *
* *
+ * Comments: This function is for compatibility purposes. Where possible the *
+ * zbx_jsonobj_query() function must be used. *
+ * *
******************************************************************************/
int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output)
{
+ int ret;
+ zbx_jsonobj_t obj;
+
+ if (SUCCEED != zbx_jsonobj_open(jp->start, &obj))
+ return FAIL;
+
+ ret = zbx_jsonobj_query(&obj, path, output);
+
+ zbx_jsonobj_clear(&obj);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: perform jsonpath query on the specified json object *
+ * *
+ * Parameters: obj - [IN] the json object *
+ * path - [IN] the jsonpath *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the query was performed successfully (empty result *
+ * being counted as successful query) *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_query(zbx_jsonobj_t *obj, const char *path, char **output)
+{
+ zbx_jsonpath_context_t ctx;
zbx_jsonpath_t jsonpath;
- int path_depth = 0, ret = SUCCEED;
- zbx_vector_json_t objects;
- unsigned char done = 0;
+ int ret = SUCCEED;
if (FAIL == zbx_jsonpath_compile(path, &jsonpath))
return FAIL;
- zbx_vector_json_create(&objects);
+ ctx.found = 0;
+ ctx.root = obj;
+ ctx.path = &jsonpath;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if ('{' == *jp->start)
- ret = jsonpath_query_object(jp, jp, &jsonpath, path_depth, &done, &objects);
- else if ('[' == *jp->start)
- ret = jsonpath_query_array(jp, jp, &jsonpath, path_depth, &done, &objects);
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(&ctx, obj, 0);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(&ctx, obj, 0);
+ break;
+ default:
+ break;
+ }
if (SUCCEED == ret)
{
+ zbx_vector_jsonobj_ref_t out;
+ int definite_path = jsonpath.definite, path_depth;
+
+ zbx_vector_jsonobj_ref_create(&out);
+
path_depth = jsonpath.segments_num;
while (0 < path_depth && ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath.segments[path_depth - 1].type)
path_depth--;
if (path_depth < jsonpath.segments_num)
- ret = jsonpath_apply_functions(jp, &objects, &jsonpath, path_depth, output);
+ {
+ if (SUCCEED == (ret = jsonpath_apply_functions(&ctx, path_depth, &definite_path, &out)))
+ ret = jsonpath_format_query_result(&out, definite_path, output);
+ }
else
- ret = jsonpath_format_query_result(&objects, &jsonpath, output);
+ ret = jsonpath_format_query_result(&ctx.objects, definite_path, output);
+
+ zbx_vector_jsonobj_ref_clear_ext(&out);
+ zbx_vector_jsonobj_ref_destroy(&out);
}
- zbx_vector_json_clear_ext(&objects);
- zbx_vector_json_destroy(&objects);
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
zbx_jsonpath_clear(&jsonpath);
return ret;
diff --git a/src/libs/zbxjson/jsonpath.h b/src/libs/zbxjson/jsonpath.h
index ae3262a1009..644aef6aa4a 100644
--- a/src/libs/zbxjson/jsonpath.h
+++ b/src/libs/zbxjson/jsonpath.h
@@ -20,9 +20,10 @@
#ifndef ZABBIX_JSONPATH_H
#define ZABBIX_JSONPATH_H
-#include "zbxalgo.h"
#include "zbxjson.h"
+typedef struct zbx_jsonpath_token zbx_jsonpath_token_t;
+
typedef enum
{
ZBX_JSONPATH_SEGMENT_UNKNOWN,
@@ -79,10 +80,19 @@ typedef struct
}
zbx_jsonpath_range_t;
+typedef enum
+{
+ ZBX_JSONPATH_EXPRESSION_INDEX_TRUE,
+ ZBX_JSONPATH_EXPRESSION_INDEX_FALSE,
+}
+zbx_json_path_expression_index_t;
+
/* expression tokens in postfix notation */
typedef struct
{
zbx_vector_ptr_t tokens;
+ zbx_jsonpath_token_t *index_token; /* relative path token that is used to index parent object */
+ zbx_jsonpath_token_t *value_token; /* the index value token */
}
zbx_jsonpath_expression_t;
@@ -151,12 +161,11 @@ typedef enum
}
zbx_jsonpath_token_type_t;
-typedef struct
+struct zbx_jsonpath_token
{
unsigned char type;
char *text;
zbx_jsonpath_t *path;
-}
-zbx_jsonpath_token_t;
+};
#endif
diff --git a/src/zabbix_agent/Makefile.am b/src/zabbix_agent/Makefile.am
index d2006c2399f..740d9cd1a3b 100644
--- a/src/zabbix_agent/Makefile.am
+++ b/src/zabbix_agent/Makefile.am
@@ -52,13 +52,13 @@ zabbix_agentd_LDADD = \
$(top_builddir)/src/libs/zbxsysinfo/simple/libsimplesysinfo.a \
$(top_builddir)/src/libs/zbxlog/libzbxlog.a \
$(top_builddir)/src/libs/zbxregexp/libzbxregexp.a \
- $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxsys/libzbxsys.a \
$(top_builddir)/src/libs/zbxnix/libzbxnix.a \
$(top_builddir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_builddir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
$(top_builddir)/src/libs/zbxconf/libzbxconf.a \
$(top_builddir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_builddir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_builddir)/src/libs/zbxexec/libzbxexec.a \
diff --git a/src/zabbix_server/Makefile.am b/src/zabbix_server/Makefile.am
index 23d1430c2db..1c03570c1b0 100644
--- a/src/zabbix_server/Makefile.am
+++ b/src/zabbix_server/Makefile.am
@@ -93,8 +93,8 @@ zabbix_server_LDADD = \
$(top_builddir)/src/libs/zbxself/libzbxself.a \
$(top_builddir)/src/libs/zbxself/libzbxself_server.a \
$(top_builddir)/src/libs/zbxnix/libzbxnix.a \
- $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxsys/libzbxsys.a \
+ $(top_builddir)/src/libs/zbxipcservice/libzbxipcservice.a \
$(top_builddir)/src/libs/zbxconf/libzbxconf.a \
$(top_builddir)/src/libs/zbxmedia/libzbxmedia.a \
$(top_builddir)/src/libs/zbxaudit/libzbxaudit.a \
@@ -104,6 +104,8 @@ zabbix_server_LDADD = \
$(top_builddir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_builddir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
$(top_builddir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
+ $(top_builddir)/src/libs/zbxvault/libzbxvault.a \
$(top_builddir)/src/libs/zbxhttp/libzbxhttp.a \
$(top_builddir)/src/libs/zbxipcservice/libzbxipcservice.a \
$(top_builddir)/src/libs/zbxexec/libzbxexec.a \
diff --git a/src/zabbix_server/preprocessor/item_preproc.c b/src/zabbix_server/preprocessor/item_preproc.c
index 2748cade102..12d81aa4bff 100644
--- a/src/zabbix_server/preprocessor/item_preproc.c
+++ b/src/zabbix_server/preprocessor/item_preproc.c
@@ -819,7 +819,8 @@ static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **
* *
* Purpose: execute jsonpath query *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -827,18 +828,59 @@ static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **
* FAIL - otherwise *
* *
******************************************************************************/
-static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, char **errmsg)
+static int item_preproc_jsonpath_op(zbx_preproc_cache_t *cache, zbx_variant_t *value, const char *params,
+ char **errmsg)
{
- struct zbx_json_parse jp;
- char *data = NULL;
+ char *data = NULL;
- if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
- return FAIL;
+ if (NULL == cache)
+ {
+ zbx_jsonobj_t obj;
+
+ if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
+ return FAIL;
- if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_jsonpath_query(&jp, params, &data))
+ if (FAIL == zbx_jsonobj_open(value->data.str, &obj))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
+
+ if (FAIL == zbx_jsonobj_query(&obj, params, &data))
+ {
+ zbx_jsonobj_clear(&obj);
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
+
+ zbx_jsonobj_clear(&obj);
+ }
+ else
{
- *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
- return FAIL;
+ zbx_jsonobj_t *obj;
+
+ if (NULL == (obj = (zbx_jsonobj_t *)zbx_preproc_cache_get(cache, ZBX_PREPROC_JSONPATH)))
+ {
+ if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
+ return FAIL;
+
+ obj = (zbx_jsonobj_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+
+ if (SUCCEED != zbx_jsonobj_open(value->data.str, obj))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ zbx_free(obj);
+ return FAIL;
+ }
+
+ zbx_preproc_cache_put(cache, ZBX_PREPROC_JSONPATH, obj);
+ }
+
+ if (FAIL == zbx_jsonobj_query(obj, params, &data))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
}
if (NULL == data)
@@ -857,7 +899,8 @@ static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, ch
* *
* Purpose: execute jsonpath query *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -865,11 +908,12 @@ static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, ch
* FAIL - otherwise *
* *
******************************************************************************/
-static int item_preproc_jsonpath(zbx_variant_t *value, const char *params, char **errmsg)
+static int item_preproc_jsonpath(zbx_preproc_cache_t *cache, zbx_variant_t *value, const char *params,
+ char **errmsg)
{
char *err = NULL;
- if (SUCCEED == item_preproc_jsonpath_op(value, params, &err))
+ if (SUCCEED == item_preproc_jsonpath_op(cache, value, params, &err))
return SUCCEED;
*errmsg = zbx_dsprintf(*errmsg, "cannot extract value from json by path \"%s\": %s", params, err);
@@ -1456,7 +1500,8 @@ fail:
* *
* Purpose: parse Prometheus format metrics *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -2033,7 +2078,7 @@ int zbx_item_preproc(zbx_preproc_cache_t *cache, unsigned char value_type, zbx_v
ret = item_preproc_xpath(value, op->params, error);
break;
case ZBX_PREPROC_JSONPATH:
- ret = item_preproc_jsonpath(value, op->params, error);
+ ret = item_preproc_jsonpath(cache, value, op->params, error);
break;
case ZBX_PREPROC_VALIDATE_RANGE:
ret = item_preproc_validate_range(value_type, value, op->params, error);
diff --git a/src/zabbix_server/preprocessor/preproc_cache.c b/src/zabbix_server/preprocessor/preproc_cache.c
index 1ea66e5267a..58803324f06 100644
--- a/src/zabbix_server/preprocessor/preproc_cache.c
+++ b/src/zabbix_server/preprocessor/preproc_cache.c
@@ -96,6 +96,11 @@ void zbx_preproc_cache_clear(zbx_preproc_cache_t *cache)
case ZBX_PREPROC_PROMETHEUS_PATTERN:
zbx_prometheus_clear((zbx_prometheus_t *)cache->refs.values[i].impl);
zbx_free(cache->refs.values[i].impl);
+ break;
+ case ZBX_PREPROC_JSONPATH:
+ zbx_jsonobj_clear((zbx_jsonobj_t *)cache->refs.values[i].impl);
+ zbx_free(cache->refs.values[i].impl);
+ break;
}
}
diff --git a/tests/libs/zbxcommon/Makefile.am b/tests/libs/zbxcommon/Makefile.am
index 3a89906dbd2..2bb97ad8eab 100644
--- a/tests/libs/zbxcommon/Makefile.am
+++ b/tests/libs/zbxcommon/Makefile.am
@@ -74,7 +74,6 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxmemory/libzbxmemory.a \
$(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
$(top_srcdir)/src/libs/zbxself/libzbxself.a \
- $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/src/libs/zbxmedia/libzbxmedia.a \
@@ -85,6 +84,7 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
diff --git a/tests/libs/zbxjson/Makefile.am b/tests/libs/zbxjson/Makefile.am
index 335cc78a2af..4053c451a5c 100644
--- a/tests/libs/zbxjson/Makefile.am
+++ b/tests/libs/zbxjson/Makefile.am
@@ -3,7 +3,7 @@ noinst_PROGRAMS = \
zbx_json_decodevalue \
zbx_json_decodevalue_dyn \
zbx_jsonpath_compile \
- zbx_jsonpath_query
+ zbx_jsonobj_query
JSON_LIBS = \
$(top_srcdir)/tests/libzbxmocktest.a \
@@ -101,22 +101,22 @@ endif
zbx_jsonpath_compile_CFLAGS = -I@top_srcdir@/tests
-# zbx_jsonpath_query
+# zbx_jsonobj_query
-zbx_jsonpath_query_SOURCES = \
- zbx_jsonpath_query.c \
+zbx_jsonobj_query_SOURCES = \
+ zbx_jsonobj_query.c \
../../zbxmocktest.h
-zbx_jsonpath_query_LDADD = $(JSON_LIBS)
+zbx_jsonobj_query_LDADD = $(JSON_LIBS)
if SERVER
-zbx_jsonpath_query_LDADD += @SERVER_LIBS@
-zbx_jsonpath_query_LDFLAGS = @SERVER_LDFLAGS@
+zbx_jsonobj_query_LDADD += @SERVER_LIBS@
+zbx_jsonobj_query_LDFLAGS = @SERVER_LDFLAGS@
else
if PROXY
-zbx_jsonpath_query_LDADD += @PROXY_LIBS@
-zbx_jsonpath_query_LDFLAGS = @PROXY_LDFLAGS@
+zbx_jsonobj_query_LDADD += @PROXY_LIBS@
+zbx_jsonobj_query_LDFLAGS = @PROXY_LDFLAGS@
endif
endif
-zbx_jsonpath_query_CFLAGS = -I@top_srcdir@/tests
+zbx_jsonobj_query_CFLAGS = -I@top_srcdir@/tests
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.c b/tests/libs/zbxjson/zbx_jsonobj_query.c
index 0beb97d1503..ce8d603e1a6 100644
--- a/tests/libs/zbxjson/zbx_jsonpath_query.c
+++ b/tests/libs/zbxjson/zbx_jsonobj_query.c
@@ -51,26 +51,13 @@ static void check_indefinite_path_result(zbx_mock_handle_t handle, const char *r
zbx_mock_assert_json_eq("Indefinite query result", expected_output, returned_output);
}
-void zbx_mock_test_entry(void **state)
+static void test_query(zbx_jsonobj_t *obj, const char *path, int expected_ret)
{
- const char *data, *path;
- struct zbx_json_parse jp;
char *output = NULL;
- int expected_ret, returned_ret;
+ int returned_ret;
zbx_mock_handle_t handle;
- ZBX_UNUSED(state);
-
- /* reset json error to check if compilation will set it */
- zbx_set_json_strerror("%s", "");
-
- data = zbx_mock_get_parameter_string("in.data");
- if (FAIL == zbx_json_open(data, &jp))
- fail_msg("Invalid json data: %s", zbx_json_strerror());
-
- path = zbx_mock_get_parameter_string("in.path");
- returned_ret = zbx_jsonpath_query(&jp, path, &output);
- expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return"));
+ returned_ret = zbx_jsonobj_query(obj, path, &output);
if (FAIL == returned_ret)
printf("\tzbx_jsonpath_query() failed with: %s\n", zbx_json_strerror());
@@ -97,4 +84,31 @@ void zbx_mock_test_entry(void **state)
zbx_mock_assert_str_ne("tzbx_jsonpath_query() error", "", zbx_json_strerror());
zbx_free(output);
+
+}
+
+void zbx_mock_test_entry(void **state)
+{
+ const char *data, *path;
+ int expected_ret;
+ zbx_jsonobj_t obj;
+
+ ZBX_UNUSED(state);
+
+ /* reset json error to check if compilation will set it */
+ zbx_set_json_strerror("%s", "");
+
+ data = zbx_mock_get_parameter_string("in.data");
+ if (FAIL == zbx_jsonobj_open(data, &obj))
+ fail_msg("Invalid json data: %s", zbx_json_strerror());
+
+ path = zbx_mock_get_parameter_string("in.path");
+ expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return"));
+
+ test_query(&obj, path, expected_ret);
+
+ /* query second time to check index reuse */
+ test_query(&obj, path, expected_ret);
+
+ zbx_jsonobj_clear(&obj);
}
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml b/tests/libs/zbxjson/zbx_jsonobj_query.inc.yaml
index 456f49ebe28..456f49ebe28 100644
--- a/tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml
+++ b/tests/libs/zbxjson/zbx_jsonobj_query.inc.yaml
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.yaml b/tests/libs/zbxjson/zbx_jsonobj_query.yaml
index a4b784b90d9..7e9aae0044d 100644
--- a/tests/libs/zbxjson/zbx_jsonpath_query.yaml
+++ b/tests/libs/zbxjson/zbx_jsonobj_query.yaml
@@ -37,7 +37,7 @@ out:
return: SUCCEED
---
test case: Query $.filters.price
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters.price
@@ -46,7 +46,7 @@ out:
value: 10
---
test case: Query $.filters.category
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters.category
@@ -55,7 +55,7 @@ out:
value: fiction
---
test case: Query $.filters.id
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters.id
@@ -63,7 +63,7 @@ out:
return: SUCCEED
---
test case: Query $.books[1].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[1].title
@@ -72,7 +72,7 @@ out:
value: Sword of Honour
---
test case: Query $['closed message']
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $['closed message']
@@ -81,7 +81,7 @@ out:
value: Store is closed
---
test case: Query $.books[-1].author
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[-1].author
@@ -90,7 +90,7 @@ out:
value: J. R. R. Tolkien
---
test case: Query $.filters
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters
@@ -104,7 +104,7 @@ out:
}
---
test case: Query $.books.length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books.length()
@@ -113,7 +113,7 @@ out:
value: 4
---
test case: Query $.tags[:]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:]
@@ -122,7 +122,7 @@ out:
value: '["a", "b", "c", "d", "e" ]'
---
test case: Query $.tags[2:]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[2:]
@@ -131,7 +131,7 @@ out:
value: '["c", "d", "e" ]'
---
test case: Query $.tags[:2]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:2]
@@ -140,7 +140,7 @@ out:
value: '["a", "b"]'
---
test case: Query $.tags[1:4]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[1:4]
@@ -149,7 +149,7 @@ out:
value: '["b", "c", "d"]'
---
test case: Query $.tags[-2:]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[-2:]
@@ -158,7 +158,7 @@ out:
value: '["d", "e"]'
---
test case: Query $.tags[:-3]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:-3]
@@ -167,7 +167,7 @@ out:
value: '["a", "b"]'
---
test case: Query $.tags[:-3].length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:-3].length()
@@ -176,25 +176,25 @@ out:
value: 2
---
test case: Query $.books[0, 2].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[0, 2].title
out:
return: SUCCEED
- value: '["Sayings of the Century", "Moby Dick"]'
+ value: '["Moby Dick", "Sayings of the Century"]'
---
test case: Query $.books[1]['author', "title"]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[1]['author', "title"]
out:
return: SUCCEED
- value: '["Evelyn Waugh", "Sword of Honour"]'
+ value: '["Sword of Honour", "Evelyn Waugh"]'
---
test case: Query $..id
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..id
@@ -203,16 +203,16 @@ out:
value: '[1, 2, 3, 4]'
---
test case: Query $.services..price
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services..price
out:
return: SUCCEED
- value: '[5, 154.99, 46, 24.5, 99.49]'
+ value: '[154.99, 5, 46, 24.5, 99.49]'
---
test case: Query $.books[?(@.id == 1 + 1)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 1 + 1)].title
@@ -221,7 +221,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 4 / 2)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 4 / 2)].title
@@ -230,7 +230,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 7 - 5)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 7 - 5)].title
@@ -239,7 +239,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 0.4 * 5)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 0.4 * 5)].title
@@ -248,7 +248,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 4 - 0.4 * 5)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 4 - 0.4 * 5)].title
@@ -257,7 +257,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == -0.4 * 5 + 4)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == -0.4 * 5 + 4)].title
@@ -266,7 +266,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 0.4 * (-5) + 4)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 0.4 * (-5) + 4)].title
@@ -275,7 +275,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 2 || @.id == 4)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2 || @.id == 4)].title
@@ -284,7 +284,7 @@ out:
value: '["Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.id == 2 && 2 * ((1 + 3) / 2 + 3) == 10)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2 && 2 * ((1 + 3) / 2 + 3) == 10)].title
@@ -293,7 +293,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 2 == 1)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2 == 1)].title
@@ -302,7 +302,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(!(@.id == 2))].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(!(@.id == 2))].title
@@ -311,7 +311,7 @@ out:
value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.id != 2)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id != 2)].title
@@ -320,7 +320,7 @@ out:
value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.title =~ " of ")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.title =~ " of ")].title
@@ -329,7 +329,7 @@ out:
value: '["Sayings of the Century", "Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.price > 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price > 12.99)].title
@@ -338,7 +338,7 @@ out:
value: '["The Lord of the Rings"]'
---
test case: Query $.books[?(@.price >= 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price >= 12.99)].title
@@ -347,7 +347,7 @@ out:
value: '["Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.price < 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price < 12.99)].title
@@ -356,7 +356,7 @@ out:
value: '["Sayings of the Century", "Moby Dick"]'
---
test case: Query $.books[?(@.price <= 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price <= 12.99)].title
@@ -365,7 +365,7 @@ out:
value: '["Sayings of the Century", "Sword of Honour", "Moby Dick"]'
---
test case: Query $.books[?(@.author > "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author > "Herman Melville")].title
@@ -374,7 +374,7 @@ out:
value: '["Sayings of the Century", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.author >= "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author >= "Herman Melville")].title
@@ -383,7 +383,7 @@ out:
value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.author < "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author < "Herman Melville")].title
@@ -392,7 +392,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.author <= "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author <= "Herman Melville")].title
@@ -401,7 +401,7 @@ out:
value: '["Sword of Honour", "Moby Dick"]'
---
test case: Query $.books[?(@.price > $.filters.price)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price > $.filters.price)].title
@@ -410,7 +410,7 @@ out:
value: '["Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.category == $.filters.category)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category == $.filters.category)].title
@@ -419,7 +419,7 @@ out:
value: '["Sword of Honour","Moby Dick","The Lord of the Rings"]'
---
test case: Query $.books[?(@.category != $.filters.category)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category != $.filters.category)].title
@@ -428,7 +428,7 @@ out:
value: '["Sayings of the Century"]'
---
test case: Query $..[?(@.id)]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..[?(@.id)]
@@ -469,7 +469,7 @@ out:
]
---
test case: Query $.services..[?(@.price > 50)].description
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services..[?(@.price > 50)].description
@@ -478,7 +478,7 @@ out:
value: '["Printing and assembling book in A5 format", "Rebinding torn book"]'
---
test case: Query $..id.length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..id.length()
@@ -487,7 +487,7 @@ out:
value: 4
---
test case: Query $.books[?(@.price >= 12.99)].length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price >= 12.99)].length()
@@ -496,7 +496,7 @@ out:
value: 2
---
test case: Query $.books[?(@.id == 2)].title.first()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2)].title.first()
@@ -505,7 +505,7 @@ out:
value: Sword of Honour
---
test case: Query $..tags.first().length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..tags.first().length()
@@ -514,7 +514,7 @@ out:
value: 5
---
test case: Query $.bad.path.first().length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.bad.path.first().length()
@@ -522,7 +522,7 @@ out:
return: FAIL
---
test case: Query $.[?(@.ElementName == "test")].values.first().length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.[?(@.ElementName == "test")].values.first().length()
@@ -562,7 +562,7 @@ out:
value: a
---
test case: Query $.books[*].price.min()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[*].price.min()
@@ -571,7 +571,7 @@ out:
value: 8.95
---
test case: Query $..price.max()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..price.max()
@@ -580,7 +580,7 @@ out:
value: 154.99
---
test case: Query $.books[?(@.category == "fiction")].price.avg()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category == "fiction")].price.avg()
@@ -589,7 +589,7 @@ out:
value: 14.99
---
test case: Query $.books[?(@.category == $.filters.xyz)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category == $.filters.xyz)].title
@@ -597,7 +597,7 @@ out:
return: SUCCEED
---
test case: Query $.filters['no filters']
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters['no filters']
@@ -606,16 +606,16 @@ out:
value: no "filters"
---
test case: Query $.services[?(@.active=="true")].servicegroup
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services[?(@.active=="true")].servicegroup
out:
return: SUCCEED
- value: '[1000,1001]'
+ value: '[1001,1000]'
---
test case: Query $.services[?(@.active=="false")].servicegroup
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services[?(@.active=="false")].servicegroup
@@ -624,7 +624,7 @@ out:
value: '[1002]'
---
test case: Query $.books[?(@.title =~ "[a-z")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.title =~ "[a-z")].title
@@ -632,7 +632,7 @@ out:
return: FAIL
---
test case: $..books[?(!@.isbn)]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..books[?(!@.isbn)]
@@ -657,7 +657,7 @@ out:
]
---
test case: $..books[?(@.isbn)]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..books[?(@.isbn)]
@@ -684,7 +684,7 @@ out:
]
---
test case: Query $.books[*].price.sum()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[*].price.sum()
@@ -725,25 +725,25 @@ out:
values: '[2]'
---
test case: Query $.*~
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.*~
out:
return: SUCCEED
- value: '["books","services","filters","closed message","tags"]'
+ value: '["filters", "services", "tags", "books", "closed message"]'
---
test case: Query $.*~.first()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.*~.first()
out:
return: SUCCEED
- value: 'books'
+ value: 'filters'
---
test case: Query $.services[?(@.servicegroup=="1002")]~
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services[?(@.servicegroup=="1002")]~
@@ -752,11 +752,49 @@ out:
value: '["restoration"]'
---
test case: Query $.books[?(@.category=="fiction")]~
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category=="fiction")]~
out:
return: SUCCEED
value: '["1","2","3"]'
+---
+test case: Query $.books[?(@.category=="reference")].price
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.category=="reference")].price
+out:
+ return: SUCCEED
+ value: '[8.95]'
+---
+test case: Query $.books[1,1].title
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1,1].title
+out:
+ return: SUCCEED
+ value: Sword of Honour
+---
+test case: Query $.books[1:2].title
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1:2].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[1]["title","title"]
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1].["title","title"]
+out:
+ return: SUCCEED
+ value: Sword of Honour
...
+
+
diff --git a/tests/libs/zbxsysinfo/Makefile.am b/tests/libs/zbxsysinfo/Makefile.am
index 17de2bbc969..db648805c5b 100644
--- a/tests/libs/zbxsysinfo/Makefile.am
+++ b/tests/libs/zbxsysinfo/Makefile.am
@@ -59,11 +59,11 @@ parse_item_key_LDADD = \
$(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
$(top_srcdir)/src/libs/zbxself/libzbxself.a \
$(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
- $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/src/libs/zbxmedia/libzbxmedia.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
@@ -102,13 +102,13 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo_httpmetrics.a \
$(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
$(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
- $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
$(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
@@ -174,6 +174,7 @@ check_key_access_rules_SOURCES = \
check_key_access_rules_LDADD = $(COMMON_LIB_FILES) \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo_http.a \
$(top_srcdir)/src/libs/zbxhttp/libzbxhttp.a
diff --git a/tests/libs/zbxsysinfo/common/Makefile.am b/tests/libs/zbxsysinfo/common/Makefile.am
index b66785e1c36..d9a22639457 100644
--- a/tests/libs/zbxsysinfo/common/Makefile.am
+++ b/tests/libs/zbxsysinfo/common/Makefile.am
@@ -22,13 +22,13 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo_http.a \
$(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
$(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
- $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
$(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
diff --git a/tests/libs/zbxsysinfo/linux/Makefile.am b/tests/libs/zbxsysinfo/linux/Makefile.am
index 498ef42b76b..03e3aed0e66 100644
--- a/tests/libs/zbxsysinfo/linux/Makefile.am
+++ b/tests/libs/zbxsysinfo/linux/Makefile.am
@@ -30,13 +30,13 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo_http.a \
$(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
$(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
- $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
$(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
diff --git a/tests/zabbix_server/poller/Makefile.am b/tests/zabbix_server/poller/Makefile.am
new file mode 100644
index 00000000000..31f478fa1bb
--- /dev/null
+++ b/tests/zabbix_server/poller/Makefile.am
@@ -0,0 +1,61 @@
+if SERVER
+SERVER_tests = zbx_poller_test
+
+noinst_PROGRAMS = $(SERVER_tests)
+
+COMMON_SRC_FILES = \
+ ../../zbxmocktest.h
+
+POLLER_LIBS = \
+ $(top_srcdir)/tests/libzbxmocktest.a \
+ $(top_srcdir)/tests/libzbxmockdata.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/libzbxserversysinfo.a \
+ $(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
+ $(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo_httpmetrics.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo_http.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/simple/libsimplesysinfo.a \
+ $(top_srcdir)/src/libs/zbxthreads/libzbxthreads.a \
+ $(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/alias/libalias.a \
+ $(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
+ $(top_srcdir)/src/libs/zbxmutexs/libzbxmutexs.a \
+ $(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
+ $(top_srcdir)/src/libs/zbxhash/libzbxhash.a \
+ $(top_srcdir)/src/libs/zbxhttp/libzbxhttp.a \
+ $(top_srcdir)/src/libs/zbxvariant/libzbxvariant.a \
+ $(top_srcdir)/src/libs/zbxnum/libzbxnum.a \
+ $(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
+ $(top_srcdir)/src/libs/zbxtime/libzbxtime.a \
+ $(top_srcdir)/src/libs/zbxstr/libzbxstr.a \
+ $(top_srcdir)/src/libs/zbxip/libzbxip.a \
+ $(top_srcdir)/src/libs/zbxparam/libzbxparam.a \
+ $(top_srcdir)/src/libs/zbxexpr/libzbxexpr.a \
+ $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
+ $(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
+ $(top_srcdir)/src/libs/zbxserialize/libzbxserialize.a \
+ $(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a
+
+zbx_poller_test_SOURCES = \
+ ../../../src/zabbix_server/poller/checks_ssh.c \
+ ../../../src/zabbix_server/poller/checks_telnet.c \
+ zbx_poller_test.c \
+ test_get_value_ssh.c \
+ test_get_value_telnet.c \
+ ../../zbxmockexit.c \
+ ../../zbxmockfile.c \
+ ../../zbxmocklog.c \
+ ../../zbxmockdir.c
+
+zbx_poller_test_LDADD = $(POLLER_LIBS)
+zbx_poller_test_LDADD += @SERVER_LIBS@
+zbx_poller_test_LDFLAGS = @SERVER_LDFLAGS@\
+ -Wl,--wrap=ssh_run \
+ -Wl,--wrap=telnet_run
+
+zbx_poller_test_CFLAGS = \
+ -I@top_srcdir@/tests @LIBXML2_CFLAGS@
+endif
diff --git a/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml b/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
index ef12178fa0a..640fcbef4b7 100644
--- a/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
+++ b/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
@@ -965,7 +965,7 @@ in:
out:
return: SUCCEED
value: |-
- {"b":[1, 2, 3]}
+ {"b":[1,2,3]}
---
test case: jsonpath5
in:
@@ -980,7 +980,7 @@ in:
out:
return: SUCCEED
value: |-
- [1, 2, 3]
+ [1,2,3]
---
test case: jsonpath6
in:
@@ -1008,7 +1008,7 @@ in:
params: $.a['b c']
out:
return: SUCCEED
- value: '["one", "two", "three"]'
+ value: '["one","two","three"]'
---
test case: jsonpath8
in: