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
dc8f914c
Commit
dc8f914c
authored
Nov 25, 2020
by
Olivier Bertrand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove based enum not accepted by most gcc compilers
parent
dae4bd0b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
2270 additions
and
568 deletions
+2270
-568
storage/connect/bson.cpp
storage/connect/bson.cpp
+586
-430
storage/connect/bson.h
storage/connect/bson.h
+95
-92
storage/connect/json.h
storage/connect/json.h
+1
-40
storage/connect/jsonudf.cpp
storage/connect/jsonudf.cpp
+1475
-1
storage/connect/jsonudf.h
storage/connect/jsonudf.h
+110
-4
storage/connect/tabjson.cpp
storage/connect/tabjson.cpp
+2
-0
storage/connect/value.cpp
storage/connect/value.cpp
+1
-1
No files found.
storage/connect/bson.cpp
View file @
dc8f914c
...
...
@@ -21,8 +21,6 @@
#include "plgdbsem.h"
#include "bson.h"
#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
#if defined(__WIN__)
#define EL "\r\n"
#else
...
...
@@ -89,43 +87,14 @@ char* NextChr(PSZ s, char sep) {
/***********************************************************************/
/* BDOC constructor. */
/***********************************************************************/
BDOC
::
BDOC
(
void
)
:
jp
(
NULL
),
base
(
NULL
),
s
(
NULL
),
len
(
0
)
BDOC
::
BDOC
(
void
*
base
)
:
BJSON
(
base
,
NULL
)
{
jp
=
NULL
;
s
=
NULL
;
len
=
0
;
pty
[
0
]
=
pty
[
1
]
=
pty
[
2
]
=
true
;
}
// end of BDOC constructor
/***********************************************************************/
/* Program for sub-allocating Bson structures. */
/***********************************************************************/
void
*
BDOC
::
BsonSubAlloc
(
PGLOBAL
g
,
size_t
size
)
{
PPOOLHEADER
pph
;
/* Points on area header. */
void
*
memp
=
g
->
Sarea
;
size
=
((
size
+
3
)
/
4
)
*
4
;
/* Round up size to multiple of 4 */
pph
=
(
PPOOLHEADER
)
memp
;
xtrc
(
16
,
"SubAlloc in %p size=%zd used=%zd free=%zd
\n
"
,
memp
,
size
,
pph
->
To_Free
,
pph
->
FreeBlk
);
if
(
size
>
pph
->
FreeBlk
)
{
/* Not enough memory left in pool */
sprintf
(
g
->
Message
,
"Not enough memory for request of %zd (used=%zd free=%zd)"
,
size
,
pph
->
To_Free
,
pph
->
FreeBlk
);
xtrc
(
1
,
"BsonSubAlloc: %s
\n
"
,
g
->
Message
);
throw
(
1234
);
}
/* endif size OS32 code */
// Do the suballocation the simplest way
memp
=
MakePtr
(
memp
,
pph
->
To_Free
);
/* Points to suballocated block */
pph
->
To_Free
+=
size
;
/* New offset of pool free block */
pph
->
FreeBlk
-=
size
;
/* New size of pool free block */
xtrc
(
16
,
"Done memp=%p used=%zd free=%zd
\n
"
,
memp
,
pph
->
To_Free
,
pph
->
FreeBlk
);
return
memp
;
}
/* end of BsonSubAlloc */
/***********************************************************************/
/* Parse a json string. */
/* Note: when pretty is not known, the caller set pretty to 3. */
...
...
@@ -133,9 +102,10 @@ void* BDOC::BsonSubAlloc(PGLOBAL g, size_t size) {
PBVAL
BDOC
::
ParseJson
(
PGLOBAL
g
,
char
*
js
,
size_t
lng
,
int
*
ptyp
,
bool
*
comma
)
{
int
i
,
pretty
=
(
ptyp
)
?
*
ptyp
:
3
;
bool
b
=
false
;
PBVAL
bvp
=
NULL
;
xtrc
(
1
,
"ParseJson: s=%.10s len=%zd
\n
"
,
s
,
len
);
s
=
js
;
len
=
lng
;
xtrc
(
1
,
"BDOC::ParseJson: s=%.10s len=%zd
\n
"
,
s
,
len
);
if
(
!
s
||
!
len
)
{
strcpy
(
g
->
Message
,
"Void JSON object"
);
...
...
@@ -147,30 +117,26 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
if
(
s
[
0
]
==
'['
&&
(
s
[
1
]
==
'\n'
||
(
s
[
1
]
==
'\r'
&&
s
[
2
]
==
'\n'
)))
pty
[
0
]
=
false
;
s
=
js
;
len
=
lng
;
try
{
bvp
=
(
PBVAL
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
BVAL
));
bvp
->
Type
=
TYPE_UNKNOWN
;
base
=
bvp
;
Bvp
=
SubAllocVal
(
g
);
Bvp
->
Type
=
TYPE_UNKNOWN
;
for
(
i
=
0
;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
'['
:
if
(
b
vp
->
Type
!=
TYPE_UNKNOWN
)
b
vp
->
To_Val
=
ParseAsArray
(
g
,
i
,
pretty
,
ptyp
);
if
(
B
vp
->
Type
!=
TYPE_UNKNOWN
)
B
vp
->
To_Val
=
ParseAsArray
(
g
,
i
,
pretty
,
ptyp
);
else
b
vp
->
To_Val
=
ParseArray
(
g
,
++
i
);
B
vp
->
To_Val
=
ParseArray
(
g
,
++
i
);
b
vp
->
Type
=
TYPE_JAR
;
B
vp
->
Type
=
TYPE_JAR
;
break
;
case
'{'
:
if
(
b
vp
->
Type
!=
TYPE_UNKNOWN
)
{
b
vp
->
To_Val
=
ParseAsArray
(
g
,
i
,
pretty
,
ptyp
);
b
vp
->
Type
=
TYPE_JAR
;
}
else
if
((
b
vp
->
To_Val
=
ParseObject
(
g
,
++
i
)))
b
vp
->
Type
=
TYPE_JOB
;
if
(
B
vp
->
Type
!=
TYPE_UNKNOWN
)
{
B
vp
->
To_Val
=
ParseAsArray
(
g
,
i
,
pretty
,
ptyp
);
B
vp
->
Type
=
TYPE_JAR
;
}
else
if
((
B
vp
->
To_Val
=
ParseObject
(
g
,
++
i
)))
B
vp
->
Type
=
TYPE_JOB
;
else
throw
2
;
...
...
@@ -181,7 +147,7 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
case
'\r'
:
break
;
case
','
:
if
(
b
vp
->
Type
!=
TYPE_UNKNOWN
&&
(
pretty
==
1
||
pretty
==
3
))
{
if
(
B
vp
->
Type
!=
TYPE_UNKNOWN
&&
(
pretty
==
1
||
pretty
==
3
))
{
if
(
comma
)
*
comma
=
true
;
...
...
@@ -201,18 +167,18 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
}
// endif b
default:
if
(
b
vp
->
Type
!=
TYPE_UNKNOWN
)
{
b
vp
->
To_Val
=
ParseAsArray
(
g
,
i
,
pretty
,
ptyp
);
b
vp
->
Type
=
TYPE_JAR
;
}
else
if
((
bvp
->
To_Val
=
MakeOff
(
base
,
ParseValue
(
g
,
i
))))
b
vp
->
Type
=
TYPE_JVAL
;
if
(
B
vp
->
Type
!=
TYPE_UNKNOWN
)
{
B
vp
->
To_Val
=
ParseAsArray
(
g
,
i
,
pretty
,
ptyp
);
B
vp
->
Type
=
TYPE_JAR
;
}
else
if
((
Bvp
->
To_Val
=
MOF
(
ParseValue
(
g
,
i
))))
B
vp
->
Type
=
TYPE_JVAL
;
else
throw
4
;
break
;
};
// endswitch s[i]
if
(
b
vp
->
Type
==
TYPE_UNKNOWN
)
if
(
B
vp
->
Type
==
TYPE_UNKNOWN
)
sprintf
(
g
->
Message
,
"Invalid Json string '%.*s'"
,
MY_MIN
((
int
)
len
,
50
),
s
);
else
if
(
ptyp
&&
pretty
==
3
)
{
*
ptyp
=
3
;
// Not recognized pretty
...
...
@@ -228,13 +194,13 @@ PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng, int* ptyp, bool* comma) {
}
catch
(
int
n
)
{
if
(
trace
(
1
))
htrc
(
"Exception %d: %s
\n
"
,
n
,
g
->
Message
);
b
vp
=
NULL
;
B
vp
=
NULL
;
}
catch
(
const
char
*
msg
)
{
strcpy
(
g
->
Message
,
msg
);
b
vp
=
NULL
;
B
vp
=
NULL
;
}
// end catch
return
b
vp
;
return
B
vp
;
}
// end of ParseJson
/***********************************************************************/
...
...
@@ -280,7 +246,7 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) {
throw
1
;
}
// endif level
return
M
akeOff
(
base
,
vlp
);
return
M
OF
(
first
vlp
);
case
'\n'
:
if
(
!
b
)
pty
[
0
]
=
pty
[
1
]
=
false
;
...
...
@@ -294,7 +260,7 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) {
throw
1
;
}
else
if
(
lastvlp
)
{
vlp
=
ParseValue
(
g
,
i
);
lastvlp
->
Next
=
M
akeOff
(
base
,
vlp
);
lastvlp
->
Next
=
M
OF
(
vlp
);
lastvlp
=
vlp
;
}
else
firstvlp
=
lastvlp
=
ParseValue
(
g
,
i
);
...
...
@@ -305,25 +271,12 @@ OFFSET BDOC::ParseArray(PGLOBAL g, int& i) {
if
(
b
)
{
// Case of Pretty == 0
return
M
akeOff
(
base
,
vlp
);
return
M
OF
(
first
vlp
);
}
// endif b
throw
(
"Unexpected EOF in array"
);
}
// end of ParseArray
/***********************************************************************/
/* Sub-allocate and initialize a BPAIR. */
/***********************************************************************/
PBPR
BDOC
::
SubAllocPair
(
PGLOBAL
g
,
OFFSET
key
)
{
PBPR
bpp
=
(
PBPR
)
BsonSubAlloc
(
g
,
sizeof
(
BPAIR
));
bpp
->
Key
=
key
;
bpp
->
Vlp
=
0
;
bpp
->
Next
=
0
;
return
bpp
;
}
// end of SubAllocPair
/***********************************************************************/
/* Parse a JSON Object. */
/***********************************************************************/
...
...
@@ -342,7 +295,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
bpp
=
SubAllocPair
(
g
,
key
);
if
(
lastbpp
)
{
lastbpp
->
Next
=
M
akeOff
(
base
,
bpp
);
lastbpp
->
Next
=
M
OF
(
bpp
);
lastbpp
=
bpp
;
}
else
firstbpp
=
lastbpp
=
bpp
;
...
...
@@ -356,7 +309,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
break
;
case
':'
:
if
(
level
==
1
)
{
lastbpp
->
Vlp
=
M
akeOff
(
base
,
ParseValue
(
g
,
++
i
));
lastbpp
->
Vlp
=
M
OF
(
ParseValue
(
g
,
++
i
));
level
=
2
;
}
else
{
sprintf
(
g
->
Message
,
"Unexpected ':' near %.*s"
,
ARGS
);
...
...
@@ -378,7 +331,7 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
throw
2
;
}
// endif level
return
M
akeOff
(
base
,
firstbpp
);
return
M
OF
(
firstbpp
);
case
'\n'
:
pty
[
0
]
=
pty
[
1
]
=
false
;
case
'\r'
:
...
...
@@ -395,20 +348,6 @@ OFFSET BDOC::ParseObject(PGLOBAL g, int& i) {
throw
2
;
}
// end of ParseObject
/***********************************************************************/
/* Sub-allocate and initialize a BVAL. */
/***********************************************************************/
PBVAL
BDOC
::
SubAllocVal
(
PGLOBAL
g
)
{
PBVAL
bvp
=
(
PBVAL
)
BsonSubAlloc
(
g
,
sizeof
(
BVAL
));
bvp
->
To_Val
=
0
;
bvp
->
Nd
=
0
;
bvp
->
Type
=
TYPE_UNKNOWN
;
bvp
->
Next
=
0
;
return
bvp
;
}
// end of SubAllocVal
/***********************************************************************/
/* Parse a JSON Value. */
/***********************************************************************/
...
...
@@ -505,7 +444,7 @@ OFFSET BDOC::ParseString(PGLOBAL g, int& i) {
case
'"'
:
p
[
n
++
]
=
0
;
PlugSubAlloc
(
g
,
NULL
,
n
);
return
M
akeOff
(
base
,
p
);
return
M
OF
(
p
);
case
'\\'
:
if
(
++
i
<
len
)
{
if
(
s
[
i
]
==
'u'
)
{
...
...
@@ -634,7 +573,7 @@ void BDOC::ParseNumeric(PGLOBAL g, int& i, PBVAL vlp) {
double
*
dvp
=
(
double
*
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
double
));
*
dvp
=
dv
;
vlp
->
To_Val
=
M
akeOff
(
base
,
dvp
);
vlp
->
To_Val
=
M
OF
(
dvp
);
vlp
->
Type
=
TYPE_DBL
;
}
else
{
vlp
->
F
=
(
float
)
dv
;
...
...
@@ -643,13 +582,13 @@ void BDOC::ParseNumeric(PGLOBAL g, int& i, PBVAL vlp) {
vlp
->
Nd
=
nd
;
}
else
{
long
long
iv
=
strtoll
(
buf
,
NULL
,
10
);
longlong
iv
=
strtoll
(
buf
,
NULL
,
10
);
if
(
iv
>
INT_MAX32
||
iv
<
INT_MIN32
)
{
long
long
*
llp
=
(
long
long
*
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
long
long
));
long
long
*
llp
=
(
longlong
*
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
long
long
));
*
llp
=
iv
;
vlp
->
To_Val
=
M
akeOff
(
base
,
llp
);
vlp
->
To_Val
=
M
OF
(
llp
);
vlp
->
Type
=
TYPE_BINT
;
}
else
{
vlp
->
N
=
(
int
)
iv
;
...
...
@@ -668,12 +607,11 @@ void BDOC::ParseNumeric(PGLOBAL g, int& i, PBVAL vlp) {
}
// end of ParseNumeric
/***********************************************************************/
/* Serialize a
JSON document tree:
*/
/* Serialize a
BJSON document tree:
*/
/***********************************************************************/
PSZ
BDOC
::
Serialize
(
PGLOBAL
g
,
PBVAL
bvp
,
char
*
fn
,
int
pretty
)
{
PSZ
str
=
NULL
;
bool
b
=
false
,
err
=
true
;
JOUT
*
jp
;
FILE
*
fs
=
NULL
;
g
->
Message
[
0
]
=
0
;
...
...
@@ -712,7 +650,7 @@ PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty) {
err
|=
SerializeObject
(
bvp
->
To_Val
);
break
;
case
TYPE_JVAL
:
err
=
SerializeValue
(
(
PBVAL
)
MakePtr
(
base
,
bvp
->
To_Val
));
err
=
SerializeValue
(
MVP
(
bvp
->
To_Val
));
break
;
default:
strcpy
(
g
->
Message
,
"Invalid json tree"
);
...
...
@@ -750,7 +688,7 @@ PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty) {
/***********************************************************************/
bool
BDOC
::
SerializeArray
(
OFFSET
arp
,
bool
b
)
{
bool
first
=
true
;
PBVAL
vp
=
(
PBVAL
)
MakePtr
(
base
,
arp
);
PBVAL
vp
=
MVP
(
arp
);
if
(
b
)
{
if
(
jp
->
Prty
())
{
...
...
@@ -764,7 +702,7 @@ bool BDOC::SerializeArray(OFFSET arp, bool b) {
}
else
if
(
jp
->
WriteChr
(
'['
))
return
true
;
for
(
vp
;
vp
;
vp
=
(
PBVAL
)
MakePtr
(
base
,
vp
->
Next
))
{
for
(
vp
;
vp
;
vp
=
MVP
(
vp
->
Next
))
{
if
(
first
)
first
=
false
;
else
if
((
!
b
||
jp
->
Prty
())
&&
jp
->
WriteChr
(
','
))
...
...
@@ -780,7 +718,7 @@ bool BDOC::SerializeArray(OFFSET arp, bool b) {
if
(
SerializeValue
(
vp
))
return
true
;
}
// endfor
i
}
// endfor
vp
if
(
b
&&
jp
->
Prty
()
==
1
&&
jp
->
WriteStr
(
EL
))
return
true
;
...
...
@@ -793,22 +731,22 @@ bool BDOC::SerializeArray(OFFSET arp, bool b) {
/***********************************************************************/
bool
BDOC
::
SerializeObject
(
OFFSET
obp
)
{
bool
first
=
true
;
PBPR
prp
=
(
PBPR
)
MakePtr
(
base
,
obp
);
PBPR
prp
=
MPP
(
obp
);
if
(
jp
->
WriteChr
(
'{'
))
return
true
;
for
(
prp
;
prp
;
prp
=
(
PBPR
)
MakePtr
(
base
,
prp
->
Next
))
{
for
(
prp
;
prp
;
prp
=
MPP
(
prp
->
Next
))
{
if
(
first
)
first
=
false
;
else
if
(
jp
->
WriteChr
(
','
))
return
true
;
if
(
jp
->
WriteChr
(
'"'
)
||
jp
->
WriteStr
(
(
const
char
*
)
MakePtr
(
base
,
prp
->
Key
))
||
jp
->
WriteStr
(
MZP
(
prp
->
Key
))
||
jp
->
WriteChr
(
'"'
)
||
jp
->
WriteChr
(
':'
)
||
SerializeValue
(
(
PBVAL
)
MakePtr
(
base
,
prp
->
Vlp
)))
SerializeValue
(
MVP
(
prp
->
Vlp
)))
return
true
;
}
// endfor i
...
...
@@ -831,18 +769,18 @@ bool BDOC::SerializeValue(PBVAL jvp) {
return
jp
->
WriteStr
(
jvp
->
B
?
"true"
:
"false"
);
case
TYPE_STRG
:
case
TYPE_DTM
:
return
jp
->
Escape
(
(
const
char
*
)
MakePtr
(
base
,
jvp
->
To_Val
));
return
jp
->
Escape
(
MZP
(
jvp
->
To_Val
));
case
TYPE_INTG
:
sprintf
(
buf
,
"%d"
,
jvp
->
N
);
return
jp
->
WriteStr
(
buf
);
case
TYPE_BINT
:
sprintf
(
buf
,
"%lld"
,
*
(
long
long
*
)
MakePtr
(
b
ase
,
jvp
->
To_Val
));
sprintf
(
buf
,
"%lld"
,
*
(
long
long
*
)
MakePtr
(
B
ase
,
jvp
->
To_Val
));
return
jp
->
WriteStr
(
buf
);
case
TYPE_FLOAT
:
sprintf
(
buf
,
"%.*f"
,
jvp
->
Nd
,
jvp
->
F
);
return
jp
->
WriteStr
(
buf
);
case
TYPE_DBL
:
sprintf
(
buf
,
"%.*lf"
,
jvp
->
Nd
,
*
(
double
*
)
MakePtr
(
b
ase
,
jvp
->
To_Val
));
sprintf
(
buf
,
"%.*lf"
,
jvp
->
Nd
,
*
(
double
*
)
MakePtr
(
B
ase
,
jvp
->
To_Val
));
return
jp
->
WriteStr
(
buf
);
case
TYPE_NULL
:
return
jp
->
WriteStr
(
"null"
);
...
...
@@ -854,84 +792,139 @@ bool BDOC::SerializeValue(PBVAL jvp) {
return
true
;
}
// end of SerializeValue
#if 0
/* -------------------------- Class JOBJECT -------------------------- */
/* --------------------------- Class BJSON --------------------------- */
/***********************************************************************/
/* Program for sub-allocating Bjson structures. */
/***********************************************************************/
void
*
BJSON
::
BsonSubAlloc
(
PGLOBAL
g
,
size_t
size
)
{
PPOOLHEADER
pph
;
/* Points on area header. */
void
*
memp
=
g
->
Sarea
;
size
=
((
size
+
3
)
/
4
)
*
4
;
/* Round up size to multiple of 4 */
pph
=
(
PPOOLHEADER
)
memp
;
xtrc
(
16
,
"SubAlloc in %p size=%zd used=%zd free=%zd
\n
"
,
memp
,
size
,
pph
->
To_Free
,
pph
->
FreeBlk
);
if
(
size
>
pph
->
FreeBlk
)
{
/* Not enough memory left in pool */
sprintf
(
g
->
Message
,
"Not enough memory for request of %zd (used=%zd free=%zd)"
,
size
,
pph
->
To_Free
,
pph
->
FreeBlk
);
xtrc
(
1
,
"BsonSubAlloc: %s
\n
"
,
g
->
Message
);
throw
(
1234
);
}
/* endif size OS32 code */
// Do the suballocation the simplest way
memp
=
MakePtr
(
memp
,
pph
->
To_Free
);
/* Points to suballocated block */
pph
->
To_Free
+=
size
;
/* New offset of pool free block */
pph
->
FreeBlk
-=
size
;
/* New size of pool free block */
xtrc
(
16
,
"Done memp=%p used=%zd free=%zd
\n
"
,
memp
,
pph
->
To_Free
,
pph
->
FreeBlk
);
return
memp
;
}
/* end of BsonSubAlloc */
/* ------------------------ Bobject functions ------------------------ */
/***********************************************************************/
/* Sub-allocate and initialize a BPAIR. */
/***********************************************************************/
PBPR
BJSON
::
SubAllocPair
(
PGLOBAL
g
,
OFFSET
key
,
OFFSET
val
)
{
PBPR
bpp
=
(
PBPR
)
BsonSubAlloc
(
g
,
sizeof
(
BPAIR
));
bpp
->
Key
=
key
;
bpp
->
Vlp
=
val
;
bpp
->
Next
=
0
;
return
bpp
;
}
// end of SubAllocPair
/***********************************************************************/
/* Return the number of pairs in this object. */
/***********************************************************************/
int JOBJECT::GetSize(bool b) {
int
BJSON
::
GetObjectSize
(
PBPR
bop
,
bool
b
)
{
int
n
=
0
;
for (P
JPR jpp = First; jpp; jpp = jpp->Next
)
for
(
P
BPR
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
)
)
// If b return only non null pairs
if (!b ||
jpp->Val && !jpp->Val->IsNull(
))
if
(
!
b
||
(
brp
->
Vlp
&&
(
MVP
(
brp
->
Vlp
))
->
Type
!=
TYPE_NULL
))
n
++
;
return
n
;
} // end of GetSize
}
// end of Get
Object
Size
/***********************************************************************/
/* Add a new pair to an Object
.
*/
/* Add a new pair to an Object
and return it.
*/
/***********************************************************************/
PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key) {
PJPR jpp = (PJPR)PlugSubAlloc(g, NULL, sizeof(JPAIR));
PBPR
BJSON
::
AddPair
(
PGLOBAL
g
,
PBPR
bop
,
PSZ
key
,
OFFSET
val
)
{
PBPR
brp
,
nrp
=
SubAllocPair
(
g
,
MOF
(
key
),
val
);
jpp->Key = key;
jpp->Next = NULL;
jpp->Val = NULL;
if
(
bop
)
{
for
(
brp
=
bop
;
brp
->
Next
;
brp
=
MPP
(
brp
->
Next
));
if (Last)
Last->Next = jpp;
else
First = jpp;
brp
->
Next
=
MOF
(
nrp
);
}
else
bop
=
nrp
;
Last = jpp;
return jpp;
return
bop
;
}
// end of AddPair
/***********************************************************************/
/* Return all
keys as an array.
*/
/* Return all
object keys as an array.
*/
/***********************************************************************/
PJAR JOBJECT::GetKeyList(PGLOBAL g) {
PJAR jarp = new(g) JARRAY();
PBVAL
BJSON
::
GetKeyList
(
PGLOBAL
g
,
PBPR
bop
)
{
PBVAL
bvp
,
lvp
,
fvp
=
NULL
;
for (PJPR jpp = First; jpp; jpp = jpp->Next)
jarp->AddArrayValue(g, new(g) JVALUE(g, jpp->Key));
for
(
PBPR
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
))
if
(
fvp
)
{
bvp
=
SubAllocVal
(
g
,
brp
->
Key
,
TYPE_STRG
);
lvp
->
Next
=
MOF
(
bvp
);
lvp
=
bvp
;
}
else
lvp
=
fvp
=
SubAllocVal
(
g
,
brp
->
Key
,
TYPE_STRG
);
jarp->InitArray(g);
return jarp;
return
fvp
;
}
// end of GetKeyList
/***********************************************************************/
/* Return all
values as an array.
*/
/* Return all
object values as an array.
*/
/***********************************************************************/
PJAR JOBJECT::GetValList(PGLOBAL g) {
PJAR jarp = new(g) JARRAY();
PBVAL
BJSON
::
GetObjectValList
(
PGLOBAL
g
,
PBPR
bop
)
{
PBVAL
bvp
,
lvp
,
fvp
=
NULL
;
for (PJPR jpp = First; jpp; jpp = jpp->Next)
jarp->AddArrayValue(g, jpp->Val);
for
(
PBPR
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
))
if
(
fvp
)
{
bvp
=
DupVal
(
g
,
MVP
(
brp
->
Vlp
));
lvp
->
Next
=
MOF
(
bvp
);
lvp
=
bvp
;
}
else
lvp
=
fvp
=
DupVal
(
g
,
MVP
(
brp
->
Vlp
));
jarp->InitArray(g);
return jarp;
} // end of GetValList
return
fvp
;
}
// end of GetObjectValList
/***********************************************************************/
/* Get the value corresponding to the given key. */
/***********************************************************************/
PJVAL JOBJECT::GetKeyValue(const char* key) {
for (PJPR jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key))
return jp->Val;
PBVAL
BJSON
::
GetKeyValue
(
PBPR
bop
,
PSZ
key
)
{
for
(
PBPR
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
))
if
(
!
strcmp
(
MZP
(
brp
->
Key
),
key
))
return
MVP
(
brp
->
Vlp
);
return
NULL
;
} // end of GetValue;
}
// end of Get
Key
Value;
/***********************************************************************/
/* Return the text corresponding to all keys (XML like). */
/***********************************************************************/
PSZ
JOBJECT::GetText(PGLOBAL g
, PSTRG text) {
if (
First
) {
PSZ
BJSON
::
GetObjectText
(
PGLOBAL
g
,
PBPR
bop
,
PSTRG
text
)
{
if
(
bop
)
{
bool
b
;
if
(
!
text
)
{
...
...
@@ -944,7 +937,8 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text) {
b
=
false
;
}
// endif text
if (b && !First->Next && !strcmp(First->Key, "$date")) {
#if 0
if (b && !bop->Next && !strcmp(MZP(bop->Key), "$date")) {
int i;
PSZ s;
...
...
@@ -964,228 +958,211 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text) {
} // endif text
} else
for (PJPR jp = First; jp; jp = jp->Next) {
jp->Val->GetText(g, text);
} else
#endif // 0
if (jp->Next)
for
(
PBPR
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
))
{
GetValueText
(
g
,
MVP
(
brp
->
Vlp
),
text
);
if
(
brp
->
Next
)
text
->
Append
(
' '
);
} // endfor
j
p
}
// endfor
br
p
if
(
b
)
{
text
->
Trim
();
return
text
->
GetStr
();
}
// endif b
} // endif
First
}
// endif
bop
return
NULL
;
} // end of GetText;
}
// end of Get
Object
Text;
/***********************************************************************/
/*
Merge two objects.
*/
/*
Set or add a value corresponding to the given key.
*/
/***********************************************************************/
bool JOBJECT::Merge(PGLOBAL g, PJSON jsp) {
if (jsp->GetType() != TYPE_JOB) {
strcpy(g->Message, "Second argument is not an object");
return true;
} // endif Type
PBPR
BJSON
::
SetKeyValue
(
PGLOBAL
g
,
PBPR
bop
,
OFFSET
bvp
,
PSZ
key
)
{
PBPR
brp
=
bop
,
prp
=
NULL
;
if
(
brp
)
{
for
(
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
))
if
(
!
strcmp
(
MZP
(
brp
->
Key
),
key
))
{
brp
->
Vlp
=
bvp
;
break
;
}
else
prp
=
brp
;
PJOB jobp = (PJOB)jsp;
if
(
!
brp
)
prp
->
Vlp
=
MOF
(
SubAllocPair
(
g
,
MOF
(
key
),
bvp
));
for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next)
SetKeyValue(g, jpp->Val, jpp->Key
);
}
else
bop
=
SubAllocPair
(
g
,
MOF
(
key
),
bvp
);
return false;
} // end of Marge;
// Return the first pair of this object
return
bop
;
}
// end of SetKeyValue
/***********************************************************************/
/*
Set or add a value corresponding to the given key.
*/
/*
Merge two objects.
*/
/***********************************************************************/
void JOBJECT::SetKeyValue(PGLOBAL g, PJVAL jvp, PCSZ key) {
PJPR jp;
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
jp->Val = jvp;
break;
} // endif key
PBPR
BJSON
::
MergeObject
(
PGLOBAL
g
,
PBPR
bop1
,
PBPR
bop2
)
{
if
(
bop1
)
for
(
PBPR
brp
=
bop2
;
brp
;
brp
=
MPP
(
brp
->
Next
))
SetKeyValue
(
g
,
bop1
,
brp
->
Vlp
,
MZP
(
brp
->
Key
));
if (!jp) {
jp = AddPair(g, key);
jp->Val = jvp;
} // endif jp
else
bop1
=
bop2
;
} // end of SetValue
return
bop1
;
}
// end of MergeObject;
/***********************************************************************/
/* Delete a value corresponding to the given key. */
/***********************************************************************/
void JOBJECT::DeleteKey(PCSZ key) {
PJPR jp, * pjp = &First;
PBPR
BJSON
::
DeleteKey
(
PBPR
bop
,
PCSZ
key
)
{
PBPR
brp
,
pbrp
=
NULL
;
for
(
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
))
if
(
!
strcmp
(
MZP
(
brp
->
Key
),
key
))
{
if
(
pbrp
)
{
pbrp
->
Next
=
brp
->
Next
;
return
bop
;
}
else
return
MPP
(
brp
->
Next
);
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
*pjp = jp->Next;
break;
}
else
p
jp = &jp->Next
;
p
brp
=
brp
;
return
bop
;
}
// end of DeleteKey
/***********************************************************************/
/* True if void or if all members are nulls. */
/***********************************************************************/
bool JOBJECT::IsNull(void) {
for (PJPR jp = First; jp; jp = jp->Next)
if (!jp->Val->IsNull())
bool
BJSON
::
IsObjectNull
(
PBPR
bop
)
{
for
(
PBPR
brp
=
bop
;
brp
;
brp
=
MPP
(
brp
->
Next
))
if
(
brp
->
Vlp
&&
(
MVP
(
brp
->
Vlp
))
->
Type
!=
TYPE_NULL
)
return
false
;
return
true
;
} // end of IsNull
}
// end of Is
Object
Null
/* -------------------------- Class JARRAY --------------------------- */
/***********************************************************************/
/* JARRAY constructor. */
/***********************************************************************/
JARRAY::JARRAY(void) : JSON() {
Type = TYPE_JAR;
Size = 0;
Alloc = 0;
First = Last = NULL;
Mvals = NULL;
} // end of JARRAY constructor
/* ------------------------- Barray functions ------------------------ */
/***********************************************************************/
/* Return the number of values in this object. */
/***********************************************************************/
int JARRAY::GetSize(bool b) {
if (b) {
// Return only non null values
int n = 0;
for (PJVAL jvp = First; jvp; jvp = jvp->Next)
if (!jvp->IsNull())
n++;
int
BJSON
::
GetArraySize
(
PBVAL
bap
,
bool
b
)
{
int
n
=
0
;
return n;
} else
return Size;
for
(
PBVAL
bvp
=
bap
;
bvp
;
bvp
=
MVP
(
bvp
->
Next
))
// If b, return only non null values
if
(
!
b
||
bvp
->
Type
!=
TYPE_NULL
)
n
++
;
} // end of GetSize
return
n
;
}
// end of GetArraySize
/***********************************************************************/
/*
Make the array of values from the values list.
*/
/*
Get the Nth value of an Array.
*/
/***********************************************************************/
void JARRAY::InitArray(PGLOBAL g) {
int i;
PJVAL jvp, * pjvp = &First;
for (Size = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp->Del)
Size++;
if (Size > Alloc) {
// No need to realloc after deleting values
Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
Alloc = Size;
} // endif Size
for (i = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp->Del) {
Mvals[i++] = jvp;
pjvp = &jvp->Next;
Last = jvp;
} else
*pjvp = jvp->Next;
PBVAL
BJSON
::
GetArrayValue
(
PBVAL
bap
,
int
n
)
{
int
i
=
0
;
} // end of InitArray
for
(
PBVAL
bvp
=
bap
;
bvp
;
bvp
=
MVP
(
bvp
->
Next
))
if
(
i
==
n
)
return
bvp
;
else
i
++
;
/***********************************************************************/
/* Get the Nth value of an Array. */
/***********************************************************************/
PJVAL JARRAY::GetArrayValue(int i) {
if (Mvals && i >= 0 && i < Size)
return Mvals[i];
else
return NULL;
} // end of GetValue
return
NULL
;
}
// end of GetArrayValue
/***********************************************************************/
/* Add a Value to the Array Value list. */
/***********************************************************************/
PJVAL JARRAY::AddArrayValue(PGLOBAL g, PJVAL jvp, int* x) {
if (!jvp)
jvp = new(g) JVALUE;
PBVAL
BJSON
::
AddArrayValue
(
PGLOBAL
g
,
PBVAL
bap
,
PBVAL
nvp
,
int
*
x
)
{
if
(
!
nvp
)
nvp
=
SubAllocVal
(
g
);
if (
x
) {
if
(
bap
)
{
int
i
=
0
,
n
=
*
x
;
P
JVAL jp, * jpp = &First
;
P
BVAL
bvp
;
for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
(*jpp) = jvp;
if (!(jvp->Next = jp))
Last = jvp;
} else {
if (!First)
First = jvp;
else if (Last == First)
First->Next = Last = jvp;
else
Last->Next = jvp;
for
(
bvp
=
bap
;
bvp
;
bvp
=
MVP
(
bvp
->
Next
),
i
++
)
if
(
!
bvp
->
Next
||
(
x
&&
i
==
n
))
{
nvp
->
Next
=
bvp
->
Next
;
bvp
->
Next
=
MOF
(
nvp
);
break
;
}
// endif Next
Last = jvp;
Last->Next = NULL;
} // endif x
}
else
bap
=
nvp
;
return
jv
p;
} // end of AddValue
return
ba
p
;
}
// end of Add
Array
Value
/***********************************************************************/
/* Merge two arrays. */
/***********************************************************************/
bool JARRAY::Merge(PGLOBAL g, PJSON jsp) {
if (jsp->GetType() != TYPE_JAR) {
strcpy(g->Message, "Second argument is not an array");
return true;
} // endif Type
PJAR arp = (PJAR)jsp;
PBVAL
BJSON
::
MergeArray
(
PGLOBAL
g
,
PBVAL
bap1
,
PBVAL
bap2
)
{
if
(
bap1
)
{
for
(
PBVAL
bvp
=
bap2
;
bvp
;
bvp
=
MVP
(
bvp
->
Next
))
AddArrayValue
(
g
,
bap1
,
bvp
);
for (int i = 0; i < arp->size(); i++)
AddArrayValue(g, arp->GetArrayValue(i));
return
bap1
;
}
else
return
bap2
;
InitArray(g);
return false;
} // end of Merge
}
// end of MergeArray
/***********************************************************************/
/* Set the nth Value of the Array Value list. */
/* Set the nth Value of the Array Value list
or add it
. */
/***********************************************************************/
bool JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n) {
int i = 0;
PJVAL jp, * jpp = &First;
PBVAL
BJSON
::
SetArrayValue
(
PGLOBAL
g
,
PBVAL
bap
,
PBVAL
nvp
,
int
n
)
{
PBVAL
bvp
=
bap
,
pvp
=
NULL
;
if
(
bvp
)
{
for
(
int
i
=
0
;
bvp
;
i
++
,
bvp
=
MVP
(
bvp
->
Next
))
if
(
i
==
n
)
{
bvp
->
To_Val
=
nvp
->
To_Val
;
bvp
->
Nd
=
nvp
->
Nd
;
bvp
->
Type
=
nvp
->
Type
;
return
bap
;
}
else
pvp
=
bvp
;
}
// endif bap
if
(
!
bvp
)
{
bvp
=
DupVal
(
g
,
nvp
);
for (jp = First; i < n; i++, jp = *(jpp = &jp->Next))
if (!jp)
*jpp = jp = new(g) JVALUE;
if
(
pvp
)
pvp
->
Next
=
MOF
(
bvp
);
else
bap
=
bvp
;
}
// endif bvp
*jpp = jvp;
jvp->Next = (jp ? jp->Next : NULL);
return false;
return
bap
;
}
// end of SetValue
/***********************************************************************/
/* Return the text corresponding to all values. */
/***********************************************************************/
PSZ
JARRAY::GetText(PGLOBAL g
, PSTRG text) {
if (
First
) {
PSZ
BJSON
::
GetArrayText
(
PGLOBAL
g
,
PBVAL
bap
,
PSTRG
text
)
{
if
(
bap
)
{
bool
b
;
PJVAL jp;
if
(
!
text
)
{
text
=
new
(
g
)
STRING
(
g
,
256
);
...
...
@@ -1197,12 +1174,12 @@ PSZ JARRAY::GetText(PGLOBAL g, PSTRG text) {
text
->
Append
(
'('
);
b
=
false
;
}
}
// endif text
for (
jp = First; jp; jp = jp->Next
) {
jp->GetText(g
, text);
for
(
PBVAL
bvp
=
bap
;
bvp
;
bvp
=
MVP
(
bvp
->
Next
)
)
{
GetValueText
(
g
,
bvp
,
text
);
if (
j
p->Next)
if
(
bv
p
->
Next
)
text
->
Append
(
", "
);
else
if
(
!
b
)
text
->
Append
(
')'
);
...
...
@@ -1222,30 +1199,89 @@ PSZ JARRAY::GetText(PGLOBAL g, PSTRG text) {
/***********************************************************************/
/* Delete a Value from the Arrays Value list. */
/***********************************************************************/
bool JARRAY::DeleteValue(int n) {
PJVAL jvp = GetArrayValue(n);
PBVAL
BJSON
::
DeleteValue
(
PBVAL
bap
,
int
n
)
{
PBVAL
bvp
=
bap
,
pvp
=
NULL
;
if (jvp) {
jvp->Del = true;
return false;
} else
return true;
if
(
bvp
)
for
(
int
i
=
0
;
bvp
;
i
++
,
bvp
=
MVP
(
bvp
->
Next
))
if
(
i
==
n
)
{
if
(
pvp
)
pvp
->
Next
=
bvp
->
Next
;
else
bap
=
bvp
;
break
;
}
// endif i
return
bap
;
}
// end of DeleteValue
/***********************************************************************/
/* True if void or if all members are nulls. */
/***********************************************************************/
bool JARRAY::IsNull(void) {
for (int i = 0; i < Size; i++)
if (!Mvals[i]->IsNull())
bool
BJSON
::
IsArrayNull
(
PBVAL
bap
)
{
for
(
PBVAL
bvp
=
bap
;
bvp
;
bvp
=
MVP
(
bvp
->
Next
))
if
(
bvp
->
Type
!=
TYPE_NULL
)
return
false
;
return
true
;
}
// end of IsNull
/* -------------------------- Class JVALUE- -------------------------- */
/* ------------------------- Bvalue functions ------------------------ */
/***********************************************************************/
/* Sub-allocate and clear a BVAL. */
/***********************************************************************/
PBVAL
BJSON
::
SubAllocVal
(
PGLOBAL
g
)
{
PBVAL
bvp
=
(
PBVAL
)
BsonSubAlloc
(
g
,
sizeof
(
BVAL
));
bvp
->
To_Val
=
0
;
bvp
->
Nd
=
0
;
bvp
->
Type
=
TYPE_UNKNOWN
;
bvp
->
Next
=
0
;
return
bvp
;
}
// end of SubAllocVal
/***********************************************************************/
/* Sub-allocate and initialize a BVAL as string. */
/***********************************************************************/
PBVAL
BJSON
::
SubAllocVal
(
PGLOBAL
g
,
OFFSET
toval
,
JTYP
type
,
short
nd
)
{
PBVAL
bvp
=
(
PBVAL
)
BsonSubAlloc
(
g
,
sizeof
(
BVAL
));
bvp
->
To_Val
=
toval
;
bvp
->
Nd
=
nd
;
bvp
->
Type
=
type
;
bvp
->
Next
=
0
;
return
bvp
;
}
// end of SubAllocVal
/***********************************************************************/
/* Allocate a BVALUE with a given string or numeric value. */
/***********************************************************************/
PBVAL
BJSON
::
SubAllocVal
(
PGLOBAL
g
,
PVAL
valp
)
{
PBVAL
vlp
=
SubAllocVal
(
g
);
SetValue
(
g
,
vlp
,
valp
);
vlp
->
Next
=
NULL
;
return
vlp
;
}
// end of SubAllocVal
/***********************************************************************/
/* Sub-allocate and initialize a BVAL from another BVAL. */
/***********************************************************************/
PBVAL
BJSON
::
DupVal
(
PGLOBAL
g
,
PBVAL
bvlp
)
{
PBVAL
bvp
=
(
PBVAL
)
BsonSubAlloc
(
g
,
sizeof
(
BVAL
));
*
bvp
=
*
bvlp
;
bvp
->
Next
=
0
;
return
bvp
;
}
// end of DupVal
#if 0
/***********************************************************************/
/* Constructor for a JVALUE. */
/***********************************************************************/
...
...
@@ -1276,7 +1312,6 @@ JVALUE::JVALUE(PJSON jsp) : JSON() {
Type = TYPE_JVAL;
} // end of JVALUE constructor
#if 0
/***********************************************************************/
/* Constructor for a JVALUE with a given string or numeric value. */
/***********************************************************************/
...
...
@@ -1289,18 +1324,7 @@ JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON() {
} // end of JVALUE constructor
#endif // 0
/***********************************************************************/
/* Constructor for a JVALUE with a given string or numeric value. */
/***********************************************************************/
JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON() {
Jsp = NULL;
//Val = NULL;
SetValue(g, valp);
Next = NULL;
Del = false;
Type = TYPE_JVAL;
} // end of JVALUE constructor
#if 0
/***********************************************************************/
/* Constructor for a given string. */
/***********************************************************************/
...
...
@@ -1339,13 +1363,31 @@ JTYP JVALUE::GetValType(void) {
return DataType;
} // end of GetValType
#endif // 0
/***********************************************************************/
/* Return the size of value's value. */
/***********************************************************************/
int
BJSON
::
GetSize
(
PBVAL
vlp
,
bool
b
)
{
switch
(
vlp
->
Type
)
{
case
TYPE_JAR
:
return
GetArraySize
(
MVP
(
vlp
->
To_Val
));
case
TYPE_JOB
:
return
GetObjectSize
(
MPP
(
vlp
->
To_Val
));
default:
return
1
;
}
// enswitch Type
}
// end of GetSize
/***********************************************************************/
/* Return the Value's Object value. */
/***********************************************************************/
PJOB JVALUE::GetObject(void) {
if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JOB)
return (PJOB)Jsp;
PBPR
BJSON
::
GetObject
(
PBVAL
vlp
)
{
if
(
vlp
->
Type
==
TYPE_JOB
)
return
MPP
(
vlp
->
To_Val
);
return
NULL
;
}
// end of GetObject
...
...
@@ -1353,24 +1395,41 @@ PJOB JVALUE::GetObject(void) {
/***********************************************************************/
/* Return the Value's Array value. */
/***********************************************************************/
PJAR JVALUE::GetArray(void) {
if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JAR)
return (PJAR)Jsp;
PBVAL
BJSON
::
GetArray
(
PBVAL
vlp
)
{
if
(
vlp
->
Type
==
TYPE_JAR
)
return
MVP
(
vlp
->
To_Val
);
return
NULL
;
}
// end of GetArray
/***********************************************************************/
/* Return the Value's as a Value
class.
*/
/* Return the Value's as a Value
struct.
*/
/***********************************************************************/
PVAL JVALUE::GetValue(PGLOBAL g) {
PVAL valp = NULL;
PVAL
BJSON
::
GetValue
(
PGLOBAL
g
,
PBVAL
vp
)
{
double
d
;
PVAL
valp
;
PBVAL
vlp
=
vp
->
Type
==
TYPE_JVAL
?
MVP
(
vp
->
To_Val
)
:
vp
;
if (DataType != TYPE_JSON)
if (DataType == TYPE_STRG)
valp = AllocateValue(g, Strp, DataType, Nd);
else
valp = AllocateValue(g, &LLn, DataType, Nd);
switch
(
vlp
->
Type
)
{
case
TYPE_STRG
:
case
TYPE_DBL
:
case
TYPE_BINT
:
valp
=
AllocateValue
(
g
,
MP
(
vlp
->
To_Val
),
vlp
->
Type
,
vlp
->
Nd
);
break
;
case
TYPE_INTG
:
case
TYPE_BOOL
:
valp
=
AllocateValue
(
g
,
vlp
,
vlp
->
Type
);
break
;
case
TYPE_FLOAT
:
d
=
(
double
)
vlp
->
F
;
valp
=
AllocateValue
(
g
,
&
d
,
TYPE_DOUBLE
,
vlp
->
Nd
);
break
;
default:
valp
=
NULL
;
break
;
}
// endswitch Type
return
valp
;
}
// end of GetValue
...
...
@@ -1378,16 +1437,30 @@ PVAL JVALUE::GetValue(PGLOBAL g) {
/***********************************************************************/
/* Return the Value's Integer value. */
/***********************************************************************/
int JVALUE::GetInteger(void) {
int n;
int
BJSON
::
GetInteger
(
PBVAL
vp
)
{
int
n
;
PBVAL
vlp
=
(
vp
->
Type
==
TYPE_JVAL
)
?
MVP
(
vp
->
To_Val
)
:
vp
;
switch (DataType) {
case TYPE_INTG: n = N; break;
case TYPE_DBL: n = (int)F; break;
switch
(
vlp
->
Type
)
{
case
TYPE_INTG
:
n
=
vlp
->
N
;
break
;
case
TYPE_FLOAT
:
n
=
(
int
)
vlp
->
F
;
break
;
case
TYPE_DTM
:
case TYPE_STRG: n = atoi(Strp); break;
case TYPE_BOOL: n = (B) ? 1 : 0; break;
case TYPE_BINT: n = (int)LLn; break;
case
TYPE_STRG
:
n
=
atoi
(
MZP
(
vlp
->
To_Val
));
break
;
case
TYPE_BOOL
:
n
=
(
vlp
->
B
)
?
1
:
0
;
break
;
case
TYPE_BINT
:
n
=
(
int
)
*
(
longlong
*
)
MP
(
vlp
->
To_Val
);
break
;
case
TYPE_DBL
:
n
=
(
int
)
*
(
double
*
)
MP
(
vlp
->
To_Val
);
break
;
default:
n
=
0
;
}
// endswitch Type
...
...
@@ -1398,16 +1471,30 @@ int JVALUE::GetInteger(void) {
/***********************************************************************/
/* Return the Value's Big integer value. */
/***********************************************************************/
long long JVALUE::GetBigint(void) {
long long lln;
longlong
BJSON
::
GetBigint
(
PBVAL
vp
)
{
longlong
lln
;
PBVAL
vlp
=
(
vp
->
Type
==
TYPE_JVAL
)
?
MVP
(
vp
->
To_Val
)
:
vp
;
switch (DataType) {
case TYPE_BINT: lln = LLn; break;
case TYPE_INTG: lln = (long long)N; break;
case TYPE_DBL: lln = (long long)F; break;
switch
(
vlp
->
Type
)
{
case
TYPE_BINT
:
lln
=
*
(
longlong
*
)
MP
(
vlp
->
To_Val
);
break
;
case
TYPE_INTG
:
lln
=
(
longlong
)
vlp
->
N
;
break
;
case
TYPE_FLOAT
:
lln
=
(
longlong
)
vlp
->
F
;
break
;
case
TYPE_DBL
:
lln
=
(
longlong
)
*
(
double
*
)
MP
(
vlp
->
To_Val
);
break
;
case
TYPE_DTM
:
case TYPE_STRG: lln = atoll(Strp); break;
case TYPE_BOOL: lln = (B) ? 1 : 0; break;
case
TYPE_STRG
:
lln
=
atoll
(
MZP
(
vlp
->
To_Val
));
break
;
case
TYPE_BOOL
:
lln
=
(
vlp
->
B
)
?
1
:
0
;
break
;
default:
lln
=
0
;
}
// endswitch Type
...
...
@@ -1418,16 +1505,31 @@ long long JVALUE::GetBigint(void) {
/***********************************************************************/
/* Return the Value's Double value. */
/***********************************************************************/
double JVALUE::GetFloat(void) {
double
BJSON
::
GetDouble
(
PBVAL
vp
)
{
double
d
;
PBVAL
vlp
=
(
vp
->
Type
==
TYPE_JVAL
)
?
MVP
(
vp
->
To_Val
)
:
vp
;
switch (DataType) {
case TYPE_DBL: d = F; break;
case TYPE_BINT: d = (double)LLn; break;
case TYPE_INTG: d = (double)N; break;
switch
(
vlp
->
Type
)
{
case
TYPE_DBL
:
d
=
*
(
double
*
)
MP
(
vlp
->
To_Val
);
break
;
case
TYPE_BINT
:
d
=
(
double
)
*
(
longlong
*
)
MP
(
vlp
->
To_Val
);
break
;
case
TYPE_INTG
:
d
=
(
double
)
vlp
->
N
;
break
;
case
TYPE_FLOAT
:
d
=
(
double
)
vlp
->
F
;
break
;
case
TYPE_DTM
:
case TYPE_STRG: d = atof(Strp); break;
case TYPE_BOOL: d = (B) ? 1.0 : 0.0; break;
case
TYPE_STRG
:
d
=
atof
(
MZP
(
vlp
->
To_Val
));
break
;
case
TYPE_BOOL
:
d
=
(
vlp
->
B
)
?
1.0
:
0.0
;
break
;
default:
d
=
0.0
;
}
// endswitch Type
...
...
@@ -1438,47 +1540,53 @@ double JVALUE::GetFloat(void) {
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ JVALUE::GetString(PGLOBAL g, char* buff) {
PSZ
BJSON
::
GetString
(
PGLOBAL
g
,
PBVAL
vp
,
char
*
buff
)
{
char
buf
[
32
];
char
*
p
=
(
buff
)
?
buff
:
buf
;
PBVAL
vlp
=
(
vp
->
Type
==
TYPE_JVAL
)
?
MVP
(
vp
->
To_Val
)
:
vp
;
switch (
Data
Type) {
switch
(
vlp
->
Type
)
{
case
TYPE_DTM
:
case
TYPE_STRG
:
p =
Strp
;
p
=
MZP
(
vlp
->
To_Val
)
;
break
;
case
TYPE_INTG
:
sprintf(p, "%d", N);
sprintf
(
p
,
"%d"
,
vlp
->
N
);
break
;
case
TYPE_FLOAT
:
sprintf
(
p
,
"%.*f"
,
vlp
->
Nd
,
vlp
->
F
);
break
;
case
TYPE_BINT
:
sprintf(p, "%lld",
LLn
);
sprintf
(
p
,
"%lld"
,
*
(
longlong
*
)
MP
(
vlp
->
To_Val
)
);
break
;
case
TYPE_DBL
:
sprintf(p, "%.*lf",
Nd, F
);
sprintf
(
p
,
"%.*lf"
,
vlp
->
Nd
,
*
(
double
*
)
MP
(
vlp
->
To_Val
)
);
break
;
case
TYPE_BOOL
:
p = (
char*)((
B) ? "true" : "false");
p
=
(
PSZ
)((
vlp
->
B
)
?
"true"
:
"false"
);
break
;
case
TYPE_NULL
:
p = (
char*
)"null";
p
=
(
PSZ
)
"null"
;
break
;
default:
p
=
NULL
;
}
// endswitch Type
return (p == buf) ? (char*)PlugDup(g, buf) : p;
return
(
p
==
buf
)
?
(
PSZ
)
PlugDup
(
g
,
buf
)
:
p
;
}
// end of GetString
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ JVALUE::GetText(PGLOBAL g, PSTRG text) {
if (DataType == TYPE_JSON)
return Jsp->GetText(g, text);
PSZ
BJSON
::
GetValueText
(
PGLOBAL
g
,
PBVAL
vlp
,
PSTRG
text
)
{
if
(
vlp
->
Type
==
TYPE_JOB
)
return
GetObjectText
(
g
,
MPP
(
vlp
->
To_Val
),
text
);
else
if
(
vlp
->
Type
==
TYPE_JAR
)
return
GetArrayText
(
g
,
MVP
(
vlp
->
To_Val
),
text
);
char
buff
[
32
];
PSZ s = (
DataType == TYPE_NULL) ? NULL : GetString(g
, buff);
PSZ
s
=
(
vlp
->
Type
==
TYPE_NULL
)
?
NULL
:
GetString
(
g
,
vlp
,
buff
);
if
(
s
)
text
->
Append
(
s
);
...
...
@@ -1488,60 +1596,81 @@ PSZ JVALUE::GetText(PGLOBAL g, PSTRG text) {
return
NULL
;
}
// end of GetText
void JVALUE::SetValue(PJSON jsp) {
if (DataType == TYPE_JSON && jsp->GetType() == TYPE_JVAL) {
Jsp = jsp->GetJsp();
Nd = ((PJVAL)jsp)->Nd;
DataType = ((PJVAL)jsp)->DataType;
// Val = ((PJVAL)jsp)->GetVal();
} else {
Jsp = jsp;
DataType = TYPE_JSON;
} // endif Type
void
BJSON
::
SetValueObj
(
PBVAL
vlp
,
PBPR
bop
)
{
vlp
->
To_Val
=
MOF
(
bop
);
vlp
->
Type
=
TYPE_JOB
;
}
// end of SetValueObj;
void
BJSON
::
SetValueArr
(
PBVAL
vlp
,
PBVAL
bap
)
{
vlp
->
To_Val
=
MOF
(
bap
);
vlp
->
Type
=
TYPE_JAR
;
}
// end of SetValue;
void JVALUE::SetValue(PGLOBAL g, PVAL valp) {
//if (!Val)
// Val = AllocVal(g, TYPE_VAL);
void
BJSON
::
SetValueVal
(
PBVAL
vlp
,
PBVAL
vp
)
{
vlp
->
To_Val
=
vp
->
To_Val
;
vlp
->
Nd
=
vp
->
Nd
;
vlp
->
Type
=
vp
->
Type
;
}
// end of SetValue;
void
BJSON
::
SetValue
(
PGLOBAL
g
,
PBVAL
vlp
,
PVAL
valp
)
{
if
(
!
valp
||
valp
->
IsNull
())
{
Data
Type = TYPE_NULL;
vlp
->
Type
=
TYPE_NULL
;
}
else
switch
(
valp
->
GetType
())
{
case
TYPE_DATE
:
if
(((
DTVAL
*
)
valp
)
->
IsFormatted
())
Strp = valp->GetCharValue(
);
vlp
->
To_Val
=
MOF
(
valp
->
GetCharValue
()
);
else
{
char
buf
[
32
];
Strp = PlugDup(g, valp->GetCharString(buf
));
vlp
->
To_Val
=
MOF
(
PlugDup
(
g
,
valp
->
GetCharString
(
buf
)
));
}
// endif Formatted
Data
Type = TYPE_DTM;
vlp
->
Type
=
TYPE_DTM
;
break
;
case
TYPE_STRING
:
Strp = valp->GetCharValue(
);
Data
Type = TYPE_STRG;
vlp
->
To_Val
=
MOF
(
valp
->
GetCharValue
()
);
vlp
->
Type
=
TYPE_STRG
;
break
;
case
TYPE_DOUBLE
:
case
TYPE_DECIM
:
F = valp->GetFloatValue()
;
vlp
->
Nd
=
(
IsTypeNum
(
valp
->
GetType
()))
?
valp
->
GetValPrec
()
:
0
;
if (IsTypeNum(valp->GetType()))
Nd = valp->GetValPrec();
if
(
vlp
->
Nd
<=
6
)
{
vlp
->
F
=
(
float
)
valp
->
GetFloatValue
();
vlp
->
Type
=
TYPE_FLOAT
;
}
else
{
double
*
dp
=
(
double
*
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
double
));
*
dp
=
valp
->
GetFloatValue
();
vlp
->
To_Val
=
MOF
(
dp
);
vlp
->
Type
=
TYPE_DBL
;
}
// endif Nd
DataType = TYPE_DBL;
break
;
case
TYPE_TINY
:
B = valp->GetTinyValue() != 0;
Data
Type = TYPE_BOOL;
vlp
->
B
=
valp
->
GetTinyValue
()
!=
0
;
vlp
->
Type
=
TYPE_BOOL
;
case
TYPE_INT
:
N = valp->GetIntValue();
Data
Type = TYPE_INTG;
vlp
->
N
=
valp
->
GetIntValue
();
vlp
->
Type
=
TYPE_INTG
;
break
;
case
TYPE_BIGINT
:
LLn = valp->GetBigintValue();
DataType = TYPE_BINT;
if
(
valp
->
GetBigintValue
()
>=
INT_MIN32
&&
valp
->
GetBigintValue
()
<=
INT_MAX32
)
{
vlp
->
N
=
valp
->
GetIntValue
();
vlp
->
Type
=
TYPE_INTG
;
}
else
{
longlong
*
llp
=
(
longlong
*
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
longlong
));
*
llp
=
valp
->
GetBigintValue
();
vlp
->
To_Val
=
MOF
(
llp
);
vlp
->
Type
=
TYPE_BINT
;
}
// endif BigintValue
break
;
default:
sprintf
(
g
->
Message
,
"Unsupported typ %d
\n
"
,
valp
->
GetType
());
...
...
@@ -1553,49 +1682,76 @@ void JVALUE::SetValue(PGLOBAL g, PVAL valp) {
/***********************************************************************/
/* Set the Value's value as the given integer. */
/***********************************************************************/
void JVALUE::SetInteger(PGLOBAL g, int n) {
N = n;
DataType = TYPE_INTG;
void
BJSON
::
SetInteger
(
PBVAL
vlp
,
int
n
)
{
vlp
->
N
=
n
;
vlp
->
Type
=
TYPE_INTG
;
}
// end of SetInteger
/***********************************************************************/
/* Set the Value's Boolean value as a tiny integer. */
/***********************************************************************/
void JVALUE::SetBool(PGLOBAL g, bool b) {
B = b;
DataType = TYPE_BOOL;
void
BJSON
::
SetBool
(
PBVAL
vlp
,
bool
b
)
{
vlp
->
B
=
b
;
vlp
->
Type
=
TYPE_BOOL
;
}
// end of SetTiny
/***********************************************************************/
/* Set the Value's value as the given big integer. */
/***********************************************************************/
void JVALUE::SetBigint(PGLOBAL g, long long ll) {
LLn = ll;
DataType = TYPE_BINT;
void
BJSON
::
SetBigint
(
PGLOBAL
g
,
PBVAL
vlp
,
longlong
ll
)
{
if
(
ll
>=
INT_MIN32
&&
ll
<=
INT_MAX32
)
{
vlp
->
N
=
(
int
)
ll
;
vlp
->
Type
=
TYPE_INTG
;
}
else
{
longlong
*
llp
=
(
longlong
*
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
longlong
));
*
llp
=
ll
;
vlp
->
To_Val
=
MOF
(
llp
);
vlp
->
Type
=
TYPE_BINT
;
}
// endif ll
}
// end of SetBigint
/***********************************************************************/
/* Set the Value's value as the given DOUBLE. */
/***********************************************************************/
void
JVALUE::SetFloat(PGLOBAL g
, double f) {
F =
f;
Nd = 6;
DataType = TYPE_DBL
;
void
BJSON
::
SetFloat
(
PBVAL
vlp
,
double
f
)
{
vlp
->
F
=
(
float
)
f
;
vlp
->
Nd
=
6
;
vlp
->
Type
=
TYPE_FLOAT
;
}
// end of SetFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
/***********************************************************************/
void
JVALUE::SetString(PGLOBAL g
, PSZ s, int ci) {
Strp = s
;
Nd = ci;
Data
Type = TYPE_STRG;
void
BJSON
::
SetString
(
PBVAL
vlp
,
PSZ
s
,
int
ci
)
{
vlp
->
To_Val
=
MOF
(
s
)
;
vlp
->
Nd
=
ci
;
vlp
->
Type
=
TYPE_STRG
;
}
// end of SetString
/***********************************************************************/
/* True when its JSON or normal value is null. */
/***********************************************************************/
bool JVALUE::IsNull(void) {
return (DataType == TYPE_JSON) ? Jsp->IsNull() : DataType == TYPE_NULL;
} // end of IsNull
#endif // 0
bool
BJSON
::
IsValueNull
(
PBVAL
vlp
)
{
bool
b
;
switch
(
vlp
->
Type
)
{
case
TYPE_NULL
:
b
=
true
;
break
;
case
TYPE_JOB
:
b
=
IsObjectNull
(
MPP
(
vlp
->
To_Val
));
break
;
case
TYPE_JAR
:
b
=
IsArrayNull
(
MVP
(
vlp
->
To_Val
));
break
;
default:
b
=
false
;
}
// endswitch Type
return
b
;
}
// end of IsNull
storage/connect/bson.h
View file @
dc8f914c
...
...
@@ -16,20 +16,25 @@
#define X
#endif
#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
#define MOF(X) MakeOff(Base, X)
#define MP(X) MakePtr(Base, X)
#define MPP(X) (PBPR)MakePtr(Base, X)
#define MVP(X) (PBVAL)MakePtr(Base, X)
#define MZP(X) (PSZ)MakePtr(Base, X)
#define LLN(X) *(longlong*)MakePtr(Base, X)
#define DBL(X) *(double*)MakePtr(Base, X)
class
BDOC
;
class
BOUT
;
//class
JSON;
class
B
JSON
;
typedef
class
BDOC
*
PBDOC
;
//typedef class BJSON* PBSON;
// BSON size should be equal on Linux and Windows
#define BMX 255
typedef
uint
OFFSET
;
typedef
class
BJSON
*
PBJSON
;
typedef
uint
OFFSET
;
/***********************************************************************/
/* Structure
JVALUE.
*/
/* Structure
BVAL. Binary representation of a JVALUE.
*/
/***********************************************************************/
typedef
struct
_jvalue
{
union
{
...
...
@@ -39,12 +44,12 @@ typedef struct _jvalue {
bool
B
;
// A boolean value True or false (0)
};
short
Nd
;
// Number of decimals
JTYP
Type
;
// The value type
short
Type
;
// The value type
OFFSET
Next
;
// Offset to the next value in array
}
BVAL
,
*
PBVAL
;
// end of struct BVALUE
/***********************************************************************/
/* Structure
J
PAIR. The pairs of a json Object. */
/* Structure
B
PAIR. The pairs of a json Object. */
/***********************************************************************/
typedef
struct
_jpair
{
OFFSET
Key
;
// Offset to this pair key name
...
...
@@ -52,26 +57,6 @@ typedef struct _jpair {
OFFSET
Next
;
// Offset to the next pair in object
}
BPAIR
,
*
PBPR
;
// end of struct BPAIR
#if 0
/***********************************************************************/
/* Structure used to return binary json to Json UDF functions. */
/* (should be moved to jsonudf.h). */
/***********************************************************************/
typedef struct _JsonBin {
char Msg[BMX + 1];
char *Filename;
PGLOBAL G;
int Pretty;
ulong Reslen;
my_bool Changed;
PBSON Top;
PBSON Jsp;
PBJN Bsp;
} BJSON, *PBJN ; // end of struct BJSON
PBJN JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp);
#endif // 0
char
*
NextChr
(
PSZ
s
,
char
sep
);
char
*
GetJsonNull
(
void
);
const
char
*
GetFmt
(
int
type
,
bool
un
);
...
...
@@ -79,15 +64,84 @@ const char* GetFmt(int type, bool un);
DllExport
bool
IsNum
(
PSZ
s
);
/***********************************************************************/
/* Class
JDOC. The class for parsing and serializing json documents.
*/
/* Class
BJSON. The class handling all BJSON operations.
*/
/***********************************************************************/
class
B
DOC
:
public
BLOCK
{
class
B
JSON
:
public
BLOCK
{
public:
BDOC
(
void
);
// Constructor
BJSON
(
void
*
base
,
PBVAL
vp
=
NULL
)
{
Base
=
base
;
Bvp
=
vp
;
}
void
*
BsonSubAlloc
(
PGLOBAL
g
,
size_t
size
);
PBPR
SubAllocPair
(
PGLOBAL
g
,
OFFSET
key
);
void
*
GetBase
(
void
)
{
return
Base
;
}
// SubAlloc functions
void
*
BsonSubAlloc
(
PGLOBAL
g
,
size_t
size
);
PBPR
SubAllocPair
(
PGLOBAL
g
,
OFFSET
key
,
OFFSET
val
=
0
);
PBVAL
SubAllocVal
(
PGLOBAL
g
);
PBVAL
SubAllocVal
(
PGLOBAL
g
,
OFFSET
toval
,
JTYP
type
=
TYPE_UNKNOWN
,
short
nd
=
0
);
PBVAL
SubAllocVal
(
PGLOBAL
g
,
PVAL
valp
);
PBVAL
DupVal
(
PGLOBAL
g
,
PBVAL
bvp
);
// Array functions
int
GetArraySize
(
PBVAL
bap
,
bool
b
=
false
);
PBVAL
GetArrayValue
(
PBVAL
bap
,
int
i
);
PSZ
GetArrayText
(
PGLOBAL
g
,
PBVAL
bap
,
PSTRG
text
);
PBVAL
MergeArray
(
PGLOBAL
g
,
PBVAL
bap1
,
PBVAL
bap2
);
PBVAL
DeleteValue
(
PBVAL
bap
,
int
n
);
PBVAL
AddArrayValue
(
PGLOBAL
g
,
PBVAL
bap
,
PBVAL
nvp
=
NULL
,
int
*
x
=
NULL
);
PBVAL
SetArrayValue
(
PGLOBAL
g
,
PBVAL
bap
,
PBVAL
nvp
,
int
n
);
bool
IsArrayNull
(
PBVAL
bap
);
// Object functions
int
GetObjectSize
(
PBPR
bop
,
bool
b
=
false
);
PSZ
GetObjectText
(
PGLOBAL
g
,
PBPR
bop
,
PSTRG
text
);
PBPR
MergeObject
(
PGLOBAL
g
,
PBPR
bop1
,
PBPR
bop2
);
PBPR
AddPair
(
PGLOBAL
g
,
PBPR
bop
,
PSZ
key
,
OFFSET
val
=
0
);
PBVAL
GetKeyValue
(
PBPR
bop
,
PSZ
key
);
PBVAL
GetKeyList
(
PGLOBAL
g
,
PBPR
bop
);
PBVAL
GetObjectValList
(
PGLOBAL
g
,
PBPR
bop
);
PBPR
SetKeyValue
(
PGLOBAL
g
,
PBPR
bop
,
OFFSET
bvp
,
PSZ
key
);
PBPR
DeleteKey
(
PBPR
bop
,
PCSZ
k
);
bool
IsObjectNull
(
PBPR
bop
);
// Value functions
int
GetSize
(
PBVAL
vlp
,
bool
b
=
false
);
PBPR
GetObject
(
PBVAL
vlp
);
PBVAL
GetArray
(
PBVAL
vlp
);
//PJSON GetJsp(void) { return (DataType == TYPE_JSON ? Jsp : NULL); }
PSZ
GetValueText
(
PGLOBAL
g
,
PBVAL
vlp
,
PSTRG
text
);
//inline PJSON GetJson(void) { return (DataType == TYPE_JSON ? Jsp : this); }
PSZ
GetString
(
PGLOBAL
g
,
PBVAL
vp
,
char
*
buff
=
NULL
);
int
GetInteger
(
PBVAL
vp
);
long
long
GetBigint
(
PBVAL
vp
);
double
GetDouble
(
PBVAL
vp
);
PVAL
GetValue
(
PGLOBAL
g
,
PBVAL
vp
);
void
SetValueObj
(
PBVAL
vlp
,
PBPR
bop
);
void
SetValueArr
(
PBVAL
vlp
,
PBVAL
bap
);
void
SetValueVal
(
PBVAL
vlp
,
PBVAL
vp
);
void
SetValue
(
PGLOBAL
g
,
PBVAL
vlp
,
PVAL
valp
);
void
SetString
(
PBVAL
vlp
,
PSZ
s
,
int
ci
=
0
);
void
SetInteger
(
PBVAL
vlp
,
int
n
);
void
SetBigint
(
PGLOBAL
g
,
PBVAL
vlp
,
longlong
ll
);
void
SetFloat
(
PBVAL
vlp
,
double
f
);
void
SetBool
(
PBVAL
vlp
,
bool
b
);
bool
IsValueNull
(
PBVAL
vlp
);
// Members
PBVAL
Bvp
;
void
*
Base
;
protected:
// Default constructor not to be used
BJSON
(
void
)
{}
};
// end of class BJSON
/***********************************************************************/
/* Class JDOC. The class for parsing and serializing json documents. */
/***********************************************************************/
class
BDOC
:
public
BJSON
{
public:
BDOC
(
void
*
);
PBVAL
ParseJson
(
PGLOBAL
g
,
char
*
s
,
size_t
n
,
int
*
prty
=
NULL
,
bool
*
b
=
NULL
);
PSZ
Serialize
(
PGLOBAL
g
,
PBVAL
bvp
,
char
*
fn
,
int
pretty
);
...
...
@@ -98,72 +152,21 @@ class BDOC : public BLOCK {
OFFSET
ParseString
(
PGLOBAL
g
,
int
&
i
);
void
ParseNumeric
(
PGLOBAL
g
,
int
&
i
,
PBVAL
bvp
);
OFFSET
ParseAsArray
(
PGLOBAL
g
,
int
&
i
,
int
pretty
,
int
*
ptyp
);
bool
SerializeArray
(
OFFSET
arp
,
bool
b
);
bool
SerializeObject
(
OFFSET
obp
);
bool
SerializeValue
(
PBVAL
vp
);
bool
SerializeArray
(
OFFSET
arp
,
bool
b
);
bool
SerializeObject
(
OFFSET
obp
);
bool
SerializeValue
(
PBVAL
vp
);
// Members used when parsing and serializing
private:
JOUT
*
jp
;
// Used with serialize
void
*
base
;
// The base for making offsets or pointers
char
*
s
;
// The Json string to parse
int
len
;
// The Json string length
bool
pty
[
3
];
// Used to guess what pretty is
// Default constructor not to be used
BDOC
(
void
)
{}
};
// end of class BDOC
#if 0
/***********************************************************************/
/* Class BJSON. The class handling all BSON operations. */
/***********************************************************************/
class BJSON : public BLOCK {
public:
// Constructor
BJSON(PBVAL vp, void* base) { Vlp = vp; Base = base; }
// Array functions
int GetSize(bool b);
PBVAL GetArrayValue(int i);
PSZ GetText(PGLOBAL g, PSTRG text);
bool Merge(PGLOBAL g, PBVAL jsp);
bool DeleteValue(int n);
PBVAL AddArrayValue(PGLOBAL g, PBVAL jvp = NULL, int* x = NULL);
bool SetArrayValue(PGLOBAL g, PBVAL jvp, int i);
// Object functions
int GetObjectSize(PBPR prp, bool b);
PSZ GetObjectText(PGLOBAL g, PBPR prp, PSTRG text);
bool MergeObject(PGLOBAL g, PBPR prp);
PJPR AddPair(PGLOBAL g, PCSZ key);
PJVAL GetKeyValue(const char* key);
PJAR GetKeyList(PGLOBAL g);
PJAR GetValList(PGLOBAL g);
void SetKeyValue(PGLOBAL g, PBVAL jvp, PCSZ key);
void DeleteKey(PCSZ k);
// Value functions
PBPR GetObject(void);
PBVAL GetArray(void);
PJSON GetJsp(void) { return (DataType == TYPE_JSON ? Jsp : NULL); }
PSZ GetValueText(PGLOBAL g, PSTRG text);
inline PJSON GetJson(void) { return (DataType == TYPE_JSON ? Jsp : this); }
PSZ GetString(PGLOBAL g, char* buff = NULL);
int GetInteger(void);
long long GetBigint(void);
double GetFloat(void);
PVAL GetValue(PGLOBAL g);
void SetValue(PJSON jsp);
void SetValue(PGLOBAL g, PVAL valp);
void SetString(PGLOBAL g, PSZ s, int ci = 0);
void SetInteger(PGLOBAL g, int n);
void SetBigint(PGLOBAL g, longlong ll);
void SetFloat(PGLOBAL g, double f);
void SetBool(PGLOBAL g, bool b);
// Members
PBVAL Vlp;
void* Base;
}; // end of class BJSON
/***********************************************************************/
/* Class JOBJECT: contains a list of value pairs. */
/***********************************************************************/
...
...
storage/connect/json.h
View file @
dc8f914c
...
...
@@ -15,10 +15,7 @@
#define X
#endif
// Required by some compilers
enum
JTYP
:
short
;
enum
JTYP
:
short
{
enum
JTYP
{
TYPE_NULL
=
TYPE_VOID
,
TYPE_STRG
=
TYPE_STRING
,
TYPE_DBL
=
TYPE_DOUBLE
,
...
...
@@ -48,9 +45,6 @@ typedef class JVALUE *PJVAL;
typedef
class
JOBJECT
*
PJOB
;
typedef
class
JARRAY
*
PJAR
;
// BSON size should be equal on Linux and Windows
#define BMX 255
typedef
struct
BSON
*
PBSON
;
typedef
struct
JPAIR
*
PJPR
;
//typedef struct VAL *PVL;
...
...
@@ -63,39 +57,6 @@ struct JPAIR {
PJPR
Next
;
// To the next pair
};
// end of struct JPAIR
#if 0
/***********************************************************************/
/* Structure VAL (string, int, float, bool or null) */
/***********************************************************************/
struct VAL {
union {
char *Strp; // Ptr to a string
int N; // An integer value
long long LLn; // A big integer value
double F; // A float value
bool B; // True or false
};
int Nd; // Decimal number
JTYP Type; // The value type
}; // end of struct VAL
#endif // 0
/***********************************************************************/
/* Structure used to return binary json to Json UDF functions. */
/***********************************************************************/
struct
BSON
{
char
Msg
[
BMX
+
1
];
char
*
Filename
;
PGLOBAL
G
;
int
Pretty
;
ulong
Reslen
;
my_bool
Changed
;
PJSON
Top
;
PJSON
Jsp
;
PBSON
Bsp
;
};
// end of struct BSON
PBSON
JbinAlloc
(
PGLOBAL
g
,
UDF_ARGS
*
args
,
ulong
len
,
PJSON
jsp
);
//PVL AllocVal(PGLOBAL g, JTYP type);
char
*
NextChr
(
PSZ
s
,
char
sep
);
char
*
GetJsonNull
(
void
);
...
...
storage/connect/jsonudf.cpp
View file @
dc8f914c
...
...
@@ -63,7 +63,7 @@ static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len)
return
jsx
;
}
/* end of JsnxNew */
/* ----------------------------------- JSNX ------------------------------------ */
/* ----------------------------------- JSNX ------------------------------------ */
/*********************************************************************************/
/* JSNX public constructor. */
...
...
@@ -1186,6 +1186,7 @@ static my_bool JsonSubSet(PGLOBAL g)
pph
->
To_Free
=
(
g
->
Saved_Size
)
?
g
->
Saved_Size
:
(
size_t
)
sizeof
(
POOLHEADER
);
pph
->
FreeBlk
=
g
->
Sarea_Size
-
pph
->
To_Free
;
g
->
Saved_Size
=
0
;
return
FALSE
;
}
/* end of JsonSubSet */
...
...
@@ -6558,3 +6559,1476 @@ long long countin(UDF_INIT *initid, UDF_ARGS *args, char *result,
free
(
str2
);
return
n
;
}
// end of countin
/* --------------------------- New Testing BJSON Stuff --------------------------*/
/*********************************************************************************/
/* SubAlloc a new BJNX class with protection against memory exhaustion. */
/*********************************************************************************/
static
PBJNX
BjnxNew
(
PGLOBAL
g
,
PBVAL
vlp
,
int
type
,
int
len
)
{
PBJNX
bjnx
;
try
{
bjnx
=
new
(
g
)
BJNX
(
g
,
vlp
,
type
,
len
);
}
catch
(...)
{
if
(
trace
(
1023
))
htrc
(
"%s
\n
"
,
g
->
Message
);
PUSH_WARNING
(
g
->
Message
);
bjnx
=
NULL
;
}
// end try/catch
return
bjnx
;
}
/* end of BjnxNew */
/* ----------------------------------- BSNX ------------------------------------ */
/*********************************************************************************/
/* BSNX public constructor. */
/*********************************************************************************/
BJNX
::
BJNX
(
PGLOBAL
g
,
PBVAL
row
,
int
type
,
int
len
,
int
prec
,
my_bool
wr
)
:
BDOC
(
g
->
Sarea
)
{
Row
=
row
;
Bvalp
=
NULL
;
Jpnp
=
NULL
;
Jp
=
NULL
;
Nodes
=
NULL
;
Value
=
AllocateValue
(
g
,
type
,
len
,
prec
);
MulVal
=
NULL
;
Jpath
=
NULL
;
Buf_Type
=
type
;
Long
=
len
;
Prec
=
prec
;
Nod
=
0
;
Xnod
=
-
1
;
K
=
0
;
I
=
-
1
;
Imax
=
9
;
B
=
0
;
Xpd
=
false
;
Parsed
=
false
;
Found
=
false
;
Wr
=
wr
;
Jb
=
false
;
}
// end of BJNX constructor
/*********************************************************************************/
/* SetJpath: set and parse the json path. */
/*********************************************************************************/
my_bool
BJNX
::
SetJpath
(
PGLOBAL
g
,
char
*
path
,
my_bool
jb
)
{
// Check Value was allocated
if
(
!
Value
)
return
true
;
Value
->
SetNullable
(
true
);
Jpath
=
path
;
// Parse the json path
Parsed
=
false
;
Nod
=
0
;
Jb
=
jb
;
return
ParseJpath
(
g
);
}
// end of SetJpath
/*********************************************************************************/
/* Analyse array processing options. */
/*********************************************************************************/
my_bool
BJNX
::
SetArrayOptions
(
PGLOBAL
g
,
char
*
p
,
int
i
,
PSZ
nm
)
{
int
n
=
(
int
)
strlen
(
p
);
my_bool
dg
=
true
,
b
=
false
;
PJNODE
jnp
=
&
Nodes
[
i
];
if
(
*
p
)
{
if
(
p
[
n
-
1
]
==
']'
)
{
p
[
--
n
]
=
0
;
}
else
if
(
!
IsNum
(
p
))
{
// Wrong array specification
sprintf
(
g
->
Message
,
"Invalid array specification %s"
,
p
);
return
true
;
}
// endif p
}
else
b
=
true
;
// To check whether a numeric Rank was specified
dg
=
IsNum
(
p
);
if
(
!
n
)
{
// Default specifications
if
(
jnp
->
Op
!=
OP_EXP
)
{
if
(
Wr
)
{
// Force append
jnp
->
Rank
=
INT_MAX32
;
jnp
->
Op
=
OP_LE
;
}
else
if
(
Jb
)
{
// Return a Json item
jnp
->
Op
=
OP_XX
;
}
else
if
(
b
)
{
// Return 1st value (B is the index base)
jnp
->
Rank
=
B
;
jnp
->
Op
=
OP_LE
;
}
else
if
(
!
Value
->
IsTypeNum
())
{
jnp
->
CncVal
=
AllocateValue
(
g
,
PlugDup
(
g
,
", "
),
TYPE_STRING
);
jnp
->
Op
=
OP_CNC
;
}
else
jnp
->
Op
=
OP_ADD
;
}
// endif OP
}
else
if
(
dg
)
{
// Return nth value
jnp
->
Rank
=
atoi
(
p
)
-
B
;
jnp
->
Op
=
OP_EQ
;
}
else
if
(
Wr
)
{
sprintf
(
g
->
Message
,
"Invalid specification %s in a write path"
,
p
);
return
true
;
}
else
if
(
n
==
1
)
{
// Set the Op value;
switch
(
*
p
)
{
case
'+'
:
jnp
->
Op
=
OP_ADD
;
break
;
case
'x'
:
jnp
->
Op
=
OP_MULT
;
break
;
case
'>'
:
jnp
->
Op
=
OP_MAX
;
break
;
case
'<'
:
jnp
->
Op
=
OP_MIN
;
break
;
case
'!'
:
jnp
->
Op
=
OP_SEP
;
break
;
// Average
case
'#'
:
jnp
->
Op
=
OP_NUM
;
break
;
case
'*'
:
// Expand this array
strcpy
(
g
->
Message
,
"Expand not supported by this function"
);
return
true
;
default:
sprintf
(
g
->
Message
,
"Invalid function specification %c"
,
*
p
);
return
true
;
}
// endswitch *p
}
else
if
(
*
p
==
'"'
&&
p
[
n
-
1
]
==
'"'
)
{
// This is a concat specification
jnp
->
Op
=
OP_CNC
;
if
(
n
>
2
)
{
// Set concat intermediate string
p
[
n
-
1
]
=
0
;
if
(
trace
(
1
))
htrc
(
"Concat string=%s
\n
"
,
p
+
1
);
jnp
->
CncVal
=
AllocateValue
(
g
,
p
+
1
,
TYPE_STRING
);
}
// endif n
}
else
{
strcpy
(
g
->
Message
,
"Wrong array specification"
);
return
true
;
}
// endif's
// For calculated arrays, a local Value must be used
switch
(
jnp
->
Op
)
{
case
OP_NUM
:
jnp
->
Valp
=
AllocateValue
(
g
,
TYPE_INT
);
break
;
case
OP_ADD
:
case
OP_MULT
:
case
OP_SEP
:
if
(
!
IsTypeChar
(
Buf_Type
))
jnp
->
Valp
=
AllocateValue
(
g
,
Buf_Type
,
0
,
GetPrecision
());
else
jnp
->
Valp
=
AllocateValue
(
g
,
TYPE_DOUBLE
,
0
,
2
);
break
;
case
OP_MIN
:
case
OP_MAX
:
jnp
->
Valp
=
AllocateValue
(
g
,
Buf_Type
,
Long
,
GetPrecision
());
break
;
case
OP_CNC
:
if
(
IsTypeChar
(
Buf_Type
))
jnp
->
Valp
=
AllocateValue
(
g
,
TYPE_STRING
,
Long
,
GetPrecision
());
else
jnp
->
Valp
=
AllocateValue
(
g
,
TYPE_STRING
,
512
);
break
;
default:
break
;
}
// endswitch Op
if
(
jnp
->
Valp
)
MulVal
=
AllocateValue
(
g
,
jnp
->
Valp
);
return
false
;
}
// end of SetArrayOptions
/*********************************************************************************/
/* Parse the eventual passed Jpath information. */
/* This information can be specified in the Fieldfmt column option when */
/* creating the table. It permits to indicate the position of the node */
/* corresponding to that column. */
/*********************************************************************************/
my_bool
BJNX
::
ParseJpath
(
PGLOBAL
g
)
{
char
*
p
,
*
p1
=
NULL
,
*
p2
=
NULL
,
*
pbuf
=
NULL
;
int
i
;
my_bool
a
,
mul
=
false
;
if
(
Parsed
)
return
false
;
// Already done
else
if
(
!
Jpath
)
// Jpath = Name;
return
true
;
if
(
trace
(
1
))
htrc
(
"ParseJpath %s
\n
"
,
SVP
(
Jpath
));
if
(
!
(
pbuf
=
PlgDBDup
(
g
,
Jpath
)))
return
true
;
if
(
*
pbuf
==
'$'
)
pbuf
++
;
if
(
*
pbuf
==
'.'
)
pbuf
++
;
if
(
*
pbuf
==
'['
)
p1
=
pbuf
++
;
// Estimate the required number of nodes
for
(
i
=
0
,
p
=
pbuf
;
(
p
=
NextChr
(
p
,
'.'
));
i
++
,
p
++
)
Nod
++
;
// One path node found
if
(
!
(
Nodes
=
(
PJNODE
)
PlgDBSubAlloc
(
g
,
NULL
,
(
++
Nod
)
*
sizeof
(
JNODE
))))
return
true
;
memset
(
Nodes
,
0
,
(
Nod
)
*
sizeof
(
JNODE
));
// Analyze the Jpath for this column
for
(
i
=
0
,
p
=
pbuf
;
p
&&
i
<
Nod
;
i
++
,
p
=
(
p2
?
p2
:
NULL
))
{
a
=
(
p1
!=
NULL
);
p1
=
strchr
(
p
,
'['
);
p2
=
strchr
(
p
,
'.'
);
if
(
!
p2
)
p2
=
p1
;
else
if
(
p1
)
{
if
(
p1
<
p2
)
p2
=
p1
;
else
if
(
p1
==
p2
+
1
)
*
p2
++
=
0
;
// Old syntax .[
else
p1
=
NULL
;
}
// endif p1
if
(
p2
)
*
p2
++
=
0
;
// Jpath must be explicit
if
(
a
||
*
p
==
0
||
*
p
==
'['
||
IsNum
(
p
))
{
// Analyse intermediate array processing
if
(
SetArrayOptions
(
g
,
p
,
i
,
Nodes
[
i
-
1
].
Key
))
return
true
;
}
else
if
(
*
p
==
'*'
)
{
if
(
Wr
)
{
sprintf
(
g
->
Message
,
"Invalid specification %c in a write path"
,
*
p
);
return
true
;
}
else
// Return JSON
Nodes
[
i
].
Op
=
OP_XX
;
}
else
{
Nodes
[
i
].
Key
=
p
;
Nodes
[
i
].
Op
=
OP_EXIST
;
}
// endif's
}
// endfor i, p
Nod
=
i
;
MulVal
=
AllocateValue
(
g
,
Value
);
if
(
trace
(
1
))
for
(
i
=
0
;
i
<
Nod
;
i
++
)
htrc
(
"Node(%d) Key=%s Op=%d Rank=%d
\n
"
,
i
,
SVP
(
Nodes
[
i
].
Key
),
Nodes
[
i
].
Op
,
Nodes
[
i
].
Rank
);
Parsed
=
true
;
return
false
;
}
// end of ParseJpath
/*********************************************************************************/
/* MakeJson: Serialize the json item and set value to it. */
/*********************************************************************************/
PVAL
BJNX
::
MakeJson
(
PGLOBAL
g
,
PBVAL
bvp
)
{
if
(
Value
->
IsTypeNum
())
{
strcpy
(
g
->
Message
,
"Cannot make Json for a numeric value"
);
Value
->
Reset
();
}
else
if
(
bvp
->
Type
!=
TYPE_JAR
&&
bvp
->
Type
!=
TYPE_JOB
)
{
strcpy
(
g
->
Message
,
"Target is not an array or object"
);
Value
->
Reset
();
}
else
Value
->
SetValue_psz
(
Serialize
(
g
,
bvp
,
NULL
,
0
));
return
Value
;
}
// end of MakeJson
/*********************************************************************************/
/* SetValue: Set a value from a JVALUE contains. */
/*********************************************************************************/
void
BJNX
::
SetJsonValue
(
PGLOBAL
g
,
PVAL
vp
,
PBVAL
vlp
)
{
if
(
vlp
)
{
vp
->
SetNull
(
false
);
if
(
Jb
)
{
vp
->
SetValue_psz
(
Serialize
(
g
,
vlp
,
NULL
,
0
));
}
else
switch
(
vlp
->
Type
)
{
case
TYPE_DTM
:
case
TYPE_STRG
:
vp
->
SetValue_psz
(
GetString
(
g
,
vlp
));
break
;
case
TYPE_INTG
:
case
TYPE_BINT
:
vp
->
SetValue
(
GetInteger
(
vlp
));
break
;
case
TYPE_DBL
:
if
(
vp
->
IsTypeNum
())
vp
->
SetValue
(
GetDouble
(
vlp
));
else
// Get the proper number of decimals
vp
->
SetValue_psz
(
GetString
(
g
,
vlp
));
break
;
case
TYPE_BOOL
:
if
(
vp
->
IsTypeNum
())
vp
->
SetValue
(
GetInteger
(
vlp
)
?
1
:
0
);
else
vp
->
SetValue_psz
(
GetString
(
g
,
vlp
));
break
;
case
TYPE_JAR
:
vp
->
SetValue_psz
(
GetArrayText
(
g
,
MVP
(
vlp
->
To_Val
),
NULL
));
break
;
case
TYPE_JOB
:
vp
->
SetValue_psz
(
GetObjectText
(
g
,
MPP
(
vlp
->
To_Val
),
NULL
));
break
;
case
TYPE_NULL
:
vp
->
SetNull
(
true
);
default:
vp
->
Reset
();
}
// endswitch Type
}
else
{
vp
->
SetNull
(
true
);
vp
->
Reset
();
}
// endif val
}
// end of SetJsonValue
/*********************************************************************************/
/* GetJson: */
/*********************************************************************************/
PBVAL
BJNX
::
GetJson
(
PGLOBAL
g
)
{
return
GetRowValue
(
g
,
Row
,
0
);
}
// end of GetJson
/*********************************************************************************/
/* ReadValue: */
/*********************************************************************************/
void
BJNX
::
ReadValue
(
PGLOBAL
g
)
{
Value
->
SetValue_pval
(
GetColumnValue
(
g
,
Row
,
0
));
}
// end of ReadValue
/*********************************************************************************/
/* GetColumnValue: */
/*********************************************************************************/
PVAL
BJNX
::
GetColumnValue
(
PGLOBAL
g
,
PBVAL
row
,
int
i
)
{
PBVAL
vlp
=
GetRowValue
(
g
,
row
,
i
);
SetJsonValue
(
g
,
Value
,
vlp
);
return
Value
;
}
// end of GetColumnValue
/*********************************************************************************/
/* GetRowValue: */
/*********************************************************************************/
PBVAL
BJNX
::
GetRowValue
(
PGLOBAL
g
,
PBVAL
row
,
int
i
,
my_bool
b
)
{
my_bool
expd
=
false
;
PBVAL
bap
;
PBVAL
vlp
=
NULL
;
for
(;
i
<
Nod
&&
row
;
i
++
)
{
if
(
Nodes
[
i
].
Op
==
OP_NUM
)
{
Value
->
SetValue
(
row
->
Type
==
TYPE_JAR
?
GetArraySize
(
MVP
(
row
->
To_Val
))
:
1
);
vlp
=
SubAllocVal
(
g
,
Value
);
return
vlp
;
}
else
if
(
Nodes
[
i
].
Op
==
OP_XX
)
{
Jb
=
b
;
// return DupVal(g, row);
return
row
;
// or last line ???
}
else
switch
(
row
->
Type
)
{
case
TYPE_JOB
:
if
(
!
Nodes
[
i
].
Key
)
{
// Expected Array was not there
if
(
Nodes
[
i
].
Op
==
OP_LE
)
{
if
(
i
<
Nod
-
1
)
continue
;
else
vlp
=
row
;
// DupVal(g, row) ???
}
else
{
strcpy
(
g
->
Message
,
"Unexpected object"
);
vlp
=
NULL
;
}
//endif Op
}
else
vlp
=
GetKeyValue
(
MPP
(
row
->
To_Val
),
Nodes
[
i
].
Key
);
break
;
case
TYPE_JAR
:
bap
=
MVP
(
row
->
To_Val
);
if
(
!
Nodes
[
i
].
Key
)
{
if
(
Nodes
[
i
].
Op
==
OP_EQ
||
Nodes
[
i
].
Op
==
OP_LE
)
vlp
=
GetArrayValue
(
bap
,
Nodes
[
i
].
Rank
);
else
if
(
Nodes
[
i
].
Op
==
OP_EXP
)
return
(
PBVAL
)
ExpandArray
(
g
,
bap
,
i
);
else
return
SubAllocVal
(
g
,
CalculateArray
(
g
,
bap
,
i
));
}
else
{
// Unexpected array, unwrap it as [0]
vlp
=
GetArrayValue
(
bap
,
0
);
i
--
;
}
// endif's
break
;
case
TYPE_JVAL
:
vlp
=
row
;
break
;
default:
sprintf
(
g
->
Message
,
"Invalid row JSON type %d"
,
row
->
Type
);
vlp
=
NULL
;
}
// endswitch Type
row
=
vlp
;
}
// endfor i
return
vlp
;
}
// end of GetRowValue
/*********************************************************************************/
/* ExpandArray: */
/*********************************************************************************/
PVAL
BJNX
::
ExpandArray
(
PGLOBAL
g
,
PBVAL
arp
,
int
n
)
{
strcpy
(
g
->
Message
,
"Expand cannot be done by this function"
);
return
NULL
;
}
// end of ExpandArray
/*********************************************************************************/
/* CalculateArray: NIY */
/*********************************************************************************/
PVAL
BJNX
::
CalculateArray
(
PGLOBAL
g
,
PBVAL
bap
,
int
n
)
{
#if 0
int i, ars = GetArraySize(bap), nv = 0;
bool err;
OPVAL op = Nodes[n].Op;
PVAL val[2], vp = Nodes[n].Valp;
PBVAL bvrp, bvp;
BVAL bval;
vp->Reset();
xtrc(1,"CalculateArray size=%d op=%d\n", ars, op);
for (i = 0; i < ars; i++) {
bvrp = GetArrayValue(bap, i);
xtrc(1, "i=%d nv=%d\n", i, nv);
if (!IsValueNull(bvrp) || (op == OP_CNC && GetJsonNull())) {
if (IsValueNull(bvrp)) {
SetString(bvrp, GetJsonNull(), 0);
bvp = bvrp;
} else if (n < Nod - 1 && bvrp->GetJson()) {
bval.SetValue(g, GetColumnValue(g, jvrp->GetJson(), n + 1));
bvp = &bval;
} else
jvp = jvrp;
if (trace(1))
htrc("jvp=%s null=%d\n",
jvp->GetString(g), jvp->IsNull() ? 1 : 0);
if (!nv++) {
SetJsonValue(g, vp, jvp);
continue;
} else
SetJsonValue(g, MulVal, jvp);
if (!MulVal->IsNull()) {
switch (op) {
case OP_CNC:
if (Nodes[n].CncVal) {
val[0] = Nodes[n].CncVal;
err = vp->Compute(g, val, 1, op);
} // endif CncVal
val[0] = MulVal;
err = vp->Compute(g, val, 1, op);
break;
// case OP_NUM:
case OP_SEP:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, OP_ADD);
break;
default:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, op);
} // endswitch Op
if (err)
vp->Reset();
if (trace(1)) {
char buf(32);
htrc("vp='%s' err=%d\n",
vp->GetCharString(&buf), err ? 1 : 0);
} // endif trace
} // endif Zero
} // endif jvrp
} // endfor i
if (op == OP_SEP) {
// Calculate average
MulVal->SetValue(nv);
val[0] = vp;
val[1] = MulVal;
if (vp->Compute(g, val, 2, OP_DIV))
vp->Reset();
} // endif Op
return vp;
#else
strcpy
(
g
->
Message
,
"Calculate array NIY"
);
return
NULL
;
#endif
}
// end of CalculateArray
/*********************************************************************************/
/* CheckPath: Checks whether the path exists in the document. */
/*********************************************************************************/
my_bool
BJNX
::
CheckPath
(
PGLOBAL
g
)
{
PBVAL
val
=
NULL
;
PBVAL
row
=
Row
;
for
(
int
i
=
0
;
i
<
Nod
&&
row
;
i
++
)
{
val
=
NULL
;
if
(
Nodes
[
i
].
Op
==
OP_NUM
||
Nodes
[
i
].
Op
==
OP_XX
)
{
}
else
switch
(
row
->
Type
)
{
case
TYPE_JOB
:
if
(
Nodes
[
i
].
Key
)
val
=
GetKeyValue
(
MPP
(
row
->
To_Val
),
Nodes
[
i
].
Key
);
break
;
case
TYPE_JAR
:
if
(
!
Nodes
[
i
].
Key
)
if
(
Nodes
[
i
].
Op
==
OP_EQ
||
Nodes
[
i
].
Op
==
OP_LE
)
val
=
GetArrayValue
(
MVP
(
row
->
To_Val
),
Nodes
[
i
].
Rank
);
break
;
case
TYPE_JVAL
:
val
=
MVP
(
row
->
To_Val
);
break
;
default:
sprintf
(
g
->
Message
,
"Invalid row JSON type %d"
,
row
->
Type
);
}
// endswitch Type
// if (i < Nod - 1)
// if (!(row = (val) ? val->GetJsp() : NULL))
// val = NULL;
row
=
val
;
}
// endfor i
return
(
val
!=
NULL
);
}
// end of CheckPath
/***********************************************************************/
/* GetRow: Set the complete path of the object to be set. */
/***********************************************************************/
PBVAL
BJNX
::
GetRow
(
PGLOBAL
g
)
{
PBVAL
val
=
NULL
;
PBVAL
arp
;
PBVAL
nwr
,
row
=
Row
;
for
(
int
i
=
0
;
i
<
Nod
-
1
&&
row
;
i
++
)
{
if
(
Nodes
[
i
].
Op
==
OP_XX
)
break
;
else
switch
(
row
->
Type
)
{
case
TYPE_JOB
:
if
(
!
Nodes
[
i
].
Key
)
// Expected Array was not there, wrap the value
continue
;
val
=
GetKeyValue
(
MPP
(
row
->
To_Val
),
Nodes
[
i
].
Key
);
break
;
case
TYPE_JAR
:
arp
=
MVP
(
row
->
To_Val
);
if
(
!
Nodes
[
i
].
Key
)
{
if
(
Nodes
[
i
].
Op
==
OP_EQ
)
val
=
GetArrayValue
(
arp
,
Nodes
[
i
].
Rank
);
else
val
=
GetArrayValue
(
arp
,
Nodes
[
i
].
Rx
);
}
else
{
// Unexpected array, unwrap it as [0]
val
=
GetArrayValue
(
arp
,
0
);
i
--
;
}
// endif Nodes
break
;
case
TYPE_JVAL
:
val
=
MVP
(
row
->
To_Val
);
break
;
default:
sprintf
(
g
->
Message
,
"Invalid row JSON type %d"
,
row
->
Type
);
val
=
NULL
;
}
// endswitch Type
if
(
val
)
{
row
=
val
;
}
else
{
// Construct missing objects
for
(
i
++
;
row
&&
i
<
Nod
;
i
++
)
{
if
(
Nodes
[
i
].
Op
==
OP_XX
)
break
;
// else if (!Nodes[i].Key)
// Construct intermediate array
// nwr = SubAllocVal(g);
// else
// nwr = SubAllocPair(g);
// Construct new row
nwr
=
SubAllocVal
(
g
);
if
(
row
->
Type
==
TYPE_JOB
)
{
SetKeyValue
(
g
,
MPP
(
row
->
To_Val
),
MOF
(
nwr
),
Nodes
[
i
-
1
].
Key
);
}
else
if
(
row
->
Type
==
TYPE_JAR
)
{
AddArrayValue
(
g
,
MVP
(
row
->
To_Val
),
nwr
);
}
else
{
strcpy
(
g
->
Message
,
"Wrong type when writing new row"
);
nwr
=
NULL
;
}
// endif's
row
=
nwr
;
}
// endfor i
break
;
}
// endelse
}
// endfor i
return
row
;
}
// end of GetRow
/***********************************************************************/
/* WriteValue: */
/***********************************************************************/
my_bool
BJNX
::
WriteValue
(
PGLOBAL
g
,
PBVAL
jvalp
)
{
PBPR
objp
=
NULL
;
PBVAL
arp
=
NULL
;
PBVAL
jvp
=
NULL
;
PBVAL
row
=
GetRow
(
g
);
if
(
!
row
)
return
true
;
switch
(
row
->
Type
)
{
case
TYPE_JOB
:
objp
=
MPP
(
row
->
To_Val
);
break
;
case
TYPE_JAR
:
arp
=
MVP
(
row
->
To_Val
);
break
;
case
TYPE_JVAL
:
jvp
=
MVP
(
row
->
To_Val
);
break
;
default:
strcpy
(
g
->
Message
,
"Invalid target type"
);
return
true
;
}
// endswitch Type
if
(
arp
)
{
if
(
!
Nodes
[
Nod
-
1
].
Key
)
{
if
(
Nodes
[
Nod
-
1
].
Op
==
OP_EQ
)
SetArrayValue
(
g
,
arp
,
jvalp
,
Nodes
[
Nod
-
1
].
Rank
);
else
AddArrayValue
(
g
,
arp
,
jvalp
);
}
// endif Key
}
else
if
(
objp
)
{
if
(
Nodes
[
Nod
-
1
].
Key
)
SetKeyValue
(
g
,
objp
,
MOF
(
jvalp
),
Nodes
[
Nod
-
1
].
Key
);
}
else
if
(
jvp
)
SetValueVal
(
jvp
,
jvalp
);
return
false
;
}
// end of WriteValue
/*********************************************************************************/
/* Locate a value in a JSON tree: */
/*********************************************************************************/
PSZ
BJNX
::
Locate
(
PGLOBAL
g
,
PBVAL
jsp
,
PBVAL
jvp
,
int
k
)
{
PSZ
str
=
NULL
;
my_bool
b
=
false
,
err
=
true
;
g
->
Message
[
0
]
=
0
;
if
(
!
jsp
)
{
strcpy
(
g
->
Message
,
"Null json tree"
);
return
NULL
;
}
// endif jsp
try
{
// Write to the path string
Jp
=
new
(
g
)
JOUTSTR
(
g
);
Jp
->
WriteChr
(
'$'
);
Bvalp
=
jvp
;
K
=
k
;
switch
(
jsp
->
Type
)
{
case
TYPE_JAR
:
err
=
LocateArray
(
g
,
MVP
(
jsp
->
To_Val
));
break
;
case
TYPE_JOB
:
err
=
LocateObject
(
g
,
MPP
(
jsp
->
To_Val
));
break
;
case
TYPE_JVAL
:
err
=
LocateValue
(
g
,
MVP
(
jsp
->
To_Val
));
break
;
default:
err
=
true
;
}
// endswitch Type
if
(
err
)
{
if
(
!
g
->
Message
[
0
])
strcpy
(
g
->
Message
,
"Invalid json tree"
);
}
else
if
(
Found
)
{
Jp
->
WriteChr
(
'\0'
);
PlugSubAlloc
(
g
,
NULL
,
Jp
->
N
);
str
=
Jp
->
Strp
;
}
// endif's
}
catch
(
int
n
)
{
if
(
trace
(
1
))
htrc
(
"Exception %d: %s
\n
"
,
n
,
g
->
Message
);
PUSH_WARNING
(
g
->
Message
);
}
catch
(
const
char
*
msg
)
{
strcpy
(
g
->
Message
,
msg
);
}
// end catch
return
str
;
}
// end of Locate
/*********************************************************************************/
/* Locate in a JSON Array. */
/*********************************************************************************/
my_bool
BJNX
::
LocateArray
(
PGLOBAL
g
,
PBVAL
jarp
)
{
char
s
[
16
];
int
n
=
GetArraySize
(
jarp
);
size_t
m
=
Jp
->
N
;
for
(
int
i
=
0
;
i
<
n
&&
!
Found
;
i
++
)
{
Jp
->
N
=
m
;
sprintf
(
s
,
"[%d]"
,
i
+
B
);
if
(
Jp
->
WriteStr
(
s
))
return
true
;
if
(
LocateValue
(
g
,
GetArrayValue
(
jarp
,
i
)))
return
true
;
}
// endfor i
return
false
;
}
// end of LocateArray
/*********************************************************************************/
/* Locate in a JSON Object. */
/*********************************************************************************/
my_bool
BJNX
::
LocateObject
(
PGLOBAL
g
,
PBPR
jobp
)
{
size_t
m
;
if
(
Jp
->
WriteChr
(
'.'
))
return
true
;
m
=
Jp
->
N
;
for
(
PBPR
pair
=
jobp
;
pair
&&
!
Found
;
pair
=
MPP
(
pair
->
Next
))
{
Jp
->
N
=
m
;
if
(
Jp
->
WriteStr
(
MZP
(
pair
->
Key
)))
return
true
;
if
(
LocateValue
(
g
,
MVP
(
pair
->
Vlp
)))
return
true
;
}
// endfor i
return
false
;
}
// end of LocateObject
/*********************************************************************************/
/* Locate a JSON Value. */
/*********************************************************************************/
my_bool
BJNX
::
LocateValue
(
PGLOBAL
g
,
PBVAL
jvp
)
{
if
(
CompareTree
(
g
,
Bvalp
,
jvp
))
Found
=
(
--
K
==
0
);
else
if
(
jvp
->
Type
==
TYPE_JAR
)
return
LocateArray
(
g
,
GetArray
(
jvp
));
else
if
(
jvp
->
Type
==
TYPE_JOB
)
return
LocateObject
(
g
,
GetObject
(
jvp
));
return
false
;
}
// end of LocateValue
/*********************************************************************************/
/* Locate all occurrences of a value in a JSON tree: */
/*********************************************************************************/
PSZ
BJNX
::
LocateAll
(
PGLOBAL
g
,
PBVAL
jsp
,
PBVAL
bvp
,
int
mx
)
{
PSZ
str
=
NULL
;
my_bool
b
=
false
,
err
=
true
;
PJPN
jnp
;
if
(
!
jsp
)
{
strcpy
(
g
->
Message
,
"Null json tree"
);
return
NULL
;
}
// endif jsp
try
{
jnp
=
(
PJPN
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
JPN
)
*
mx
);
memset
(
jnp
,
0
,
sizeof
(
JPN
)
*
mx
);
g
->
Message
[
0
]
=
0
;
// Write to the path string
Jp
=
new
(
g
)
JOUTSTR
(
g
);
Bvalp
=
bvp
;
Imax
=
mx
-
1
;
Jpnp
=
jnp
;
Jp
->
WriteChr
(
'['
);
switch
(
jsp
->
Type
)
{
case
TYPE_JAR
:
err
=
LocateArrayAll
(
g
,
MVP
(
jsp
->
To_Val
));
break
;
case
TYPE_JOB
:
err
=
LocateObjectAll
(
g
,
MPP
(
jsp
->
To_Val
));
break
;
case
TYPE_JVAL
:
err
=
LocateValueAll
(
g
,
MVP
(
jsp
->
To_Val
));
break
;
default:
err
=
LocateValueAll
(
g
,
jsp
);
}
// endswitch Type
if
(
!
err
)
{
if
(
Jp
->
N
>
1
)
Jp
->
N
--
;
Jp
->
WriteChr
(
']'
);
Jp
->
WriteChr
(
'\0'
);
PlugSubAlloc
(
g
,
NULL
,
Jp
->
N
);
str
=
Jp
->
Strp
;
}
else
if
(
!
g
->
Message
[
0
])
strcpy
(
g
->
Message
,
"Invalid json tree"
);
}
catch
(
int
n
)
{
xtrc
(
1
,
"Exception %d: %s
\n
"
,
n
,
g
->
Message
);
PUSH_WARNING
(
g
->
Message
);
}
catch
(
const
char
*
msg
)
{
strcpy
(
g
->
Message
,
msg
);
}
// end catch
return
str
;
}
// end of LocateAll
/*********************************************************************************/
/* Locate in a JSON Array. */
/*********************************************************************************/
my_bool
BJNX
::
LocateArrayAll
(
PGLOBAL
g
,
PBVAL
jarp
)
{
int
i
=
0
;
if
(
I
<
Imax
)
{
Jpnp
[
++
I
].
Type
=
TYPE_JAR
;
for
(
PBVAL
vp
=
jarp
;
vp
;
vp
=
MVP
(
vp
->
Next
))
{
Jpnp
[
I
].
N
=
i
;
if
(
LocateValueAll
(
g
,
GetArrayValue
(
jarp
,
i
)))
return
true
;
i
++
;
}
// endfor i
I
--
;
}
// endif I
return
false
;
}
// end of LocateArrayAll
/*********************************************************************************/
/* Locate in a JSON Object. */
/*********************************************************************************/
my_bool
BJNX
::
LocateObjectAll
(
PGLOBAL
g
,
PBPR
jobp
)
{
if
(
I
<
Imax
)
{
Jpnp
[
++
I
].
Type
=
TYPE_JOB
;
for
(
PBPR
pair
=
jobp
;
pair
;
pair
=
MPP
(
pair
->
Next
))
{
Jpnp
[
I
].
Key
=
MZP
(
pair
->
Key
);
if
(
LocateValueAll
(
g
,
MVP
(
pair
->
Vlp
)))
return
true
;
}
// endfor i
I
--
;
}
// endif I
return
false
;
}
// end of LocateObjectAll
/*********************************************************************************/
/* Locate a JSON Value. */
/*********************************************************************************/
my_bool
BJNX
::
LocateValueAll
(
PGLOBAL
g
,
PBVAL
jvp
)
{
if
(
CompareTree
(
g
,
Bvalp
,
jvp
))
return
AddPath
();
else
if
(
jvp
->
Type
==
TYPE_JAR
)
return
LocateArrayAll
(
g
,
GetArray
(
jvp
));
else
if
(
jvp
->
Type
==
TYPE_JOB
)
return
LocateObjectAll
(
g
,
GetObject
(
jvp
));
return
false
;
}
// end of LocateValueAll
/*********************************************************************************/
/* Compare two JSON trees. */
/*********************************************************************************/
my_bool
BJNX
::
CompareTree
(
PGLOBAL
g
,
PBVAL
jp1
,
PBVAL
jp2
)
{
if
(
!
jp1
||
!
jp2
||
jp1
->
Type
!=
jp2
->
Type
||
GetSize
(
jp1
)
!=
GetSize
(
jp2
))
return
false
;
my_bool
found
=
true
;
if
(
jp1
->
Type
==
TYPE_JAR
)
{
for
(
int
i
=
0
;
found
&&
i
<
GetArraySize
(
jp1
);
i
++
)
found
=
(
CompareValues
(
g
,
GetArrayValue
(
jp1
,
i
),
GetArrayValue
(
jp2
,
i
)));
}
else
if
(
jp1
->
Type
==
TYPE_JOB
)
{
PBPR
p1
=
MPP
(
jp1
->
To_Val
),
p2
=
MPP
(
jp2
->
To_Val
);
// Keys can be differently ordered
for
(;
found
&&
p1
&&
p2
;
p1
=
MPP
(
p1
->
Next
))
found
=
CompareValues
(
g
,
MVP
(
p1
->
Vlp
),
GetKeyValue
(
p2
,
MZP
(
p1
->
Key
)));
}
else
if
(
jp1
->
Type
==
TYPE_JVAL
)
{
found
=
CompareTree
(
g
,
MVP
(
jp1
->
To_Val
),
(
MVP
(
jp2
->
To_Val
)));
}
else
found
=
CompareValues
(
g
,
jp1
,
jp2
);
return
found
;
}
// end of CompareTree
/*********************************************************************************/
/* Compare two VAL values and return true if they are equal. */
/*********************************************************************************/
my_bool
BJNX
::
CompareValues
(
PGLOBAL
g
,
PBVAL
v1
,
PBVAL
v2
)
{
my_bool
b
=
false
;
if
(
v1
&&
v2
)
switch
(
v1
->
Type
)
{
case
TYPE_JAR
:
if
(
v2
->
Type
==
TYPE_JAR
)
b
=
CompareTree
(
g
,
MVP
(
v1
->
To_Val
),
MVP
(
v2
->
To_Val
));
break
;
case
TYPE_STRG
:
if
(
v2
->
Type
==
TYPE_STRG
)
{
if
(
v1
->
Nd
||
v2
->
Nd
)
// Case insensitive
b
=
(
!
stricmp
(
MZP
(
v1
->
To_Val
),
MZP
(
v2
->
To_Val
)));
else
b
=
(
!
strcmp
(
MZP
(
v1
->
To_Val
),
MZP
(
v2
->
To_Val
)));
}
// endif Type
break
;
case
TYPE_DTM
:
if
(
v2
->
Type
==
TYPE_DTM
)
b
=
(
!
strcmp
(
MZP
(
v1
->
To_Val
),
MZP
(
v2
->
To_Val
)));
break
;
case
TYPE_INTG
:
if
(
v2
->
Type
==
TYPE_INTG
)
b
=
(
v1
->
N
==
v2
->
N
);
else
if
(
v2
->
Type
==
TYPE_BINT
)
b
=
((
longlong
)
v1
->
N
==
LLN
(
v2
->
To_Val
));
break
;
case
TYPE_BINT
:
if
(
v2
->
Type
==
TYPE_INTG
)
b
=
(
LLN
(
v1
->
To_Val
)
==
(
longlong
)
v2
->
N
);
else
if
(
v2
->
Type
==
TYPE_BINT
)
b
=
(
LLN
(
v1
->
To_Val
)
==
LLN
(
v2
->
To_Val
));
break
;
case
TYPE_FLOAT
:
if
(
v2
->
Type
==
TYPE_FLOAT
)
b
=
(
v1
->
F
==
v2
->
F
);
else
if
(
v2
->
Type
==
TYPE_DBL
)
b
=
((
double
)
v1
->
F
==
DBL
(
v2
->
To_Val
));
break
;
case
TYPE_DBL
:
if
(
v2
->
Type
==
TYPE_DBL
)
b
=
(
DBL
(
v1
->
To_Val
)
==
DBL
(
v2
->
To_Val
));
else
if
(
v2
->
Type
==
TYPE_FLOAT
)
b
=
(
DBL
(
v1
->
To_Val
)
==
(
double
)
v2
->
F
);
break
;
case
TYPE_BOOL
:
if
(
v2
->
Type
==
TYPE_BOOL
)
b
=
(
v1
->
B
==
v2
->
B
);
break
;
case
TYPE_NULL
:
b
=
(
v2
->
Type
==
TYPE_NULL
);
break
;
default:
break
;
}
// endswitch Type
else
b
=
(
!
v1
&&
!
v2
);
return
b
;
}
// end of CompareValues
/*********************************************************************************/
/* Add the found path to the list. */
/*********************************************************************************/
my_bool
BJNX
::
AddPath
(
void
)
{
char
s
[
16
];
if
(
Jp
->
WriteStr
(
"
\"
$"
))
return
true
;
for
(
int
i
=
0
;
i
<=
I
;
i
++
)
{
if
(
Jpnp
[
i
].
Type
==
TYPE_JAR
)
{
sprintf
(
s
,
"[%d]"
,
Jpnp
[
i
].
N
+
B
);
if
(
Jp
->
WriteStr
(
s
))
return
true
;
}
else
{
if
(
Jp
->
WriteChr
(
'.'
))
return
true
;
if
(
Jp
->
WriteStr
(
Jpnp
[
i
].
Key
))
return
true
;
}
// endif's
}
// endfor i
if
(
Jp
->
WriteStr
(
"
\"
,"
))
return
true
;
return
false
;
}
// end of AddPath
/*********************************************************************************/
/* Make a BVAL value from the passed argument. */
/*********************************************************************************/
static
PBVAL
MakeBinValue
(
PGLOBAL
g
,
UDF_ARGS
*
args
,
uint
i
)
{
char
*
sap
=
(
args
->
arg_count
>
i
)
?
args
->
args
[
i
]
:
NULL
;
int
n
,
len
;
int
ci
;
longlong
bigint
;
void
*
Base
=
g
->
Sarea
;
// Required by MOF
BDOC
doc
(
Base
);
PBVAL
bp
;
PBVAL
bvp
=
doc
.
SubAllocVal
(
g
);
if
(
sap
)
switch
(
args
->
arg_type
[
i
])
{
case
STRING_RESULT
:
if
((
len
=
args
->
lengths
[
i
]))
{
if
((
n
=
IsJson
(
args
,
i
))
<
3
)
sap
=
MakePSZ
(
g
,
args
,
i
);
if
(
n
)
{
if
(
n
==
2
)
{
if
(
!
(
sap
=
GetJsonFile
(
g
,
sap
)))
{
PUSH_WARNING
(
g
->
Message
);
return
NULL
;
}
// endif sap
len
=
strlen
(
sap
);
}
// endif 2
if
(
!
(
bp
=
doc
.
ParseJson
(
g
,
sap
,
strlen
(
sap
))))
PUSH_WARNING
(
g
->
Message
);
bvp
=
bp
;
}
else
{
// Check whether this string is a valid json string
JsonMemSave
(
g
);
if
(
!
(
bvp
=
doc
.
ParseJson
(
g
,
sap
,
strlen
(
sap
))))
{
// Recover suballocated memory
JsonSubSet
(
g
);
ci
=
(
strnicmp
(
args
->
attributes
[
i
],
"ci"
,
2
))
?
0
:
1
;
bvp
=
doc
.
SubAllocVal
(
g
,
MOF
(
sap
),
TYPE_STRG
,
ci
);
}
else
g
->
Saved_Size
=
0
;
}
// endif n
}
// endif len
break
;
case
INT_RESULT
:
bigint
=
*
(
longlong
*
)
sap
;
if
((
bigint
==
0LL
&&
!
strcmp
(
args
->
attributes
[
i
],
"FALSE"
))
||
(
bigint
==
1LL
&&
!
strcmp
(
args
->
attributes
[
i
],
"TRUE"
)))
doc
.
SetBool
(
bvp
,
(
bool
)
bigint
);
else
doc
.
SetBigint
(
g
,
bvp
,
bigint
);
break
;
case
REAL_RESULT
:
doc
.
SetFloat
(
bvp
,
*
(
double
*
)
sap
);
break
;
case
DECIMAL_RESULT
:
doc
.
SetFloat
(
bvp
,
atof
(
MakePSZ
(
g
,
args
,
i
)));
break
;
case
TIME_RESULT
:
case
ROW_RESULT
:
default:
bvp
=
NULL
;
break
;
}
// endswitch arg_type
return
bvp
;
}
// end of MakeBinValue
/*********************************************************************************/
/* Test BJSON parse and serialize. */
/*********************************************************************************/
my_bool
json_test_bson_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
,
more
=
1000
;
if
(
args
->
arg_count
==
0
)
{
strcpy
(
message
,
"At least 1 argument required (json)"
);
return
true
;
}
else
if
(
!
IsJson
(
args
,
0
)
&&
args
->
arg_type
[
0
]
!=
STRING_RESULT
)
{
strcpy
(
message
,
"First argument must be a json item"
);
return
true
;
}
else
CalcLen
(
args
,
false
,
reslen
,
memlen
);
return
JsonInit
(
initid
,
args
,
message
,
true
,
reslen
,
memlen
,
more
);
}
// end of json_test_bson_init
char
*
json_test_bson
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
str
=
NULL
,
*
sap
=
NULL
,
*
fn
=
NULL
;
int
pretty
=
1
;
PBVAL
bvp
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
BDOC
doc
(
g
);
if
(
g
->
N
)
{
str
=
(
char
*
)
g
->
Activityp
;
goto
err
;
}
else
if
(
initid
->
const_item
)
g
->
N
=
1
;
try
{
if
(
!
g
->
Xchk
)
{
if
(
CheckMemory
(
g
,
initid
,
args
,
1
,
!
g
->
Xchk
))
{
PUSH_WARNING
(
"CheckMemory error"
);
*
error
=
1
;
goto
err
;
}
else
if
(
!
(
bvp
=
MakeBinValue
(
g
,
args
,
0
)))
{
PUSH_WARNING
(
g
->
Message
);
goto
err
;
}
// endif bvp
if
(
g
->
Mrr
)
{
// First argument is a constant
g
->
Xchk
=
bvp
;
JsonMemSave
(
g
);
}
// endif Mrr
}
else
bvp
=
(
PBVAL
)
g
->
Xchk
;
for
(
uint
i
=
1
;
i
<
args
->
arg_count
;
i
++
)
if
(
args
->
arg_type
[
i
]
==
STRING_RESULT
)
fn
=
args
->
args
[
i
];
else
if
(
args
->
arg_type
[
i
]
==
INT_RESULT
)
pretty
=
(
int
)
*
(
longlong
*
)
args
->
args
[
i
];
// Serialize the parse tree
str
=
doc
.
Serialize
(
g
,
bvp
,
fn
,
pretty
);
if
(
initid
->
const_item
)
// Keep result of constant function
g
->
Activityp
=
(
PACTIVITY
)
str
;
}
catch
(
int
n
)
{
xtrc
(
1
,
"json_test_bson: error %d: %s
\n
"
,
n
,
g
->
Message
);
PUSH_WARNING
(
g
->
Message
);
*
error
=
1
;
str
=
NULL
;
}
catch
(
const
char
*
msg
)
{
strcpy
(
g
->
Message
,
msg
);
PUSH_WARNING
(
g
->
Message
);
*
error
=
1
;
str
=
NULL
;
}
// end catch
err:
if
(
!
str
)
{
*
res_length
=
0
;
*
is_null
=
1
;
}
else
*
res_length
=
strlen
(
str
);
return
str
;
}
// end of json_test_bson
void
json_test_bson_deinit
(
UDF_INIT
*
initid
)
{
JsonFreeMem
((
PGLOBAL
)
initid
->
ptr
);
}
// end of json_test_bson_deinit
/*********************************************************************************/
/* Locate a value in a Json tree. */
/*********************************************************************************/
my_bool
jsonlocate_bson_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
,
more
=
1000
;
if
(
args
->
arg_count
<
2
)
{
strcpy
(
message
,
"At least 2 arguments required"
);
return
true
;
}
else
if
(
!
IsJson
(
args
,
0
)
&&
args
->
arg_type
[
0
]
!=
STRING_RESULT
)
{
strcpy
(
message
,
"First argument must be a json item"
);
return
true
;
}
else
if
(
args
->
arg_count
>
2
&&
args
->
arg_type
[
2
]
!=
INT_RESULT
)
{
strcpy
(
message
,
"Third argument is not an integer (rank)"
);
return
true
;
}
// endifs args
CalcLen
(
args
,
false
,
reslen
,
memlen
);
// TODO: calculate this
if
(
IsJson
(
args
,
0
)
==
3
)
more
=
0
;
return
JsonInit
(
initid
,
args
,
message
,
true
,
reslen
,
memlen
,
more
);
}
// end of jsonlocate_bson_init
char
*
jsonlocate_bson
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
path
=
NULL
;
int
k
;
PBVAL
bvp
,
bvp2
;
PBJNX
bnxp
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
if
(
g
->
N
)
{
if
(
g
->
Activityp
)
{
path
=
(
char
*
)
g
->
Activityp
;
*
res_length
=
strlen
(
path
);
return
path
;
}
else
{
*
res_length
=
0
;
*
is_null
=
1
;
return
NULL
;
}
// endif Activityp
}
else
if
(
initid
->
const_item
)
g
->
N
=
1
;
try
{
if
(
!
g
->
Xchk
)
{
if
(
CheckMemory
(
g
,
initid
,
args
,
1
,
!
g
->
Xchk
))
{
PUSH_WARNING
(
"CheckMemory error"
);
*
error
=
1
;
goto
err
;
}
else
bvp
=
MakeBinValue
(
g
,
args
,
0
);
if
(
!
bvp
)
{
PUSH_WARNING
(
"First argument is not a valid JSON item"
);
goto
err
;
}
// endif bvp
if
(
g
->
Mrr
)
{
// First argument is a constant
g
->
Xchk
=
bvp
;
JsonMemSave
(
g
);
}
// endif Mrr
}
else
bvp
=
(
PBVAL
)
g
->
Xchk
;
// The item to locate
bvp2
=
MakeBinValue
(
g
,
args
,
1
);
k
=
(
args
->
arg_count
>
2
)
?
(
int
)
*
(
long
long
*
)
args
->
args
[
2
]
:
1
;
bnxp
=
new
(
g
)
BJNX
(
g
,
bvp
,
TYPE_STRING
);
path
=
bnxp
->
Locate
(
g
,
bvp
,
bvp2
,
k
);
if
(
initid
->
const_item
)
// Keep result of constant function
g
->
Activityp
=
(
PACTIVITY
)
path
;
}
catch
(
int
n
)
{
xtrc
(
1
,
"Exception %d: %s
\n
"
,
n
,
g
->
Message
);
PUSH_WARNING
(
g
->
Message
);
*
error
=
1
;
path
=
NULL
;
}
catch
(
const
char
*
msg
)
{
strcpy
(
g
->
Message
,
msg
);
PUSH_WARNING
(
g
->
Message
);
*
error
=
1
;
path
=
NULL
;
}
// end catch
err:
if
(
!
path
)
{
*
res_length
=
0
;
*
is_null
=
1
;
}
else
*
res_length
=
strlen
(
path
);
return
path
;
}
// end of jsonlocate_bson
void
jsonlocate_bson_deinit
(
UDF_INIT
*
initid
)
{
JsonFreeMem
((
PGLOBAL
)
initid
->
ptr
);
}
// end of jsonlocate_bson_deinit
/*********************************************************************************/
/* Locate all occurences of a value in a Json tree. */
/*********************************************************************************/
my_bool
json_locate_all_bson_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
,
more
=
1000
;
if
(
args
->
arg_count
<
2
)
{
strcpy
(
message
,
"At least 2 arguments required"
);
return
true
;
}
else
if
(
!
IsJson
(
args
,
0
)
&&
args
->
arg_type
[
0
]
!=
STRING_RESULT
)
{
strcpy
(
message
,
"First argument must be a json item"
);
return
true
;
}
else
if
(
args
->
arg_count
>
2
&&
args
->
arg_type
[
2
]
!=
INT_RESULT
)
{
strcpy
(
message
,
"Third argument is not an integer (Depth)"
);
return
true
;
}
// endifs
CalcLen
(
args
,
false
,
reslen
,
memlen
);
// TODO: calculate this
if
(
IsJson
(
args
,
0
)
==
3
)
more
=
0
;
return
JsonInit
(
initid
,
args
,
message
,
true
,
reslen
,
memlen
,
more
);
}
// end of json_locate_all_bson_init
char
*
json_locate_all_bson
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
path
=
NULL
;
int
mx
=
10
;
PBVAL
bvp
,
bvp2
;
PBJNX
bnxp
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
if
(
g
->
N
)
{
if
(
g
->
Activityp
)
{
path
=
(
char
*
)
g
->
Activityp
;
*
res_length
=
strlen
(
path
);
return
path
;
}
else
{
*
error
=
1
;
*
res_length
=
0
;
*
is_null
=
1
;
return
NULL
;
}
// endif Activityp
}
else
if
(
initid
->
const_item
)
g
->
N
=
1
;
try
{
if
(
!
g
->
Xchk
)
{
if
(
CheckMemory
(
g
,
initid
,
args
,
1
,
true
))
{
PUSH_WARNING
(
"CheckMemory error"
);
*
error
=
1
;
goto
err
;
}
else
bvp
=
MakeBinValue
(
g
,
args
,
0
);
if
(
!
bvp
)
{
PUSH_WARNING
(
"First argument is not a valid JSON item"
);
goto
err
;
}
// endif bvp
if
(
g
->
Mrr
)
{
// First argument is a constant
g
->
Xchk
=
bvp
;
JsonMemSave
(
g
);
}
// endif Mrr
}
else
bvp
=
(
PBVAL
)
g
->
Xchk
;
// The item to locate
bvp2
=
MakeBinValue
(
g
,
args
,
1
);
if
(
args
->
arg_count
>
2
)
mx
=
(
int
)
*
(
long
long
*
)
args
->
args
[
2
];
bnxp
=
new
(
g
)
BJNX
(
g
,
bvp
,
TYPE_STRING
);
path
=
bnxp
->
LocateAll
(
g
,
bvp
,
bvp2
,
mx
);
if
(
initid
->
const_item
)
// Keep result of constant function
g
->
Activityp
=
(
PACTIVITY
)
path
;
}
catch
(
int
n
)
{
xtrc
(
1
,
"Exception %d: %s
\n
"
,
n
,
g
->
Message
);
PUSH_WARNING
(
g
->
Message
);
*
error
=
1
;
path
=
NULL
;
}
catch
(
const
char
*
msg
)
{
strcpy
(
g
->
Message
,
msg
);
PUSH_WARNING
(
g
->
Message
);
*
error
=
1
;
path
=
NULL
;
}
// end catch
err:
if
(
!
path
)
{
*
res_length
=
0
;
*
is_null
=
1
;
}
else
*
res_length
=
strlen
(
path
);
return
path
;
}
// end of json_locate_all_bson
void
json_locate_all_bson_deinit
(
UDF_INIT
*
initid
)
{
JsonFreeMem
((
PGLOBAL
)
initid
->
ptr
);
}
// end of json_locate_all_bson_deinit
storage/connect/jsonudf.h
View file @
dc8f914c
/******************** tabjson H Declares Source Code File (.H) *******************/
/* Name: jsonudf.h Version 1.
3
*/
/* Name: jsonudf.h Version 1.
4
*/
/* */
/* (C) Copyright to the author Olivier BERTRAND 2015-20
17
*/
/* (C) Copyright to the author Olivier BERTRAND 2015-20
20
*/
/* */
/* This file contains the JSON UDF function and class declares. */
/*********************************************************************************/
...
...
@@ -15,6 +15,27 @@
#define UDF_EXEC_ARGS \
UDF_INIT*, UDF_ARGS*, char*, unsigned long*, char*, char*
// BSON size should be equal on Linux and Windows
#define BMX 255
typedef
struct
BSON
*
PBSON
;
/***********************************************************************/
/* Structure used to return binary json to Json UDF functions. */
/***********************************************************************/
struct
BSON
{
char
Msg
[
BMX
+
1
];
char
*
Filename
;
PGLOBAL
G
;
int
Pretty
;
ulong
Reslen
;
my_bool
Changed
;
PJSON
Top
;
PJSON
Jsp
;
PBSON
Bsp
;
};
// end of struct BSON
PBSON
JbinAlloc
(
PGLOBAL
g
,
UDF_ARGS
*
args
,
ulong
len
,
PJSON
jsp
);
/*********************************************************************************/
/* The JSON tree node. Can be an Object or an Array. */
/*********************************************************************************/
...
...
@@ -29,8 +50,6 @@ typedef struct _jnode {
}
JNODE
,
*
PJNODE
;
typedef
class
JSNX
*
PJSNX
;
typedef
class
JOUTPATH
*
PJTP
;
typedef
class
JOUTALL
*
PJTA
;
extern
"C"
{
DllExport
my_bool
jsonvalue_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
...
...
@@ -368,3 +387,90 @@ class JUP : public BLOCK {
int
k
,
recl
;
};
// end of class JUP
/* --------------------------- New Testing BJSON Stuff --------------------------*/
typedef
class
BJNX
*
PBJNX
;
/*********************************************************************************/
/* Class BJNX: BJSON access methods. */
/*********************************************************************************/
class
BJNX
:
public
BDOC
{
public:
// Constructors
BJNX
(
PGLOBAL
g
,
PBVAL
row
,
int
type
,
int
len
=
64
,
int
prec
=
0
,
my_bool
wr
=
false
);
// Implementation
int
GetPrecision
(
void
)
{
return
Prec
;
}
PVAL
GetValue
(
void
)
{
return
Value
;
}
// Methods
my_bool
SetJpath
(
PGLOBAL
g
,
char
*
path
,
my_bool
jb
=
false
);
my_bool
ParseJpath
(
PGLOBAL
g
);
void
ReadValue
(
PGLOBAL
g
);
PBVAL
GetRowValue
(
PGLOBAL
g
,
PBVAL
row
,
int
i
,
my_bool
b
=
true
);
PBVAL
GetJson
(
PGLOBAL
g
);
my_bool
CheckPath
(
PGLOBAL
g
);
my_bool
WriteValue
(
PGLOBAL
g
,
PBVAL
jvalp
);
char
*
Locate
(
PGLOBAL
g
,
PBVAL
jsp
,
PBVAL
jvp
,
int
k
=
1
);
char
*
LocateAll
(
PGLOBAL
g
,
PBVAL
jsp
,
PBVAL
jvp
,
int
mx
=
10
);
protected:
my_bool
SetArrayOptions
(
PGLOBAL
g
,
char
*
p
,
int
i
,
PSZ
nm
);
PVAL
GetColumnValue
(
PGLOBAL
g
,
PBVAL
row
,
int
i
);
PVAL
ExpandArray
(
PGLOBAL
g
,
PBVAL
arp
,
int
n
);
PVAL
CalculateArray
(
PGLOBAL
g
,
PBVAL
arp
,
int
n
);
PVAL
MakeJson
(
PGLOBAL
g
,
PBVAL
bvp
);
void
SetJsonValue
(
PGLOBAL
g
,
PVAL
vp
,
PBVAL
vlp
);
PBVAL
GetRow
(
PGLOBAL
g
);
my_bool
CompareValues
(
PGLOBAL
g
,
PBVAL
v1
,
PBVAL
v2
);
my_bool
LocateArray
(
PGLOBAL
g
,
PBVAL
jarp
);
my_bool
LocateObject
(
PGLOBAL
g
,
PBPR
jobp
);
my_bool
LocateValue
(
PGLOBAL
g
,
PBVAL
jvp
);
my_bool
LocateArrayAll
(
PGLOBAL
g
,
PBVAL
jarp
);
my_bool
LocateObjectAll
(
PGLOBAL
g
,
PBPR
jobp
);
my_bool
LocateValueAll
(
PGLOBAL
g
,
PBVAL
jvp
);
my_bool
CompareTree
(
PGLOBAL
g
,
PBVAL
jp1
,
PBVAL
jp2
);
my_bool
AddPath
(
void
);
// Default constructor not to be used
BJNX
(
void
)
{}
// Members
PBVAL
Row
;
PBVAL
Bvalp
;
PJPN
Jpnp
;
JOUTSTR
*
Jp
;
JNODE
*
Nodes
;
// The intermediate objects
PVAL
Value
;
PVAL
MulVal
;
// To value used by multiple column
char
*
Jpath
;
// The json path
int
Buf_Type
;
int
Long
;
int
Prec
;
int
Nod
;
// The number of intermediate objects
int
Xnod
;
// Index of multiple values
int
K
;
// Kth item to locate
int
I
;
// Index of JPN
int
Imax
;
// Max number of JPN's
int
B
;
// Index base
my_bool
Xpd
;
// True for expandable column
my_bool
Parsed
;
// True when parsed
my_bool
Found
;
// Item found by locate
my_bool
Wr
;
// Write mode
my_bool
Jb
;
// Must return json item
};
// end of class BJNX
extern
"C"
{
DllExport
my_bool
json_test_bson_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
char
*
json_test_bson
(
UDF_EXEC_ARGS
);
DllExport
void
json_test_bson_deinit
(
UDF_INIT
*
);
DllExport
my_bool
jsonlocate_bson_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
char
*
jsonlocate_bson
(
UDF_EXEC_ARGS
);
DllExport
void
jsonlocate_bson_deinit
(
UDF_INIT
*
);
DllExport
my_bool
json_locate_all_bson_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
char
*
json_locate_all_bson
(
UDF_EXEC_ARGS
);
DllExport
void
json_locate_all_bson_deinit
(
UDF_INIT
*
);
}
// extern "C"
storage/connect/tabjson.cpp
View file @
dc8f914c
...
...
@@ -1596,6 +1596,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
if
(
Value
->
IsTypeNum
())
{
strcpy
(
g
->
Message
,
"Cannot make Json for a numeric column"
);
Value
->
Reset
();
#if 0
} else if (Value->GetType() == TYPE_BIN) {
if ((unsigned)Value->GetClen() >= sizeof(BSON)) {
ulong len = Tjp->Lrecl ? Tjp->Lrecl : 500;
...
...
@@ -1607,6 +1608,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
strcpy(g->Message, "Column size too small");
Value->SetValue_char(NULL, 0);
} // endif Clen
#endif 0
}
else
Value
->
SetValue_psz
(
Serialize
(
g
,
jsp
,
NULL
,
0
));
...
...
storage/connect/value.cpp
View file @
dc8f914c
...
...
@@ -197,7 +197,7 @@ const char *GetFormatType(int type)
case
TYPE_DOUBLE
:
c
=
"F"
;
break
;
case
TYPE_DATE
:
c
=
"D"
;
break
;
case
TYPE_TINY
:
c
=
"T"
;
break
;
case
TYPE_DECIM
:
c
=
"
M
"
;
break
;
case
TYPE_DECIM
:
c
=
"
F
"
;
break
;
case
TYPE_BIN
:
c
=
"B"
;
break
;
case
TYPE_PCHAR
:
c
=
"P"
;
break
;
}
// endswitch type
...
...
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