Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
04aa31c7
Commit
04aa31c7
authored
Dec 09, 2016
by
Alexey Botchkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-11469 JSON_SEARCH returns incorrect results.
Support for '**' in json path expressions added.
parent
0f7864a9
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
125 additions
and
55 deletions
+125
-55
include/json_lib.h
include/json_lib.h
+15
-6
mysql-test/r/func_json.result
mysql-test/r/func_json.result
+6
-0
mysql-test/t/func_json.test
mysql-test/t/func_json.test
+2
-0
sql/item_jsonfunc.cc
sql/item_jsonfunc.cc
+56
-19
strings/json_lib.c
strings/json_lib.c
+42
-26
unittest/json_lib/json_lib-t.c
unittest/json_lib/json_lib-t.c
+4
-4
No files found.
include/json_lib.h
View file @
04aa31c7
...
...
@@ -69,17 +69,26 @@ int json_read_string_const_chr(json_string_t *js);
*/
/* Path step types - actually bitmasks to let '&' or '|' operations. */
enum
json_path_step_types
{
JSON_PATH_KEY
=
0
,
JSON_PATH_ARRAY
=
1
JSON_PATH_KEY_NULL
=
0
,
JSON_PATH_KEY
=
1
,
/* Must be equal to JSON_VALUE_OBJECT. */
JSON_PATH_ARRAY
=
2
,
/* Must be equal to JSON_VALUE_ARRAY. */
JSON_PATH_KEY_OR_ARRAY
=
3
,
JSON_PATH_WILD
=
4
,
/* Step like .* or [*] */
JSON_PATH_DOUBLE_WILD
=
8
,
/* Step like **.k or **[1] */
JSON_PATH_KEY_WILD
=
1
+
4
,
JSON_PATH_KEY_DOUBLEWILD
=
1
+
8
,
JSON_PATH_ARRAY_WILD
=
2
+
4
,
JSON_PATH_ARRAY_DOUBLEWILD
=
2
+
8
};
typedef
struct
st_json_path_step_t
{
enum
json_path_step_types
type
;
/* The type of the step -
KEY or ARRAY
*/
int
wild
;
/* If the step is a wildcard
*/
enum
json_path_step_types
type
;
/* The type of the step -
*/
/* see json_path_step_types
*/
const
uchar
*
key
;
/* Pointer to the beginning of the key. */
const
uchar
*
key_end
;
/* Pointer to the end of the key. */
uint
n_item
;
/* Item number in an array. No meaning for the key step. */
...
...
@@ -162,8 +171,8 @@ enum json_states {
enum
json_value_types
{
JSON_VALUE_OBJECT
=
0
,
JSON_VALUE_ARRAY
=
1
,
JSON_VALUE_OBJECT
=
1
,
JSON_VALUE_ARRAY
=
2
,
JSON_VALUE_STRING
,
JSON_VALUE_NUMBER
,
JSON_VALUE_TRUE
,
...
...
mysql-test/r/func_json.result
View file @
04aa31c7
...
...
@@ -40,6 +40,9 @@ NULL
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
json_query('{"key1":123, "key1": [1,2,3]}', '$.key1')
[1,2,3]
select json_query('{"key1":123, "key1": [1,2,3]}', concat('$', repeat('.k', 1000)));
json_query('{"key1":123, "key1": [1,2,3]}', concat('$', repeat('.k', 1000)))
NULL
select json_array();
json_array()
[]
...
...
@@ -289,6 +292,9 @@ json_search(@j, 'all', '10', NULL, '$[*]')
select json_search(@j, 'all', '10', NULL, '$[*][0].k');
json_search(@j, 'all', '10', NULL, '$[*][0].k')
"$[1][0].k"
select json_search(@j, 'all', '10', NULL, '$**.k');
json_search(@j, 'all', '10', NULL, '$**.k')
"$[1][0].k"
create table t1( json_col text );
insert into t1 values
('{ "a": "foobar" }'),
...
...
mysql-test/t/func_json.test
View file @
04aa31c7
...
...
@@ -14,6 +14,7 @@ select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2');
select
json_query
(
'{"key1":{"a":1, "b":[1,2]}}'
,
'$.key1'
);
select
json_query
(
'{"key1": 1}'
,
'$.key1'
);
select
json_query
(
'{"key1":123, "key1": [1,2,3]}'
,
'$.key1'
);
select
json_query
(
'{"key1":123, "key1": [1,2,3]}'
,
concat
(
'$'
,
repeat
(
'.k'
,
1000
)));
select
json_array
();
select
json_array
(
1
);
...
...
@@ -120,6 +121,7 @@ select json_search(@j, 'all', 'abc', NULL, '$');
select
json_search
(
@
j
,
'all'
,
'10'
,
NULL
,
'$'
);
select
json_search
(
@
j
,
'all'
,
'10'
,
NULL
,
'$[*]'
);
select
json_search
(
@
j
,
'all'
,
'10'
,
NULL
,
'$[*][0].k'
);
select
json_search
(
@
j
,
'all'
,
'10'
,
NULL
,
'$**.k'
);
create
table
t1
(
json_col
text
);
insert
into
t1
values
(
'{ "a": "foobar" }'
),
...
...
sql/item_jsonfunc.cc
View file @
04aa31c7
...
...
@@ -1506,7 +1506,7 @@ String *Item_func_json_insert::val_str(String *str)
goto
error
;
lp
=
c_path
->
p
.
last_step
+
1
;
if
(
lp
->
type
==
JSON_PATH_ARRAY
)
if
(
lp
->
type
&
JSON_PATH_ARRAY
)
{
uint
n_item
=
0
;
...
...
@@ -1722,7 +1722,7 @@ String *Item_func_json_remove::val_str(String *str)
goto
error
;
lp
=
c_path
->
p
.
last_step
+
1
;
if
(
lp
->
type
==
JSON_PATH_ARRAY
)
if
(
lp
->
type
&
JSON_PATH_ARRAY
)
{
if
(
je
.
value_type
!=
JSON_VALUE_ARRAY
)
continue
;
...
...
@@ -1982,7 +1982,7 @@ static int append_json_path(String *str, const json_path_t *p)
for
(
c
=
p
->
steps
+
1
;
c
<=
p
->
last_step
;
c
++
)
{
if
(
c
->
type
==
JSON_PATH_KEY
)
if
(
c
->
type
&
JSON_PATH_KEY
)
{
if
(
str
->
append
(
"."
,
1
)
||
append_simple
(
str
,
c
->
key
,
c
->
key_end
-
c
->
key
))
...
...
@@ -2002,6 +2002,7 @@ static int append_json_path(String *str, const json_path_t *p)
}
#ifdef DUMMY
static
int
json_path_compare
(
const
json_path_t
*
a
,
const
json_path_t
*
b
)
{
uint
i
,
a_len
=
a
->
last_step
-
a
->
steps
,
b_len
=
b
->
last_step
-
b
->
steps
;
...
...
@@ -2014,17 +2015,17 @@ static int json_path_compare(const json_path_t *a, const json_path_t *b)
const
json_path_step_t
*
sa
=
a
->
steps
+
i
;
const
json_path_step_t
*
sb
=
b
->
steps
+
i
;
if
(
sa
->
type
!=
sb
->
type
)
if
(
!
((
sa
->
type
&
sb
->
type
)
&
JSON_PATH_KEY_OR_ARRAY
)
)
return
-
1
;
if
(
sa
->
type
==
JSON_PATH_ARRAY
)
if
(
sa
->
type
&
JSON_PATH_ARRAY
)
{
if
(
!
sa
->
wild
&&
sa
->
n_item
!=
sb
->
n_item
)
if
(
!
(
sa
->
type
&
JSON_PATH_WILD
)
&&
sa
->
n_item
!=
sb
->
n_item
)
return
-
1
;
}
else
/* JSON_PATH_KEY */
{
if
(
!
sa
->
wild
&&
if
(
!
(
sa
->
type
&
JSON_PATH_WILD
)
&&
(
sa
->
key_end
-
sa
->
key
!=
sb
->
key_end
-
sb
->
key
||
memcmp
(
sa
->
key
,
sb
->
key
,
sa
->
key_end
-
sa
->
key
)
!=
0
))
return
-
1
;
...
...
@@ -2033,6 +2034,49 @@ static int json_path_compare(const json_path_t *a, const json_path_t *b)
return
b_len
>
a_len
;
}
#endif
/*DUMMY*/
static
int
json_path_compare
(
const
json_path_t
*
a
,
const
json_path_t
*
b
)
{
const
json_path_step_t
*
sa
=
a
->
steps
+
1
;
const
json_path_step_t
*
sb
=
b
->
steps
+
1
;
if
(
a
->
last_step
-
sa
>
b
->
last_step
-
sb
)
return
-
2
;
while
(
sa
<=
a
->
last_step
)
{
if
(
sb
>
b
->
last_step
)
return
-
2
;
if
(
!
((
sa
->
type
&
sb
->
type
)
&
JSON_PATH_KEY_OR_ARRAY
))
goto
step_failed
;
if
(
sa
->
type
&
JSON_PATH_ARRAY
)
{
if
(
!
(
sa
->
type
&
JSON_PATH_WILD
)
&&
sa
->
n_item
!=
sb
->
n_item
)
goto
step_failed
;
}
else
/* JSON_PATH_KEY */
{
if
(
!
(
sa
->
type
&
JSON_PATH_WILD
)
&&
(
sa
->
key_end
-
sa
->
key
!=
sb
->
key_end
-
sb
->
key
||
memcmp
(
sa
->
key
,
sb
->
key
,
sa
->
key_end
-
sa
->
key
)
!=
0
))
goto
step_failed
;
}
sb
++
;
sa
++
;
continue
;
step_failed:
if
(
!
(
sa
->
type
&
JSON_PATH_DOUBLE_WILD
))
return
-
1
;
sb
++
;
}
return
sb
<=
b
->
last_step
;
}
static
bool
path_ok
(
const
json_path_with_flags
*
paths_list
,
int
n_paths
,
...
...
@@ -2088,8 +2132,7 @@ String *Item_func_json_search::val_str(String *str)
(
const
uchar
*
)
js
->
ptr
()
+
js
->
length
());
p
.
last_step
=
p
.
steps
;
p
.
steps
[
0
].
wild
=
0
;
p
.
steps
[
0
].
type
=
JSON_PATH_ARRAY
;
p
.
steps
[
0
].
type
=
JSON_PATH_ARRAY_WILD
;
p
.
steps
[
0
].
n_item
=
0
;
do
...
...
@@ -2133,27 +2176,21 @@ String *Item_func_json_search::val_str(String *str)
if
(
mode_one
)
goto
end
;
}
if
(
p
.
last_step
->
type
==
JSON_PATH_ARRAY
)
if
(
p
.
last_step
->
type
&
JSON_PATH_ARRAY
)
p
.
last_step
->
n_item
++
;
}
else
{
p
.
last_step
++
;
if
(
je
.
value_type
==
JSON_VALUE_ARRAY
)
{
p
.
last_step
->
type
=
JSON_PATH_ARRAY
;
p
.
last_step
->
n_item
=
0
;
}
else
/*JSON_VALUE_OBJECT*/
p
.
last_step
->
type
=
JSON_PATH_KEY
;
p
.
last_step
->
type
=
(
enum
json_path_step_types
)
je
.
value_type
;
p
.
last_step
->
n_item
=
0
;
}
break
;
case
JST_OBJ_END
:
case
JST_ARRAY_END
:
p
.
last_step
--
;
if
(
p
.
last_step
->
type
==
JSON_PATH_ARRAY
)
if
(
p
.
last_step
->
type
&
JSON_PATH_ARRAY
)
p
.
last_step
->
n_item
++
;
break
;
default:
...
...
strings/json_lib.c
View file @
04aa31c7
...
...
@@ -1006,6 +1006,8 @@ enum json_path_states {
PS_KEY
,
/* Key. */
PS_KNM
,
/* Parse key name. */
PS_KWD
,
/* Key wildcard. */
PS_AST
,
/* Asterisk. */
PS_DWD
,
/* Double wildcard. */
N_PATH_STATES
,
/* Below are states that aren't in the transitions table. */
PS_SCT
,
/* Parse the 'strict' keyword. */
PS_EKY
,
/* '.' after the keyname so next step is the key. */
...
...
@@ -1029,7 +1031,7 @@ static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]=
/* LAX */
{
JE_EOS
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
PS_LAX
,
JE_SYN
,
PS_GO
,
JE_SYN
,
JE_SYN
,
JE_NOT_JSON_CHR
,
JE_BAD_CHR
},
/* PT */
{
PS_OK
,
JE_SYN
,
JE_SYN
,
PS_AR
,
JE_SYN
,
PS_KEY
,
JE_SYN
,
JE_SYN
,
/* PT */
{
PS_OK
,
JE_SYN
,
PS_AST
,
PS_AR
,
JE_SYN
,
PS_KEY
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_NOT_JSON_CHR
,
JE_BAD_CHR
},
/* AR */
{
JE_EOS
,
JE_SYN
,
PS_AWD
,
JE_SYN
,
PS_PT
,
JE_SYN
,
PS_Z
,
...
...
@@ -1050,11 +1052,17 @@ static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]=
/* KEY */
{
JE_EOS
,
PS_KNM
,
PS_KWD
,
JE_SYN
,
PS_KNM
,
JE_SYN
,
PS_KNM
,
PS_KNM
,
PS_KNM
,
PS_KNM
,
PS_KNM
,
JE_SYN
,
PS_KNM
,
JE_NOT_JSON_CHR
,
JE_BAD_CHR
},
/* KNM */
{
PS_KOK
,
PS_KNM
,
PS_
KNM
,
PS_EAR
,
PS_KNM
,
PS_EKY
,
PS_KNM
,
/* KNM */
{
PS_KOK
,
PS_KNM
,
PS_
AST
,
PS_EAR
,
PS_KNM
,
PS_EKY
,
PS_KNM
,
PS_KNM
,
PS_KNM
,
PS_KNM
,
PS_KNM
,
PS_ESC
,
PS_KNM
,
JE_NOT_JSON_CHR
,
JE_BAD_CHR
},
/* KWD */
{
PS_OK
,
JE_SYN
,
JE_SYN
,
PS_AR
,
JE_SYN
,
PS_EKY
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_NOT_JSON_CHR
,
JE_BAD_CHR
},
/* AST */
{
JE_SYN
,
JE_SYN
,
PS_DWD
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_NOT_JSON_CHR
,
JE_BAD_CHR
},
/* DWD */
{
JE_SYN
,
JE_SYN
,
PS_AST
,
PS_AR
,
JE_SYN
,
PS_KEY
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_SYN
,
JE_NOT_JSON_CHR
,
JE_BAD_CHR
}
};
...
...
@@ -1063,11 +1071,11 @@ int json_path_setup(json_path_t *p,
CHARSET_INFO
*
i_cs
,
const
uchar
*
str
,
const
uchar
*
end
)
{
int
c_len
,
t_next
,
state
=
PS_GO
;
enum
json_path_step_types
double_wildcard
=
JSON_PATH_KEY_NULL
;
json_string_setup
(
&
p
->
s
,
i_cs
,
str
,
end
);
p
->
steps
[
0
].
type
=
JSON_PATH_ARRAY
;
p
->
steps
[
0
].
wild
=
1
;
p
->
steps
[
0
].
type
=
JSON_PATH_ARRAY_WILD
;
p
->
last_step
=
p
->
steps
;
p
->
mode_strict
=
FALSE
;
...
...
@@ -1096,8 +1104,11 @@ int json_path_setup(json_path_t *p,
p
->
mode_strict
=
TRUE
;
state
=
PS_LAX
;
continue
;
case
PS_KWD
:
case
PS_AWD
:
p
->
last_step
->
wild
=
1
;
if
(
p
->
last_step
->
type
&
JSON_PATH_DOUBLE_WILD
)
return
p
->
s
.
error
=
JE_SYN
;
p
->
last_step
->
type
|=
JSON_PATH_WILD
;
continue
;
case
PS_INT
:
p
->
last_step
->
n_item
*=
10
;
...
...
@@ -1109,8 +1120,10 @@ int json_path_setup(json_path_t *p,
/* Note no 'continue' here. */
case
PS_KEY
:
p
->
last_step
++
;
p
->
last_step
->
type
=
JSON_PATH_KEY
;
p
->
last_step
->
wild
=
0
;
if
(
p
->
last_step
-
p
->
steps
>=
JSON_DEPTH_LIMIT
)
return
p
->
s
.
error
=
JE_DEPTH
;
p
->
last_step
->
type
=
JSON_PATH_KEY
|
double_wildcard
;
double_wildcard
=
JSON_PATH_KEY_NULL
;
p
->
last_step
->
key
=
p
->
s
.
c_str
;
continue
;
case
PS_EAR
:
...
...
@@ -1119,13 +1132,12 @@ int json_path_setup(json_path_t *p,
/* Note no 'continue' here. */
case
PS_AR
:
p
->
last_step
++
;
p
->
last_step
->
type
=
JSON_PATH_ARRAY
;
p
->
last_step
->
wild
=
0
;
if
(
p
->
last_step
-
p
->
steps
>=
JSON_DEPTH_LIMIT
)
return
p
->
s
.
error
=
JE_DEPTH
;
p
->
last_step
->
type
=
JSON_PATH_ARRAY
|
double_wildcard
;
double_wildcard
=
JSON_PATH_KEY_NULL
;
p
->
last_step
->
n_item
=
0
;
continue
;
case
PS_KWD
:
p
->
last_step
->
wild
=
1
;
continue
;
case
PS_ESC
:
if
(
json_handle_esc
(
&
p
->
s
))
return
1
;
...
...
@@ -1133,11 +1145,14 @@ int json_path_setup(json_path_t *p,
case
PS_KOK
:
p
->
last_step
->
key_end
=
p
->
s
.
c_str
-
c_len
;
state
=
PS_OK
;
break
;
break
;
/* 'break' as the loop supposed to end after that. */
case
PS_DWD
:
double_wildcard
=
JSON_PATH_DOUBLE_WILD
;
continue
;
};
}
while
(
state
!=
PS_OK
);
return
0
;
return
double_wildcard
?
(
p
->
s
.
error
=
JE_SYN
)
:
0
;
}
...
...
@@ -1196,7 +1211,8 @@ static int handle_match(json_engine_t *je, json_path_t *p,
(
*
p_cur_step
)
++
;
array_counters
[
*
p_cur_step
-
p
->
steps
]
=
0
;
if
((
int
)
je
->
value_type
!=
(
int
)
(
*
p_cur_step
)
->
type
)
if
((
int
)
je
->
value_type
!=
(
int
)
((
*
p_cur_step
)
->
type
&
JSON_PATH_KEY_OR_ARRAY
))
{
(
*
p_cur_step
)
--
;
return
json_skip_level
(
je
);
...
...
@@ -1240,8 +1256,8 @@ int json_find_path(json_engine_t *je,
switch
(
je
->
state
)
{
case
JST_KEY
:
DBUG_ASSERT
(
cur_step
->
type
==
JSON_PATH_KEY
);
if
(
!
cur_step
->
wild
)
DBUG_ASSERT
(
cur_step
->
type
&
JSON_PATH_KEY
);
if
(
!
(
cur_step
->
type
&
JSON_PATH_WILD
)
)
{
json_string_set_str
(
&
key_name
,
cur_step
->
key
,
cur_step
->
key_end
);
if
(
!
json_key_matches
(
je
,
&
key_name
))
...
...
@@ -1256,8 +1272,8 @@ int json_find_path(json_engine_t *je,
goto
exit
;
break
;
case
JST_VALUE
:
DBUG_ASSERT
(
cur_step
->
type
==
JSON_PATH_ARRAY
);
if
(
cur_step
->
wild
||
DBUG_ASSERT
(
cur_step
->
type
&
JSON_PATH_ARRAY
);
if
(
cur_step
->
type
&
JSON_PATH_WILD
||
cur_step
->
n_item
==
array_counters
[
cur_step
-
p
->
steps
])
{
/* Array item matches. */
...
...
@@ -1316,11 +1332,11 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state)
json_path_step_t
*
cur_step
;
if
(
state
->
path_depths
[
p_c
]
<
state
->
cur_depth
/* Path already failed. */
||
(
cur_step
=
state
->
paths
[
p_c
].
steps
+
state
->
cur_depth
)
->
type
!=
JSON_PATH_KEY
)
!
((
cur_step
=
state
->
paths
[
p_c
].
steps
+
state
->
cur_depth
)
->
type
&
JSON_PATH_KEY
)
)
continue
;
if
(
!
cur_step
->
wild
)
if
(
!
(
cur_step
->
type
&
JSON_PATH_WILD
)
)
{
json_string_t
key_name
;
json_string_setup
(
&
key_name
,
state
->
paths
[
p_c
].
s
.
cs
,
...
...
@@ -1354,10 +1370,10 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state)
{
json_path_step_t
*
cur_step
;
if
(
state
->
path_depths
[
p_c
]
<
state
->
cur_depth
/* Path already failed. */
||
(
cur_step
=
state
->
paths
[
p_c
].
steps
+
state
->
cur_depth
)
->
type
!=
JSON_PATH_ARRAY
)
!
((
cur_step
=
state
->
paths
[
p_c
].
steps
+
state
->
cur_depth
)
->
type
&
JSON_PATH_ARRAY
)
)
continue
;
if
(
cur_step
->
wild
||
if
(
cur_step
->
type
&
JSON_PATH_WILD
||
cur_step
->
n_item
==
state
->
array_counters
[
state
->
cur_depth
])
{
/* Array item matches. */
...
...
@@ -1386,7 +1402,7 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state)
if
(
state
->
path_depths
[
p_c
]
<
state
->
cur_depth
)
/* Path already failed. */
continue
;
if
(
state
->
paths
[
p_c
].
steps
[
state
->
cur_depth
].
type
==
if
(
state
->
paths
[
p_c
].
steps
[
state
->
cur_depth
].
type
&
(
je
->
state
==
JST_OBJ_START
)
?
JSON_PATH_KEY
:
JSON_PATH_ARRAY
)
state
->
path_depths
[
p_c
]
++
;
}
...
...
unittest/json_lib/json_lib-t.c
View file @
04aa31c7
...
...
@@ -117,11 +117,11 @@ test_path_parsing()
if
(
json_path_setup
(
&
p
,
ci
,
s_e
(
p0
)))
return
;
ok
(
p
.
last_step
-
p
.
steps
==
4
&&
p
.
steps
[
0
].
type
==
JSON_PATH_ARRAY
&&
p
.
steps
[
0
].
wild
==
1
&&
p
.
steps
[
1
].
type
==
JSON_PATH_KEY
&&
p
.
steps
[
1
].
wild
==
0
&&
p
.
steps
[
0
].
type
==
JSON_PATH_ARRAY
_WILD
&&
p
.
steps
[
1
].
type
==
JSON_PATH_KEY
&&
p
.
steps
[
2
].
type
==
JSON_PATH_ARRAY
&&
p
.
steps
[
2
].
n_item
==
12
&&
p
.
steps
[
3
].
type
==
JSON_PATH_KEY
&&
p
.
steps
[
3
].
wild
==
1
&&
p
.
steps
[
4
].
type
==
JSON_PATH_ARRAY
&&
p
.
steps
[
4
].
wild
==
1
,
p
.
steps
[
3
].
type
==
JSON_PATH_KEY
_WILD
&&
p
.
steps
[
4
].
type
==
JSON_PATH_ARRAY
_WILD
,
"path"
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment