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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
56114a41
Commit
56114a41
authored
Feb 19, 2015
by
Sergei Golubchik
Browse files
Options
Browse Files
Download
Plain Diff
merge 10.0-connect
parents
174bccd3
d9175f38
Changes
34
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
2431 additions
and
1490 deletions
+2431
-1490
storage/connect/CMakeLists.txt
storage/connect/CMakeLists.txt
+3
-8
storage/connect/array.h
storage/connect/array.h
+1
-0
storage/connect/checklvl.h
storage/connect/checklvl.h
+7
-0
storage/connect/connect.cc
storage/connect/connect.cc
+4
-1
storage/connect/ha_connect.cc
storage/connect/ha_connect.cc
+172
-81
storage/connect/json.cpp
storage/connect/json.cpp
+1106
-1055
storage/connect/json.h
storage/connect/json.h
+14
-1
storage/connect/jsonudf.cpp
storage/connect/jsonudf.cpp
+494
-0
storage/connect/myconn.cpp
storage/connect/myconn.cpp
+3
-2
storage/connect/mysql-test/connect/r/json.result
storage/connect/mysql-test/connect/r/json.result
+32
-8
storage/connect/mysql-test/connect/t/json.test
storage/connect/mysql-test/connect/t/json.test
+2
-2
storage/connect/myutil.cpp
storage/connect/myutil.cpp
+12
-10
storage/connect/odbccat.h
storage/connect/odbccat.h
+11
-3
storage/connect/odbconn.cpp
storage/connect/odbconn.cpp
+51
-24
storage/connect/odbconn.h
storage/connect/odbconn.h
+11
-5
storage/connect/tabdos.h
storage/connect/tabdos.h
+1
-0
storage/connect/tabjson.cpp
storage/connect/tabjson.cpp
+330
-214
storage/connect/tabjson.h
storage/connect/tabjson.h
+13
-11
storage/connect/tabmysql.cpp
storage/connect/tabmysql.cpp
+6
-9
storage/connect/taboccur.cpp
storage/connect/taboccur.cpp
+1
-1
storage/connect/tabodbc.cpp
storage/connect/tabodbc.cpp
+64
-36
storage/connect/tabodbc.h
storage/connect/tabodbc.h
+8
-2
storage/connect/tabpivot.cpp
storage/connect/tabpivot.cpp
+3
-3
storage/connect/tabpivot.h
storage/connect/tabpivot.h
+2
-1
storage/connect/tabtbl.cpp
storage/connect/tabtbl.cpp
+8
-6
storage/connect/tabutil.cpp
storage/connect/tabutil.cpp
+22
-1
storage/connect/tabutil.h
storage/connect/tabutil.h
+8
-1
storage/connect/tabxcl.cpp
storage/connect/tabxcl.cpp
+1
-1
storage/connect/tabxcl.h
storage/connect/tabxcl.h
+1
-0
storage/connect/valblk.h
storage/connect/valblk.h
+6
-0
storage/connect/value.cpp
storage/connect/value.cpp
+7
-4
storage/connect/xindex.h
storage/connect/xindex.h
+1
-0
storage/connect/xobject.cpp
storage/connect/xobject.cpp
+25
-0
storage/connect/xobject.h
storage/connect/xobject.h
+1
-0
No files found.
storage/connect/CMakeLists.txt
View file @
56114a41
...
...
@@ -21,9 +21,9 @@ ha_connect.cc connect.cc user_connect.cc mycat.cc
fmdlex.c osutil.c plugutil.c rcmsg.c rcmsg.h
array.cpp blkfil.cpp colblk.cpp csort.cpp
filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp filamzip.cpp
filter.cpp json.cpp
maputil.cpp myutil.cpp plgdbutl.cpp reldef.cpp tabcol
.cpp
tab
dos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul.cpp taboccur
.cpp
tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvct.cpp tabvir.cpp
filter.cpp json.cpp
jsonudf.cpp maputil.cpp myutil.cpp plgdbutl.cpp reldef
.cpp
tab
col.cpp tabdos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul
.cpp
tab
occur.cpp tab
pivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvct.cpp tabvir.cpp
tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp
array.h blkfil.h block.h catalog.h checklvl.h colblk.h connect.h csort.h
...
...
@@ -72,11 +72,6 @@ IF(UNIX)
message
(
STATUS
"CONNECT: GCC: Some warnings disabled"
)
endif
(
WITH_WARNINGS
)
# Avoid compilation failure in maintainer mode
IF
(
CMAKE_COMPILER_IS_GNUCXX
)
SET
(
CMAKE_CXX_FLAGS
"
${
CMAKE_CXX_FLAGS
}
-Wno-overloaded-virtual -Wno-error=type-limits"
)
ENDIF
(
CMAKE_COMPILER_IS_GNUCXX
)
add_definitions
(
-DUNIX -DLINUX -DUBUNTU
)
SET
(
CMAKE_CXX_FLAGS
"
${
CMAKE_CXX_FLAGS
}
-fpermissive -fexceptions -fPIC "
)
...
...
storage/connect/array.h
View file @
56114a41
...
...
@@ -50,6 +50,7 @@ class DllExport ARRAY : public XOBJECT, public CSORT { // Array descblock
// void SetCorrel(bool b) {Correlated = b;}
// Methods
using
XOBJECT
::
GetIntValue
;
virtual
void
Reset
(
void
)
{
Bot
=
-
1
;}
virtual
int
Qcompare
(
int
*
,
int
*
);
virtual
bool
Compare
(
PXOB
)
{
assert
(
FALSE
);
return
FALSE
;}
...
...
storage/connect/checklvl.h
View file @
56114a41
...
...
@@ -40,4 +40,11 @@ enum USETEMP {TMP_NO = 0, /* Never */
TMP_FORCE
=
3
,
/* Forced for MAP tables */
TMP_TEST
=
4
};
/* Testing value */
/***********************************************************************/
/* Following definitions indicate conversion of TEXT columns. */
/***********************************************************************/
enum
TYPCONV
{
TPC_NO
=
0
,
/* Never */
TPC_YES
=
1
,
/* Always */
TPC_SKIP
=
2
};
/* Skip TEXT columns */
#endif // _CHKLVL_DEFINED_
storage/connect/connect.cc
View file @
56114a41
...
...
@@ -469,9 +469,12 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
}
while
(
rc
==
RC_NF
);
if
(
rc
==
RC_OK
)
rc
=
EvalColumns
(
g
,
tdbp
,
false
);
err:
g
->
jump_level
--
;
return
(
rc
!=
RC_OK
)
?
rc
:
EvalColumns
(
g
,
tdbp
,
false
)
;
return
rc
;
}
// end of CntReadNext
/***********************************************************************/
...
...
storage/connect/ha_connect.cc
View file @
56114a41
...
...
@@ -170,18 +170,18 @@
#define SZWMIN 4194304 // Minimum work area size 4M
extern
"C"
{
char
version
[]
=
"Version 1.03.0006 January 13, 2015"
;
char
compver
[]
=
"Version 1.03.0006 "
__DATE__
" "
__TIME__
;
char
version
[]
=
"Version 1.03.0006 February 06, 2015"
;
#if defined(WIN32)
char
compver
[]
=
"Version 1.03.0006 "
__DATE__
" "
__TIME__
;
char
slash
=
'\\'
;
#else // !WIN32
char
slash
=
'/'
;
#endif // !WIN32
// int trace= 0; // The general trace value
ulong
xconv
=
0
;
// The type conversion option
int
zconv
=
0
;
// The text conversion size
//
ulong xconv= 0; // The type conversion option
//
int zconv= 0; // The text conversion size
}
// extern "C"
#if defined(XMAP)
...
...
@@ -215,6 +215,8 @@ bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
const
char
*
db
,
char
*
tab
,
const
char
*
src
,
int
port
);
bool
ExactInfo
(
void
);
USETEMP
UseTemp
(
void
);
int
GetConvSize
(
void
);
TYPCONV
GetTypeConv
(
void
);
uint
GetWorkSize
(
void
);
void
SetWorkSize
(
uint
);
extern
"C"
const
char
*
msglang
(
void
);
...
...
@@ -289,6 +291,38 @@ static MYSQL_THDVAR_UINT(work_size,
"Size of the CONNECT work area."
,
NULL
,
NULL
,
SZWORK
,
SZWMIN
,
UINT_MAX
,
1
);
// Size used when converting TEXT columns to VARCHAR
static
MYSQL_THDVAR_INT
(
conv_size
,
PLUGIN_VAR_RQCMDARG
,
// opt
"Size used when converting TEXT columns."
,
NULL
,
NULL
,
SZCONV
,
0
,
65500
,
1
);
/**
Type conversion:
no: Unsupported types -> TYPE_ERROR
yes: TEXT -> VARCHAR
skip: skip unsupported type columns in Discovery
*/
const
char
*
xconv_names
[]
=
{
"NO"
,
"YES"
,
"SKIP"
,
NullS
};
TYPELIB
xconv_typelib
=
{
array_elements
(
xconv_names
)
-
1
,
"xconv_typelib"
,
xconv_names
,
NULL
};
static
MYSQL_THDVAR_ENUM
(
type_conv
,
// name
PLUGIN_VAR_RQCMDARG
,
// opt
"Unsupported types conversion."
,
// comment
NULL
,
// check
NULL
,
// update function
0
,
// def (no)
&
xconv_typelib
);
// typelib
#if defined(XMSG) || defined(NEWMSG)
const
char
*
language_names
[]
=
{
...
...
@@ -317,6 +351,8 @@ static MYSQL_THDVAR_ENUM(
extern
"C"
int
GetTraceValue
(
void
)
{
return
THDVAR
(
current_thd
,
xtrace
);}
bool
ExactInfo
(
void
)
{
return
THDVAR
(
current_thd
,
exact_info
);}
USETEMP
UseTemp
(
void
)
{
return
(
USETEMP
)
THDVAR
(
current_thd
,
use_tempfile
);}
int
GetConvSize
(
void
)
{
return
THDVAR
(
current_thd
,
conv_size
);}
TYPCONV
GetTypeConv
(
void
)
{
return
(
TYPCONV
)
THDVAR
(
current_thd
,
type_conv
);}
uint
GetWorkSize
(
void
)
{
return
THDVAR
(
current_thd
,
work_size
);}
void
SetWorkSize
(
uint
n
)
{
...
...
@@ -598,7 +634,11 @@ static int connect_init_func(void *p)
}
#endif // 0 (LINUX)
#if defined(WIN32)
sql_print_information
(
"CONNECT: %s"
,
compver
);
#else // !WIN32
sql_print_information
(
"CONNECT: %s"
,
version
);
#endif // !WIN32
#ifdef LIBXML2_SUPPORT
XmlInitParserLib
();
...
...
@@ -934,6 +974,9 @@ ulonglong ha_connect::table_flags() const
char
*
GetListOption
(
PGLOBAL
g
,
const
char
*
opname
,
const
char
*
oplist
,
const
char
*
def
)
{
if
(
!
oplist
)
return
(
char
*
)
def
;
char
key
[
16
],
val
[
256
];
char
*
pk
,
*
pv
,
*
pn
;
char
*
opval
=
(
char
*
)
def
;
...
...
@@ -997,8 +1040,12 @@ char *ha_connect::GetRealString(const char *s)
char
*
sv
;
if
(
IsPartitioned
()
&&
s
)
{
sv
=
(
char
*
)
PlugSubAlloc
(
xp
->
g
,
NULL
,
strlen
(
s
)
+
strlen
(
partname
));
// sv= (char*)PlugSubAlloc(xp->g, NULL, strlen(s) + strlen(partname));
// With wrong string pattern, the size of the constructed string
// can be more than strlen(s) + strlen(partname)
sv
=
(
char
*
)
PlugSubAlloc
(
xp
->
g
,
NULL
,
0
);
sprintf
(
sv
,
s
,
partname
);
PlugSubAlloc
(
xp
->
g
,
NULL
,
strlen
(
sv
)
+
1
);
}
else
sv
=
(
char
*
)
s
;
...
...
@@ -1064,9 +1111,16 @@ char *ha_connect::GetStringOption(char *opname, char *sdef)
}
// endif Table_charset
if
(
!
opval
&&
options
&&
options
->
oplist
)
if
(
!
opval
&&
options
&&
options
->
oplist
)
{
opval
=
GetListOption
(
xp
->
g
,
opname
,
options
->
oplist
);
if
(
opval
&&
(
!
stricmp
(
opname
,
"connect"
)
||
!
stricmp
(
opname
,
"tabname"
)
||
!
stricmp
(
opname
,
"filename"
)))
opval
=
GetRealString
(
opval
);
}
// endif opval
if
(
!
opval
)
{
if
(
sdef
&&
!
strcmp
(
sdef
,
"*"
))
{
// Return the handler default value
...
...
@@ -2467,6 +2521,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
char
*
body
=
filp
->
Body
;
unsigned
int
i
;
bool
ismul
=
false
,
x
=
(
tty
==
TYPE_AM_MYX
||
tty
==
TYPE_AM_XDBC
);
bool
nonul
=
(
tty
==
TYPE_AM_ODBC
&&
(
tdbp
->
GetMode
()
==
MODE_INSERT
||
tdbp
->
GetMode
()
==
MODE_DELETE
));
OPVAL
vop
=
OP_XX
;
if
(
!
cond
)
...
...
@@ -2484,7 +2540,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
if
(
trace
)
htrc
(
"Cond: Ftype=%d name=%s
\n
"
,
cond_item
->
functype
(),
cond_item
->
func_name
());
cond_item
->
func_name
());
switch
(
cond_item
->
functype
())
{
case
Item_func
:
:
COND_AND_FUNC
:
vop
=
OP_AND
;
break
;
...
...
@@ -2503,7 +2559,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
for
(
i
=
0
;
i
<
arglist
->
elements
;
i
++
)
if
((
subitem
=
li
++
))
{
if
(
!
CheckCond
(
g
,
filp
,
tty
,
subitem
))
{
if
(
vop
==
OP_OR
)
if
(
vop
==
OP_OR
||
nonul
)
return
NULL
;
else
*
p2
=
0
;
...
...
@@ -2599,6 +2655,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
if
(
trace
)
{
htrc
(
"Field index=%d
\n
"
,
pField
->
field
->
field_index
);
htrc
(
"Field name=%s
\n
"
,
pField
->
field
->
field_name
);
htrc
(
"Field type=%d
\n
"
,
pField
->
field
->
type
());
htrc
(
"Field_type=%d
\n
"
,
args
[
i
]
->
field_type
());
}
// endif trace
// IN and BETWEEN clauses should be col VOP list
...
...
@@ -2618,8 +2676,9 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
char
buff
[
256
];
String
*
res
,
tmp
(
buff
,
sizeof
(
buff
),
&
my_charset_bin
);
Item_basic_constant
*
pval
=
(
Item_basic_constant
*
)
args
[
i
];
Item
::
Type
type
=
args
[
i
]
->
real_type
();
switch
(
args
[
i
]
->
real_type
()
)
{
switch
(
type
)
{
case
COND
:
:
STRING_ITEM
:
case
COND
:
:
INT_ITEM
:
case
COND
:
:
REAL_ITEM
:
...
...
@@ -2644,10 +2703,64 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
if
(
!
x
)
{
// Append the value to the filter
if
(
args
[
i
]
->
field_type
()
==
MYSQL_TYPE_VARCHAR
)
strcat
(
strncat
(
strcat
(
body
,
"'"
),
res
->
ptr
(),
res
->
length
()),
"'"
);
else
strncat
(
body
,
res
->
ptr
(),
res
->
length
());
switch
(
args
[
i
]
->
field_type
())
{
case
MYSQL_TYPE_TIMESTAMP
:
case
MYSQL_TYPE_DATETIME
:
if
(
tty
==
TYPE_AM_ODBC
)
{
strcat
(
body
,
"{ts '"
);
strcat
(
strncat
(
body
,
res
->
ptr
(),
res
->
length
()),
"'}"
);
break
;
}
// endif ODBC
case
MYSQL_TYPE_DATE
:
if
(
tty
==
TYPE_AM_ODBC
)
{
strcat
(
body
,
"{d '"
);
strcat
(
strncat
(
body
,
res
->
ptr
(),
res
->
length
()),
"'}"
);
break
;
}
// endif ODBC
case
MYSQL_TYPE_TIME
:
if
(
tty
==
TYPE_AM_ODBC
)
{
strcat
(
body
,
"{t '"
);
strcat
(
strncat
(
body
,
res
->
ptr
(),
res
->
length
()),
"'}"
);
break
;
}
// endif ODBC
case
MYSQL_TYPE_VARCHAR
:
if
(
tty
==
TYPE_AM_ODBC
&&
i
)
{
switch
(
args
[
0
]
->
field_type
())
{
case
MYSQL_TYPE_TIMESTAMP
:
case
MYSQL_TYPE_DATETIME
:
strcat
(
body
,
"{ts '"
);
strncat
(
body
,
res
->
ptr
(),
res
->
length
());
strcat
(
body
,
"'}"
);
break
;
case
MYSQL_TYPE_DATE
:
strcat
(
body
,
"{d '"
);
strncat
(
body
,
res
->
ptr
(),
res
->
length
());
strcat
(
body
,
"'}"
);
break
;
case
MYSQL_TYPE_TIME
:
strcat
(
body
,
"{t '"
);
strncat
(
body
,
res
->
ptr
(),
res
->
length
());
strcat
(
body
,
"'}"
);
break
;
default:
strcat
(
body
,
"'"
);
strncat
(
body
,
res
->
ptr
(),
res
->
length
());
strcat
(
body
,
"'"
);
}
// endswitch field type
}
else
{
strcat
(
body
,
"'"
);
strncat
(
body
,
res
->
ptr
(),
res
->
length
());
strcat
(
body
,
"'"
);
}
// endif tty
break
;
default:
strncat
(
body
,
res
->
ptr
(),
res
->
length
());
}
// endswitch field type
}
else
{
if
(
args
[
i
]
->
field_type
()
==
MYSQL_TYPE_VARCHAR
)
{
...
...
@@ -2753,7 +2866,7 @@ const COND *ha_connect::cond_push(const COND *cond)
}
else
if
(
x
&&
cond
)
tdbp
->
SetCondFil
(
filp
);
// Wrong filter
}
else
}
else
if
(
tty
!=
TYPE_AM_JSN
&&
tty
!=
TYPE_AM_JSON
)
tdbp
->
SetFilter
(
CondFilter
(
g
,
(
Item
*
)
cond
));
fin:
...
...
@@ -4620,7 +4733,7 @@ static bool add_field(String *sql, const char *field_name, int typ,
char
*
dft
,
char
*
xtra
,
int
flag
,
bool
dbf
,
char
v
)
{
char
var
=
(
len
>
255
)
?
'V'
:
v
;
bool
error
=
false
;
bool
q
,
error
=
false
;
const
char
*
type
=
PLGtoMYSQLtype
(
typ
,
dbf
,
var
);
error
|=
sql
->
append
(
'`'
);
...
...
@@ -4661,7 +4774,12 @@ static bool add_field(String *sql, const char *field_name, int typ,
if
(
dft
&&
*
dft
)
{
error
|=
sql
->
append
(
" DEFAULT "
);
if
(
!
IsTypeNum
(
typ
))
{
if
(
typ
==
TYPE_DATE
)
q
=
(
strspn
(
dft
,
"0123456789 -:/"
)
==
strlen
(
dft
));
else
q
=
!
IsTypeNum
(
typ
);
if
(
q
)
{
error
|=
sql
->
append
(
"'"
);
error
|=
sql
->
append_for_single_quote
(
dft
,
strlen
(
dft
));
error
|=
sql
->
append
(
"'"
);
...
...
@@ -4831,6 +4949,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
int
port
=
0
,
hdr
=
0
,
mxr
__attribute__
((
unused
))
=
0
,
mxe
=
0
,
rc
=
0
;
int
cop
__attribute__
((
unused
))
=
0
;
#if defined(ODBC_SUPPORT)
POPARM
sop
=
NULL
;
char
*
ucnc
=
NULL
;
bool
cnc
=
false
;
int
cto
=
-
1
,
qto
=
-
1
;
#endif // ODBC_SUPPORT
uint
tm
,
fnc
=
FNC_NO
,
supfnc
=
(
FNC_NO
|
FNC_COL
);
...
...
@@ -4875,7 +4996,8 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
if
(
topt
->
oplist
)
{
host
=
GetListOption
(
g
,
"host"
,
topt
->
oplist
,
"localhost"
);
user
=
GetListOption
(
g
,
"user"
,
topt
->
oplist
,
"root"
);
user
=
GetListOption
(
g
,
"user"
,
topt
->
oplist
,
(
ttp
==
TAB_ODBC
?
NULL
:
"root"
));
// Default value db can come from the DBNAME=xxx option.
db
=
GetListOption
(
g
,
"database"
,
topt
->
oplist
,
db
);
col
=
GetListOption
(
g
,
"colist"
,
topt
->
oplist
,
col
);
...
...
@@ -4894,6 +5016,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
mxr
=
atoi
(
GetListOption
(
g
,
"maxres"
,
topt
->
oplist
,
"0"
));
cto
=
atoi
(
GetListOption
(
g
,
"ConnectTimeout"
,
topt
->
oplist
,
"-1"
));
qto
=
atoi
(
GetListOption
(
g
,
"QueryTimeout"
,
topt
->
oplist
,
"-1"
));
if
((
ucnc
=
GetListOption
(
g
,
"UseDSN"
,
topt
->
oplist
)))
cnc
=
(
!*
ucnc
||
*
ucnc
==
'y'
||
*
ucnc
==
'Y'
||
atoi
(
ucnc
)
!=
0
);
#endif
mxe
=
atoi
(
GetListOption
(
g
,
"maxerr"
,
topt
->
oplist
,
"0"
));
#if defined(PROMPT_OK)
...
...
@@ -4901,7 +5026,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
#endif // PROMPT_OK
}
else
{
host
=
"localhost"
;
user
=
"root"
;
user
=
(
ttp
==
TAB_ODBC
?
NULL
:
"root"
)
;
}
// endif option_list
if
(
!
(
shm
=
(
char
*
)
db
))
...
...
@@ -4978,10 +5103,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
}
// endif dsn
#endif // PROMPT_OK
}
else
if
(
!
dsn
)
}
else
if
(
!
dsn
)
{
sprintf
(
g
->
Message
,
"Missing %s connection string"
,
topt
->
type
);
else
}
else
{
// Store ODBC additional parameters
sop
=
(
POPARM
)
PlugSubAlloc
(
g
,
NULL
,
sizeof
(
ODBCPARM
));
sop
->
User
=
(
char
*
)
user
;
sop
->
Pwd
=
(
char
*
)
pwd
;
sop
->
Cto
=
cto
;
sop
->
Qto
=
qto
;
sop
->
UseCnc
=
cnc
;
ok
=
true
;
}
// endif's
supfnc
|=
(
FNC_TABLE
|
FNC_DSN
|
FNC_DRIVER
);
break
;
...
...
@@ -5112,15 +5245,15 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
case
FNC_NO
:
case
FNC_COL
:
if
(
src
)
{
qrp
=
ODBCSrcCols
(
g
,
dsn
,
(
char
*
)
src
,
cto
,
qto
);
qrp
=
ODBCSrcCols
(
g
,
dsn
,
(
char
*
)
src
,
sop
);
src
=
NULL
;
// for next tests
}
else
qrp
=
ODBCColumns
(
g
,
dsn
,
shm
,
tab
,
NULL
,
mxr
,
cto
,
qto
,
fnc
==
FNC_COL
);
qrp
=
ODBCColumns
(
g
,
dsn
,
shm
,
tab
,
NULL
,
mxr
,
fnc
==
FNC_COL
,
sop
);
break
;
case
FNC_TABLE
:
qrp
=
ODBCTables
(
g
,
dsn
,
shm
,
tab
,
mxr
,
cto
,
qto
,
true
);
qrp
=
ODBCTables
(
g
,
dsn
,
shm
,
tab
,
mxr
,
true
,
sop
);
break
;
case
FNC_DSN
:
qrp
=
ODBCDataSources
(
g
,
mxr
,
true
);
...
...
@@ -5237,9 +5370,10 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
for
(
crp
=
qrp
->
Colresp
;
crp
;
crp
=
crp
->
Next
)
switch
(
crp
->
Fld
)
{
case
FLD_NAME
:
if
(
ttp
==
TAB_CSV
&&
topt
->
data_charset
&&
if
(
ttp
==
TAB_PRX
||
(
ttp
==
TAB_CSV
&&
topt
->
data_charset
&&
(
!
stricmp
(
topt
->
data_charset
,
"UTF8"
)
||
!
stricmp
(
topt
->
data_charset
,
"UTF-8"
)))
!
stricmp
(
topt
->
data_charset
,
"UTF-8"
)))
)
cnm
=
crp
->
Kdata
->
GetCharValue
(
i
);
else
cnm
=
encode
(
g
,
crp
->
Kdata
->
GetCharValue
(
i
));
...
...
@@ -5299,9 +5433,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
// typ must be PLG type, not SQL type
if
(
!
(
plgtyp
=
TranslateSQLType
(
typ
,
dec
,
prec
,
v
)))
{
sprintf
(
g
->
Message
,
"Unsupported SQL type %d"
,
typ
);
my_message
(
ER_UNKNOWN_ERROR
,
g
->
Message
,
MYF
(
0
));
goto
err
;
if
(
GetTypeConv
()
==
TPC_SKIP
)
{
// Skip this column
sprintf
(
g
->
Message
,
"Column %s skipped (unsupported type %d)"
,
cnm
,
typ
);
push_warning
(
thd
,
Sql_condition
::
WARN_LEVEL_WARN
,
0
,
g
->
Message
);
continue
;
}
else
{
sprintf
(
g
->
Message
,
"Unsupported SQL type %d"
,
typ
);
my_message
(
ER_UNKNOWN_ERROR
,
g
->
Message
,
MYF
(
0
));
goto
err
;
}
// endif type_conv
}
else
typ
=
plgtyp
;
...
...
@@ -6341,58 +6484,6 @@ struct st_mysql_storage_engine connect_storage_engine=
/***********************************************************************/
/* CONNECT global variables definitions. */
/***********************************************************************/
// Size used when converting TEXT columns to VARCHAR
#if defined(_DEBUG)
static
MYSQL_SYSVAR_INT
(
conv_size
,
zconv
,
PLUGIN_VAR_RQCMDARG
,
// opt
"Size used when converting TEXT columns."
,
NULL
,
NULL
,
SZCONV
,
0
,
65500
,
1
);
#else
static
MYSQL_SYSVAR_INT
(
conv_size
,
zconv
,
PLUGIN_VAR_RQCMDARG
|
PLUGIN_VAR_READONLY
,
// opt
"Size used when converting TEXT columns."
,
NULL
,
NULL
,
SZCONV
,
0
,
65500
,
1
);
#endif
/**
Type conversion:
no: Unsupported types -> TYPE_ERROR
yes: TEXT -> VARCHAR
skip: skip unsupported type columns in Discovery
*/
const
char
*
xconv_names
[]
=
{
"NO"
,
"YES"
,
"SKIP"
,
NullS
};
TYPELIB
xconv_typelib
=
{
array_elements
(
xconv_names
)
-
1
,
"xconv_typelib"
,
xconv_names
,
NULL
};
#if defined(_DEBUG)
static
MYSQL_SYSVAR_ENUM
(
type_conv
,
// name
xconv
,
// varname
PLUGIN_VAR_RQCMDARG
,
// opt
"Unsupported types conversion."
,
// comment
NULL
,
// check
NULL
,
// update function
0
,
// def (no)
&
xconv_typelib
);
// typelib
#else
static
MYSQL_SYSVAR_ENUM
(
type_conv
,
// name
xconv
,
// varname
PLUGIN_VAR_RQCMDARG
|
PLUGIN_VAR_READONLY
,
"Unsupported types conversion."
,
// comment
NULL
,
// check
NULL
,
// update function
0
,
// def (no)
&
xconv_typelib
);
// typelib
#endif
#if defined(XMAP)
// Using file mapping for indexes if true
static
MYSQL_SYSVAR_BOOL
(
indx_map
,
xmap
,
PLUGIN_VAR_RQCMDARG
,
...
...
storage/connect/json.cpp
View file @
56114a41
/*************** json CPP Declares Source Code File (.H) ***************/
/* Name: json.cpp Version 1.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */
/* */
/* This file contains the JSON classes functions. */
/***********************************************************************/
/***********************************************************************/
/* Include relevant sections of the MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
/***********************************************************************/
/* Include application header files: */
/* global.h is header containing all global declarations. */
/* plgdbsem.h is header containing the DB application declarations. */
/* xjson.h is header containing the JSON classes declarations. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "json.h"
#define ARGS MY_MIN(24,len-i),s+MY_MAX(i-3,0)
#if defined(WIN32)
#define EL "\r\n"
#else
#define EL "\n"
#endif
/***********************************************************************/
/* Parse a json string. */
/***********************************************************************/
PJSON
ParseJson
(
PGLOBAL
g
,
char
*
s
,
int
len
,
int
pretty
,
bool
*
comma
)
{
int
i
;
bool
b
=
false
;
PJSON
jsp
=
NULL
;
STRG
src
;
if
(
!
s
||
!
len
)
{
strcpy
(
g
->
Message
,
"Void JSON object"
);
return
NULL
;
}
else
if
(
comma
)
*
comma
=
false
;
src
.
str
=
s
;
src
.
len
=
len
;
for
(
i
=
0
;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
'['
:
if
(
jsp
)
{
strcpy
(
g
->
Message
,
"More than one item in file"
);
return
NULL
;
}
else
if
(
!
(
jsp
=
ParseArray
(
g
,
++
i
,
src
)))
return
NULL
;
break
;
case
'{'
:
if
(
jsp
)
{
strcpy
(
g
->
Message
,
"More than one item in file"
);
return
NULL
;
}
else
if
(
!
(
jsp
=
ParseObject
(
g
,
++
i
,
src
)))
return
NULL
;
break
;
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
case
','
:
if
(
jsp
&&
pretty
==
1
)
{
if
(
comma
)
*
comma
=
true
;
break
;
}
// endif pretty
sprintf
(
g
->
Message
,
"Unexpected ',' (pretty=%d)"
,
pretty
);
return
NULL
;
case
'('
:
b
=
true
;
break
;
case
')'
:
if
(
b
)
{
b
=
false
;
break
;
}
// endif b
default:
sprintf
(
g
->
Message
,
"Bad '%c' character near %.*s"
,
s
[
i
],
ARGS
);
return
NULL
;
};
// endswitch s[i]
if
(
!
jsp
)
sprintf
(
g
->
Message
,
"Invalid Json string '%.*s'"
,
50
,
s
);
return
jsp
;
}
// end of ParseJson
/***********************************************************************/
/* Parse a JSON Array. */
/***********************************************************************/
PJAR
ParseArray
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
s
=
src
.
str
;
int
len
=
src
.
len
;
int
level
=
0
;
PJAR
jarp
=
new
(
g
)
JARRAY
;
PJVAL
jvp
=
NULL
;
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
','
:
if
(
level
<
2
)
{
sprintf
(
g
->
Message
,
"Unexpected ',' near %.*s"
,
ARGS
);
return
NULL
;
}
else
level
=
1
;
break
;
case
']'
:
if
(
level
==
1
)
{
sprintf
(
g
->
Message
,
"Unexpected ',]' near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
jarp
->
InitArray
(
g
);
return
jarp
;
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
default:
if
(
level
==
2
)
{
sprintf
(
g
->
Message
,
"Unexpected value near %.*s"
,
ARGS
);
return
NULL
;
}
else
if
((
jvp
=
ParseValue
(
g
,
i
,
src
)))
{
jarp
->
AddValue
(
g
,
jvp
);
level
=
2
;
}
else
return
NULL
;
level
=
2
;
break
;
};
// endswitch s[i]
strcpy
(
g
->
Message
,
"Unexpected EOF in array"
);
return
NULL
;
}
// end of ParseArray
/***********************************************************************/
/* Parse a JSON Object. */
/***********************************************************************/
PJOB
ParseObject
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
PSZ
key
;
char
*
s
=
src
.
str
;
int
len
=
src
.
len
;
int
level
=
0
;
PJOB
jobp
=
new
(
g
)
JOBJECT
;
PJPR
jpp
=
NULL
;
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
'"'
:
if
(
level
<
2
)
{
if
((
key
=
ParseString
(
g
,
++
i
,
src
)))
{
jpp
=
jobp
->
AddPair
(
g
,
key
);
level
=
1
;
}
else
return
NULL
;
}
else
{
sprintf
(
g
->
Message
,
"misplaced string near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
break
;
case
':'
:
if
(
level
==
1
)
{
if
(
!
(
jpp
->
Val
=
ParseValue
(
g
,
++
i
,
src
)))
return
NULL
;
level
=
2
;
}
else
{
sprintf
(
g
->
Message
,
"Unexpected ':' near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
break
;
case
','
:
if
(
level
<
2
)
{
sprintf
(
g
->
Message
,
"Unexpected ',' near %.*s"
,
ARGS
);
return
NULL
;
}
else
level
=
1
;
break
;
case
'}'
:
if
(
level
==
1
)
{
sprintf
(
g
->
Message
,
"Unexpected '}' near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
return
jobp
;
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
default:
sprintf
(
g
->
Message
,
"Unexpected character '%c' near %.*s"
,
s
[
i
],
ARGS
);
return
NULL
;
};
// endswitch s[i]
strcpy
(
g
->
Message
,
"Unexpected EOF in Object"
);
return
NULL
;
}
// end of ParseObject
/***********************************************************************/
/* Parse a JSON Value. */
/***********************************************************************/
PJVAL
ParseValue
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
strval
,
*
s
=
src
.
str
;
int
n
,
len
=
src
.
len
;
PJVAL
jvp
=
new
(
g
)
JVALUE
;
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
default:
goto
suite
;
}
// endswitch
suite:
switch
(
s
[
i
])
{
case
'['
:
if
(
!
(
jvp
->
Jsp
=
ParseArray
(
g
,
++
i
,
src
)))
return
NULL
;
break
;
case
'{'
:
if
(
!
(
jvp
->
Jsp
=
ParseObject
(
g
,
++
i
,
src
)))
return
NULL
;
break
;
case
'"'
:
if
((
strval
=
ParseString
(
g
,
++
i
,
src
)))
jvp
->
Value
=
AllocateValue
(
g
,
strval
,
TYPE_STRING
);
else
return
NULL
;
break
;
case
't'
:
if
(
!
strncmp
(
s
+
i
,
"true"
,
4
))
{
n
=
1
;
jvp
->
Value
=
AllocateValue
(
g
,
&
n
,
TYPE_TINY
);
i
+=
3
;
}
else
goto
err
;
break
;
case
'f'
:
if
(
!
strncmp
(
s
+
i
,
"false"
,
5
))
{
n
=
0
;
jvp
->
Value
=
AllocateValue
(
g
,
&
n
,
TYPE_TINY
);
i
+=
4
;
}
else
goto
err
;
break
;
case
'n'
:
if
(
!
strncmp
(
s
+
i
,
"null"
,
4
))
i
+=
3
;
else
goto
err
;
break
;
case
'-'
:
default:
if
(
s
[
i
]
==
'-'
||
isdigit
(
s
[
i
]))
{
if
(
!
(
jvp
->
Value
=
ParseNumeric
(
g
,
i
,
src
)))
goto
err
;
}
else
goto
err
;
};
// endswitch s[i]
jvp
->
Size
=
1
;
return
jvp
;
err:
sprintf
(
g
->
Message
,
"Unexpected character '%c' near %.*s"
,
s
[
i
],
ARGS
);
return
NULL
;
}
// end of ParseValue
/***********************************************************************/
/* Unescape and parse a JSON string. */
/***********************************************************************/
char
*
ParseString
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
p
,
*
s
=
src
.
str
;
int
n
=
0
,
len
=
src
.
len
;
// The size to allocate is not known yet
p
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
0
);
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
'"'
:
p
[
n
++
]
=
0
;
PlugSubAlloc
(
g
,
NULL
,
n
);
return
p
;
case
'\\'
:
if
(
++
i
<
len
)
{
if
(
s
[
i
]
==
'u'
)
{
if
(
len
-
i
>
5
)
{
// if (charset == utf8) {
char
xs
[
5
];
uint
hex
;
xs
[
0
]
=
s
[
++
i
];
xs
[
1
]
=
s
[
++
i
];
xs
[
2
]
=
s
[
++
i
];
xs
[
3
]
=
s
[
++
i
];
xs
[
4
]
=
0
;
hex
=
strtoul
(
xs
,
NULL
,
16
);
if
(
hex
<
0x80
)
{
p
[
n
]
=
(
uchar
)
hex
;
}
else
if
(
hex
<
0x800
)
{
p
[
n
++
]
=
(
uchar
)(
0xC0
|
(
hex
>>
6
));
p
[
n
]
=
(
uchar
)(
0x80
|
(
hex
&
0x3F
));
}
else
if
(
hex
<
0x10000
)
{
p
[
n
++
]
=
(
uchar
)(
0xE0
|
(
hex
>>
12
));
p
[
n
++
]
=
(
uchar
)(
0x80
|
((
hex
>>
6
)
&
0x3f
));
p
[
n
]
=
(
uchar
)(
0x80
|
(
hex
&
0x3f
));
}
else
p
[
n
]
=
'?'
;
#if 0
} else {
char xs[3];
UINT hex;
i += 2;
xs[0] = s[++i];
xs[1] = s[++i];
xs[2] = 0;
hex = strtoul(xs, NULL, 16);
p[n] = (char)hex;
} // endif charset
#endif // 0
}
else
goto
err
;
}
else
switch
(
s
[
i
])
{
case
't'
:
p
[
n
]
=
'\t'
;
break
;
case
'n'
:
p
[
n
]
=
'\n'
;
break
;
case
'r'
:
p
[
n
]
=
'\r'
;
break
;
case
'b'
:
p
[
n
]
=
'\b'
;
break
;
case
'f'
:
p
[
n
]
=
'\f'
;
break
;
default:
p
[
n
]
=
s
[
i
];
break
;
}
// endswitch
n
++
;
}
else
goto
err
;
break
;
default:
p
[
n
++
]
=
s
[
i
];
break
;
};
// endswitch s[i]
err:
strcpy
(
g
->
Message
,
"Unexpected EOF in String"
);
return
NULL
;
}
// end of ParseString
/***********************************************************************/
/* Parse a JSON numeric value. */
/***********************************************************************/
PVAL
ParseNumeric
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
s
=
src
.
str
,
buf
[
50
];
int
n
=
0
,
len
=
src
.
len
;
short
nd
=
0
;
bool
has_dot
=
false
;
bool
has_e
=
false
;
bool
found_digit
=
false
;
PVAL
valp
=
NULL
;
for
(;
i
<
len
;
i
++
)
{
switch
(
s
[
i
])
{
case
'.'
:
if
(
!
found_digit
||
has_dot
||
has_e
)
goto
err
;
has_dot
=
true
;
break
;
case
'e'
:
case
'E'
:
if
(
!
found_digit
||
has_e
)
goto
err
;
has_e
=
true
;
found_digit
=
false
;
break
;
case
'+'
:
if
(
!
has_e
)
goto
err
;
// passthru
case
'-'
:
if
(
found_digit
)
goto
err
;
break
;
default:
if
(
isdigit
(
s
[
i
]))
{
if
(
has_dot
&&
!
has_e
)
nd
++
;
// Number of decimals
found_digit
=
true
;
}
else
goto
fin
;
};
// endswitch s[i]
buf
[
n
++
]
=
s
[
i
];
}
// endfor i
fin:
if
(
found_digit
)
{
buf
[
n
]
=
0
;
if
(
has_dot
||
has_e
)
{
double
dv
=
strtod
(
buf
,
NULL
);
valp
=
AllocateValue
(
g
,
&
dv
,
TYPE_DOUBLE
,
nd
);
}
else
{
int
iv
=
strtol
(
buf
,
NULL
,
10
);
valp
=
AllocateValue
(
g
,
&
iv
,
TYPE_INT
);
}
// endif has
i
--
;
// Unstack following character
return
valp
;
}
else
{
strcpy
(
g
->
Message
,
"No digit found"
);
return
NULL
;
}
// endif found_digit
err:
strcpy
(
g
->
Message
,
"Unexpected EOF in number"
);
return
NULL
;
}
// end of ParseNumeric
/***********************************************************************/
/* Serialize a JSON tree: */
/***********************************************************************/
PSZ
Serialize
(
PGLOBAL
g
,
PJSON
jsp
,
FILE
*
fs
,
int
pretty
)
{
bool
b
=
false
,
err
=
true
;
JOUT
*
jp
;
g
->
Message
[
0
]
=
0
;
if
(
!
jsp
)
{
strcpy
(
g
->
Message
,
"Null json tree"
);
return
NULL
;
}
else
if
(
!
fs
)
{
// Serialize to a string
jp
=
new
(
g
)
JOUTSTR
(
g
);
b
=
pretty
==
1
;
}
else
if
(
pretty
==
2
)
{
// Serialize to a pretty file
jp
=
new
(
g
)
JOUTPRT
(
g
,
fs
);
}
else
{
// Serialize to a flat file
jp
=
new
(
g
)
JOUTFILE
(
g
,
fs
);
b
=
pretty
==
1
;
}
// endif's
switch
(
jsp
->
GetType
())
{
case
TYPE_JAR
:
err
=
SerializeArray
(
jp
,
(
PJAR
)
jsp
,
b
);
break
;
case
TYPE_JOB
:
err
=
(
b
&&
jp
->
WriteChr
(
'\t'
));
err
|=
SerializeObject
(
jp
,
(
PJOB
)
jsp
);
break
;
default:
strcpy
(
g
->
Message
,
"json tree is not an Array or an Object"
);
}
// endswitch Type
if
(
fs
)
{
fputc
(
'\n'
,
fs
);
fclose
(
fs
);
return
(
err
)
?
g
->
Message
:
NULL
;
}
else
if
(
!
err
)
{
PSZ
str
=
((
JOUTSTR
*
)
jp
)
->
Strp
;
jp
->
WriteChr
(
'\0'
);
PlugSubAlloc
(
g
,
NULL
,
((
JOUTSTR
*
)
jp
)
->
N
);
return
str
;
}
else
{
if
(
!
g
->
Message
[
0
])
strcpy
(
g
->
Message
,
"Error in Serialize"
);
return
NULL
;
}
// endif's
}
// end of Serialize
/***********************************************************************/
/* Serialize a JSON Array. */
/***********************************************************************/
bool
SerializeArray
(
JOUT
*
js
,
PJAR
jarp
,
bool
b
)
{
bool
first
=
true
;
if
(
js
->
WriteChr
(
'['
))
return
true
;
else
if
(
b
&&
(
js
->
WriteStr
(
EL
)
||
js
->
WriteChr
(
'\t'
)))
return
true
;
for
(
int
i
=
0
;
i
<
jarp
->
size
();
i
++
)
{
if
(
first
)
first
=
false
;
else
if
(
js
->
WriteChr
(
','
))
return
true
;
else
if
(
b
&&
(
js
->
WriteStr
(
EL
)
||
js
->
WriteChr
(
'\t'
)))
return
true
;
if
(
SerializeValue
(
js
,
jarp
->
GetValue
(
i
)))
return
true
;
}
// endfor i
if
(
b
&&
js
->
WriteStr
(
EL
))
return
true
;
return
js
->
WriteChr
(
']'
);
}
// end of SerializeArray
/***********************************************************************/
/* Serialize a JSON Object. */
/***********************************************************************/
bool
SerializeObject
(
JOUT
*
js
,
PJOB
jobp
)
{
bool
first
=
true
;
if
(
js
->
WriteChr
(
'{'
))
return
true
;
for
(
PJPR
pair
=
jobp
->
First
;
pair
;
pair
=
pair
->
Next
)
{
if
(
first
)
first
=
false
;
else
if
(
js
->
WriteChr
(
','
))
return
true
;
if
(
js
->
WriteChr
(
'\"'
)
||
js
->
WriteStr
(
pair
->
Key
)
||
js
->
WriteChr
(
'\"'
)
||
js
->
WriteChr
(
':'
)
||
SerializeValue
(
js
,
pair
->
Val
))
return
true
;
}
// endfor i
return
js
->
WriteChr
(
'}'
);
}
// end of SerializeObject
/***********************************************************************/
/* Serialize a JSON Value. */
/***********************************************************************/
bool
SerializeValue
(
JOUT
*
js
,
PJVAL
jvp
)
{
PJAR
jap
;
PJOB
jop
;
PVAL
valp
;
if
((
jap
=
jvp
->
GetArray
()))
return
SerializeArray
(
js
,
jap
,
false
);
else
if
((
jop
=
jvp
->
GetObject
()))
return
SerializeObject
(
js
,
jop
);
else
if
(
!
(
valp
=
jvp
->
Value
)
||
valp
->
IsNull
())
return
js
->
WriteStr
(
"null"
);
else
switch
(
valp
->
GetType
())
{
case
TYPE_TINY
:
return
js
->
WriteStr
(
valp
->
GetTinyValue
()
?
"true"
:
"false"
);
case
TYPE_STRING
:
return
js
->
Escape
(
valp
->
GetCharValue
());
default:
if
(
valp
->
IsTypeNum
())
{
char
buf
[
32
];
return
js
->
WriteStr
(
valp
->
GetCharString
(
buf
));
}
// endif valp
}
// endswitch Type
strcpy
(
js
->
g
->
Message
,
"Unrecognized value"
);
return
true
;
}
// end of SerializeValue
/* -------------------------- Class JOUTSTR -------------------------- */
/***********************************************************************/
/* JOUTSTR constructor. */
/***********************************************************************/
JOUTSTR
::
JOUTSTR
(
PGLOBAL
g
)
:
JOUT
(
g
)
{
PPOOLHEADER
pph
=
(
PPOOLHEADER
)
g
->
Sarea
;
N
=
0
;
Max
=
pph
->
FreeBlk
;
Max
=
(
Max
>
512
)
?
Max
-
512
:
Max
;
Strp
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
0
);
// Size not know yet
}
// end of JOUTSTR constructor
/***********************************************************************/
/* Concatenate a string to the Serialize string. */
/***********************************************************************/
bool
JOUTSTR
::
WriteStr
(
const
char
*
s
)
{
if
(
s
)
{
size_t
len
=
strlen
(
s
);
if
(
N
+
len
>
Max
)
return
true
;
memcpy
(
Strp
+
N
,
s
,
len
);
N
+=
len
;
return
false
;
}
else
return
true
;
}
// end of WriteStr
/***********************************************************************/
/* Concatenate a character to the Serialize string. */
/***********************************************************************/
bool
JOUTSTR
::
WriteChr
(
const
char
c
)
{
if
(
N
+
1
>
Max
)
return
true
;
Strp
[
N
++
]
=
c
;
return
false
;
}
// end of WriteChr
/***********************************************************************/
/* Escape and Concatenate a string to the Serialize string. */
/***********************************************************************/
bool
JOUTSTR
::
Escape
(
const
char
*
s
)
{
WriteChr
(
'"'
);
for
(
unsigned
int
i
=
0
;
i
<
strlen
(
s
);
i
++
)
switch
(
s
[
i
])
{
case
'\t'
:
case
'\n'
:
case
'\r'
:
case
'\b'
:
case
'\f'
:
case
'"'
:
WriteChr
(
'\\'
);
// passthru
default:
WriteChr
(
s
[
i
]);
break
;
}
// endswitch s[i]
WriteChr
(
'"'
);
return
false
;
}
// end of Escape
/* ------------------------- Class JOUTFILE -------------------------- */
/***********************************************************************/
/* Write a string to the Serialize file. */
/***********************************************************************/
bool
JOUTFILE
::
WriteStr
(
const
char
*
s
)
{
// This is temporary
fputs
(
s
,
Stream
);
return
false
;
}
// end of WriteStr
/***********************************************************************/
/* Write a character to the Serialize file. */
/***********************************************************************/
bool
JOUTFILE
::
WriteChr
(
const
char
c
)
{
// This is temporary
fputc
(
c
,
Stream
);
return
false
;
}
// end of WriteChr
/***********************************************************************/
/* Escape and Concatenate a string to the Serialize string. */
/***********************************************************************/
bool
JOUTFILE
::
Escape
(
const
char
*
s
)
{
// This is temporary
fputc
(
'"'
,
Stream
);
for
(
unsigned
int
i
=
0
;
i
<
strlen
(
s
);
i
++
)
switch
(
s
[
i
])
{
case
'\t'
:
fputs
(
"
\\
t"
,
Stream
);
break
;
case
'\n'
:
fputs
(
"
\\
n"
,
Stream
);
break
;
case
'\r'
:
fputs
(
"
\\
r"
,
Stream
);
break
;
case
'\b'
:
fputs
(
"
\\
b"
,
Stream
);
break
;
case
'\f'
:
fputs
(
"
\\
f"
,
Stream
);
break
;
case
'"'
:
fputs
(
"
\\\"
"
,
Stream
);
break
;
default:
fputc
(
s
[
i
],
Stream
);
break
;
}
// endswitch s[i]
fputc
(
'"'
,
Stream
);
return
false
;
}
// end of Escape
/* ------------------------- Class JOUTPRT --------------------------- */
/***********************************************************************/
/* Write a string to the Serialize pretty file. */
/***********************************************************************/
bool
JOUTPRT
::
WriteStr
(
const
char
*
s
)
{
// This is temporary
if
(
B
)
{
fputs
(
EL
,
Stream
);
M
--
;
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
B
=
false
;
}
// endif B
fputs
(
s
,
Stream
);
return
false
;
}
// end of WriteStr
/***********************************************************************/
/* Write a character to the Serialize pretty file. */
/***********************************************************************/
bool
JOUTPRT
::
WriteChr
(
const
char
c
)
{
switch
(
c
)
{
case
':'
:
fputs
(
": "
,
Stream
);
break
;
case
'{'
:
case
'['
:
#if 0
if (M)
fputs(EL, Stream);
for (int i = 0; i < M; i++)
fputc('\t', Stream);
#endif // 0
fputc
(
c
,
Stream
);
fputs
(
EL
,
Stream
);
M
++
;
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
break
;
case
'}'
:
case
']'
:
M
--
;
fputs
(
EL
,
Stream
);
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
fputc
(
c
,
Stream
);
B
=
true
;
break
;
case
','
:
fputc
(
c
,
Stream
);
fputs
(
EL
,
Stream
);
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
B
=
false
;
break
;
default:
fputc
(
c
,
Stream
);
}
// endswitch c
return
false
;
}
// end of WriteChr
/* -------------------------- Class JOBJECT -------------------------- */
/***********************************************************************/
/* Add a new pair to an Object. */
/***********************************************************************/
PJPR
JOBJECT
::
AddPair
(
PGLOBAL
g
,
PSZ
key
)
{
PJPR
jpp
=
new
(
g
)
JPAIR
(
key
);
if
(
Last
)
Last
->
Next
=
jpp
;
else
First
=
jpp
;
Last
=
jpp
;
Size
++
;
return
jpp
;
}
// end of AddPair
/***********************************************************************/
/* Get the value corresponding to the given key. */
/***********************************************************************/
PJVAL
JOBJECT
::
GetValue
(
const
char
*
key
)
{
for
(
PJPR
jp
=
First
;
jp
;
jp
=
jp
->
Next
)
if
(
!
strcmp
(
jp
->
Key
,
key
))
return
jp
->
Val
;
return
NULL
;
}
// end of GetValue;
/***********************************************************************/
/* Return the text corresponding to all keys (XML like). */
/***********************************************************************/
PSZ
JOBJECT
::
GetText
(
PGLOBAL
g
)
{
char
*
p
,
*
text
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
0
);
bool
b
=
true
;
if
(
!
First
)
return
NULL
;
else
for
(
PJPR
jp
=
First
;
jp
;
jp
=
jp
->
Next
)
{
if
(
!
(
p
=
jp
->
Val
->
GetString
()))
p
=
"???"
;
if
(
b
)
{
strcpy
(
text
,
p
);
b
=
false
;
}
else
strcat
(
strcat
(
text
,
" "
),
p
);
}
// endfor jp
PlugSubAlloc
(
g
,
NULL
,
strlen
(
text
)
+
1
);
return
text
;
}
// end of GetValue;
/***********************************************************************/
/* Set or add a value corresponding to the given key. */
/***********************************************************************/
void
JOBJECT
::
SetValue
(
PGLOBAL
g
,
PJVAL
jvp
,
PSZ
key
)
{
PJPR
jp
;
for
(
jp
=
First
;
jp
;
jp
=
jp
->
Next
)
if
(
!
strcmp
(
jp
->
Key
,
key
))
{
jp
->
Val
=
jvp
;
break
;
}
// endif key
if
(
!
jp
)
{
jp
=
AddPair
(
g
,
key
);
jp
->
Val
=
jvp
;
}
// endif jp
}
// end of SetValue
/* -------------------------- Class JARRAY --------------------------- */
/***********************************************************************/
/* Make the array of values from the values list. */
/***********************************************************************/
void
JARRAY
::
InitArray
(
PGLOBAL
g
)
{
int
i
;
PJVAL
jvp
;
for
(
Size
=
0
,
jvp
=
First
;
jvp
;
jvp
=
jvp
->
Next
)
if
(
!
jvp
->
Del
)
Size
++
;
if
(
!
Size
)
{
return
;
}
else
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
;
}
// end of InitArray
/***********************************************************************/
/* Get the Nth value of an Array. */
/***********************************************************************/
PJVAL
JARRAY
::
GetValue
(
int
i
)
{
if
(
Mvals
&&
i
>=
0
&&
i
<
Size
)
return
Mvals
[
i
];
else
return
NULL
;
}
// end of GetValue
/***********************************************************************/
/* Add a Value to the Arrays Value list. */
/***********************************************************************/
PJVAL
JARRAY
::
AddValue
(
PGLOBAL
g
,
PJVAL
jvp
)
{
if
(
!
jvp
)
jvp
=
new
(
g
)
JVALUE
;
if
(
Last
)
Last
->
Next
=
jvp
;
else
First
=
jvp
;
Last
=
jvp
;
return
jvp
;
}
// end of AddValue
/***********************************************************************/
/* Add a Value to the Arrays Value list. */
/***********************************************************************/
bool
JARRAY
::
SetValue
(
PGLOBAL
g
,
PJVAL
jvp
,
int
n
)
{
int
i
=
0
;
PJVAL
jp
,
*
jpp
=
&
First
;
for
(
i
=
0
,
jp
=
First
;
i
<
n
;
i
++
,
jp
=
*
(
jpp
=
&
jp
->
Next
))
if
(
!
jp
)
*
jpp
=
jp
=
new
(
g
)
JVALUE
;
*
jpp
=
jvp
;
jvp
->
Next
=
(
jp
?
jp
->
Next
:
NULL
);
return
false
;
}
// end of SetValue
/***********************************************************************/
/* Delete a Value from the Arrays Value list. */
/***********************************************************************/
bool
JARRAY
::
DeleteValue
(
int
n
)
{
PJVAL
jvp
=
GetValue
(
n
);
if
(
jvp
)
{
jvp
->
Del
=
true
;
return
false
;
}
else
return
true
;
}
// end of DeleteValue
/* -------------------------- Class JVALUE- -------------------------- */
/***********************************************************************/
/* Constructor for a Value with a given string or numeric value. */
/***********************************************************************/
JVALUE
::
JVALUE
(
PGLOBAL
g
,
PVAL
valp
)
:
JSON
()
{
Jsp
=
NULL
;
Value
=
AllocateValue
(
g
,
valp
);
Next
=
NULL
;
Del
=
false
;
}
// end of JVALUE constructor
/***********************************************************************/
/* Returns the type of the Value's value. */
/***********************************************************************/
JTYP
JVALUE
::
GetValType
(
void
)
{
if
(
Jsp
)
return
Jsp
->
GetType
();
else
if
(
Value
)
return
(
JTYP
)
Value
->
GetType
();
else
return
(
JTYP
)
TYPE_VOID
;
}
// end of GetValType
/***********************************************************************/
/* Return the Value's Object value. */
/***********************************************************************/
PJOB
JVALUE
::
GetObject
(
void
)
{
if
(
Jsp
&&
Jsp
->
GetType
()
==
TYPE_JOB
)
return
(
PJOB
)
Jsp
;
return
NULL
;
}
// end of GetObject
/***********************************************************************/
/* Return the Value's Array value. */
/***********************************************************************/
PJAR
JVALUE
::
GetArray
(
void
)
{
if
(
Jsp
&&
Jsp
->
GetType
()
==
TYPE_JAR
)
return
(
PJAR
)
Jsp
;
return
NULL
;
}
// end of GetArray
/***********************************************************************/
/* Return the Value's Integer value. */
/***********************************************************************/
int
JVALUE
::
GetInteger
(
void
)
{
return
(
Value
)
?
Value
->
GetIntValue
()
:
0
;
}
// end of GetInteger
/***********************************************************************/
/* Return the Value's Double value. */
/***********************************************************************/
double
JVALUE
::
GetFloat
(
void
)
{
return
(
Value
)
?
Value
->
GetFloatValue
()
:
0.0
;
}
// end of GetFloat
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ
JVALUE
::
GetString
(
void
)
{
char
buf
[
32
];
return
(
Value
)
?
Value
->
GetCharString
(
buf
)
:
NULL
;
}
// end of GetString
/*************** json CPP Declares Source Code File (.H) ***************/
/* Name: json.cpp Version 1.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */
/* */
/* This file contains the JSON classes functions. */
/***********************************************************************/
/***********************************************************************/
/* Include relevant sections of the MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
/***********************************************************************/
/* Include application header files: */
/* global.h is header containing all global declarations. */
/* plgdbsem.h is header containing the DB application declarations. */
/* xjson.h is header containing the JSON classes declarations. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "json.h"
#define ARGS MY_MIN(24,len-i),s+MY_MAX(i-3,0)
#if defined(WIN32)
#define EL "\r\n"
#else
#define EL "\n"
#endif
/***********************************************************************/
/* Parse a json string. */
/***********************************************************************/
PJSON
ParseJson
(
PGLOBAL
g
,
char
*
s
,
int
len
,
int
pretty
,
bool
*
comma
)
{
int
i
,
rc
;
bool
b
=
false
;
PJSON
jsp
=
NULL
;
STRG
src
;
if
(
!
s
||
!
len
)
{
strcpy
(
g
->
Message
,
"Void JSON object"
);
return
NULL
;
}
else
if
(
comma
)
*
comma
=
false
;
src
.
str
=
s
;
src
.
len
=
len
;
// Save stack and allocation environment and prepare error return
if
(
g
->
jump_level
==
MAX_JUMP
)
{
strcpy
(
g
->
Message
,
MSG
(
TOO_MANY_JUMPS
));
return
NULL
;
}
// endif jump_level
if
((
rc
=
setjmp
(
g
->
jumper
[
++
g
->
jump_level
]))
!=
0
)
{
goto
err
;
}
// endif rc
for
(
i
=
0
;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
'['
:
if
(
jsp
)
{
strcpy
(
g
->
Message
,
"More than one item in file"
);
goto
err
;
}
else
if
(
!
(
jsp
=
ParseArray
(
g
,
++
i
,
src
)))
goto
err
;
break
;
case
'{'
:
if
(
jsp
)
{
strcpy
(
g
->
Message
,
"More than one item in file"
);
goto
err
;
}
else
if
(
!
(
jsp
=
ParseObject
(
g
,
++
i
,
src
)))
goto
err
;
break
;
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
case
','
:
if
(
jsp
&&
pretty
==
1
)
{
if
(
comma
)
*
comma
=
true
;
break
;
}
// endif pretty
sprintf
(
g
->
Message
,
"Unexpected ',' (pretty=%d)"
,
pretty
);
goto
err
;
case
'('
:
b
=
true
;
break
;
case
')'
:
if
(
b
)
{
b
=
false
;
break
;
}
// endif b
default:
sprintf
(
g
->
Message
,
"Bad '%c' character near %.*s"
,
s
[
i
],
ARGS
);
goto
err
;
};
// endswitch s[i]
if
(
!
jsp
)
sprintf
(
g
->
Message
,
"Invalid Json string '%.*s'"
,
50
,
s
);
g
->
jump_level
--
;
return
jsp
;
err:
g
->
jump_level
--
;
return
NULL
;
}
// end of ParseJson
/***********************************************************************/
/* Parse a JSON Array. */
/***********************************************************************/
PJAR
ParseArray
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
s
=
src
.
str
;
int
len
=
src
.
len
;
int
level
=
0
;
PJAR
jarp
=
new
(
g
)
JARRAY
;
PJVAL
jvp
=
NULL
;
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
','
:
if
(
level
<
2
)
{
sprintf
(
g
->
Message
,
"Unexpected ',' near %.*s"
,
ARGS
);
return
NULL
;
}
else
level
=
1
;
break
;
case
']'
:
if
(
level
==
1
)
{
sprintf
(
g
->
Message
,
"Unexpected ',]' near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
jarp
->
InitArray
(
g
);
return
jarp
;
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
default:
if
(
level
==
2
)
{
sprintf
(
g
->
Message
,
"Unexpected value near %.*s"
,
ARGS
);
return
NULL
;
}
else
if
((
jvp
=
ParseValue
(
g
,
i
,
src
)))
{
jarp
->
AddValue
(
g
,
jvp
);
level
=
2
;
}
else
return
NULL
;
level
=
2
;
break
;
};
// endswitch s[i]
strcpy
(
g
->
Message
,
"Unexpected EOF in array"
);
return
NULL
;
}
// end of ParseArray
/***********************************************************************/
/* Parse a JSON Object. */
/***********************************************************************/
PJOB
ParseObject
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
PSZ
key
;
char
*
s
=
src
.
str
;
int
len
=
src
.
len
;
int
level
=
0
;
PJOB
jobp
=
new
(
g
)
JOBJECT
;
PJPR
jpp
=
NULL
;
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
'"'
:
if
(
level
<
2
)
{
if
((
key
=
ParseString
(
g
,
++
i
,
src
)))
{
jpp
=
jobp
->
AddPair
(
g
,
key
);
level
=
1
;
}
else
return
NULL
;
}
else
{
sprintf
(
g
->
Message
,
"misplaced string near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
break
;
case
':'
:
if
(
level
==
1
)
{
if
(
!
(
jpp
->
Val
=
ParseValue
(
g
,
++
i
,
src
)))
return
NULL
;
level
=
2
;
}
else
{
sprintf
(
g
->
Message
,
"Unexpected ':' near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
break
;
case
','
:
if
(
level
<
2
)
{
sprintf
(
g
->
Message
,
"Unexpected ',' near %.*s"
,
ARGS
);
return
NULL
;
}
else
level
=
1
;
break
;
case
'}'
:
if
(
level
==
1
)
{
sprintf
(
g
->
Message
,
"Unexpected '}' near %.*s"
,
ARGS
);
return
NULL
;
}
// endif level
return
jobp
;
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
default:
sprintf
(
g
->
Message
,
"Unexpected character '%c' near %.*s"
,
s
[
i
],
ARGS
);
return
NULL
;
};
// endswitch s[i]
strcpy
(
g
->
Message
,
"Unexpected EOF in Object"
);
return
NULL
;
}
// end of ParseObject
/***********************************************************************/
/* Parse a JSON Value. */
/***********************************************************************/
PJVAL
ParseValue
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
strval
,
*
s
=
src
.
str
;
int
n
,
len
=
src
.
len
;
PJVAL
jvp
=
new
(
g
)
JVALUE
;
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
break
;
default:
goto
suite
;
}
// endswitch
suite:
switch
(
s
[
i
])
{
case
'['
:
if
(
!
(
jvp
->
Jsp
=
ParseArray
(
g
,
++
i
,
src
)))
return
NULL
;
break
;
case
'{'
:
if
(
!
(
jvp
->
Jsp
=
ParseObject
(
g
,
++
i
,
src
)))
return
NULL
;
break
;
case
'"'
:
if
((
strval
=
ParseString
(
g
,
++
i
,
src
)))
jvp
->
Value
=
AllocateValue
(
g
,
strval
,
TYPE_STRING
);
else
return
NULL
;
break
;
case
't'
:
if
(
!
strncmp
(
s
+
i
,
"true"
,
4
))
{
n
=
1
;
jvp
->
Value
=
AllocateValue
(
g
,
&
n
,
TYPE_TINY
);
i
+=
3
;
}
else
goto
err
;
break
;
case
'f'
:
if
(
!
strncmp
(
s
+
i
,
"false"
,
5
))
{
n
=
0
;
jvp
->
Value
=
AllocateValue
(
g
,
&
n
,
TYPE_TINY
);
i
+=
4
;
}
else
goto
err
;
break
;
case
'n'
:
if
(
!
strncmp
(
s
+
i
,
"null"
,
4
))
i
+=
3
;
else
goto
err
;
break
;
case
'-'
:
default:
if
(
s
[
i
]
==
'-'
||
isdigit
(
s
[
i
]))
{
if
(
!
(
jvp
->
Value
=
ParseNumeric
(
g
,
i
,
src
)))
goto
err
;
}
else
goto
err
;
};
// endswitch s[i]
jvp
->
Size
=
1
;
return
jvp
;
err:
sprintf
(
g
->
Message
,
"Unexpected character '%c' near %.*s"
,
s
[
i
],
ARGS
);
return
NULL
;
}
// end of ParseValue
/***********************************************************************/
/* Unescape and parse a JSON string. */
/***********************************************************************/
char
*
ParseString
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
s
=
src
.
str
;
uchar
*
p
;
int
n
=
0
,
len
=
src
.
len
;
// Be sure of memory availability
if
(
len
+
1
-
i
>
(
signed
)((
PPOOLHEADER
)
g
->
Sarea
)
->
FreeBlk
)
{
strcpy
(
g
->
Message
,
"ParseString: Out of memory"
);
return
NULL
;
}
// endif len
// The size to allocate is not known yet
p
=
(
uchar
*
)
PlugSubAlloc
(
g
,
NULL
,
0
);
for
(;
i
<
len
;
i
++
)
switch
(
s
[
i
])
{
case
'"'
:
p
[
n
++
]
=
0
;
PlugSubAlloc
(
g
,
NULL
,
n
);
return
(
char
*
)
p
;
case
'\\'
:
if
(
++
i
<
len
)
{
if
(
s
[
i
]
==
'u'
)
{
if
(
len
-
i
>
5
)
{
// if (charset == utf8) {
char
xs
[
5
];
uint
hex
;
xs
[
0
]
=
s
[
++
i
];
xs
[
1
]
=
s
[
++
i
];
xs
[
2
]
=
s
[
++
i
];
xs
[
3
]
=
s
[
++
i
];
xs
[
4
]
=
0
;
hex
=
strtoul
(
xs
,
NULL
,
16
);
if
(
hex
<
0x80
)
{
p
[
n
]
=
(
uchar
)
hex
;
}
else
if
(
hex
<
0x800
)
{
p
[
n
++
]
=
(
uchar
)(
0xC0
|
(
hex
>>
6
));
p
[
n
]
=
(
uchar
)(
0x80
|
(
hex
&
0x3F
));
}
else
if
(
hex
<
0x10000
)
{
p
[
n
++
]
=
(
uchar
)(
0xE0
|
(
hex
>>
12
));
p
[
n
++
]
=
(
uchar
)(
0x80
|
((
hex
>>
6
)
&
0x3f
));
p
[
n
]
=
(
uchar
)(
0x80
|
(
hex
&
0x3f
));
}
else
p
[
n
]
=
'?'
;
#if 0
} else {
char xs[3];
UINT hex;
i += 2;
xs[0] = s[++i];
xs[1] = s[++i];
xs[2] = 0;
hex = strtoul(xs, NULL, 16);
p[n] = (char)hex;
} // endif charset
#endif // 0
}
else
goto
err
;
}
else
switch
(
s
[
i
])
{
case
't'
:
p
[
n
]
=
'\t'
;
break
;
case
'n'
:
p
[
n
]
=
'\n'
;
break
;
case
'r'
:
p
[
n
]
=
'\r'
;
break
;
case
'b'
:
p
[
n
]
=
'\b'
;
break
;
case
'f'
:
p
[
n
]
=
'\f'
;
break
;
default:
p
[
n
]
=
s
[
i
];
break
;
}
// endswitch
n
++
;
}
else
goto
err
;
break
;
default:
p
[
n
++
]
=
s
[
i
];
break
;
};
// endswitch s[i]
err:
strcpy
(
g
->
Message
,
"Unexpected EOF in String"
);
return
NULL
;
}
// end of ParseString
/***********************************************************************/
/* Parse a JSON numeric value. */
/***********************************************************************/
PVAL
ParseNumeric
(
PGLOBAL
g
,
int
&
i
,
STRG
&
src
)
{
char
*
s
=
src
.
str
,
buf
[
50
];
int
n
=
0
,
len
=
src
.
len
;
short
nd
=
0
;
bool
has_dot
=
false
;
bool
has_e
=
false
;
bool
found_digit
=
false
;
PVAL
valp
=
NULL
;
for
(;
i
<
len
;
i
++
)
{
switch
(
s
[
i
])
{
case
'.'
:
if
(
!
found_digit
||
has_dot
||
has_e
)
goto
err
;
has_dot
=
true
;
break
;
case
'e'
:
case
'E'
:
if
(
!
found_digit
||
has_e
)
goto
err
;
has_e
=
true
;
found_digit
=
false
;
break
;
case
'+'
:
if
(
!
has_e
)
goto
err
;
// passthru
case
'-'
:
if
(
found_digit
)
goto
err
;
break
;
default:
if
(
isdigit
(
s
[
i
]))
{
if
(
has_dot
&&
!
has_e
)
nd
++
;
// Number of decimals
found_digit
=
true
;
}
else
goto
fin
;
};
// endswitch s[i]
buf
[
n
++
]
=
s
[
i
];
}
// endfor i
fin:
if
(
found_digit
)
{
buf
[
n
]
=
0
;
if
(
has_dot
||
has_e
)
{
double
dv
=
strtod
(
buf
,
NULL
);
valp
=
AllocateValue
(
g
,
&
dv
,
TYPE_DOUBLE
,
nd
);
}
else
{
int
iv
=
strtol
(
buf
,
NULL
,
10
);
valp
=
AllocateValue
(
g
,
&
iv
,
TYPE_INT
);
}
// endif has
i
--
;
// Unstack following character
return
valp
;
}
else
{
strcpy
(
g
->
Message
,
"No digit found"
);
return
NULL
;
}
// endif found_digit
err:
strcpy
(
g
->
Message
,
"Unexpected EOF in number"
);
return
NULL
;
}
// end of ParseNumeric
/***********************************************************************/
/* Serialize a JSON tree: */
/***********************************************************************/
PSZ
Serialize
(
PGLOBAL
g
,
PJSON
jsp
,
FILE
*
fs
,
int
pretty
)
{
bool
b
=
false
,
err
=
true
;
JOUT
*
jp
;
g
->
Message
[
0
]
=
0
;
if
(
!
jsp
)
{
strcpy
(
g
->
Message
,
"Null json tree"
);
return
NULL
;
}
else
if
(
!
fs
)
{
// Serialize to a string
jp
=
new
(
g
)
JOUTSTR
(
g
);
b
=
pretty
==
1
;
}
else
if
(
pretty
==
2
)
{
// Serialize to a pretty file
jp
=
new
(
g
)
JOUTPRT
(
g
,
fs
);
}
else
{
// Serialize to a flat file
jp
=
new
(
g
)
JOUTFILE
(
g
,
fs
);
b
=
pretty
==
1
;
}
// endif's
switch
(
jsp
->
GetType
())
{
case
TYPE_JAR
:
err
=
SerializeArray
(
jp
,
(
PJAR
)
jsp
,
b
);
break
;
case
TYPE_JOB
:
err
=
(
b
&&
jp
->
WriteChr
(
'\t'
));
err
|=
SerializeObject
(
jp
,
(
PJOB
)
jsp
);
break
;
case
TYPE_JVAL
:
err
=
SerializeValue
(
jp
,
(
PJVAL
)
jsp
);
break
;
default:
strcpy
(
g
->
Message
,
"Invalid json tree"
);
}
// endswitch Type
if
(
fs
)
{
fputc
(
'\n'
,
fs
);
fclose
(
fs
);
return
(
err
)
?
g
->
Message
:
NULL
;
}
else
if
(
!
err
)
{
PSZ
str
=
((
JOUTSTR
*
)
jp
)
->
Strp
;
jp
->
WriteChr
(
'\0'
);
PlugSubAlloc
(
g
,
NULL
,
((
JOUTSTR
*
)
jp
)
->
N
);
return
str
;
}
else
{
if
(
!
g
->
Message
[
0
])
strcpy
(
g
->
Message
,
"Error in Serialize"
);
return
NULL
;
}
// endif's
}
// end of Serialize
/***********************************************************************/
/* Serialize a JSON Array. */
/***********************************************************************/
bool
SerializeArray
(
JOUT
*
js
,
PJAR
jarp
,
bool
b
)
{
bool
first
=
true
;
if
(
js
->
WriteChr
(
'['
))
return
true
;
else
if
(
b
&&
(
js
->
WriteStr
(
EL
)
||
js
->
WriteChr
(
'\t'
)))
return
true
;
for
(
int
i
=
0
;
i
<
jarp
->
size
();
i
++
)
{
if
(
first
)
first
=
false
;
else
if
(
js
->
WriteChr
(
','
))
return
true
;
else
if
(
b
&&
(
js
->
WriteStr
(
EL
)
||
js
->
WriteChr
(
'\t'
)))
return
true
;
if
(
SerializeValue
(
js
,
jarp
->
GetValue
(
i
)))
return
true
;
}
// endfor i
if
(
b
&&
js
->
WriteStr
(
EL
))
return
true
;
return
js
->
WriteChr
(
']'
);
}
// end of SerializeArray
/***********************************************************************/
/* Serialize a JSON Object. */
/***********************************************************************/
bool
SerializeObject
(
JOUT
*
js
,
PJOB
jobp
)
{
bool
first
=
true
;
if
(
js
->
WriteChr
(
'{'
))
return
true
;
for
(
PJPR
pair
=
jobp
->
First
;
pair
;
pair
=
pair
->
Next
)
{
if
(
first
)
first
=
false
;
else
if
(
js
->
WriteChr
(
','
))
return
true
;
if
(
js
->
WriteChr
(
'"'
)
||
js
->
WriteStr
(
pair
->
Key
)
||
js
->
WriteChr
(
'"'
)
||
js
->
WriteChr
(
':'
)
||
SerializeValue
(
js
,
pair
->
Val
))
return
true
;
}
// endfor i
return
js
->
WriteChr
(
'}'
);
}
// end of SerializeObject
/***********************************************************************/
/* Serialize a JSON Value. */
/***********************************************************************/
bool
SerializeValue
(
JOUT
*
js
,
PJVAL
jvp
)
{
PJAR
jap
;
PJOB
jop
;
PVAL
valp
;
if
((
jap
=
jvp
->
GetArray
()))
return
SerializeArray
(
js
,
jap
,
false
);
else
if
((
jop
=
jvp
->
GetObject
()))
return
SerializeObject
(
js
,
jop
);
else
if
(
!
(
valp
=
jvp
->
Value
)
||
valp
->
IsNull
())
return
js
->
WriteStr
(
"null"
);
else
switch
(
valp
->
GetType
())
{
case
TYPE_TINY
:
return
js
->
WriteStr
(
valp
->
GetTinyValue
()
?
"true"
:
"false"
);
case
TYPE_STRING
:
return
js
->
Escape
(
valp
->
GetCharValue
());
default:
if
(
valp
->
IsTypeNum
())
{
char
buf
[
32
];
return
js
->
WriteStr
(
valp
->
GetCharString
(
buf
));
}
// endif valp
}
// endswitch Type
strcpy
(
js
->
g
->
Message
,
"Unrecognized value"
);
return
true
;
}
// end of SerializeValue
/* -------------------------- Class JOUTSTR -------------------------- */
/***********************************************************************/
/* JOUTSTR constructor. */
/***********************************************************************/
JOUTSTR
::
JOUTSTR
(
PGLOBAL
g
)
:
JOUT
(
g
)
{
PPOOLHEADER
pph
=
(
PPOOLHEADER
)
g
->
Sarea
;
N
=
0
;
Max
=
pph
->
FreeBlk
;
Max
=
(
Max
>
512
)
?
Max
-
512
:
Max
;
Strp
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
0
);
// Size not know yet
}
// end of JOUTSTR constructor
/***********************************************************************/
/* Concatenate a string to the Serialize string. */
/***********************************************************************/
bool
JOUTSTR
::
WriteStr
(
const
char
*
s
)
{
if
(
s
)
{
size_t
len
=
strlen
(
s
);
if
(
N
+
len
>
Max
)
return
true
;
memcpy
(
Strp
+
N
,
s
,
len
);
N
+=
len
;
return
false
;
}
else
return
true
;
}
// end of WriteStr
/***********************************************************************/
/* Concatenate a character to the Serialize string. */
/***********************************************************************/
bool
JOUTSTR
::
WriteChr
(
const
char
c
)
{
if
(
N
+
1
>
Max
)
return
true
;
Strp
[
N
++
]
=
c
;
return
false
;
}
// end of WriteChr
/***********************************************************************/
/* Escape and Concatenate a string to the Serialize string. */
/***********************************************************************/
bool
JOUTSTR
::
Escape
(
const
char
*
s
)
{
WriteChr
(
'"'
);
for
(
unsigned
int
i
=
0
;
i
<
strlen
(
s
);
i
++
)
switch
(
s
[
i
])
{
case
'"'
:
case
'\\'
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
case
'\b'
:
case
'\f'
:
WriteChr
(
'\\'
);
// passthru
default:
WriteChr
(
s
[
i
]);
break
;
}
// endswitch s[i]
WriteChr
(
'"'
);
return
false
;
}
// end of Escape
/* ------------------------- Class JOUTFILE -------------------------- */
/***********************************************************************/
/* Write a string to the Serialize file. */
/***********************************************************************/
bool
JOUTFILE
::
WriteStr
(
const
char
*
s
)
{
// This is temporary
fputs
(
s
,
Stream
);
return
false
;
}
// end of WriteStr
/***********************************************************************/
/* Write a character to the Serialize file. */
/***********************************************************************/
bool
JOUTFILE
::
WriteChr
(
const
char
c
)
{
// This is temporary
fputc
(
c
,
Stream
);
return
false
;
}
// end of WriteChr
/***********************************************************************/
/* Escape and Concatenate a string to the Serialize string. */
/***********************************************************************/
bool
JOUTFILE
::
Escape
(
const
char
*
s
)
{
// This is temporary
fputc
(
'"'
,
Stream
);
for
(
unsigned
int
i
=
0
;
i
<
strlen
(
s
);
i
++
)
switch
(
s
[
i
])
{
case
'"'
:
fputs
(
"
\\\"
"
,
Stream
);
break
;
case
'\\'
:
fputs
(
"
\\\\
"
,
Stream
);
break
;
case
'\t'
:
fputs
(
"
\\
t"
,
Stream
);
break
;
case
'\n'
:
fputs
(
"
\\
n"
,
Stream
);
break
;
case
'\r'
:
fputs
(
"
\\
r"
,
Stream
);
break
;
case
'\b'
:
fputs
(
"
\\
b"
,
Stream
);
break
;
case
'\f'
:
fputs
(
"
\\
f"
,
Stream
);
break
;
default:
fputc
(
s
[
i
],
Stream
);
break
;
}
// endswitch s[i]
fputc
(
'"'
,
Stream
);
return
false
;
}
// end of Escape
/* ------------------------- Class JOUTPRT --------------------------- */
/***********************************************************************/
/* Write a string to the Serialize pretty file. */
/***********************************************************************/
bool
JOUTPRT
::
WriteStr
(
const
char
*
s
)
{
// This is temporary
if
(
B
)
{
fputs
(
EL
,
Stream
);
M
--
;
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
B
=
false
;
}
// endif B
fputs
(
s
,
Stream
);
return
false
;
}
// end of WriteStr
/***********************************************************************/
/* Write a character to the Serialize pretty file. */
/***********************************************************************/
bool
JOUTPRT
::
WriteChr
(
const
char
c
)
{
switch
(
c
)
{
case
':'
:
fputs
(
": "
,
Stream
);
break
;
case
'{'
:
case
'['
:
#if 0
if (M)
fputs(EL, Stream);
for (int i = 0; i < M; i++)
fputc('\t', Stream);
#endif // 0
fputc
(
c
,
Stream
);
fputs
(
EL
,
Stream
);
M
++
;
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
break
;
case
'}'
:
case
']'
:
M
--
;
fputs
(
EL
,
Stream
);
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
fputc
(
c
,
Stream
);
B
=
true
;
break
;
case
','
:
fputc
(
c
,
Stream
);
fputs
(
EL
,
Stream
);
for
(
int
i
=
0
;
i
<
M
;
i
++
)
fputc
(
'\t'
,
Stream
);
B
=
false
;
break
;
default:
fputc
(
c
,
Stream
);
}
// endswitch c
return
false
;
}
// end of WriteChr
/* -------------------------- Class JOBJECT -------------------------- */
/***********************************************************************/
/* Add a new pair to an Object. */
/***********************************************************************/
PJPR
JOBJECT
::
AddPair
(
PGLOBAL
g
,
PSZ
key
)
{
PJPR
jpp
=
new
(
g
)
JPAIR
(
key
);
if
(
Last
)
Last
->
Next
=
jpp
;
else
First
=
jpp
;
Last
=
jpp
;
Size
++
;
return
jpp
;
}
// end of AddPair
/***********************************************************************/
/* Get the value corresponding to the given key. */
/***********************************************************************/
PJVAL
JOBJECT
::
GetValue
(
const
char
*
key
)
{
for
(
PJPR
jp
=
First
;
jp
;
jp
=
jp
->
Next
)
if
(
!
strcmp
(
jp
->
Key
,
key
))
return
jp
->
Val
;
return
NULL
;
}
// end of GetValue;
/***********************************************************************/
/* Return the text corresponding to all keys (XML like). */
/***********************************************************************/
PSZ
JOBJECT
::
GetText
(
PGLOBAL
g
)
{
char
*
p
,
*
text
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
0
);
bool
b
=
true
;
if
(
!
First
)
return
NULL
;
else
for
(
PJPR
jp
=
First
;
jp
;
jp
=
jp
->
Next
)
{
if
(
!
(
p
=
jp
->
Val
->
GetString
()))
p
=
"???"
;
if
(
b
)
{
strcpy
(
text
,
p
);
b
=
false
;
}
else
strcat
(
strcat
(
text
,
" "
),
p
);
}
// endfor jp
PlugSubAlloc
(
g
,
NULL
,
strlen
(
text
)
+
1
);
return
text
;
}
// end of GetValue;
/***********************************************************************/
/* Set or add a value corresponding to the given key. */
/***********************************************************************/
void
JOBJECT
::
SetValue
(
PGLOBAL
g
,
PJVAL
jvp
,
PSZ
key
)
{
PJPR
jp
;
for
(
jp
=
First
;
jp
;
jp
=
jp
->
Next
)
if
(
!
strcmp
(
jp
->
Key
,
key
))
{
jp
->
Val
=
jvp
;
break
;
}
// endif key
if
(
!
jp
)
{
jp
=
AddPair
(
g
,
key
);
jp
->
Val
=
jvp
;
}
// endif jp
}
// end of SetValue
/* -------------------------- Class JARRAY --------------------------- */
/***********************************************************************/
/* Make the array of values from the values list. */
/***********************************************************************/
void
JARRAY
::
InitArray
(
PGLOBAL
g
)
{
int
i
;
PJVAL
jvp
;
for
(
Size
=
0
,
jvp
=
First
;
jvp
;
jvp
=
jvp
->
Next
)
if
(
!
jvp
->
Del
)
Size
++
;
if
(
!
Size
)
{
return
;
}
else
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
;
}
// end of InitArray
/***********************************************************************/
/* Get the Nth value of an Array. */
/***********************************************************************/
PJVAL
JARRAY
::
GetValue
(
int
i
)
{
if
(
Mvals
&&
i
>=
0
&&
i
<
Size
)
return
Mvals
[
i
];
else
return
NULL
;
}
// end of GetValue
/***********************************************************************/
/* Add a Value to the Arrays Value list. */
/***********************************************************************/
PJVAL
JARRAY
::
AddValue
(
PGLOBAL
g
,
PJVAL
jvp
)
{
if
(
!
jvp
)
jvp
=
new
(
g
)
JVALUE
;
if
(
Last
)
Last
->
Next
=
jvp
;
else
First
=
jvp
;
Last
=
jvp
;
return
jvp
;
}
// end of AddValue
/***********************************************************************/
/* Add a Value to the Arrays Value list. */
/***********************************************************************/
bool
JARRAY
::
SetValue
(
PGLOBAL
g
,
PJVAL
jvp
,
int
n
)
{
int
i
=
0
;
PJVAL
jp
,
*
jpp
=
&
First
;
for
(
i
=
0
,
jp
=
First
;
i
<
n
;
i
++
,
jp
=
*
(
jpp
=
&
jp
->
Next
))
if
(
!
jp
)
*
jpp
=
jp
=
new
(
g
)
JVALUE
;
*
jpp
=
jvp
;
jvp
->
Next
=
(
jp
?
jp
->
Next
:
NULL
);
return
false
;
}
// end of SetValue
/***********************************************************************/
/* Delete a Value from the Arrays Value list. */
/***********************************************************************/
bool
JARRAY
::
DeleteValue
(
int
n
)
{
PJVAL
jvp
=
GetValue
(
n
);
if
(
jvp
)
{
jvp
->
Del
=
true
;
return
false
;
}
else
return
true
;
}
// end of DeleteValue
/* -------------------------- Class JVALUE- -------------------------- */
/***********************************************************************/
/* Constructor for a Value with a given string or numeric value. */
/***********************************************************************/
JVALUE
::
JVALUE
(
PGLOBAL
g
,
PVAL
valp
)
:
JSON
()
{
Jsp
=
NULL
;
Value
=
AllocateValue
(
g
,
valp
);
Next
=
NULL
;
Del
=
false
;
}
// end of JVALUE constructor
/***********************************************************************/
/* Returns the type of the Value's value. */
/***********************************************************************/
JTYP
JVALUE
::
GetValType
(
void
)
{
if
(
Jsp
)
return
Jsp
->
GetType
();
else
if
(
Value
)
return
(
JTYP
)
Value
->
GetType
();
else
return
(
JTYP
)
TYPE_VOID
;
}
// end of GetValType
/***********************************************************************/
/* Return the Value's Object value. */
/***********************************************************************/
PJOB
JVALUE
::
GetObject
(
void
)
{
if
(
Jsp
&&
Jsp
->
GetType
()
==
TYPE_JOB
)
return
(
PJOB
)
Jsp
;
return
NULL
;
}
// end of GetObject
/***********************************************************************/
/* Return the Value's Array value. */
/***********************************************************************/
PJAR
JVALUE
::
GetArray
(
void
)
{
if
(
Jsp
&&
Jsp
->
GetType
()
==
TYPE_JAR
)
return
(
PJAR
)
Jsp
;
return
NULL
;
}
// end of GetArray
/***********************************************************************/
/* Return the Value's Integer value. */
/***********************************************************************/
int
JVALUE
::
GetInteger
(
void
)
{
return
(
Value
)
?
Value
->
GetIntValue
()
:
0
;
}
// end of GetInteger
/***********************************************************************/
/* Return the Value's Double value. */
/***********************************************************************/
double
JVALUE
::
GetFloat
(
void
)
{
return
(
Value
)
?
Value
->
GetFloatValue
()
:
0.0
;
}
// end of GetFloat
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ
JVALUE
::
GetString
(
void
)
{
char
buf
[
32
];
return
(
Value
)
?
Value
->
GetCharString
(
buf
)
:
NULL
;
}
// end of GetString
/***********************************************************************/
/* Set the Value's value as the given integer. */
/***********************************************************************/
void
JVALUE
::
SetInteger
(
PGLOBAL
g
,
int
n
)
{
Value
=
AllocateValue
(
g
,
&
n
,
TYPE_INT
);
}
// end of AddInteger
/***********************************************************************/
/* Set the Value's value as the given DOUBLE. */
/***********************************************************************/
void
JVALUE
::
SetFloat
(
PGLOBAL
g
,
double
f
)
{
Value
=
AllocateValue
(
g
,
&
f
,
TYPE_DOUBLE
,
6
);
}
// end of AddFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
/***********************************************************************/
void
JVALUE
::
SetString
(
PGLOBAL
g
,
PSZ
s
)
{
Value
=
AllocateValue
(
g
,
s
,
TYPE_STRING
);
}
// end of AddFloat
storage/connect/json.h
View file @
56114a41
...
...
@@ -18,7 +18,8 @@ enum JTYP {TYPE_STRG = 1,
TYPE_BOOL
=
4
,
TYPE_INTG
=
7
,
TYPE_JSON
=
12
,
TYPE_JAR
,
TYPE_JOB
,
TYPE_JAR
,
TYPE_JOB
,
TYPE_JVAL
};
class
JOUT
;
...
...
@@ -156,6 +157,9 @@ class JSON : public BLOCK {
virtual
void
SetValue
(
PGLOBAL
g
,
PJVAL
jvp
,
PSZ
key
)
{
X
}
virtual
void
SetValue
(
PVAL
valp
)
{
X
}
virtual
void
SetValue
(
PJSON
jsp
)
{
X
}
virtual
void
SetString
(
PGLOBAL
g
,
PSZ
s
)
{
X
}
virtual
void
SetInteger
(
PGLOBAL
g
,
int
n
)
{
X
}
virtual
void
SetFloat
(
PGLOBAL
g
,
double
f
)
{
X
}
virtual
bool
DeleteValue
(
int
i
)
{
X
return
true
;}
protected:
...
...
@@ -171,6 +175,8 @@ class JOBJECT : public JSON {
public:
JOBJECT
(
void
)
:
JSON
()
{
First
=
Last
=
NULL
;}
using
JSON
::
GetValue
;
using
JSON
::
SetValue
;
virtual
void
Clear
(
void
)
{
First
=
Last
=
NULL
;
Size
=
0
;}
virtual
JTYP
GetType
(
void
)
{
return
TYPE_JOB
;}
virtual
PJPR
AddPair
(
PGLOBAL
g
,
PSZ
key
);
...
...
@@ -192,6 +198,8 @@ class JARRAY : public JSON {
public:
JARRAY
(
void
)
:
JSON
()
{
Alloc
=
0
;
First
=
Last
=
NULL
;
Mvals
=
NULL
;}
using
JSON
::
GetValue
;
using
JSON
::
SetValue
;
virtual
void
Clear
(
void
)
{
First
=
Last
=
NULL
;
Size
=
0
;}
virtual
JTYP
GetType
(
void
)
{
return
TYPE_JAR
;}
virtual
PJAR
GetArray
(
void
)
{
return
this
;}
...
...
@@ -223,6 +231,8 @@ class JVALUE : public JSON {
{
Jsp
=
jsp
;
Value
=
NULL
;
Next
=
NULL
;
Del
=
false
;}
JVALUE
(
PGLOBAL
g
,
PVAL
valp
);
using
JSON
::
GetValue
;
using
JSON
::
SetValue
;
virtual
void
Clear
(
void
)
{
Jsp
=
NULL
;
Value
=
NULL
;
Next
=
NULL
;
Del
=
false
;
Size
=
0
;}
virtual
JTYP
GetType
(
void
)
{
return
TYPE_JVAL
;}
...
...
@@ -236,6 +246,9 @@ class JVALUE : public JSON {
virtual
PSZ
GetString
(
void
);
virtual
void
SetValue
(
PVAL
valp
)
{
Value
=
valp
;}
virtual
void
SetValue
(
PJSON
jsp
)
{
Jsp
=
jsp
;}
virtual
void
SetString
(
PGLOBAL
g
,
PSZ
s
);
virtual
void
SetInteger
(
PGLOBAL
g
,
int
n
);
virtual
void
SetFloat
(
PGLOBAL
g
,
double
f
);
protected:
PJSON
Jsp
;
// To the json value
...
...
storage/connect/jsonudf.cpp
0 → 100644
View file @
56114a41
/************* jsonudf C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: jsonudf Version 1.0 */
/* (C) Copyright to the author Olivier BERTRAND 2015 */
/* This program are the JSON User Defined Functions . */
/***********************************************************************/
/***********************************************************************/
/* Include relevant sections of the MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
#include <mysql.h>
#include "global.h"
#include "plgdbsem.h"
#include "json.h"
extern
"C"
{
DllExport
my_bool
Json_Value_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
char
*
Json_Value
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
,
unsigned
long
*
,
char
*
,
char
*
);
DllExport
void
Json_Value_deinit
(
UDF_INIT
*
);
DllExport
my_bool
Json_Array_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
char
*
Json_Array
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
,
unsigned
long
*
,
char
*
,
char
*
);
DllExport
void
Json_Array_deinit
(
UDF_INIT
*
);
DllExport
my_bool
Json_Object_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
char
*
Json_Object
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
,
unsigned
long
*
,
char
*
,
char
*
);
DllExport
void
Json_Object_deinit
(
UDF_INIT
*
);
DllExport
my_bool
Json_Array_Grp_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
void
Json_Array_Grp_add
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
,
char
*
);
DllExport
char
*
Json_Array_Grp
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
,
unsigned
long
*
,
char
*
,
char
*
);
DllExport
void
Json_Array_Grp_clear
(
UDF_INIT
*
,
char
*
,
char
*
);
DllExport
void
Json_Array_Grp_deinit
(
UDF_INIT
*
);
DllExport
my_bool
Json_Object_Grp_init
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
);
DllExport
void
Json_Object_Grp_add
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
,
char
*
);
DllExport
char
*
Json_Object_Grp
(
UDF_INIT
*
,
UDF_ARGS
*
,
char
*
,
unsigned
long
*
,
char
*
,
char
*
);
DllExport
void
Json_Object_Grp_clear
(
UDF_INIT
*
,
char
*
,
char
*
);
DllExport
void
Json_Object_Grp_deinit
(
UDF_INIT
*
);
}
// extern "C"
/***********************************************************************/
/* Allocate and initialise the memory area. */
/***********************************************************************/
static
my_bool
JsonInit
(
UDF_INIT
*
initid
,
char
*
message
,
unsigned
long
reslen
,
unsigned
long
memlen
)
{
PGLOBAL
g
=
PlugInit
(
NULL
,
memlen
);
if
(
!
g
)
{
strcpy
(
message
,
"Allocation error"
);
return
true
;
}
else
if
(
g
->
Sarea_Size
==
0
)
{
strcpy
(
message
,
g
->
Message
);
PlugExit
(
g
);
return
true
;
}
else
initid
->
ptr
=
(
char
*
)
g
;
initid
->
maybe_null
=
false
;
initid
->
max_length
=
reslen
;
return
false
;
}
// end of Json_Object_init
/***********************************************************************/
/* Returns true if the argument is a JSON string. */
/***********************************************************************/
static
my_bool
IsJson
(
UDF_ARGS
*
args
,
int
i
)
{
return
(
args
->
arg_type
[
i
]
==
STRING_RESULT
&&
!
strnicmp
(
args
->
attributes
[
i
],
"Json_"
,
5
));
}
// end of IsJson
/***********************************************************************/
/* Calculate the reslen and memlen needed by a function. */
/***********************************************************************/
static
my_bool
CalcLen
(
UDF_ARGS
*
args
,
my_bool
obj
,
unsigned
long
&
reslen
,
unsigned
long
&
memlen
)
{
unsigned
long
i
,
k
;
reslen
=
args
->
arg_count
+
2
;
// Calculate the result max length
for
(
i
=
0
;
i
<
args
->
arg_count
;
i
++
)
{
if
(
obj
)
{
if
(
!
(
k
=
args
->
attribute_lengths
[
i
]))
k
=
strlen
(
args
->
attributes
[
i
]);
reslen
+=
(
k
+
3
);
// For quotes and :
}
// endif obj
switch
(
args
->
arg_type
[
i
])
{
case
STRING_RESULT
:
if
(
IsJson
(
args
,
i
))
reslen
+=
args
->
lengths
[
i
];
else
reslen
+=
(
args
->
lengths
[
i
]
+
1
)
*
2
;
// Pessimistic !
break
;
case
INT_RESULT
:
reslen
+=
20
;
break
;
case
REAL_RESULT
:
reslen
+=
31
;
break
;
case
DECIMAL_RESULT
:
reslen
+=
(
args
->
lengths
[
i
]
+
7
);
// 6 decimals
break
;
case
TIME_RESULT
:
case
ROW_RESULT
:
case
IMPOSSIBLE_RESULT
:
default:
// What should we do here ?
break
;
}
// endswitch arg_type
}
// endfor i
// Calculate the amount of memory needed
memlen
=
1024
+
sizeof
(
JOUTSTR
)
+
reslen
;
for
(
i
=
0
;
i
<
args
->
arg_count
;
i
++
)
{
memlen
+=
(
args
->
lengths
[
i
]
+
sizeof
(
JVALUE
));
if
(
obj
)
{
if
(
!
(
k
=
args
->
attribute_lengths
[
i
]))
k
=
strlen
(
args
->
attributes
[
i
]);
memlen
+=
(
k
+
sizeof
(
JOBJECT
)
+
sizeof
(
JPAIR
));
}
else
memlen
+=
sizeof
(
JARRAY
);
switch
(
args
->
arg_type
[
i
])
{
case
STRING_RESULT
:
if
(
IsJson
(
args
,
i
))
memlen
+=
args
->
lengths
[
i
]
*
5
;
// Estimate parse memory
memlen
+=
sizeof
(
TYPVAL
<
PSZ
>
);
break
;
case
INT_RESULT
:
memlen
+=
sizeof
(
TYPVAL
<
int
>
);
break
;
case
REAL_RESULT
:
case
DECIMAL_RESULT
:
memlen
+=
sizeof
(
TYPVAL
<
double
>
);
break
;
case
TIME_RESULT
:
case
ROW_RESULT
:
case
IMPOSSIBLE_RESULT
:
default:
// What should we do here ?
break
;
}
// endswitch arg_type
}
// endfor i
return
false
;
}
// end of CalcLen
/***********************************************************************/
/* Make a zero terminated string from the passed argument. */
/***********************************************************************/
static
PSZ
MakePSZ
(
PGLOBAL
g
,
UDF_ARGS
*
args
,
int
i
)
{
if
(
args
->
args
[
i
])
{
int
n
=
args
->
lengths
[
i
];
PSZ
s
=
(
PSZ
)
PlugSubAlloc
(
g
,
NULL
,
n
+
1
);
memcpy
(
s
,
args
->
args
[
i
],
n
);
s
[
n
]
=
0
;
return
s
;
}
else
return
NULL
;
}
// end of MakePSZ
/***********************************************************************/
/* Make a valid key from the passed argument. */
/***********************************************************************/
static
PSZ
MakeKey
(
PGLOBAL
g
,
UDF_ARGS
*
args
,
int
i
)
{
int
n
=
args
->
attribute_lengths
[
i
];
bool
b
;
// true if attribute is zero terminated
PSZ
p
,
s
=
args
->
attributes
[
i
];
if
(
s
&&
*
s
&&
(
n
||
*
s
==
'\''
))
{
if
((
b
=
(
!
n
||
!
s
[
n
])))
n
=
strlen
(
s
);
if
(
n
>
5
&&
IsJson
(
args
,
i
))
{
s
+=
5
;
n
-=
5
;
}
else
if
(
*
s
==
'\''
&&
s
[
n
-
1
]
==
'\''
)
{
s
++
;
n
-=
2
;
b
=
false
;
}
// endif *s
if
(
n
<
1
)
return
"Key"
;
if
(
!
b
)
{
p
=
(
PSZ
)
PlugSubAlloc
(
g
,
NULL
,
n
+
1
);
memcpy
(
p
,
s
,
n
);
p
[
n
]
=
0
;
s
=
p
;
}
// endif b
}
// endif s
return
s
;
}
// end of MakeKey
/***********************************************************************/
/* Make a JSON value from the passed argument. */
/***********************************************************************/
static
PJVAL
MakeValue
(
PGLOBAL
g
,
UDF_ARGS
*
args
,
int
i
)
{
char
*
sap
=
args
->
args
[
i
];
PJVAL
jvp
=
new
(
g
)
JVALUE
;
if
(
sap
)
switch
(
args
->
arg_type
[
i
])
{
case
STRING_RESULT
:
if
(
args
->
lengths
[
i
])
{
if
(
IsJson
(
args
,
i
))
jvp
->
SetValue
(
ParseJson
(
g
,
sap
,
args
->
lengths
[
i
],
0
));
else
jvp
->
SetString
(
g
,
MakePSZ
(
g
,
args
,
i
));
}
// endif str
break
;
case
INT_RESULT
:
jvp
->
SetInteger
(
g
,
*
(
int
*
)
sap
);
break
;
case
REAL_RESULT
:
jvp
->
SetFloat
(
g
,
*
(
double
*
)
sap
);
break
;
case
DECIMAL_RESULT
:
jvp
->
SetFloat
(
g
,
atof
(
MakePSZ
(
g
,
args
,
i
)));
break
;
case
TIME_RESULT
:
case
ROW_RESULT
:
case
IMPOSSIBLE_RESULT
:
default:
break
;
}
// endswitch arg_type
return
jvp
;
}
// end of MakeValue
/***********************************************************************/
/* Make a Json value containing the parameter. */
/***********************************************************************/
my_bool
Json_Value_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
;
if
(
args
->
arg_count
>
1
)
{
strcpy
(
message
,
"Json_Value cannot accept more than 1 argument"
);
return
true
;
}
else
CalcLen
(
args
,
false
,
reslen
,
memlen
);
return
JsonInit
(
initid
,
message
,
reslen
,
memlen
);
}
// end of Json_Value_init
char
*
Json_Value
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
str
;
PJVAL
jvp
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PlugSubSet
(
g
,
g
->
Sarea
,
g
->
Sarea_Size
);
jvp
=
MakeValue
(
g
,
args
,
0
);
if
(
!
(
str
=
Serialize
(
g
,
jvp
,
NULL
,
0
)))
str
=
strcpy
(
result
,
g
->
Message
);
*
res_length
=
strlen
(
str
);
return
str
;
}
// end of Json_Value
void
Json_Value_deinit
(
UDF_INIT
*
initid
)
{
PlugExit
((
PGLOBAL
)
initid
->
ptr
);
}
// end of Json_Value_deinit
/***********************************************************************/
/* Make a Json array containing all the parameters. */
/***********************************************************************/
my_bool
Json_Array_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
;
CalcLen
(
args
,
false
,
reslen
,
memlen
);
return
JsonInit
(
initid
,
message
,
reslen
,
memlen
);
}
// end of Json_Array_init
char
*
Json_Array
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
str
;
uint
i
;
PJAR
arp
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PlugSubSet
(
g
,
g
->
Sarea
,
g
->
Sarea_Size
);
arp
=
new
(
g
)
JARRAY
;
for
(
i
=
0
;
i
<
args
->
arg_count
;
i
++
)
arp
->
AddValue
(
g
,
MakeValue
(
g
,
args
,
i
));
arp
->
InitArray
(
g
);
if
(
!
(
str
=
Serialize
(
g
,
arp
,
NULL
,
0
)))
str
=
strcpy
(
result
,
g
->
Message
);
*
res_length
=
strlen
(
str
);
return
str
;
}
// end of Json_Array
void
Json_Array_deinit
(
UDF_INIT
*
initid
)
{
PlugExit
((
PGLOBAL
)
initid
->
ptr
);
}
// end of Json_Array_deinit
/***********************************************************************/
/* Make a Json Oject containing all the parameters. */
/***********************************************************************/
my_bool
Json_Object_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
;
CalcLen
(
args
,
true
,
reslen
,
memlen
);
return
JsonInit
(
initid
,
message
,
reslen
,
memlen
);
}
// end of Json_Object_init
char
*
Json_Object
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
str
;
uint
i
;
PJOB
objp
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PlugSubSet
(
g
,
g
->
Sarea
,
g
->
Sarea_Size
);
objp
=
new
(
g
)
JOBJECT
;
for
(
i
=
0
;
i
<
args
->
arg_count
;
i
++
)
objp
->
SetValue
(
g
,
MakeValue
(
g
,
args
,
i
),
MakeKey
(
g
,
args
,
i
));
if
(
!
(
str
=
Serialize
(
g
,
objp
,
NULL
,
0
)))
str
=
strcpy
(
result
,
g
->
Message
);
*
res_length
=
strlen
(
str
);
return
str
;
}
// end of Json_Object
void
Json_Object_deinit
(
UDF_INIT
*
initid
)
{
PlugExit
((
PGLOBAL
)
initid
->
ptr
);
}
// end of Json_Object_deinit
/***********************************************************************/
/* Make a Json array from values comming from rows. */
/***********************************************************************/
my_bool
Json_Array_Grp_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
,
n
=
10
;
if
(
args
->
arg_count
!=
1
)
{
strcpy
(
message
,
"Json_Array_Grp can only accept 1 argument"
);
return
true
;
}
else
CalcLen
(
args
,
false
,
reslen
,
memlen
);
reslen
*=
n
;
memlen
*=
n
;
if
(
JsonInit
(
initid
,
message
,
reslen
,
memlen
))
return
true
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PlugSubSet
(
g
,
g
->
Sarea
,
g
->
Sarea_Size
);
g
->
Activityp
=
(
PACTIVITY
)
new
(
g
)
JARRAY
;
return
false
;
}
// end of Json_Array_Grp_init
void
Json_Array_Grp_add
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
is_null
,
char
*
error
)
{
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PJAR
arp
=
(
PJAR
)
g
->
Activityp
;
arp
->
AddValue
(
g
,
MakeValue
(
g
,
args
,
0
));
}
// end of Json_Array_Grp_add
char
*
Json_Array_Grp
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
str
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PJAR
arp
=
(
PJAR
)
g
->
Activityp
;
arp
->
InitArray
(
g
);
if
(
!
(
str
=
Serialize
(
g
,
arp
,
NULL
,
0
)))
str
=
strcpy
(
result
,
g
->
Message
);
*
res_length
=
strlen
(
str
);
return
str
;
}
// end of Json_Array_Grp
void
Json_Array_Grp_clear
(
UDF_INIT
*
initid
,
char
*
is_null
,
char
*
error
)
{
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PlugSubSet
(
g
,
g
->
Sarea
,
g
->
Sarea_Size
);
g
->
Activityp
=
(
PACTIVITY
)
new
(
g
)
JARRAY
;
}
// end of Json_Array_Grp_clear
void
Json_Array_Grp_deinit
(
UDF_INIT
*
initid
)
{
PlugExit
((
PGLOBAL
)
initid
->
ptr
);
}
// end of Json_Array_Grp_deinit
/***********************************************************************/
/* Make a Json object from values comming from rows. */
/***********************************************************************/
my_bool
Json_Object_Grp_init
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
message
)
{
unsigned
long
reslen
,
memlen
,
n
=
10
;
if
(
args
->
arg_count
!=
2
)
{
strcpy
(
message
,
"Json_Array_Grp can only accept 2 argument"
);
return
true
;
}
else
CalcLen
(
args
,
true
,
reslen
,
memlen
);
reslen
*=
n
;
memlen
*=
n
;
if
(
JsonInit
(
initid
,
message
,
reslen
,
memlen
))
return
true
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PlugSubSet
(
g
,
g
->
Sarea
,
g
->
Sarea_Size
);
g
->
Activityp
=
(
PACTIVITY
)
new
(
g
)
JOBJECT
;
return
false
;
}
// end of Json_Object_Grp_init
void
Json_Object_Grp_add
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
is_null
,
char
*
error
)
{
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PJOB
objp
=
(
PJOB
)
g
->
Activityp
;
objp
->
SetValue
(
g
,
MakeValue
(
g
,
args
,
0
),
MakePSZ
(
g
,
args
,
1
));
}
// end of Json_Object_Grp_add
char
*
Json_Object_Grp
(
UDF_INIT
*
initid
,
UDF_ARGS
*
args
,
char
*
result
,
unsigned
long
*
res_length
,
char
*
is_null
,
char
*
error
)
{
char
*
str
;
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PJOB
objp
=
(
PJOB
)
g
->
Activityp
;
if
(
!
(
str
=
Serialize
(
g
,
objp
,
NULL
,
0
)))
str
=
strcpy
(
result
,
g
->
Message
);
*
res_length
=
strlen
(
str
);
return
str
;
}
// end of Json_Object_Grp
void
Json_Object_Grp_clear
(
UDF_INIT
*
initid
,
char
*
is_null
,
char
*
error
)
{
PGLOBAL
g
=
(
PGLOBAL
)
initid
->
ptr
;
PlugSubSet
(
g
,
g
->
Sarea
,
g
->
Sarea_Size
);
g
->
Activityp
=
(
PACTIVITY
)
new
(
g
)
JOBJECT
;
}
// end of Json_Object_Grp_clear
void
Json_Object_Grp_deinit
(
UDF_INIT
*
initid
)
{
PlugExit
((
PGLOBAL
)
initid
->
ptr
);
}
// end of Json_Object_Grp_deinit
storage/connect/myconn.cpp
View file @
56114a41
...
...
@@ -51,7 +51,8 @@
#define DLL_EXPORT // Items are exported from this DLL
#include "myconn.h"
extern
"C"
int
zconv
;
//extern "C" int zconv;
int
GetConvSize
(
void
);
extern
MYSQL_PLUGIN_IMPORT
uint
mysqld_port
;
extern
MYSQL_PLUGIN_IMPORT
char
*
mysqld_unix_port
;
...
...
@@ -265,7 +266,7 @@ PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db,
return
NULL
;
}
else
if
(
type
==
TYPE_STRING
)
{
if
(
v
==
'X'
)
{
len
=
zconv
;
len
=
GetConvSize
()
;
sprintf
(
g
->
Message
,
"Column %s converted to varchar(%d)"
,
colname
,
len
);
PushWarning
(
g
,
thd
);
...
...
storage/connect/mysql-test/connect/r/json.result
View file @
56114a41
...
...
@@ -89,8 +89,8 @@ ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher L
UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab';
SELECT * FROM t1 WHERE ISBN = '9782212090819';
ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
9782212090819 fr applications
Jean-Christoph
e Bernadac Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications
Philippe
Knab Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications
Philipp
e Bernadac Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications
Franois
Knab Construire une application XML Eyrolles Paris 1999
#
# To add an author a new table must be created
#
...
...
@@ -104,8 +104,8 @@ William J. Pardi
INSERT INTO t2 VALUES('Charles','Dickens');
SELECT * FROM t1;
ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
9782212090819 fr applications
Jean-Christoph
e Bernadac Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications
Philippe
Knab Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications
Philipp
e Bernadac Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications
Franois
Knab Construire une application XML Eyrolles Paris 1999
9782840825685 fr applications William J. Pardi XML en Action adapt de l'anglais par James Guerin Microsoft Press Paris 1999
9782840825685 fr applications Charles Dickens XML en Action adapt de l'anglais par James Guerin Microsoft Press Paris 1999
DROP TABLE t1;
...
...
@@ -127,11 +127,11 @@ line
"SUBJECT": "applications",
"AUTHOR": [
{
"FIRSTNAME": "
Jean-Christoph
e",
"FIRSTNAME": "
Philipp
e",
"LASTNAME": "Bernadac"
},
{
"FIRSTNAME": "
Philippe
",
"FIRSTNAME": "
Franois
",
"LASTNAME": "Knab"
}
],
...
...
@@ -192,7 +192,7 @@ Janet 4 Car 17.00
Janet 5 Beer+Car+Beer+Food 57.00
DROP TABLE t1;
#
#
Cannot
be fully expanded
#
Now it can
be fully expanded
#
CREATE TABLE t1 (
WHO CHAR(12),
...
...
@@ -201,7 +201,31 @@ WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:WHAT',
AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT')
ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.jsn';
SELECT * FROM t1;
ERROR HY000: Got error 174 'Cannot expand more than one array' from CONNECT
WHO WEEK WHAT AMOUNT
Joe 3 Beer 18.00
Joe 3 Food 12.00
Joe 3 Food 19.00
Joe 3 Car 20.00
Joe 4 Beer 19.00
Joe 4 Beer 16.00
Joe 4 Food 17.00
Joe 4 Food 17.00
Joe 4 Beer 14.00
Joe 5 Beer 14.00
Joe 5 Food 12.00
Beth 3 Beer 16.00
Beth 4 Food 17.00
Beth 4 Beer 15.00
Beth 5 Food 12.00
Beth 5 Beer 20.00
Janet 3 Car 19.00
Janet 3 Food 18.00
Janet 3 Beer 18.00
Janet 4 Car 17.00
Janet 5 Beer 14.00
Janet 5 Car 12.00
Janet 5 Beer 19.00
Janet 5 Food 12.00
DROP TABLE t1;
#
# Expand expense in 3 one week tables
...
...
storage/connect/mysql-test/connect/t/json.test
View file @
56114a41
...
...
@@ -128,7 +128,7 @@ SELECT * FROM t1;
DROP
TABLE
t1
;
--
echo
#
--
echo
#
Cannot
be fully expanded
--
echo
#
Now it can
be fully expanded
--
echo
#
CREATE
TABLE
t1
(
WHO
CHAR
(
12
),
...
...
@@ -136,7 +136,7 @@ WEEK INT(2) FIELD_FORMAT='WEEK:[X]:NUMBER',
WHAT
CHAR
(
32
)
FIELD_FORMAT
=
'WEEK:[X]:EXPENSE:[X]:WHAT'
,
AMOUNT
DOUBLE
(
8
,
2
)
FIELD_FORMAT
=
'WEEK:[X]:EXPENSE:[X]:AMOUNT'
)
ENGINE
=
CONNECT
TABLE_TYPE
=
JSON
FILE_NAME
=
'expense.jsn'
;
--
error
ER_GET_ERRMSG
#
--error ER_GET_ERRMSG
SELECT
*
FROM
t1
;
DROP
TABLE
t1
;
...
...
storage/connect/myutil.cpp
View file @
56114a41
...
...
@@ -26,14 +26,16 @@
#include "myutil.h"
#define DLL_EXPORT // Items are exported from this DLL
extern
"C"
int
xconv
;
//extern "C" int xconv;
TYPCONV
GetTypeConv
(
void
);
/************************************************************************/
/* Convert from MySQL type name to PlugDB type number */
/************************************************************************/
int
MYSQLtoPLG
(
char
*
typname
,
char
*
var
)
{
int
type
;
int
type
;
TYPCONV
xconv
=
GetTypeConv
();
if
(
!
stricmp
(
typname
,
"int"
)
||
!
stricmp
(
typname
,
"mediumint"
)
||
!
stricmp
(
typname
,
"integer"
))
...
...
@@ -57,13 +59,13 @@ int MYSQLtoPLG(char *typname, char *var)
type
=
TYPE_TINY
;
else
if
(
!
stricmp
(
typname
,
"text"
)
&&
var
)
{
switch
(
xconv
)
{
case
1
:
case
TPC_YES
:
type
=
TYPE_STRING
;
*
var
=
'X'
;
break
;
case
2
:
case
TPC_SKIP
:
*
var
=
'K'
;
default:
default:
// TPC_NO
type
=
TYPE_ERROR
;
}
// endswitch xconv
...
...
@@ -88,7 +90,7 @@ int MYSQLtoPLG(char *typname, char *var)
}
else
if
(
type
==
TYPE_STRING
&&
!
stricmp
(
typname
,
"varchar"
))
// This is to make the difference between CHAR and VARCHAR
*
var
=
'V'
;
else
if
(
type
==
TYPE_ERROR
&&
xconv
==
2
)
else
if
(
type
==
TYPE_ERROR
&&
xconv
==
TPC_SKIP
)
*
var
=
'K'
;
else
*
var
=
0
;
...
...
@@ -174,7 +176,7 @@ const char *PLGtoMYSQLtype(int type, bool dbf, char v)
/************************************************************************/
int
MYSQLtoPLG
(
int
mytype
,
char
*
var
)
{
int
type
;
int
type
,
xconv
=
GetTypeConv
()
;
switch
(
mytype
)
{
case
MYSQL_TYPE_SHORT
:
...
...
@@ -221,7 +223,7 @@ int MYSQLtoPLG(int mytype, char *var)
case
MYSQL_TYPE_LONG_BLOB
:
if
(
var
)
{
switch
(
xconv
)
{
case
1
:
case
TPC_YES
:
if
(
*
var
!=
'B'
)
{
// This is a TEXT column
type
=
TYPE_STRING
;
...
...
@@ -230,9 +232,9 @@ int MYSQLtoPLG(int mytype, char *var)
type
=
TYPE_ERROR
;
break
;
case
2
:
case
TPC_SKIP
:
*
var
=
'K'
;
// Skip
default:
default:
// TPC_NO
type
=
TYPE_ERROR
;
}
// endswitch xconv
...
...
storage/connect/odbccat.h
View file @
56114a41
...
...
@@ -2,6 +2,14 @@
#define DEFAULT_LOGIN_TIMEOUT -1 // means do not set
#define DEFAULT_QUERY_TIMEOUT -1 // means do not set
typedef
struct
odbc_parms
{
char
*
User
;
// User connect info
char
*
Pwd
;
// Password connect info
int
Cto
;
// Connect timeout
int
Qto
;
// Query timeout
bool
UseCnc
;
// Use SQLConnect (!SQLDriverConnect)
}
ODBCPARM
,
*
POPARM
;
/***********************************************************************/
/* ODBC catalog function prototypes. */
/***********************************************************************/
...
...
@@ -10,8 +18,8 @@ char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
#endif // PROMPT_OK
PQRYRES
ODBCDataSources
(
PGLOBAL
g
,
int
maxres
,
bool
info
);
PQRYRES
ODBCColumns
(
PGLOBAL
g
,
char
*
dsn
,
char
*
db
,
char
*
table
,
char
*
colpat
,
int
maxres
,
int
cto
,
int
qto
,
bool
info
);
PQRYRES
ODBCSrcCols
(
PGLOBAL
g
,
char
*
dsn
,
char
*
src
,
int
cto
,
int
qto
);
char
*
colpat
,
int
maxres
,
bool
info
,
POPARM
sop
);
PQRYRES
ODBCSrcCols
(
PGLOBAL
g
,
char
*
dsn
,
char
*
src
,
POPARM
sop
);
PQRYRES
ODBCTables
(
PGLOBAL
g
,
char
*
dsn
,
char
*
db
,
char
*
tabpat
,
int
maxres
,
int
cto
,
int
qto
,
bool
info
);
int
maxres
,
bool
info
,
POPARM
sop
);
PQRYRES
ODBCDrivers
(
PGLOBAL
g
,
int
maxres
,
bool
info
);
storage/connect/odbconn.cpp
View file @
56114a41
...
...
@@ -37,8 +37,8 @@
#include "xobject.h"
//#include "kindex.h"
#include "xtable.h"
#include "tabodbc.h"
#include "odbccat.h"
#include "tabodbc.h"
#include "plgcnx.h" // For DB types
#include "resource.h"
#include "valblk.h"
...
...
@@ -53,6 +53,8 @@
extern
"C"
HINSTANCE
s_hModule
;
// Saved module handle
#endif // WIN32
int
GetConvSize
();
/***********************************************************************/
/* Some macro's (should be defined elsewhere to be more accessible) */
/***********************************************************************/
...
...
@@ -122,7 +124,7 @@ int TranslateSQLType(int stp, int prec, int& len, char& v)
case
SQL_LONGVARCHAR
:
// (-1)
v
=
'V'
;
type
=
TYPE_STRING
;
len
=
MY_MIN
(
abs
(
len
),
256
);
len
=
MY_MIN
(
abs
(
len
),
GetConvSize
()
);
break
;
case
SQL_NUMERIC
:
// 2
case
SQL_DECIMAL
:
// 3
...
...
@@ -291,7 +293,7 @@ static void ResetNullValues(CATPARM *cap)
/* of an ODBC table that will be retrieved by GetData commands. */
/***********************************************************************/
PQRYRES
ODBCColumns
(
PGLOBAL
g
,
char
*
dsn
,
char
*
db
,
char
*
table
,
char
*
colpat
,
int
maxres
,
int
cto
,
int
qto
,
bool
info
)
char
*
colpat
,
int
maxres
,
bool
info
,
POPARM
sop
)
{
int
buftyp
[]
=
{
TYPE_STRING
,
TYPE_STRING
,
TYPE_STRING
,
TYPE_STRING
,
TYPE_SHORT
,
TYPE_STRING
,
TYPE_INT
,
TYPE_INT
,
...
...
@@ -310,10 +312,8 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
/************************************************************************/
if
(
!
info
)
{
ocp
=
new
(
g
)
ODBConn
(
g
,
NULL
);
ocp
->
SetLoginTimeout
((
DWORD
)
cto
);
ocp
->
SetQueryTimeout
((
DWORD
)
qto
);
if
(
ocp
->
Open
(
dsn
,
10
)
<
1
)
// openReadOnly + noODBCdialog
if
(
ocp
->
Open
(
dsn
,
sop
,
10
)
<
1
)
// openReadOnly + noODBCdialog
return
NULL
;
if
(
table
&&
!
strchr
(
table
,
'%'
))
{
...
...
@@ -342,7 +342,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
}
// endif ocp
if
(
trace
)
htrc
(
"ODBCColumns: max=%d len=%d,%d,%d
\n
"
,
htrc
(
"ODBCColumns: max=%d len=%d,%d,%d
,%d
\n
"
,
maxres
,
length
[
0
],
length
[
1
],
length
[
2
],
length
[
3
]);
/************************************************************************/
...
...
@@ -388,12 +388,13 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
/* ODBCSrcCols: constructs the result blocks containing the */
/* description of all the columns of a Srcdef option. */
/**************************************************************************/
PQRYRES
ODBCSrcCols
(
PGLOBAL
g
,
char
*
dsn
,
char
*
src
,
int
cto
,
int
qto
)
PQRYRES
ODBCSrcCols
(
PGLOBAL
g
,
char
*
dsn
,
char
*
src
,
POPARM
sop
)
{
ODBConn
*
ocp
=
new
(
g
)
ODBConn
(
g
,
NULL
);
ocp
->
SetLoginTimeout
((
DWORD
)
cto
);
ocp
->
SetQueryTimeout
((
DWORD
)
qto
);
if
(
ocp
->
Open
(
dsn
,
sop
,
10
)
<
1
)
// openReadOnly + noOdbcDialog
return
NULL
;
return
ocp
->
GetMetaData
(
g
,
dsn
,
src
);
}
// end of ODBCSrcCols
...
...
@@ -574,7 +575,7 @@ PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info)
/* an ODBC database that will be retrieved by GetData commands. */
/**************************************************************************/
PQRYRES
ODBCTables
(
PGLOBAL
g
,
char
*
dsn
,
char
*
db
,
char
*
tabpat
,
int
maxres
,
int
cto
,
int
qto
,
bool
info
)
int
maxres
,
bool
info
,
POPARM
sop
)
{
int
buftyp
[]
=
{
TYPE_STRING
,
TYPE_STRING
,
TYPE_STRING
,
TYPE_STRING
,
TYPE_STRING
};
...
...
@@ -594,10 +595,8 @@ PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
/* Open the connection with the ODBC data source. */
/**********************************************************************/
ocp
=
new
(
g
)
ODBConn
(
g
,
NULL
);
ocp
->
SetLoginTimeout
((
DWORD
)
cto
);
ocp
->
SetQueryTimeout
((
DWORD
)
qto
);
if
(
ocp
->
Open
(
dsn
,
2
)
<
1
)
// 2 is openReadOnly
if
(
ocp
->
Open
(
dsn
,
sop
,
2
)
<
1
)
// 2 is openReadOnly
return
NULL
;
if
(
!
maxres
)
...
...
@@ -925,11 +924,14 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
m_Catver
=
(
tdbp
)
?
tdbp
->
Catver
:
0
;
m_Rows
=
0
;
m_Connect
=
NULL
;
m_User
=
NULL
;
m_Pwd
=
NULL
;
m_Updatable
=
true
;
m_Transact
=
false
;
m_Scrollable
=
(
tdbp
)
?
tdbp
->
Scrollable
:
false
;
m_First
=
true
;
m_Full
=
false
;
m_UseCnc
=
false
;
m_IDQuoteChar
[
0
]
=
'"'
;
m_IDQuoteChar
[
1
]
=
0
;
//*m_ErrMsg = '\0';
...
...
@@ -1061,7 +1063,7 @@ void ODBConn::OnSetOptions(HSTMT hstmt)
/***********************************************************************/
/* Open: connect to a data source. */
/***********************************************************************/
int
ODBConn
::
Open
(
PSZ
ConnectString
,
DWORD
options
)
int
ODBConn
::
Open
(
PSZ
ConnectString
,
POPARM
sop
,
DWORD
options
)
{
PGLOBAL
&
g
=
m_G
;
//ASSERT_VALID(this);
...
...
@@ -1070,6 +1072,11 @@ int ODBConn::Open(PSZ ConnectString, DWORD options)
m_Updatable
=
!
(
options
&
openReadOnly
);
m_Connect
=
ConnectString
;
m_User
=
sop
->
User
;
m_Pwd
=
sop
->
Pwd
;
m_LoginTimeout
=
sop
->
Cto
;
m_QueryTimeout
=
sop
->
Qto
;
m_UseCnc
=
sop
->
UseCnc
;
// Allocate the HDBC and make connection
try
{
...
...
@@ -1078,10 +1085,14 @@ int ODBConn::Open(PSZ ConnectString, DWORD options)
AllocConnect
(
options
);
/*ver = GetStringInfo(SQL_ODBC_VER);*/
if
(
Connect
(
options
))
{
strcpy
(
g
->
Message
,
MSG
(
CONNECT_CANCEL
));
return
0
;
}
// endif
if
(
!
m_UseCnc
)
{
if
(
DriverConnect
(
options
))
{
strcpy
(
g
->
Message
,
MSG
(
CONNECT_CANCEL
));
return
0
;
}
// endif
}
else
// Connect using SQLConnect
Connect
();
/*ver = GetStringInfo(SQL_DRIVER_ODBC_VER);*/
// Verify support for required functionality and cache info
...
...
@@ -1163,10 +1174,27 @@ void ODBConn::AllocConnect(DWORD Options)
return
;
}
// end of AllocConnect
/***********************************************************************/
/* Connect to data source using SQLConnect. */
/***********************************************************************/
void
ODBConn
::
Connect
(
void
)
{
SQLRETURN
rc
;
SQLSMALLINT
ul
=
(
m_User
?
SQL_NTS
:
0
);
SQLSMALLINT
pl
=
(
m_Pwd
?
SQL_NTS
:
0
);
rc
=
SQLConnect
(
m_hdbc
,
(
SQLCHAR
*
)
m_Connect
,
SQL_NTS
,
(
SQLCHAR
*
)
m_User
,
ul
,
(
SQLCHAR
*
)
m_Pwd
,
pl
);
if
(
!
Check
(
rc
))
ThrowDBX
(
rc
,
"SQLConnect"
);
}
// end of Connect
/***********************************************************************/
/* Connect to data source using SQLDriverConnect. */
/***********************************************************************/
bool
ODBConn
::
Connect
(
DWORD
Options
)
bool
ODBConn
::
Driver
Connect
(
DWORD
Options
)
{
RETCODE
rc
;
SWORD
nResult
;
...
...
@@ -1213,7 +1241,7 @@ bool ODBConn::Connect(DWORD Options)
// All done
return
false
;
}
// end of Connect
}
// end of
Driver
Connect
void
ODBConn
::
VerifyConnect
()
{
...
...
@@ -1712,6 +1740,8 @@ bool ODBConn::BindParam(ODBCCOL *colp)
strcpy
(
m_G
->
Message
,
x
->
GetErrorMessage
(
0
));
colsize
=
colp
->
GetPrecision
();
sqlt
=
GetSQLType
(
buftype
);
dec
=
IsTypeChar
(
buftype
)
?
0
:
colp
->
GetScale
();
nul
=
SQL_NULLABLE_UNKNOWN
;
}
// end try/catch
buf
=
colp
->
GetBuffer
(
0
);
...
...
@@ -1865,9 +1895,6 @@ PQRYRES ODBConn::GetMetaData(PGLOBAL g, char *dsn, char *src)
RETCODE
rc
;
HSTMT
hstmt
;
if
(
Open
(
dsn
,
10
)
<
1
)
// openReadOnly + noOdbcDialog
return
NULL
;
try
{
rc
=
SQLAllocStmt
(
m_hdbc
,
&
hstmt
);
...
...
storage/connect/odbconn.h
View file @
56114a41
...
...
@@ -119,7 +119,7 @@ class ODBConn : public BLOCK {
noOdbcDialog
=
0x0008
,
// Don't display ODBC Connect dialog
forceOdbcDialog
=
0x0010
};
// Always display ODBC connect dialog
int
Open
(
PSZ
ConnectString
,
DWORD
Options
=
0
);
int
Open
(
PSZ
ConnectString
,
POPARM
sop
,
DWORD
Options
=
0
);
int
Rewind
(
char
*
sql
,
ODBCCOL
*
tocols
);
void
Close
(
void
);
PQRYRES
AllocateResult
(
PGLOBAL
g
);
...
...
@@ -135,8 +135,10 @@ class ODBConn : public BLOCK {
public:
// Operations
void
SetLoginTimeout
(
DWORD
sec
)
{
m_LoginTimeout
=
sec
;}
void
SetQueryTimeout
(
DWORD
sec
)
{
m_QueryTimeout
=
sec
;}
//void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
//void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
//void SetUserName(PSZ user) {m_User = user;}
//void SetUserPwd(PSZ pwd) {m_Pwd = pwd;}
int
GetResultSize
(
char
*
sql
,
ODBCCOL
*
colp
);
int
ExecDirectSQL
(
char
*
sql
,
ODBCCOL
*
tocols
);
int
Fetch
(
void
);
...
...
@@ -155,7 +157,7 @@ class ODBConn : public BLOCK {
// Implementation
public:
//
virtual ~ODBConn();
//virtual ~ODBConn();
// ODBC operations
protected:
...
...
@@ -163,7 +165,8 @@ class ODBConn : public BLOCK {
void
ThrowDBX
(
RETCODE
rc
,
PSZ
msg
,
HSTMT
hstmt
=
SQL_NULL_HSTMT
);
void
ThrowDBX
(
PSZ
msg
);
void
AllocConnect
(
DWORD
dwOptions
);
bool
Connect
(
DWORD
Options
);
void
Connect
(
void
);
bool
DriverConnect
(
DWORD
Options
);
void
VerifyConnect
(
void
);
void
GetConnectInfo
(
void
);
void
Free
(
void
);
...
...
@@ -185,11 +188,14 @@ class ODBConn : public BLOCK {
DWORD
m_RowsetSize
;
char
m_IDQuoteChar
[
2
];
PSZ
m_Connect
;
PSZ
m_User
;
PSZ
m_Pwd
;
int
m_Catver
;
int
m_Rows
;
bool
m_Updatable
;
bool
m_Transact
;
bool
m_Scrollable
;
bool
m_UseCnc
;
bool
m_First
;
bool
m_Full
;
};
// end of ODBConn class definition
storage/connect/tabdos.h
View file @
56114a41
...
...
@@ -222,6 +222,7 @@ class DllExport DOSCOL : public COLBLK {
virtual
PVBLK
GetDval
(
void
)
{
return
Dval
;}
// Methods
using
COLBLK
::
Print
;
virtual
bool
VarSize
(
void
);
virtual
bool
SetBuffer
(
PGLOBAL
g
,
PVAL
value
,
bool
ok
,
bool
check
);
virtual
void
ReadColumn
(
PGLOBAL
g
);
...
...
storage/connect/tabjson.cpp
View file @
56114a41
/************* tabjson C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: tab
xjson Version 1.0
*/
/* PROGRAM NAME: tab
json Version 1.0
*/
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */
/* This program are the JSON class DB execution routines. */
/***********************************************************************/
...
...
@@ -119,12 +119,12 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
Fpos
=
-
1
;
Spos
=
N
=
0
;
Limit
=
tdp
->
Limit
;
NextSame
=
0
;
SameRow
=
0
;
Xval
=
-
1
;
Pretty
=
tdp
->
Pretty
;
Strict
=
tdp
->
Strict
;
NextSame
=
false
;
Comma
=
false
;
SameRow
=
0
;
Xval
=
-
1
;
}
// end of TDBJSN standard constructor
TDBJSN
::
TDBJSN
(
TDBJSN
*
tdbp
)
:
TDBDOS
(
NULL
,
tdbp
)
...
...
@@ -137,12 +137,12 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
Spos
=
tdbp
->
Spos
;
N
=
tdbp
->
N
;
Limit
=
tdbp
->
Limit
;
Pretty
=
tdbp
->
Pretty
;
Strict
=
tdbp
->
Strict
;
NextSame
=
tdbp
->
NextSame
;
Comma
=
tdbp
->
Comma
;
SameRow
=
tdbp
->
SameRow
;
Xval
=
tdbp
->
Xval
;
Pretty
=
tdbp
->
Pretty
;
Strict
=
tdbp
->
Strict
;
Comma
=
tdbp
->
Comma
;
}
// end of TDBJSN copy constructor
// Used for update
...
...
@@ -221,14 +221,9 @@ bool TDBJSN::OpenDB(PGLOBAL g)
/*******************************************************************/
/* Table already open replace it at its beginning. */
/*******************************************************************/
for
(
PJCOL
cp
=
(
PJCOL
)
Columns
;
cp
;
cp
=
(
PJCOL
)
cp
->
GetNext
())
{
cp
->
Nx
=
0
;
cp
->
Arp
=
NULL
;
}
// endfor cp
Fpos
=
-
1
;
Spos
=
0
;
NextSame
=
false
;
NextSame
=
0
;
SameRow
=
0
;
}
else
{
/*******************************************************************/
...
...
@@ -292,7 +287,8 @@ int TDBJSN::ReadDB(PGLOBAL g)
N
++
;
if
(
NextSame
)
{
SameRow
++
;
SameRow
=
NextSame
;
NextSame
=
0
;
return
RC_OK
;
}
else
if
((
rc
=
TDBDOS
::
ReadDB
(
g
))
==
RC_OK
)
if
(
!
IsRead
()
&&
((
rc
=
ReadBuffer
(
g
))
!=
RC_OK
))
{
...
...
@@ -333,21 +329,20 @@ int TDBJSN::ReadDB(PGLOBAL g)
}
// end of PrepareWriting
/* ----------------------------
- JSNCOL -
------------------------------ */
/* ----------------------------
JSONCOL
------------------------------ */
/***********************************************************************/
/* JS
NCOL public constructor.
*/
/* JS
ONCOL public constructor.
*/
/***********************************************************************/
JSONCOL
::
JSONCOL
(
PGLOBAL
g
,
PCOLDEF
cdp
,
PTDB
tdbp
,
PCOL
cprec
,
int
i
)
:
DOSCOL
(
g
,
cdp
,
tdbp
,
cprec
,
i
,
"DOS"
)
{
Tjp
=
(
TDBJSN
*
)(
tdbp
->
GetOrig
()
?
tdbp
->
GetOrig
()
:
tdbp
);
Arp
=
NULL
;
Jpath
=
cdp
->
GetFmt
();
MulVal
=
NULL
;
Nodes
=
NULL
;
Nod
=
Nx
=
0
;
Ival
=
-
1
;
Nod
=
0
;
Xnod
=
-
1
;
Xpd
=
false
;
Parsed
=
false
;
}
// end of JSONCOL constructor
...
...
@@ -359,13 +354,11 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
JSONCOL
::
JSONCOL
(
JSONCOL
*
col1
,
PTDB
tdbp
)
:
DOSCOL
(
col1
,
tdbp
)
{
Tjp
=
col1
->
Tjp
;
Arp
=
col1
->
Arp
;
Jpath
=
col1
->
Jpath
;
MulVal
=
col1
->
MulVal
;
Nodes
=
col1
->
Nodes
;
Nod
=
col1
->
Nod
;
Ival
=
col1
->
Ival
;
Nx
=
col1
->
Nx
;
Xnod
=
col1
->
Xnod
;
Xpd
=
col1
->
Xpd
;
Parsed
=
col1
->
Parsed
;
}
// end of JSONCOL copy constructor
...
...
@@ -387,17 +380,16 @@ bool JSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
}
// end of SetBuffer
/***********************************************************************/
/*
Analyse array processing options.
*/
/*
Check whether this object is expanded.
*/
/***********************************************************************/
bool
JSONCOL
::
CheckExpand
(
PGLOBAL
g
,
int
i
,
PSZ
nm
,
bool
b
)
{
if
(
Tjp
->
Xcol
&&
nm
&&
!
strcmp
(
nm
,
Tjp
->
Xcol
)
&&
(
Tjp
->
Xval
<
0
||
Tjp
->
Xval
==
i
)
)
{
if
(
(
Tjp
->
Xcol
&&
nm
&&
!
strcmp
(
nm
,
Tjp
->
Xcol
)
&&
(
Tjp
->
Xval
<
0
||
Tjp
->
Xval
==
i
))
||
Xpd
)
{
Xpd
=
true
;
// Expandable object
Nodes
[
i
].
Op
=
OP_XX
;
Tjp
->
Xval
=
i
;
Nodes
[
i
].
Op
=
OP_EXP
;
}
else
if
(
b
)
{
strcpy
(
g
->
Message
,
"Cannot expand more than one
array
"
);
strcpy
(
g
->
Message
,
"Cannot expand more than one
branch
"
);
return
true
;
}
// endif Xcol
...
...
@@ -434,7 +426,7 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
// Default specifications
if
(
CheckExpand
(
g
,
i
,
nm
,
false
))
return
true
;
else
if
(
jnp
->
Op
!=
OP_
XX
)
else
if
(
jnp
->
Op
!=
OP_
EXP
)
if
(
!
Value
->
IsTypeNum
())
{
jnp
->
CncVal
=
AllocateValue
(
g
,
(
void
*
)
", "
,
TYPE_STRING
);
jnp
->
Op
=
OP_CNC
;
...
...
@@ -456,13 +448,13 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
case
'*'
:
jnp
->
Op
=
OP_MULT
;
break
;
case
'>'
:
jnp
->
Op
=
OP_MAX
;
break
;
case
'<'
:
jnp
->
Op
=
OP_MIN
;
break
;
case
'#'
:
jnp
->
Op
=
OP_NUM
;
break
;
case
'!'
:
jnp
->
Op
=
OP_SEP
;
break
;
// Average
case
'#'
:
jnp
->
Op
=
OP_NUM
;
break
;
case
'x'
:
case
'X'
:
// Expand this array
if
(
!
Tjp
->
Xcol
&&
nm
)
{
Xpd
=
true
;
jnp
->
Op
=
OP_
XX
;
jnp
->
Op
=
OP_
EXP
;
Tjp
->
Xval
=
i
;
Tjp
->
Xcol
=
nm
;
}
else
if
(
CheckExpand
(
g
,
i
,
nm
,
true
))
...
...
@@ -490,6 +482,38 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
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
);
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
...
...
@@ -533,6 +557,9 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
if
(
SetArrayOptions
(
g
,
p
,
i
,
Nodes
[
i
-
1
].
Key
))
return
true
;
}
else
if
(
*
p
==
'*'
)
{
// Return JSON
Nodes
[
i
].
Op
=
OP_XX
;
}
else
{
Nodes
[
i
].
Key
=
p
;
Nodes
[
i
].
Op
=
OP_EXIST
;
...
...
@@ -545,60 +572,262 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
return
false
;
}
// end of ParseJpath
/***********************************************************************/
/* MakeJson: Serialize the json item and set value to it. */
/***********************************************************************/
PVAL
JSONCOL
::
MakeJson
(
PGLOBAL
g
,
PJSON
jsp
)
{
if
(
Value
->
IsTypeNum
())
{
strcpy
(
g
->
Message
,
"Cannot make Json for a numeric column"
);
Value
->
Reset
();
}
else
Value
->
SetValue_psz
(
Serialize
(
g
,
jsp
,
NULL
,
0
));
return
Value
;
}
// end of MakeJson
/***********************************************************************/
/* SetValue: Set a value from a JVALUE contains. */
/***********************************************************************/
void
JSONCOL
::
SetJsonValue
(
PGLOBAL
g
,
PVAL
vp
,
PJVAL
val
,
int
n
)
{
if
(
val
)
{
if
(
Nodes
[
n
].
Op
==
OP_NUM
)
vp
->
SetValue
(
1
);
else
{
again:
switch
(
val
->
GetValType
())
{
case
TYPE_STRG
:
case
TYPE_INTG
:
case
TYPE_DBL
:
vp
->
SetValue_pval
(
val
->
GetValue
());
break
;
case
TYPE_BOOL
:
if
(
vp
->
IsTypeNum
())
vp
->
SetValue
(
val
->
GetInteger
()
?
1
:
0
);
else
vp
->
SetValue_psz
((
PSZ
)(
val
->
GetInteger
()
?
"true"
:
"false"
));
switch
(
val
->
GetValType
())
{
case
TYPE_STRG
:
case
TYPE_INTG
:
case
TYPE_DBL
:
vp
->
SetValue_pval
(
val
->
GetValue
());
break
;
case
TYPE_BOOL
:
if
(
vp
->
IsTypeNum
())
vp
->
SetValue
(
val
->
GetInteger
()
?
1
:
0
);
else
vp
->
SetValue_psz
((
PSZ
)(
val
->
GetInteger
()
?
"true"
:
"false"
));
break
;
case
TYPE_JAR
:
SetJsonValue
(
g
,
vp
,
val
->
GetArray
()
->
GetValue
(
0
),
n
);
break
;
case
TYPE_JOB
:
// if (!vp->IsTypeNum() || !Strict) {
vp
->
SetValue_psz
(
val
->
GetObject
()
->
GetText
(
g
));
break
;
case
TYPE_JAR
:
val
=
val
->
GetArray
()
->
GetValue
(
0
);
goto
again
;
case
TYPE_JOB
:
if
(
!
vp
->
IsTypeNum
())
{
vp
->
SetValue_psz
(
val
->
GetObject
()
->
GetText
(
g
));
break
;
}
// endif Type
// } // endif Type
default:
vp
->
Reset
();
}
// endswitch Type
}
// endelse
default:
vp
->
Reset
();
}
// endswitch Type
}
else
vp
->
Reset
();
}
// end of SetJsonValue
/***********************************************************************/
/* ReadColumn: */
/***********************************************************************/
void
JSONCOL
::
ReadColumn
(
PGLOBAL
g
)
{
if
(
!
Tjp
->
SameRow
||
Xnod
>=
Tjp
->
SameRow
)
Value
->
SetValue_pval
(
GetColumnValue
(
g
,
Tjp
->
Row
,
0
));
}
// end of ReadColumn
/***********************************************************************/
/* GetColumnValue: */
/***********************************************************************/
PVAL
JSONCOL
::
GetColumnValue
(
PGLOBAL
g
,
PJSON
row
,
int
i
)
{
int
n
=
Nod
-
1
;
bool
expd
=
false
;
PJAR
arp
;
PJVAL
val
=
NULL
;
for
(;
i
<
Nod
&&
row
;
i
++
)
{
if
(
Nodes
[
i
].
Op
==
OP_NUM
)
{
Value
->
SetValue
(
row
->
GetType
()
==
TYPE_JAR
?
row
->
size
()
:
1
);
return
(
Value
);
}
else
if
(
Nodes
[
i
].
Op
==
OP_XX
)
{
return
MakeJson
(
g
,
row
);
}
else
switch
(
row
->
GetType
())
{
case
TYPE_JOB
:
if
(
!
Nodes
[
i
].
Key
)
{
// Expected Array was not there
if
(
i
<
Nod
-
1
)
continue
;
else
val
=
new
(
g
)
JVALUE
(
row
);
}
else
val
=
((
PJOB
)
row
)
->
GetValue
(
Nodes
[
i
].
Key
);
break
;
case
TYPE_JAR
:
arp
=
(
PJAR
)
row
;
if
(
!
Nodes
[
i
].
Key
)
{
if
(
Nodes
[
i
].
Op
!=
OP_NULL
)
{
if
(
Nodes
[
i
].
Rank
)
{
val
=
arp
->
GetValue
(
Nodes
[
i
].
Rank
-
1
);
}
else
if
(
Nodes
[
i
].
Op
==
OP_EXP
)
{
return
ExpandArray
(
g
,
arp
,
i
);
}
else
return
CalculateArray
(
g
,
arp
,
i
);
}
else
val
=
NULL
;
}
else
if
(
i
<
Nod
-
1
)
{
strcpy
(
g
->
Message
,
"Unexpected array"
);
val
=
NULL
;
// Not an expected array
}
else
val
=
arp
->
GetValue
(
0
);
break
;
case
TYPE_JVAL
:
val
=
(
PJVAL
)
row
;
break
;
default:
sprintf
(
g
->
Message
,
"Invalid row JSON type %d"
,
row
->
GetType
());
val
=
NULL
;
}
// endswitch Type
if
(
i
<
Nod
-
1
)
row
=
(
val
)
?
val
->
GetJson
()
:
NULL
;
}
// endfor i
SetJsonValue
(
g
,
Value
,
val
,
n
);
return
Value
;
}
// end of GetColumnValue
/***********************************************************************/
/* ExpandArray: */
/***********************************************************************/
PVAL
JSONCOL
::
ExpandArray
(
PGLOBAL
g
,
PJAR
arp
,
int
n
)
{
int
ars
;
PJVAL
jvp
;
JVALUE
jval
;
ars
=
MY_MIN
(
Tjp
->
Limit
,
arp
->
size
());
if
(
!
(
jvp
=
arp
->
GetValue
(
Nodes
[
n
].
Nx
)))
{
strcpy
(
g
->
Message
,
"Logical error expanding array"
);
longjmp
(
g
->
jumper
[
g
->
jump_level
],
666
);
}
// endif jvp
if
(
n
<
Nod
-
1
&&
jvp
->
GetJson
())
{
jval
.
SetValue
(
GetColumnValue
(
g
,
jvp
->
GetJson
(),
n
+
1
));
jvp
=
&
jval
;
}
// endif n
if
(
n
>=
Tjp
->
NextSame
)
{
if
(
++
Nodes
[
n
].
Nx
==
ars
)
{
Nodes
[
n
].
Nx
=
0
;
Xnod
=
0
;
}
else
Xnod
=
n
;
Tjp
->
NextSame
=
Xnod
;
}
// endif NextSame
SetJsonValue
(
g
,
Value
,
jvp
,
n
);
return
Value
;
}
// end of ExpandArray
/***********************************************************************/
/* CalculateArray: */
/***********************************************************************/
PVAL
JSONCOL
::
CalculateArray
(
PGLOBAL
g
,
PJAR
arp
,
int
n
)
{
int
i
,
ars
,
nv
=
0
,
nextsame
=
Tjp
->
NextSame
;
bool
err
;
OPVAL
op
=
Nodes
[
n
].
Op
;
PVAL
val
[
2
],
vp
=
Nodes
[
n
].
Valp
;
PJVAL
jvrp
,
jvp
;
JVALUE
jval
;
vp
->
Reset
();
ars
=
MY_MIN
(
Tjp
->
Limit
,
arp
->
size
());
for
(
i
=
0
;
i
<
ars
;
i
++
)
{
jvrp
=
arp
->
GetValue
(
i
);
do
{
if
(
n
<
Nod
-
1
&&
jvrp
->
GetJson
())
{
Tjp
->
NextSame
=
nextsame
;
jval
.
SetValue
(
GetColumnValue
(
g
,
jvrp
->
GetJson
(),
n
+
1
));
jvp
=
&
jval
;
}
else
jvp
=
jvrp
;
if
(
!
nv
++
)
{
SetJsonValue
(
g
,
vp
,
jvp
,
n
);
continue
;
}
else
SetJsonValue
(
g
,
MulVal
,
jvp
,
n
);
if
(
!
MulVal
->
IsZero
())
{
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
();
}
// endif Zero
}
while
(
Tjp
->
NextSame
>
nextsame
);
}
// 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
Tjp
->
NextSame
=
nextsame
;
return
vp
;
}
// end of CalculateArray
/***********************************************************************/
/* GetRow: Get the object containing this column. */
/***********************************************************************/
PJSON
JSONCOL
::
GetRow
(
PGLOBAL
g
,
int
mode
)
PJSON
JSONCOL
::
GetRow
(
PGLOBAL
g
)
{
PJVAL
val
;
PJAR
arp
;
PJSON
nwr
,
row
=
Tjp
->
Row
;
for
(
int
i
=
0
;
i
<
Nod
-
1
&&
row
;
i
++
)
{
switch
(
row
->
GetType
())
{
if
(
Nodes
[
i
+
1
].
Op
==
OP_XX
)
break
;
else
switch
(
row
->
GetType
())
{
case
TYPE_JOB
:
if
(
!
Nodes
[
i
].
Key
)
// Expected Array was not there
...
...
@@ -609,21 +838,13 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
case
TYPE_JAR
:
if
(
!
Nodes
[
i
].
Key
)
{
if
(
Nodes
[
i
].
Op
!=
OP_NULL
)
{
Ival
=
i
;
arp
=
(
PJAR
)
row
;
if
(
mode
<
2
)
// First pass
Arp
=
arp
;
if
(
Nodes
[
i
].
Op
!=
OP_XX
)
{
if
(
Nodes
[
i
].
Rank
)
val
=
arp
->
GetValue
(
Nodes
[
i
].
Rank
-
1
);
else
val
=
arp
->
GetValue
(
arp
==
Arp
?
Nx
:
0
);
if
(
Nodes
[
i
].
Rank
)
val
=
arp
->
GetValue
(
Nodes
[
i
].
Rank
-
1
);
else
val
=
arp
->
GetValue
(
Nodes
[
i
].
Nx
);
}
else
val
=
arp
->
GetValue
(
Tjp
->
SameRow
);
}
else
val
=
NULL
;
...
...
@@ -643,15 +864,16 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
if
(
val
)
{
row
=
val
->
GetJson
();
}
else
if
(
mode
==
1
)
{
// mode write
}
else
{
// Construct missing objects
for
(
i
++
;
row
&&
i
<
Nod
;
i
++
)
{
if
(
!
Nodes
[
i
].
Key
)
{
if
(
Nodes
[
i
].
Op
==
OP_XX
)
break
;
else
if
(
!
Nodes
[
i
].
Key
)
// Construct intermediate array
nwr
=
new
(
g
)
JARRAY
;
}
else
{
else
nwr
=
new
(
g
)
JOBJECT
;
}
// endif Nodes
if
(
row
->
GetType
()
==
TYPE_JOB
)
{
((
PJOB
)
row
)
->
SetValue
(
g
,
new
(
g
)
JVALUE
(
nwr
),
Nodes
[
i
-
1
].
Key
);
...
...
@@ -667,139 +889,13 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
}
// endfor i
break
;
}
else
row
=
NULL
;
}
// endelse
}
// endfor i
return
row
;
}
// end of GetRow
/***********************************************************************/
/* ReadColumn: */
/***********************************************************************/
void
JSONCOL
::
ReadColumn
(
PGLOBAL
g
)
{
int
mode
=
0
,
n
=
Nod
-
1
;
PJSON
row
;
PJVAL
val
=
NULL
;
evenmore:
row
=
GetRow
(
g
,
mode
);
more:
if
(
row
)
switch
(
row
->
GetType
())
{
case
TYPE_JOB
:
if
(
Nodes
[
n
].
Key
)
val
=
row
->
GetValue
(
Nodes
[
n
].
Key
);
else
val
=
new
(
g
)
JVALUE
(
row
);
break
;
case
TYPE_JAR
:
// Multiple column ?
if
(
Nodes
[
n
].
Op
!=
OP_NULL
)
{
Arp
=
(
PJAR
)
row
;
val
=
Arp
->
GetValue
(
Nodes
[
n
].
Rank
>
0
?
Nodes
[
n
].
Rank
-
1
:
Nodes
[
n
].
Op
==
OP_XX
?
Tjp
->
SameRow
:
Nx
);
Ival
=
n
;
}
else
val
=
NULL
;
break
;
case
TYPE_JVAL
:
val
=
(
PJVAL
)
row
;
break
;
default:
sprintf
(
g
->
Message
,
"Wrong return value type %d"
,
row
->
GetType
());
Value
->
Reset
();
return
;
}
// endswitch Type
if
(
!
Nx
/*|| (Xpd)*/
)
SetJsonValue
(
g
,
Value
,
val
,
n
);
if
(
Arp
)
{
// Multiple column
int
ars
=
(
Nodes
[
Ival
].
Rank
>
0
)
?
1
:
MY_MIN
(
Tjp
->
Limit
,
Arp
->
size
());
if
(
Nodes
[
Ival
].
Op
==
OP_XX
)
{
if
(
ars
>
Tjp
->
SameRow
+
1
)
Tjp
->
NextSame
=
true
;
// More to come
else
{
Tjp
->
NextSame
=
false
;
Arp
=
NULL
;
}
// endelse
}
else
{
if
(
Nx
&&
val
)
{
SetJsonValue
(
g
,
MulVal
,
val
,
Ival
);
if
(
!
MulVal
->
IsZero
())
{
PVAL
val
[
2
];
bool
err
;
switch
(
Nodes
[
Ival
].
Op
)
{
case
OP_CNC
:
if
(
Nodes
[
Ival
].
CncVal
)
{
val
[
0
]
=
Nodes
[
Ival
].
CncVal
;
err
=
Value
->
Compute
(
g
,
val
,
1
,
Nodes
[
Ival
].
Op
);
}
// endif CncVal
val
[
0
]
=
MulVal
;
err
=
Value
->
Compute
(
g
,
val
,
1
,
Nodes
[
Ival
].
Op
);
break
;
case
OP_NUM
:
case
OP_SEP
:
val
[
0
]
=
Value
;
val
[
1
]
=
MulVal
;
err
=
Value
->
Compute
(
g
,
val
,
2
,
OP_ADD
);
break
;
default:
val
[
0
]
=
Value
;
val
[
1
]
=
MulVal
;
err
=
Value
->
Compute
(
g
,
val
,
2
,
Nodes
[
Ival
].
Op
);
}
// endswitch Op
if
(
err
)
Value
->
Reset
();
}
// endif Zero
}
// endif Nx
if
(
ars
>
++
Nx
)
{
if
(
Ival
!=
n
)
{
mode
=
2
;
goto
evenmore
;
}
else
goto
more
;
}
else
{
if
(
Nodes
[
Ival
].
Op
==
OP_SEP
)
{
// Calculate average
PVAL
val
[
2
];
MulVal
->
SetValue
(
ars
);
val
[
0
]
=
Value
;
val
[
1
]
=
MulVal
;
if
(
Value
->
Compute
(
g
,
val
,
2
,
OP_DIV
))
Value
->
Reset
();
}
// endif Op
Arp
=
NULL
;
Nx
=
0
;
}
// endif ars
}
// endif Op
}
// endif Arp
}
// end of ReadColumn
/***********************************************************************/
/* WriteColumn: */
/***********************************************************************/
...
...
@@ -817,10 +913,11 @@ void JSONCOL::WriteColumn(PGLOBAL g)
if
(
Value
->
IsNull
()
&&
Tjp
->
Mode
==
MODE_INSERT
)
return
;
char
*
s
;
PJOB
objp
=
NULL
;
PJAR
arp
=
NULL
;
PJVAL
jvp
=
NULL
;
PJSON
row
=
GetRow
(
g
,
1
);
PJSON
jsp
,
row
=
GetRow
(
g
);
JTYP
type
=
row
->
GetType
();
switch
(
row
->
GetType
())
{
...
...
@@ -832,6 +929,28 @@ void JSONCOL::WriteColumn(PGLOBAL g)
if
(
row
)
switch
(
Buf_Type
)
{
case
TYPE_STRING
:
if
(
Nodes
[
Nod
-
1
].
Op
==
OP_XX
)
{
s
=
Value
->
GetCharValue
();
jsp
=
ParseJson
(
g
,
s
,
(
int
)
strlen
(
s
),
0
);
if
(
arp
)
{
if
(
Nod
>
1
&&
Nodes
[
Nod
-
2
].
Rank
)
arp
->
SetValue
(
g
,
new
(
g
)
JVALUE
(
jsp
),
Nodes
[
Nod
-
2
].
Rank
-
1
);
else
arp
->
AddValue
(
g
,
new
(
g
)
JVALUE
(
jsp
));
arp
->
InitArray
(
g
);
}
else
if
(
objp
)
{
if
(
Nod
>
1
&&
Nodes
[
Nod
-
2
].
Key
)
objp
->
SetValue
(
g
,
new
(
g
)
JVALUE
(
jsp
),
Nodes
[
Nod
-
2
].
Key
);
}
else
if
(
jvp
)
jvp
->
SetValue
(
jsp
);
break
;
}
// endif Op
// Passthru
case
TYPE_DATE
:
case
TYPE_INT
:
case
TYPE_DOUBLE
:
...
...
@@ -1175,11 +1294,6 @@ bool TDBJSON::OpenDB(PGLOBAL g)
/*******************************************************************/
/* Table already open replace it at its beginning. */
/*******************************************************************/
for
(
PJCOL
cp
=
(
PJCOL
)
Columns
;
cp
;
cp
=
(
PJCOL
)
cp
->
GetNext
())
{
cp
->
Nx
=
0
;
cp
->
Arp
=
NULL
;
}
// endfor cp
Fpos
=
-
1
;
Spos
=
0
;
NextSame
=
false
;
...
...
@@ -1217,7 +1331,8 @@ int TDBJSON::ReadDB(PGLOBAL g)
N
++
;
if
(
NextSame
)
{
SameRow
++
;
SameRow
=
NextSame
;
NextSame
=
false
;
rc
=
RC_OK
;
}
else
if
(
++
Fpos
<
(
signed
)
Doc
->
size
())
{
Row
=
Doc
->
GetValue
(
Fpos
);
...
...
@@ -1257,9 +1372,10 @@ int TDBJSON::WriteDB(PGLOBAL g)
return
RC_FX
;
}
else
{
// if (Jmode == MODE_VALUE)
if
(
Mode
==
MODE_INSERT
)
if
(
Mode
==
MODE_INSERT
)
{
Doc
->
AddValue
(
g
,
(
PJVAL
)
Row
);
else
if
(
Doc
->
SetValue
(
g
,
(
PJVAL
)
Row
,
Fpos
))
Row
=
new
(
g
)
JVALUE
;
}
else
if
(
Doc
->
SetValue
(
g
,
(
PJVAL
)
Row
,
Fpos
))
return
RC_FX
;
}
// endif Jmode
...
...
storage/connect/tabjson.h
View file @
56114a41
...
...
@@ -16,8 +16,6 @@ typedef class JSONDEF *PJDEF;
typedef
class
TDBJSON
*
PJTDB
;
typedef
class
JSONCOL
*
PJCOL
;
class
TDBJSN
;
/***********************************************************************/
/* The JSON tree node. Can be an Object or an Array. */
/***********************************************************************/
...
...
@@ -25,7 +23,9 @@ typedef struct _jnode {
PSZ
Key
;
// The key used for object
OPVAL
Op
;
// Operator used for this node
PVAL
CncVal
;
// To cont value used for OP_CNC
PVAL
Valp
;
// The internal array VALUE
int
Rank
;
// The rank in array
int
Nx
;
// Same row number
}
JNODE
,
*
PJNODE
;
/***********************************************************************/
...
...
@@ -77,7 +77,7 @@ class TDBJSN : public TDBDOS {
virtual
PTDB
CopyOne
(
PTABS
t
);
virtual
PCOL
MakeCol
(
PGLOBAL
g
,
PCOLDEF
cdp
,
PCOL
cprec
,
int
n
);
virtual
PCOL
InsertSpecialColumn
(
PGLOBAL
g
,
PCOL
colp
);
virtual
int
RowNumber
(
PGLOBAL
g
,
BOOL
b
=
FALSE
)
virtual
int
RowNumber
(
PGLOBAL
g
,
bool
b
=
FALSE
)
{
return
(
b
)
?
N
:
Fpos
+
1
;}
// Database routines
...
...
@@ -98,11 +98,11 @@ class TDBJSN : public TDBDOS {
int
N
;
// The current Rownum
int
Limit
;
// Limit of multiple values
int
Pretty
;
// Depends on file structure
bool
Strict
;
// Strict syntax checking
bool
NextSame
;
// Same next row
bool
Comma
;
// Row has final comma
int
NextSame
;
// Same next row
int
SameRow
;
// Same row nb
int
Xval
;
// Index of expandable array
bool
Strict
;
// Strict syntax checking
bool
Comma
;
// Row has final comma
};
// end of class TDBJSN
/* -------------------------- JSONCOL class -------------------------- */
...
...
@@ -130,8 +130,12 @@ class JSONCOL : public DOSCOL {
protected:
bool
CheckExpand
(
PGLOBAL
g
,
int
i
,
PSZ
nm
,
bool
b
);
bool
SetArrayOptions
(
PGLOBAL
g
,
char
*
p
,
int
i
,
PSZ
nm
);
PJSON
GetRow
(
PGLOBAL
g
,
int
mode
);
PVAL
GetColumnValue
(
PGLOBAL
g
,
PJSON
row
,
int
i
);
PVAL
ExpandArray
(
PGLOBAL
g
,
PJAR
arp
,
int
n
);
PVAL
CalculateArray
(
PGLOBAL
g
,
PJAR
arp
,
int
n
);
PVAL
MakeJson
(
PGLOBAL
g
,
PJSON
jsp
);
void
SetJsonValue
(
PGLOBAL
g
,
PVAL
vp
,
PJVAL
val
,
int
n
);
PJSON
GetRow
(
PGLOBAL
g
);
// Default constructor not to be used
JSONCOL
(
void
)
{}
...
...
@@ -139,12 +143,10 @@ class JSONCOL : public DOSCOL {
// Members
TDBJSN
*
Tjp
;
// To the JSN table block
PVAL
MulVal
;
// To value used by multiple column
PJAR
Arp
;
// The intermediate array
char
*
Jpath
;
// The json path
JNODE
*
Nodes
;
// The intermediate objects
JNODE
*
Nodes
;
// The intermediate objects
int
Nod
;
// The number of intermediate objects
int
Ival
;
// Index of multiple values
int
Nx
;
// The last read sub-row
int
Xnod
;
// Index of multiple values
bool
Xpd
;
// True for expandable column
bool
Parsed
;
// True when parsed
};
// end of class JSONCOL
...
...
storage/connect/tabmysql.cpp
View file @
56114a41
...
...
@@ -1141,19 +1141,16 @@ int TDBMYSQL::WriteDB(PGLOBAL g)
int
rc
;
uint
len
=
Query
->
GetLength
();
char
buf
[
64
];
bool
b
,
oom
=
false
;
bool
oom
=
false
;
// Make the Insert command value list
for
(
PCOL
colp
=
Columns
;
colp
;
colp
=
colp
->
GetNext
())
{
if
(
!
colp
->
GetValue
()
->
IsNull
())
{
if
((
b
=
colp
->
GetResultType
()
==
TYPE_STRING
||
colp
->
GetResultType
()
==
TYPE_DATE
))
oom
|=
Query
->
Append
(
'\''
);
oom
|=
Query
->
Append
(
colp
->
GetValue
()
->
GetCharString
(
buf
));
if
(
b
)
oom
|=
Query
->
Append
(
'\''
);
if
(
colp
->
GetResultType
()
==
TYPE_STRING
||
colp
->
GetResultType
()
==
TYPE_DATE
)
oom
|=
Query
->
Append_quoted
(
colp
->
GetValue
()
->
GetCharString
(
buf
));
else
oom
|=
Query
->
Append
(
colp
->
GetValue
()
->
GetCharString
(
buf
));
}
else
oom
|=
Query
->
Append
(
"NULL"
);
...
...
storage/connect/taboccur.cpp
View file @
56114a41
...
...
@@ -355,7 +355,7 @@ bool TDBOCCUR::MakeColumnList(PGLOBAL g)
for
(
colp
=
Columns
;
colp
;
colp
=
colp
->
GetNext
())
if
(
colp
->
GetAmType
()
==
TYPE_AM_PRX
)
if
(((
PPRXCOL
)
colp
)
->
Init
(
g
))
if
(((
PPRXCOL
)
colp
)
->
Init
(
g
,
NULL
))
return
true
;
Col
=
(
PCOL
*
)
PlugSubAlloc
(
g
,
NULL
,
Mult
*
sizeof
(
PCOL
));
...
...
storage/connect/tabodbc.cpp
View file @
56114a41
...
...
@@ -66,8 +66,8 @@
#include "plgdbsem.h"
#include "mycat.h"
#include "xtable.h"
#include "tabodbc.h"
#include "odbccat.h"
#include "tabodbc.h"
#include "tabmul.h"
#include "reldef.h"
#include "tabcol.h"
...
...
@@ -93,9 +93,10 @@ bool ExactInfo(void);
/***********************************************************************/
ODBCDEF
::
ODBCDEF
(
void
)
{
Connect
=
Tabname
=
Tabschema
=
Tabcat
=
Srcdef
=
Qchar
=
Qrystr
=
Sep
=
NULL
;
Connect
=
Tabname
=
Tabschema
=
Username
=
Password
=
NULL
;
Tabcat
=
Srcdef
=
Qchar
=
Qrystr
=
Sep
=
NULL
;
Catver
=
Options
=
Cto
=
Qto
=
Quoted
=
Maxerr
=
Maxres
=
0
;
Scrollable
=
Memory
=
Xsrc
=
false
;
Scrollable
=
Memory
=
Xsrc
=
UseCnc
=
false
;
}
// end of ODBCDEF constructor
/***********************************************************************/
...
...
@@ -117,6 +118,8 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Tabschema
=
GetStringCatInfo
(
g
,
"Schema"
,
Tabschema
);
Tabcat
=
GetStringCatInfo
(
g
,
"Qualifier"
,
NULL
);
Tabcat
=
GetStringCatInfo
(
g
,
"Catalog"
,
Tabcat
);
Username
=
GetStringCatInfo
(
g
,
"User"
,
NULL
);
Password
=
GetStringCatInfo
(
g
,
"Password"
,
NULL
);
if
((
Srcdef
=
GetStringCatInfo
(
g
,
"Srcdef"
,
NULL
)))
Read_Only
=
true
;
...
...
@@ -133,6 +136,7 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Cto
=
GetIntCatInfo
(
"ConnectTimeout"
,
DEFAULT_LOGIN_TIMEOUT
);
Qto
=
GetIntCatInfo
(
"QueryTimeout"
,
DEFAULT_QUERY_TIMEOUT
);
Scrollable
=
GetBoolCatInfo
(
"Scrollable"
,
false
);
UseCnc
=
GetBoolCatInfo
(
"UseDSN"
,
false
);
Memory
=
GetBoolCatInfo
(
"Memory"
,
false
);
Pseudo
=
2
;
// FILID is Ok but not ROWID
return
false
;
...
...
@@ -190,34 +194,40 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Connect
=
tdp
->
Connect
;
TableName
=
tdp
->
Tabname
;
Schema
=
tdp
->
Tabschema
;
Ops
.
User
=
tdp
->
Username
;
Ops
.
Pwd
=
tdp
->
Password
;
Catalog
=
tdp
->
Tabcat
;
Srcdef
=
tdp
->
Srcdef
;
Qrystr
=
tdp
->
Qrystr
;
Sep
=
tdp
->
GetSep
();
Options
=
tdp
->
Options
;
Cto
=
tdp
->
Cto
;
Qto
=
tdp
->
Qto
;
Ops
.
Cto
=
tdp
->
Cto
;
Ops
.
Qto
=
tdp
->
Qto
;
Quoted
=
MY_MAX
(
0
,
tdp
->
GetQuoted
());
Rows
=
tdp
->
GetElemt
();
Catver
=
tdp
->
Catver
;
Memory
=
(
tdp
->
Memory
)
?
1
:
0
;
Scrollable
=
tdp
->
Scrollable
;
Ops
.
UseCnc
=
tdp
->
UseCnc
;
}
else
{
Connect
=
NULL
;
TableName
=
NULL
;
Schema
=
NULL
;
Ops
.
User
=
NULL
;
Ops
.
Pwd
=
NULL
;
Catalog
=
NULL
;
Srcdef
=
NULL
;
Qrystr
=
NULL
;
Sep
=
0
;
Options
=
0
;
Cto
=
DEFAULT_LOGIN_TIMEOUT
;
Qto
=
DEFAULT_QUERY_TIMEOUT
;
Ops
.
Cto
=
DEFAULT_LOGIN_TIMEOUT
;
Ops
.
Qto
=
DEFAULT_QUERY_TIMEOUT
;
Quoted
=
0
;
Rows
=
0
;
Catver
=
0
;
Memory
=
0
;
Scrollable
=
false
;
Ops
.
UseCnc
=
false
;
}
// endif tdp
Quote
=
NULL
;
...
...
@@ -242,6 +252,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
Connect
=
tdbp
->
Connect
;
TableName
=
tdbp
->
TableName
;
Schema
=
tdbp
->
Schema
;
Ops
=
tdbp
->
Ops
;
Catalog
=
tdbp
->
Catalog
;
Srcdef
=
tdbp
->
Srcdef
;
Qrystr
=
tdbp
->
Qrystr
;
...
...
@@ -254,8 +265,6 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
MulConn
=
tdbp
->
MulConn
;
DBQ
=
tdbp
->
DBQ
;
Options
=
tdbp
->
Options
;
Cto
=
tdbp
->
Cto
;
Qto
=
tdbp
->
Qto
;
Quoted
=
tdbp
->
Quoted
;
Rows
=
tdbp
->
Rows
;
Fpos
=
tdbp
->
Fpos
;
...
...
@@ -370,7 +379,7 @@ int TDBODBC::Decode(char *txt, char *buf, size_t n)
/***********************************************************************/
char
*
TDBODBC
::
MakeSQL
(
PGLOBAL
g
,
bool
cnt
)
{
char
*
colist
,
*
tabname
,
*
sql
,
buf
[
64
];
char
*
colist
,
*
tabname
,
*
sql
,
buf
[
NAM_LEN
*
3
];
LPCSTR
schmp
=
NULL
,
catp
=
NULL
;
int
len
,
ncol
=
0
;
bool
first
=
true
;
...
...
@@ -474,6 +483,9 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
if
(
To_CondFil
)
strcat
(
strcat
(
sql
,
" WHERE "
),
To_CondFil
->
Body
);
if
(
trace
)
htrc
(
"sql: '%s'
\n
"
,
sql
);
return
sql
;
}
// end of MakeSQL
...
...
@@ -483,7 +495,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
/***********************************************************************/
char
*
TDBODBC
::
MakeInsert
(
PGLOBAL
g
)
{
char
*
stmt
,
*
colist
,
*
valist
;
char
*
stmt
,
*
colist
,
*
valist
,
buf
[
NAM_LEN
*
3
]
;
// char *tk = "`";
int
len
=
0
;
bool
b
=
FALSE
;
...
...
@@ -510,10 +522,13 @@ char *TDBODBC::MakeInsert(PGLOBAL g)
}
else
b
=
true
;
// Column name can be in UTF-8 encoding
Decode
(
colp
->
GetName
(),
buf
,
sizeof
(
buf
));
if
(
Quote
)
strcat
(
strcat
(
strcat
(
colist
,
Quote
),
colp
->
GetName
()
),
Quote
);
strcat
(
strcat
(
strcat
(
colist
,
Quote
),
buf
),
Quote
);
else
strcat
(
colist
,
colp
->
GetName
()
);
strcat
(
colist
,
buf
);
strcat
(
valist
,
"?"
);
// Parameter marker
}
// endfor colp
...
...
@@ -558,8 +573,7 @@ bool TDBODBC::BindParameters(PGLOBAL g)
/***********************************************************************/
char
*
TDBODBC
::
MakeCommand
(
PGLOBAL
g
)
{
char
*
p
,
name
[
68
],
*
qc
=
Ocp
->
GetQuoteChar
();
char
*
stmt
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
strlen
(
Qrystr
)
+
64
);
char
*
p
,
*
stmt
,
name
[
68
],
*
body
=
NULL
,
*
qc
=
Ocp
->
GetQuoteChar
();
char
*
qrystr
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
strlen
(
Qrystr
)
+
1
);
bool
qtd
=
Quoted
>
0
;
int
i
=
0
,
k
=
0
;
...
...
@@ -570,6 +584,15 @@ char *TDBODBC::MakeCommand(PGLOBAL g)
qrystr
[
i
]
=
(
Qrystr
[
i
]
==
'`'
)
?
*
qc
:
tolower
(
Qrystr
[
i
]);
}
while
(
Qrystr
[
i
++
]);
if
(
To_CondFil
&&
(
p
=
strstr
(
qrystr
,
" where "
)))
{
p
[
7
]
=
0
;
// Remove where clause
Qrystr
[(
p
-
qrystr
)
+
7
]
=
0
;
body
=
To_CondFil
->
Body
;
stmt
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
strlen
(
qrystr
)
+
strlen
(
body
)
+
64
);
}
else
stmt
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
strlen
(
Qrystr
)
+
64
);
// Check whether the table name is equal to a keyword
// If so, it must be quoted in the original query
strlwr
(
strcat
(
strcat
(
strcpy
(
name
,
" "
),
Name
),
" "
));
...
...
@@ -597,6 +620,9 @@ char *TDBODBC::MakeCommand(PGLOBAL g)
stmt
[
i
++
]
=
(
Qrystr
[
k
]
==
'`'
)
?
*
qc
:
Qrystr
[
k
];
}
while
(
Qrystr
[
k
++
]);
if
(
body
)
strcat
(
stmt
,
body
);
}
else
{
sprintf
(
g
->
Message
,
"Cannot use this %s command"
,
(
Mode
==
MODE_UPDATE
)
?
"UPDATE"
:
"DELETE"
);
...
...
@@ -698,10 +724,7 @@ int TDBODBC::Cardinality(PGLOBAL g)
char
qry
[
96
],
tbn
[
64
];
ODBConn
*
ocp
=
new
(
g
)
ODBConn
(
g
,
this
);
ocp
->
SetLoginTimeout
((
DWORD
)
Cto
);
ocp
->
SetQueryTimeout
((
DWORD
)
Qto
);
if
(
ocp
->
Open
(
Connect
,
Options
)
<
1
)
if
(
ocp
->
Open
(
Connect
,
&
Ops
,
Options
)
<
1
)
return
-
1
;
// Table name can be encoded in UTF-8
...
...
@@ -762,7 +785,7 @@ int TDBODBC::GetProgMax(PGLOBAL g)
/***********************************************************************/
bool
TDBODBC
::
OpenDB
(
PGLOBAL
g
)
{
bool
rc
=
fals
e
;
bool
rc
=
tru
e
;
if
(
g
->
Trace
)
htrc
(
"ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d
\n
"
,
...
...
@@ -802,14 +825,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
/* and if so to allocate just a new result set. But this only for */
/* drivers allowing concurency in getting results ??? */
/*********************************************************************/
if
(
!
Ocp
)
{
if
(
!
Ocp
)
Ocp
=
new
(
g
)
ODBConn
(
g
,
this
);
Ocp
->
SetLoginTimeout
((
DWORD
)
Cto
);
Ocp
->
SetQueryTimeout
((
DWORD
)
Qto
);
}
else
if
(
Ocp
->
IsOpen
())
else
if
(
Ocp
->
IsOpen
())
Ocp
->
Close
();
if
(
Ocp
->
Open
(
Connect
,
Options
)
<
1
)
if
(
Ocp
->
Open
(
Connect
,
&
Ops
,
Options
)
<
1
)
return
true
;
else
if
(
Quoted
)
Quote
=
Ocp
->
GetQuoteChar
();
...
...
@@ -839,12 +860,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
}
// endif Query
}
else
if
(
Mode
==
MODE_UPDATE
||
Mode
==
MODE_DELETE
)
Query
=
MakeCommand
(
g
);
else
}
else
if
(
Mode
==
MODE_UPDATE
||
Mode
==
MODE_DELETE
)
{
rc
=
false
;
// wait for CheckCond before calling
MakeCommand(g);
}
else
sprintf
(
g
->
Message
,
"Invalid mode %d"
,
Mode
);
if
(
!
Query
||
rc
)
{
if
(
rc
)
{
Ocp
->
Close
();
return
true
;
}
// endif rc
...
...
@@ -876,6 +897,9 @@ int TDBODBC::ReadDB(PGLOBAL g)
GetTdb_No
(),
Mode
,
To_Key_Col
,
To_Link
,
To_Kindex
);
if
(
Mode
==
MODE_UPDATE
||
Mode
==
MODE_DELETE
)
{
if
(
!
Query
&&
!
(
Query
=
MakeCommand
(
g
)))
return
RC_FX
;
// Send the UPDATE/DELETE command to the remote table
if
(
!
Ocp
->
ExecSQLcommand
(
Query
))
{
sprintf
(
g
->
Message
,
"%s: %d affected rows"
,
TableName
,
AftRows
);
...
...
@@ -945,6 +969,9 @@ int TDBODBC::WriteDB(PGLOBAL g)
int
TDBODBC
::
DeleteDB
(
PGLOBAL
g
,
int
irc
)
{
if
(
irc
==
RC_FX
)
{
if
(
!
Query
&&
!
(
Query
=
MakeCommand
(
g
)))
return
RC_FX
;
// Send the DELETE (all) command to the remote table
if
(
!
Ocp
->
ExecSQLcommand
(
Query
))
{
sprintf
(
g
->
Message
,
"%s: %d affected rows"
,
TableName
,
AftRows
);
...
...
@@ -1415,12 +1442,10 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
/*********************************************************************/
if
(
!
Ocp
)
{
Ocp
=
new
(
g
)
ODBConn
(
g
,
this
);
Ocp
->
SetLoginTimeout
((
DWORD
)
Cto
);
Ocp
->
SetQueryTimeout
((
DWORD
)
Qto
);
}
else
if
(
Ocp
->
IsOpen
())
Ocp
->
Close
();
if
(
Ocp
->
Open
(
Connect
,
Options
)
<
1
)
if
(
Ocp
->
Open
(
Connect
,
&
Ops
,
Options
)
<
1
)
return
true
;
Use
=
USE_OPEN
;
// Do it now in case we are recursively called
...
...
@@ -1554,8 +1579,11 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
Dsn
=
tdp
->
GetConnect
();
Schema
=
tdp
->
GetTabschema
();
Tab
=
tdp
->
GetTabname
();
Cto
=
tdp
->
Cto
;
Qto
=
tdp
->
Qto
;
Ops
.
User
=
tdp
->
Username
;
Ops
.
Pwd
=
tdp
->
Password
;
Ops
.
Cto
=
tdp
->
Cto
;
Ops
.
Qto
=
tdp
->
Qto
;
Ops
.
UseCnc
=
tdp
->
UseCnc
;
}
// end of TDBOTB constructor
/***********************************************************************/
...
...
@@ -1563,7 +1591,7 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
/***********************************************************************/
PQRYRES
TDBOTB
::
GetResult
(
PGLOBAL
g
)
{
return
ODBCTables
(
g
,
Dsn
,
Schema
,
Tab
,
Maxres
,
Cto
,
Qto
,
false
);
return
ODBCTables
(
g
,
Dsn
,
Schema
,
Tab
,
Maxres
,
false
,
&
Ops
);
}
// end of GetResult
/* ---------------------------TDBOCL class --------------------------- */
...
...
@@ -1573,7 +1601,7 @@ PQRYRES TDBOTB::GetResult(PGLOBAL g)
/***********************************************************************/
PQRYRES
TDBOCL
::
GetResult
(
PGLOBAL
g
)
{
return
ODBCColumns
(
g
,
Dsn
,
Schema
,
Tab
,
NULL
,
Maxres
,
Cto
,
Qto
,
false
);
return
ODBCColumns
(
g
,
Dsn
,
Schema
,
Tab
,
NULL
,
Maxres
,
false
,
&
Ops
);
}
// end of GetResult
/* ------------------------ End of Tabodbc --------------------------- */
storage/connect/tabodbc.h
View file @
56114a41
...
...
@@ -50,6 +50,8 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ
Connect
;
/* ODBC connection string */
PSZ
Tabname
;
/* External table name */
PSZ
Tabschema
;
/* External table schema */
PSZ
Username
;
/* User connect name */
PSZ
Password
;
/* Password connect info */
PSZ
Tabcat
;
/* External table catalog */
PSZ
Srcdef
;
/* The source table SQL definition */
PSZ
Qchar
;
/* Identifier quoting character */
...
...
@@ -65,6 +67,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
bool
Scrollable
;
/* Use scrollable cursor */
bool
Memory
;
/* Put result set in memory */
bool
Xsrc
;
/* Execution type */
bool
UseCnc
;
/* Use SQLConnect (!SQLDriverConnect) */
};
// end of ODBCDEF
#if !defined(NODBC)
...
...
@@ -124,9 +127,12 @@ class TDBODBC : public TDBASE {
// Members
ODBConn
*
Ocp
;
// Points to an ODBC connection class
ODBCCOL
*
Cnp
;
// Points to count(*) column
ODBCPARM
Ops
;
// Additional parameters
char
*
Connect
;
// Points to connection string
char
*
TableName
;
// Points to ODBC table name
char
*
Schema
;
// Points to ODBC table Schema
char
*
User
;
// User connect info
char
*
Pwd
;
// Password connect info
char
*
Catalog
;
// Points to ODBC table Catalog
char
*
Srcdef
;
// The source table SQL definition
char
*
Query
;
// Points to SQL statement
...
...
@@ -151,6 +157,7 @@ class TDBODBC : public TDBASE {
int
Nparm
;
// The number of statement parameters
int
Memory
;
// 0: No 1: Alloc 2: Put 3: Get
bool
Scrollable
;
// Use scrollable cursor
bool
UseCnc
;
// Use SQLConnect (!SQLDriverConnect)
PQRYRES
Qrp
;
// Points to storage result
};
// end of class TDBODBC
...
...
@@ -316,8 +323,7 @@ class TDBOTB : public TDBDRV {
char
*
Dsn
;
// Points to connection string
char
*
Schema
;
// Points to schema name or NULL
char
*
Tab
;
// Points to ODBC table name or pattern
int
Cto
;
// Connect timeout
int
Qto
;
// Query timeout
ODBCPARM
Ops
;
// Additional parameters
};
// end of class TDBOTB
/***********************************************************************/
...
...
storage/connect/tabpivot.cpp
View file @
56114a41
...
...
@@ -558,7 +558,7 @@ bool TDBPIVOT::MakePivotColumns(PGLOBAL g)
// Check and initialize the subtable columns
for
(
PCOL
cp
=
Columns
;
cp
;
cp
=
cp
->
GetNext
())
if
(
cp
->
GetAmType
()
==
TYPE_AM_SRC
)
{
if
(((
PSRCCOL
)
cp
)
->
Init
(
g
))
if
(((
PSRCCOL
)
cp
)
->
Init
(
g
,
NULL
))
return
TRUE
;
}
else
if
(
cp
->
GetAmType
()
==
TYPE_AM_FNC
)
...
...
@@ -874,9 +874,9 @@ SRCCOL::SRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int n)
/***********************************************************************/
/* Initialize the column as pointing to the source column. */
/***********************************************************************/
bool
SRCCOL
::
Init
(
PGLOBAL
g
)
bool
SRCCOL
::
Init
(
PGLOBAL
g
,
PTDBASE
tp
)
{
if
(
PRXCOL
::
Init
(
g
))
if
(
PRXCOL
::
Init
(
g
,
tp
))
return
true
;
AddStatus
(
BUF_READ
);
// All is done here
...
...
storage/connect/tabpivot.h
View file @
56114a41
...
...
@@ -180,9 +180,10 @@ class SRCCOL : public PRXCOL {
virtual
int
GetAmType
(
void
)
{
return
TYPE_AM_SRC
;}
// Methods
using
PRXCOL
::
Init
;
virtual
void
Reset
(
void
)
{}
void
SetColumn
(
void
);
bool
Init
(
PGLOBAL
g
);
virtual
bool
Init
(
PGLOBAL
g
,
PTDBASE
tp
);
bool
CompareLast
(
void
);
protected:
...
...
storage/connect/tabtbl.cpp
View file @
56114a41
...
...
@@ -266,7 +266,7 @@ bool TDBTBL::InitTableList(PGLOBAL g)
// Real initialization will be done later.
for
(
colp
=
Columns
;
colp
;
colp
=
colp
->
GetNext
())
if
(
!
colp
->
IsSpecial
())
if
(((
PPRXCOL
)
colp
)
->
Init
(
g
)
&&
!
Accept
)
if
(((
PPRXCOL
)
colp
)
->
Init
(
g
,
NULL
)
&&
!
Accept
)
return
TRUE
;
if
(
Tablist
)
...
...
@@ -352,7 +352,9 @@ bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp)
/***********************************************************************/
int
TDBTBL
::
Cardinality
(
PGLOBAL
g
)
{
if
(
Cardinal
<
0
)
{
if
(
!
g
)
return
0
;
// Cannot make the table list
else
if
(
Cardinal
<
0
)
{
int
tsz
;
if
(
!
Tablist
&&
InitTableList
(
g
))
...
...
@@ -468,7 +470,7 @@ bool TDBTBL::OpenDB(PGLOBAL g)
for
(
PCOL
cp
=
Columns
;
cp
;
cp
=
cp
->
GetNext
())
if
(
cp
->
GetAmType
()
==
TYPE_AM_TABID
)
cp
->
COLBLK
::
Reset
();
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
)
&&
!
Accept
)
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
,
NULL
)
&&
!
Accept
)
return
TRUE
;
if
(
trace
)
...
...
@@ -523,7 +525,7 @@ int TDBTBL::ReadDB(PGLOBAL g)
if
(
cp
->
GetAmType
()
==
TYPE_AM_TABID
||
cp
->
GetAmType
()
==
TYPE_AM_SRVID
)
cp
->
COLBLK
::
Reset
();
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
)
&&
!
Accept
)
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
,
NULL
)
&&
!
Accept
)
return
RC_FX
;
if
(
trace
)
...
...
@@ -716,7 +718,7 @@ bool TDBTBM::OpenDB(PGLOBAL g)
for
(
PCOL
cp
=
Columns
;
cp
;
cp
=
cp
->
GetNext
())
if
(
cp
->
GetAmType
()
==
TYPE_AM_TABID
)
cp
->
COLBLK
::
Reset
();
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
)
&&
!
Accept
)
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
,
NULL
)
&&
!
Accept
)
return
TRUE
;
if
(
trace
)
...
...
@@ -807,7 +809,7 @@ int TDBTBM::ReadNextRemote(PGLOBAL g)
for
(
PCOL
cp
=
Columns
;
cp
;
cp
=
cp
->
GetNext
())
if
(
cp
->
GetAmType
()
==
TYPE_AM_TABID
)
cp
->
COLBLK
::
Reset
();
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
)
&&
!
Accept
)
else
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
,
NULL
)
&&
!
Accept
)
return
RC_FX
;
if
(
trace
)
...
...
storage/connect/tabutil.cpp
View file @
56114a41
...
...
@@ -54,7 +54,8 @@
#include "tabutil.h"
#include "ha_connect.h"
extern
"C"
int
zconv
;
//extern "C" int zconv;
int
GetConvSize
(
void
);
/************************************************************************/
/* Used by MYSQL tables to get MySQL parameters from the calling proxy */
...
...
@@ -132,6 +133,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
char
*
fld
,
*
colname
,
*
chset
,
*
fmt
,
v
;
int
i
,
n
,
ncol
=
sizeof
(
buftyp
)
/
sizeof
(
int
);
int
prec
,
len
,
type
,
scale
;
int
zconv
=
GetConvSize
();
bool
mysql
;
TABLE_SHARE
*
s
=
NULL
;
Field
*
*
field
;
...
...
@@ -668,6 +670,22 @@ PRXCOL::PRXCOL(PRXCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
Colnum
=
col1
->
Colnum
;
}
// end of PRXCOL copy constructor
/***********************************************************************/
/* Convert an UTF-8 name to latin characters. */
/***********************************************************************/
char
*
PRXCOL
::
Decode
(
PGLOBAL
g
,
const
char
*
cnm
)
{
char
*
buf
=
(
char
*
)
PlugSubAlloc
(
g
,
NULL
,
strlen
(
cnm
)
+
1
);
uint
dummy_errors
;
uint32
len
=
copy_and_convert
(
buf
,
strlen
(
cnm
)
+
1
,
&
my_charset_latin1
,
cnm
,
strlen
(
cnm
),
&
my_charset_utf8_general_ci
,
&
dummy_errors
);
buf
[
len
]
=
'\0'
;
return
buf
;
}
// end of Decode
/***********************************************************************/
/* PRXCOL initialization routine. */
/* Look for the matching column in the object table. */
...
...
@@ -683,6 +701,9 @@ bool PRXCOL::Init(PGLOBAL g, PTDBASE tp)
if
(
Colp
)
{
MODE
mode
=
To_Tdb
->
GetMode
();
// Needed for MYSQL subtables
((
XCOLBLK
*
)
Colp
)
->
Name
=
Decode
(
g
,
Colp
->
GetName
());
// May not have been done elsewhere
Colp
->
InitValue
(
g
);
To_Val
=
Colp
->
GetValue
();
...
...
storage/connect/tabutil.h
View file @
56114a41
...
...
@@ -108,15 +108,18 @@ class DllExport PRXCOL : public COLBLK {
virtual
int
GetAmType
(
void
)
{
return
TYPE_AM_PRX
;}
// Methods
using
COLBLK
::
Init
;
virtual
void
Reset
(
void
);
virtual
bool
IsSpecial
(
void
)
{
return
Pseudo
;}
virtual
bool
SetBuffer
(
PGLOBAL
g
,
PVAL
value
,
bool
ok
,
bool
check
)
{
return
false
;}
virtual
void
ReadColumn
(
PGLOBAL
g
);
virtual
void
WriteColumn
(
PGLOBAL
g
);
virtual
bool
Init
(
PGLOBAL
g
,
PTDBASE
tp
=
NULL
);
virtual
bool
Init
(
PGLOBAL
g
,
PTDBASE
tp
);
protected:
char
*
Decode
(
PGLOBAL
g
,
const
char
*
cnm
);
// Default constructor not to be used
PRXCOL
(
void
)
{}
...
...
@@ -144,4 +147,8 @@ class TDBTBC : public TDBCAT {
PSZ
Tab
;
// Table name
};
// end of class TDBMCL
class
XCOLBLK
:
public
COLBLK
{
friend
class
PRXCOL
;
};
// end of class XCOLBLK
#endif // TABUTIL
storage/connect/tabxcl.cpp
View file @
56114a41
...
...
@@ -183,7 +183,7 @@ bool TDBXCL::OpenDB(PGLOBAL g)
/*********************************************************************/
for
(
PCOL
cp
=
Columns
;
cp
;
cp
=
cp
->
GetNext
())
if
(
!
cp
->
IsSpecial
())
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
))
if
(((
PPRXCOL
)
cp
)
->
Init
(
g
,
NULL
))
return
TRUE
;
/*********************************************************************/
...
...
storage/connect/tabxcl.h
View file @
56114a41
...
...
@@ -88,6 +88,7 @@ class XCLCOL : public PRXCOL {
XCLCOL
(
PGLOBAL
g
,
PCOLDEF
cdp
,
PTDB
tdbp
,
PCOL
cprec
,
int
i
);
// Methods
using
PRXCOL
::
Init
;
virtual
void
Reset
(
void
)
{}
// Evaluated only by TDBXCL
virtual
void
ReadColumn
(
PGLOBAL
g
);
virtual
bool
Init
(
PGLOBAL
g
,
PTDBASE
tp
=
NULL
);
...
...
storage/connect/valblk.h
View file @
56114a41
...
...
@@ -163,6 +163,7 @@ class TYPBLK : public VALBLK {
virtual
void
Reset
(
int
n
)
{
Typp
[
n
]
=
0
;}
// Methods
using
VALBLK
::
SetValue
;
virtual
void
SetValue
(
PSZ
sp
,
int
n
);
virtual
void
SetValue
(
char
*
sp
,
uint
len
,
int
n
);
virtual
void
SetValue
(
short
sval
,
int
n
)
...
...
@@ -233,6 +234,7 @@ class CHRBLK : public VALBLK {
virtual
bool
IsCi
(
void
)
{
return
Ci
;}
// Methods
using
VALBLK
::
SetValue
;
virtual
void
SetValue
(
PSZ
sp
,
int
n
);
virtual
void
SetValue
(
char
*
sp
,
uint
len
,
int
n
);
virtual
void
SetValue
(
PVAL
valp
,
int
n
);
...
...
@@ -286,6 +288,7 @@ class STRBLK : public VALBLK {
virtual
void
Reset
(
int
n
)
{
Strp
[
n
]
=
NULL
;}
// Methods
using
VALBLK
::
SetValue
;
virtual
void
SetValue
(
PSZ
sp
,
int
n
);
virtual
void
SetValue
(
char
*
sp
,
uint
len
,
int
n
);
virtual
void
SetValue
(
PVAL
valp
,
int
n
);
...
...
@@ -322,6 +325,7 @@ class DATBLK : public TYPBLK<int> {
virtual
char
*
GetCharString
(
char
*
p
,
int
n
);
// Methods
using
TYPBLK
<
int
>::
SetValue
;
virtual
void
SetValue
(
PSZ
sp
,
int
n
);
protected:
...
...
@@ -345,6 +349,8 @@ class PTRBLK : public STRBLK {
// Implementation
// Methods
using
STRBLK
::
SetValue
;
using
STRBLK
::
CompVal
;
virtual
void
SetValue
(
PSZ
p
,
int
n
)
{
Strp
[
n
]
=
p
;}
virtual
int
CompVal
(
int
i1
,
int
i2
);
...
...
storage/connect/value.cpp
View file @
56114a41
...
...
@@ -436,6 +436,9 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns)
bool
un
=
(
uns
<
0
)
?
false
:
(
uns
>
0
)
?
true
:
valp
->
IsUnsigned
();
PVAL
vp
;
if
(
!
valp
)
return
NULL
;
if
(
newtype
==
TYPE_VOID
)
// Means allocate a value of the same type
newtype
=
valp
->
GetType
();
...
...
@@ -443,8 +446,8 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns)
case
TYPE_STRING
:
p
=
(
PSZ
)
PlugSubAlloc
(
g
,
NULL
,
1
+
valp
->
GetValLen
());
if
((
sp
=
valp
->
GetCharString
(
p
))
!=
p
)
strcpy
(
p
,
sp
);
if
((
sp
=
valp
->
GetCharString
(
p
))
!=
p
&&
sp
)
strcpy
(
p
,
sp
);
vp
=
new
(
g
)
TYPVAL
<
PSZ
>
(
g
,
p
,
valp
->
GetValLen
(),
valp
->
GetValPrec
());
break
;
...
...
@@ -1216,12 +1219,12 @@ TYPVAL<PSZ>::TYPVAL(PSZ s) : VALUE(TYPE_STRING)
TYPVAL
<
PSZ
>::
TYPVAL
(
PGLOBAL
g
,
PSZ
s
,
int
n
,
int
c
)
:
VALUE
(
TYPE_STRING
)
{
Len
=
(
g
)
?
n
:
strlen
(
s
)
;
Len
=
(
g
)
?
n
:
(
s
)
?
strlen
(
s
)
:
0
;
if
(
!
s
)
{
if
(
g
)
{
if
((
Strp
=
(
char
*
)
PlgDBSubAlloc
(
g
,
NULL
,
Len
+
1
)))
Strp
[
Len
]
=
'\0'
;
memset
(
Strp
,
0
,
Len
+
1
)
;
else
Len
=
0
;
...
...
storage/connect/xindex.h
View file @
56114a41
...
...
@@ -391,6 +391,7 @@ class DllExport XHUGE : public XLOAD {
XHUGE
(
void
)
:
XLOAD
()
{}
// Methods
using
XLOAD
::
Close
;
virtual
bool
Open
(
PGLOBAL
g
,
char
*
filename
,
int
id
,
MODE
mode
);
virtual
bool
Seek
(
PGLOBAL
g
,
int
low
,
int
high
,
int
origin
);
virtual
bool
Read
(
PGLOBAL
g
,
void
*
buf
,
int
n
,
int
size
);
...
...
storage/connect/xobject.cpp
View file @
56114a41
...
...
@@ -346,6 +346,31 @@ bool STRING::Append(char c)
return
false
;
}
// end of Append
/***********************************************************************/
/* Append a quoted PSZ to a STRING. */
/***********************************************************************/
bool
STRING
::
Append_quoted
(
PSZ
s
)
{
bool
b
=
Append
(
'\''
);
if
(
s
)
for
(
char
*
p
=
s
;
!
b
&&
*
p
;
p
++
)
switch
(
*
p
)
{
case
'\''
:
case
'\\'
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
case
'\b'
:
case
'\f'
:
b
|=
Append
(
'\\'
);
// passthru
default:
b
|=
Append
(
*
p
);
break
;
}
// endswitch *p
return
(
b
|=
Append
(
'\''
));
}
// end of Append_quoted
/***********************************************************************/
/* Resize to given length but only when last suballocated. */
/* New size should be greater than string length. */
...
...
storage/connect/xobject.h
View file @
56114a41
...
...
@@ -138,6 +138,7 @@ class DllExport STRING : public BLOCK {
bool
Append
(
STRING
&
str
);
bool
Append
(
char
c
);
bool
Resize
(
uint
n
);
bool
Append_quoted
(
PSZ
s
);
inline
void
Trim
(
void
)
{(
void
)
Resize
(
Length
+
1
);}
inline
void
Chop
(
void
)
{
if
(
Length
)
Strp
[
--
Length
]
=
0
;}
inline
void
RepLast
(
char
c
)
{
if
(
Length
)
Strp
[
Length
-
1
]
=
c
;}
...
...
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