Commit 55cb3d8b authored by Olivier Bertrand's avatar Olivier Bertrand

Add new json UDFs and make possible to use a json file name as json item.

  modified:   storage/connect/json.cpp
  modified:   storage/connect/json.h
  modified:   storage/connect/jsonudf.cpp
  modified:   storage/connect/mysql-test/connect/r/json_udf.result
  modified:   storage/connect/mysql-test/connect/t/json.test
  modified:   storage/connect/tabjson.cpp

Fix wrong calculation of Estimated Length when the table has virtual or special columns
  modified:   storage/connect/reldef.h
  modified:   storage/connect/tabdos.cpp

Fix wrong handling of null values in ODBCCOL::ReadColumn
  modified:   storage/connect/tabodbc.cpp

Fix crash when SetValue_char is called with a negative length value.
This can happen in odbconn.cpp when SQLFetch returns SQL_NO_TOTAL (-4) as length.
  modified:   storage/connect/odbconn.cpp
  modified:   storage/connect/value.cpp
parent 3b040a06
/*************** json CPP Declares Source Code File (.H) ***************/
/* Name: json.cpp Version 1.1 */
/* Name: json.cpp Version 1.2 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */
/* */
......@@ -31,6 +31,7 @@
/***********************************************************************/
/* Parse a json string. */
/* Note: when pretty is not known, the caller set pretty to 3. */
/***********************************************************************/
PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
{
......@@ -62,16 +63,24 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
switch (s[i]) {
case '[':
if (jsp) {
if (pretty < 3) {
strcpy(g->Message, "More than one item in file");
goto err;
} else
goto tryit;
} else if (!(jsp = ParseArray(g, ++i, src)))
goto err;
break;
case '{':
if (jsp) {
if (pretty < 3) {
strcpy(g->Message, "More than one item in file");
goto err;
} else
goto tryit;
} else if (!(jsp = ParseObject(g, ++i, src)))
goto err;
......@@ -91,11 +100,6 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
goto err;
case '"':
if (!(jsp = ParseValue(g, i, src)))
goto err;
break;
case '(':
b = true;
break;
......@@ -106,9 +110,10 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
} // endif b
default:
sprintf(g->Message, "Bad '%c' character near %.*s",
s[i], ARGS);
if (!(jsp = ParseValue(g, i, src)))
goto err;
break;
}; // endswitch s[i]
if (!jsp)
......@@ -117,7 +122,13 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
g->jump_level--;
return jsp;
err:
tryit:
i = 0;
jsp = ParseArray(g, i, src);
g->jump_level--;
return jsp;
err:
g->jump_level--;
return NULL;
} // end of ParseJson
......@@ -130,6 +141,7 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src)
char *s = src.str;
int len = src.len;
int level = 0;
bool pty = (!i);
PJAR jarp = new(g) JARRAY;
PJVAL jvp = NULL;
......@@ -160,16 +172,21 @@ PJAR ParseArray(PGLOBAL g, int& i, STRG& src)
if (level == 2) {
sprintf(g->Message, "Unexpected value near %.*s", ARGS);
return NULL;
} else if ((jvp = ParseValue(g, i, src))) {
} else if ((jvp = ParseValue(g, i, src)))
jarp->AddValue(g, jvp);
level = 2;
} else
else
return NULL;
level = 2;
level = (pty) ? 1 : 2;
break;
}; // endswitch s[i]
if (pty) {
// Case of Pretty == 0
jarp->InitArray(g);
return jarp;
} // endif pty
strcpy(g->Message, "Unexpected EOF in array");
return NULL;
} // end of ParseArray
......@@ -501,29 +518,38 @@ PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src)
/***********************************************************************/
/* Serialize a JSON tree: */
/***********************************************************************/
PSZ Serialize(PGLOBAL g, PJSON jsp, FILE *fs, int pretty)
PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty)
{
bool b = false, err = true;
JOUT *jp;
FILE *fs = NULL;
g->Message[0] = 0;
if (!jsp) {
strcpy(g->Message, "Null json tree");
return NULL;
} else if (!fs) {
} else if (!fn) {
// Serialize to a string
jp = new(g) JOUTSTR(g);
b = pretty == 1;
} else if (pretty == 2) {
} else {
if (!(fs = fopen(fn, "wb"))) {
sprintf(g->Message, MSG(OPEN_MODE_ERROR),
"w", (int)errno, fn);
strcat(strcat(g->Message, ": "), strerror(errno));
return g->Message;
} else if (pretty >= 2) {
// Serialize to a pretty file
jp = new(g) JOUTPRT(g, fs);
jp = new(g)JOUTPRT(g, fs);
} else {
// Serialize to a flat file
jp = new(g) JOUTFILE(g, fs);
jp = new(g)JOUTFILE(g, fs);
b = pretty == 1;
} // endif's
}
switch (jsp->GetType()) {
case TYPE_JAR:
err = SerializeArray(jp, (PJAR)jsp, b);
......@@ -923,6 +949,22 @@ void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PSZ key)
} // end of SetValue
/***********************************************************************/
/* Delete a value corresponding to the given key. */
/***********************************************************************/
void JOBJECT::DeleteKey(PSZ key)
{
PJPR jp, *pjp = &First;
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
*pjp = jp->Next;
break;
} else
pjp = &jp->Next;
} // end of DeleteKey
/***********************************************************************/
/* True if void or if all members are nulls. */
/***********************************************************************/
......@@ -943,23 +985,25 @@ bool JOBJECT::IsNull(void)
void JARRAY::InitArray(PGLOBAL g)
{
int i;
PJVAL jvp;
PJVAL jvp, *pjvp = &First;
for (Size = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp->Del)
Size++;
if (!Size) {
return;
} else if (Size > Alloc) {
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)
if (!jvp->Del) {
Mvals[i++] = jvp;
pjvp = &jvp->Next;
Last = jvp;
} else
*pjvp = jvp->Next;
} // end of InitArray
......@@ -975,31 +1019,45 @@ PJVAL JARRAY::GetValue(int i)
} // end of GetValue
/***********************************************************************/
/* Add a Value to the Arrays Value list. */
/* Add a Value to the Array Value list. */
/***********************************************************************/
PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp)
PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp, int *x)
{
if (!jvp)
jvp = new(g) JVALUE;
if (x) {
int i = 0, n = *x;
PJVAL jp, *jpp = &First;
for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
(*jpp) = jvp;
if (!(jvp->Next = jp))
Last = jvp;
} else {
if (Last)
Last->Next = jvp;
else
First = jvp;
Last = jvp;
} // endif x
return jvp;
} // end of AddValue
/***********************************************************************/
/* Add a Value to the Arrays Value list. */
/* Set the nth Value of the Array 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))
for (jp = First; i < n; i++, jp = *(jpp = &jp->Next))
if (!jp)
*jpp = jp = new(g) JVALUE;
......@@ -1092,6 +1150,14 @@ int JVALUE::GetInteger(void)
return (Value) ? Value->GetIntValue() : 0;
} // end of GetInteger
/***********************************************************************/
/* Return the Value's Big integer value. */
/***********************************************************************/
long long JVALUE::GetBigint(void)
{
return (Value) ? Value->GetBigintValue() : 0;
} // end of GetBigint
/***********************************************************************/
/* Return the Value's Double value. */
/***********************************************************************/
......@@ -1134,7 +1200,15 @@ PSZ JVALUE::GetText(PGLOBAL g, PSZ text)
void JVALUE::SetInteger(PGLOBAL g, int n)
{
Value = AllocateValue(g, &n, TYPE_INT);
} // end of AddInteger
} // end of SetInteger
/***********************************************************************/
/* Set the Value's value as the given big integer. */
/***********************************************************************/
void JVALUE::SetBigint(PGLOBAL g, long long ll)
{
Value = AllocateValue(g, &ll, TYPE_BIGINT);
} // end of SetBigint
/***********************************************************************/
/* Set the Value's value as the given DOUBLE. */
......@@ -1142,7 +1216,7 @@ void JVALUE::SetInteger(PGLOBAL g, int n)
void JVALUE::SetFloat(PGLOBAL g, double f)
{
Value = AllocateValue(g, &f, TYPE_DOUBLE, 6);
} // end of AddFloat
} // end of SetFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
......@@ -1150,7 +1224,7 @@ void JVALUE::SetFloat(PGLOBAL g, double f)
void JVALUE::SetString(PGLOBAL g, PSZ s)
{
Value = AllocateValue(g, s, TYPE_STRING);
} // end of AddFloat
} // end of SetString
/***********************************************************************/
/* True when its JSON or normal value is null. */
......
/**************** json H Declares Source Code File (.H) ****************/
/* Name: json.h Version 1.1 */
/* Name: json.h Version 1.2 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */
/* */
......@@ -16,6 +16,7 @@
enum JTYP {TYPE_STRG = 1,
TYPE_DBL = 2,
TYPE_BOOL = 4,
TYPE_BINT = 5,
TYPE_INTG = 7,
TYPE_JSON = 12,
TYPE_JAR,
......@@ -40,13 +41,13 @@ typedef struct {
int len;
} STRG, *PSG;
PJSON ParseJson(PGLOBAL g, char *s, int n, int prty, bool *b = NULL);
PJSON ParseJson(PGLOBAL g, char *s, int n, int prty = 2, bool *b = NULL);
PJAR ParseArray(PGLOBAL g, int& i, STRG& src);
PJOB ParseObject(PGLOBAL g, int& i, STRG& src);
PJVAL ParseValue(PGLOBAL g, int& i, STRG& src);
char *ParseString(PGLOBAL g, int& i, STRG& src);
PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src);
PSZ Serialize(PGLOBAL g, PJSON jsp, FILE *fs, int pretty);
PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty);
bool SerializeArray(JOUT *js, PJAR jarp, bool b);
bool SerializeObject(JOUT *js, PJOB jobp);
bool SerializeValue(JOUT *js, PJVAL jvp);
......@@ -118,6 +119,7 @@ class JOUTPRT : public JOUTFILE {
/***********************************************************************/
class JPAIR : public BLOCK {
friend class JOBJECT;
friend class JSNX;
friend PJOB ParseObject(PGLOBAL, int&, STRG&);
friend bool SerializeObject(JOUT *, PJOB);
public:
......@@ -145,7 +147,7 @@ class JSON : public BLOCK {
virtual JTYP GetType(void) {return TYPE_JSON;}
virtual JTYP GetValType(void) {X return TYPE_JSON;}
virtual void InitArray(PGLOBAL g) {X}
virtual PJVAL AddValue(PGLOBAL g, PJVAL jvp = NULL) {X return NULL;}
virtual PJVAL AddValue(PGLOBAL g, PJVAL jvp = NULL, int *x = NULL) {X return NULL;}
virtual PJPR AddPair(PGLOBAL g, PSZ key) {X return NULL;}
virtual PJVAL GetValue(const char *key) {X return NULL;}
virtual PJOB GetObject(void) {return NULL;}
......@@ -165,6 +167,7 @@ class JSON : public BLOCK {
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 void DeleteKey(char *k) {X}
virtual bool DeleteValue(int i) {X return true;}
virtual bool IsNull(void) {X return true;}
......@@ -178,6 +181,7 @@ class JSON : public BLOCK {
class JOBJECT : public JSON {
friend PJOB ParseObject(PGLOBAL, int&, STRG&);
friend bool SerializeObject(JOUT *, PJOB);
friend class JSNX;
public:
JOBJECT(void) : JSON() {First = Last = NULL;}
......@@ -191,6 +195,7 @@ class JOBJECT : public JSON {
virtual PJVAL GetValue(const char* key);
virtual PSZ GetText(PGLOBAL g, PSZ text);
virtual void SetValue(PGLOBAL g, PJVAL jvp, PSZ key);
virtual void DeleteKey(char *k);
virtual bool IsNull(void);
protected:
......@@ -211,7 +216,7 @@ class JARRAY : public JSON {
virtual void Clear(void) {First = Last = NULL; Size = 0;}
virtual JTYP GetType(void) {return TYPE_JAR;}
virtual PJAR GetArray(void) {return this;}
virtual PJVAL AddValue(PGLOBAL g, PJVAL jvp = NULL);
virtual PJVAL AddValue(PGLOBAL g, PJVAL jvp = NULL, int *x = NULL);
virtual void InitArray(PGLOBAL g);
virtual PJVAL GetValue(int i);
virtual bool SetValue(PGLOBAL g, PJVAL jvp, int i);
......@@ -231,6 +236,7 @@ class JARRAY : public JSON {
/***********************************************************************/
class JVALUE : public JSON {
friend class JARRAY;
friend class JSNX;
friend PJVAL ParseValue(PGLOBAL, int&, STRG&);
friend bool SerializeValue(JOUT *, PJVAL);
public:
......@@ -251,6 +257,7 @@ class JVALUE : public JSON {
virtual PVAL GetValue(void) {return Value;}
virtual PJSON GetJson(void) {return (Jsp ? Jsp : this);}
virtual int GetInteger(void);
virtual long long GetBigint(void);
virtual double GetFloat(void);
virtual PSZ GetString(void);
virtual PSZ GetText(PGLOBAL g, PSZ text);
......@@ -258,6 +265,7 @@ class JVALUE : public JSON {
virtual void SetValue(PJSON jsp) {Jsp = jsp;}
virtual void SetString(PGLOBAL g, PSZ s);
virtual void SetInteger(PGLOBAL g, int n);
virtual void SetBigint(PGLOBAL g, longlong ll);
virtual void SetFloat(PGLOBAL g, double f);
virtual bool IsNull(void);
......
This diff is collapsed.
/*************** tabjson H Declares Source Code File (.H) **************/
/* Name: jsonudf.h Version 1.1 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2015 */
/* */
/* This file contains the JSON UDF function and classe declares. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "block.h"
#include "osutil.h"
#include "maputil.h"
#include "json.h"
#define UDF_EXEC_ARGS \
UDF_INIT*, UDF_ARGS*, char*, unsigned long*, char*, char*
/***********************************************************************/
/* The JSON tree node. Can be an Object or an Array. */
/***********************************************************************/
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 Rx; // Read row number
int Nx; // Next to read row number
} JNODE, *PJNODE;
typedef class JSNX *PJSNX;
typedef class JOUTPATH *PJTP;
extern "C" {
DllExport my_bool Json_Value_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Value(UDF_EXEC_ARGS);
DllExport void Json_Value_deinit(UDF_INIT*);
DllExport my_bool Json_Array_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array(UDF_EXEC_ARGS);
DllExport void Json_Array_deinit(UDF_INIT*);
DllExport my_bool Json_Array_Add_Values_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array_Add_Values(UDF_EXEC_ARGS);
DllExport void Json_Array_Add_Values_deinit(UDF_INIT*);
DllExport my_bool Json_Array_Add_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array_Add(UDF_EXEC_ARGS);
DllExport void Json_Array_Add_deinit(UDF_INIT*);
DllExport my_bool Json_Array_Delete_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array_Delete(UDF_EXEC_ARGS);
DllExport void Json_Array_Delete_deinit(UDF_INIT*);
DllExport my_bool Json_Object_Nonull_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Object_Nonull(UDF_EXEC_ARGS);
DllExport void Json_Object_Nonull_deinit(UDF_INIT*);
DllExport my_bool Json_Object_Add_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Object_Add(UDF_EXEC_ARGS);
DllExport void Json_Object_Add_deinit(UDF_INIT*);
DllExport my_bool Json_Object_Delete_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Object_Delete(UDF_EXEC_ARGS);
DllExport void Json_Object_Delete_deinit(UDF_INIT*);
DllExport my_bool Json_Object_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Object(UDF_EXEC_ARGS);
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_EXEC_ARGS);
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_EXEC_ARGS);
DllExport void Json_Object_Grp_clear(UDF_INIT *, char *, char *);
DllExport void Json_Object_Grp_deinit(UDF_INIT*);
DllExport my_bool Json_Get_String_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Get_String(UDF_EXEC_ARGS);
DllExport void Json_Get_String_deinit(UDF_INIT*);
DllExport my_bool Json_Get_Int_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport long long Json_Get_Int(UDF_EXEC_ARGS);
DllExport void Json_Get_Int_deinit(UDF_INIT*);
DllExport my_bool Json_Get_Real_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport double Json_Get_Real(UDF_EXEC_ARGS);
DllExport void Json_Get_Real_deinit(UDF_INIT*);
DllExport my_bool Json_Locate_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Locate(UDF_EXEC_ARGS);
DllExport void Json_Locate_deinit(UDF_INIT*);
DllExport my_bool Json_File_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_File(UDF_EXEC_ARGS);
DllExport void Json_File_deinit(UDF_INIT*);
DllExport my_bool Json_Make_File_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Make_File(UDF_EXEC_ARGS);
DllExport void Json_Make_File_deinit(UDF_INIT*);
} // extern "C"
/***********************************************************************/
/* Class JSNX: JSON access method. */
/***********************************************************************/
class JSNX : public BLOCK {
public:
// Constructors
JSNX(PGLOBAL g, PJSON row, int type, int len = 64, int prec = 0);
// Implementation
int GetPrecision(void) {return Prec;}
PVAL GetValue(void) {return Value;}
// Methods
my_bool SetJpath(PGLOBAL g, char *path);
my_bool ParseJpath(PGLOBAL g);
void ReadValue(PGLOBAL g);
PJVAL GetJson(PGLOBAL g);
char *Locate(PGLOBAL g, PJSON jsp, char *what,
enum Item_result type, unsigned long len);
protected:
my_bool CheckExpand(PGLOBAL g, int i, PSZ nm, my_bool b);
my_bool SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm);
PVAL GetColumnValue(PGLOBAL g, PJSON row, int i);
PJVAL GetValue(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);
my_bool LocateArray(PJAR jarp);
my_bool LocateObject(PJOB jobp);
my_bool LocateValue(PJVAL jvp);
// Default constructor not to be used
JSNX(void) {}
// Members
PJSON Row;
PVAL Value;
PVAL MulVal; // To value used by multiple column
PJTP Jp;
JNODE *Nodes; // The intermediate objects
char *Jpath; // The json path
int Buf_Type;
int Long;
int Prec;
int Nod; // The number of intermediate objects
int Xnod; // Index of multiple values
int B; // Index base
my_bool Xpd; // True for expandable column
my_bool Parsed; // True when parsed
}; // end of class JSNX
/***********************************************************************/
/* Class JOUTPATH. Used to make the locate path. */
/***********************************************************************/
class JOUTPATH : public JOUTSTR {
public:
JOUTPATH(PGLOBAL g, char *w, enum Item_result type, unsigned long len)
: JOUTSTR(g) {What = w; Type = type; Len = len; Found = false;}
// Members
enum Item_result Type;
unsigned long Len;
char *What;
my_bool Found;
}; // end of class JOUTPATH
......@@ -14,20 +14,23 @@ SELECT Json_Array(56,3.1416,'My name is "Foo"',NULL);
Json_Array(56,3.1416,'My name is "Foo"',NULL)
[56,3.141600,"My name is \"Foo\"",null]
SELECT Json_Array_Add(Json_Array(56,3.1416,'foo',NULL)) Array;
ERROR HY000: Can't initialize function 'Json_Array_Add'; Json_Value_Add must have at least 2 arguments
ERROR HY000: Can't initialize function 'Json_Array_Add'; Json_Array_Add must have at least 2 arguments
SELECT Json_Array_Add(Json_Array(56,3.1416,'foo',NULL),'One more') Array;
Array
[56,3.141600,"foo",null,"One more"]
SELECT Json_Array_Add(Json_Value('one value'),'One more');
Json_Array_Add(Json_Value('one value'),'One more')
["one value","One more"]
"one value"
Warnings:
Warning 1105 First argument is not an array
SELECT Json_Array_Add('one value','One more');
ERROR HY000: Can't initialize function 'Json_Array_Add'; Json_Value_Add first argument must be a json item
ERROR HY000: Can't initialize function 'Json_Array_Add'; Json_Array_Add first argument must be a json item
SELECT Json_Array_Add('one value' json_,'One more');
Json_Array_Add('one value' json_,'One more')
[null,"One more"]
one value
Warnings:
Warning 1105 Bad 'o' character near one value
Warning 1105 Unexpected character 'o' near one value
Warning 1105 First argument is not an array
SELECT Json_Value(56,3.1416,'foo',NULL);
ERROR HY000: Can't initialize function 'Json_Value'; Json_Value cannot accept more than 1 argument
SELECT Json_Value(3.1416);
......
{"ISBN":"9782212090819","LANG":"fr","SUBJECT":"applications","AUTHOR":[{"FIRSTNAME":"Jean-Michel","LASTNAME":"Bernadac"},{"FIRSTNAME":"Franois","LASTNAME":"Knab"}],"TITLE":"Construire une application XML","PUBLISHER":{"NAME":"Eyrolles","PLACE":"Paris"},"DATEPUB":1999}
{"ISBN":"9782840825685","LANG":"fr","SUBJECT":"applications","AUTHOR":[{"FIRSTNAME":"William J.","LASTNAME":"Pardi"}],"TITLE":"XML en Action","TRANSLATED":{"PREFIX":"adapt de l'anglais par","TRANSLATOR":{"FIRSTNAME":"James","LASTNAME":"Guerin"}},"PUBLISHER":{"NAME":"Microsoft Press","PLACE":"Paris"},"DATEPUB":2001}
......@@ -4,6 +4,7 @@
let $MYSQLD_DATADIR= `select @@datadir`;
--copy_file $MTR_SUITE_DIR/std_data/biblio.json $MYSQLD_DATADIR/test/biblio.json
--copy_file $MTR_SUITE_DIR/std_data/bib0.json $MYSQLD_DATADIR/test/bib0.json
--copy_file $MTR_SUITE_DIR/std_data/expense.json $MYSQLD_DATADIR/test/expense.json
--copy_file $MTR_SUITE_DIR/std_data/mulexp3.json $MYSQLD_DATADIR/test/mulexp3.json
--copy_file $MTR_SUITE_DIR/std_data/mulexp4.json $MYSQLD_DATADIR/test/mulexp4.json
......@@ -115,6 +116,33 @@ ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='biblio.json';
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # Testing a pretty=0 file
--echo #
CREATE TABLE t1
(
ISBN CHAR(15) NOT NULL,
Language CHAR(2) FIELD_FORMAT='LANG',
Subject CHAR(32) FIELD_FORMAT='SUBJECT',
AuthorFN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:FIRSTNAME',
AuthorLN CHAR(128) FIELD_FORMAT='AUTHOR:[X]:LASTNAME',
Title CHAR(32) FIELD_FORMAT='TITLE',
Translation CHAR(32) FIELD_FORMAT='TRANSLATED:PREFIX',
TranslatorFN CHAR(80) FIELD_FORMAT='TRANSLATED:TRANSLATOR:FIRSTNAME',
TranslatorLN CHAR(80) FIELD_FORMAT='TRANSLATED:TRANSLATOR:LASTNAME',
Publisher CHAR(20) FIELD_FORMAT='PUBLISHER:NAME',
Location CHAR(16) FIELD_FORMAT='PUBLISHER:PLACE',
Year int(4) FIELD_FORMAT='DATEPUB',
INDEX IX(ISBN)
)
ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bib0.json' LRECL=320 OPTION_LIST='Pretty=0';
SHOW INDEX FROM t1;
SELECT * FROM t1;
DESCRIBE SELECT * FROM t1 WHERE ISBN = '9782212090819';
--error ER_GET_ERRMSG
UPDATE t1 SET AuthorFN = 'Philippe' WHERE ISBN = '9782212090819';
DROP TABLE t1;
--echo #
--echo # A file with 2 arrays
--echo #
......@@ -258,6 +286,8 @@ DROP TABLE t1, t2, t3, t4;
# Clean up
#
--remove_file $MYSQLD_DATADIR/test/biblio.json
--remove_file $MYSQLD_DATADIR/test/bib0.dnx
--remove_file $MYSQLD_DATADIR/test/bib0.json
--remove_file $MYSQLD_DATADIR/test/expense.json
--remove_file $MYSQLD_DATADIR/test/mulexp3.json
--remove_file $MYSQLD_DATADIR/test/mulexp4.json
......
......@@ -2360,9 +2360,11 @@ int ODBConn::GetCatInfo(CATPARM *cap)
} // endif rc
for (n = 0, crp = qrp->Colresp; crp; n++, crp = crp->Next) {
if (vlen[n] == SQL_NULL_DATA)
if (vlen[n] == SQL_NO_TOTAL)
ThrowDBX("Unexpected SQL_NO_TOTAL returned from SQLFetch");
else if (vlen[n] == SQL_NULL_DATA)
pval[n]->SetNull(true);
else if (crp->Type == TYPE_STRING && vlen[n] != SQL_NULL_DATA)
else if (crp->Type == TYPE_STRING/* && vlen[n] != SQL_NULL_DATA*/)
pval[n]->SetValue_char(pbuf[n], vlen[n]);
else
pval[n]->SetNull(false);
......
......@@ -193,7 +193,8 @@ class DllExport COLDEF : public COLCRT { /* Column description block
friend class COLBLK;
friend class DBFFAM;
friend class TDBASE;
public:
friend class TDBDOS;
public:
COLDEF(void); // Constructor
// Implementation
......
......@@ -2018,6 +2018,7 @@ int TDBDOS::EstimatedLength(void)
// result if we set dep to 1
dep = 1 + cdp->GetLong() / 20; // Why 20 ?????
} else for (; cdp; cdp = cdp->GetNext())
if (!(cdp->Flags & (U_VIRTUAL|U_SPECIAL)))
dep = MY_MAX(dep, cdp->GetOffset());
return (int)dep;
......@@ -2203,7 +2204,7 @@ bool TDBDOS::PrepareWriting(PGLOBAL)
} // endif Mode
return false;
} // end of WriteDB
} // end of PrepareWriting
/***********************************************************************/
/* WriteDB: Data Base write routine for DOS access method. */
......@@ -2215,7 +2216,7 @@ int TDBDOS::WriteDB(PGLOBAL g)
// Make the line to write
if (PrepareWriting(g))
return true;
return RC_FX;
if (trace > 1)
htrc("Write: line is='%s'\n", To_Line);
......
......@@ -755,7 +755,6 @@ int TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp)
} else
strcpy(To_Line, s);
Row->Clear();
return false;
} else
return true;
......@@ -979,6 +978,7 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
if (!stricmp(Name, colp->GetName())) {
Nod = colp->Nod;
Nodes = colp->Nodes;
Xpd = colp->Xpd;
goto fin;
} // endif Name
......@@ -1045,6 +1045,7 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
switch (val->GetValType()) {
case TYPE_STRG:
case TYPE_INTG:
case TYPE_BINT:
case TYPE_DBL:
vp->SetValue_pval(val->GetValue());
break;
......@@ -1347,6 +1348,11 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
/***********************************************************************/
void JSONCOL::WriteColumn(PGLOBAL g)
{
if (Xpd && Tjp->Pretty < 2) {
strcpy(g->Message, "Cannot write expanded column when Pretty is not 2");
longjmp(g->jumper[g->jump_level], 666);
} // endif Xpd
/*********************************************************************/
/* Check whether this node must be written. */
/*********************************************************************/
......@@ -1534,7 +1540,7 @@ int TDBJSON::MakeDocument(PGLOBAL g)
if (*objpath != '[') { // objpass is a key
if (jsp->GetType() != TYPE_JOB) {
strcpy(g->Message, "Table path does no match json file");
strcpy(g->Message, "Table path does not match the json file");
return RC_FX;
} // endif Type
......@@ -1550,7 +1556,7 @@ int TDBJSON::MakeDocument(PGLOBAL g)
} else if (objpath[strlen(objpath)-1] == ']') {
if (jsp->GetType() != TYPE_JAR) {
strcpy(g->Message, "Table path does no match json file");
strcpy(g->Message, "Table path does not match the json file");
return RC_FX;
} // endif Type
......@@ -1831,7 +1837,6 @@ void TDBJSON::CloseDB(PGLOBAL g)
// Save the modified document
char filename[_MAX_PATH];
PSZ msg;
FILE *fop;
Doc->InitArray(g);
......@@ -1839,11 +1844,7 @@ void TDBJSON::CloseDB(PGLOBAL g)
PlugSetPath(filename, ((PJDEF)To_Def)->Fn, GetPath());
// Serialize the modified table
if (!(fop = fopen(filename, "wb"))) {
sprintf(g->Message, MSG(OPEN_MODE_ERROR),
"w", (int)errno, filename);
strcat(strcat(g->Message, ": "), strerror(errno));
} else if ((msg = Serialize(g, Top, fop, Pretty)))
if ((msg = Serialize(g, Top, filename, Pretty)))
puts(msg);
} // end of CloseDB
......
......@@ -1358,10 +1358,6 @@ void ODBCCOL::ReadColumn(PGLOBAL g)
} // endif Buf_Type
// Handle null values
if (Value->IsZero())
Value->SetNull(Nullable);
if (trace > 1) {
char buf[64];
......
......@@ -103,6 +103,7 @@ ulonglong CharToNumber(char *p, int n, ulonglong maxval,
if (minus) *minus = false;
if (rc) *rc = false;
if (n <= 0) return 0LL;
// Eliminate leading blanks or 0
for (p2 = p + n; p < p2 && (*p == ' ' || *p == '0'); p++) ;
......@@ -705,7 +706,7 @@ bool TYPVAL<TYPE>::SetValue_char(char *p, int n)
template <>
bool TYPVAL<double>::SetValue_char(char *p, int n)
{
if (p) {
if (p && n > 0) {
char buf[64];
for (; n > 0 && *p == ' '; p++)
......@@ -1345,7 +1346,7 @@ bool TYPVAL<PSZ>::SetValue_char(char *p, int n)
{
bool rc;
if (p) {
if (p && n > 0) {
rc = n > Len;
if ((n = MY_MIN(n, Len))) {
......@@ -1804,7 +1805,7 @@ bool DECVAL::SetValue_char(char *p, int n)
{
bool rc;
if (p) {
if (p && n > 0) {
rc = n > Len;
if ((n = MY_MIN(n, Len))) {
......@@ -2095,7 +2096,7 @@ bool BINVAL::SetValue_char(char *p, int n)
{
bool rc;
if (p) {
if (p && n > 0) {
rc = n > Clen;
Len = MY_MIN(n, Clen);
memcpy(Binp, p, Len);
......@@ -2672,13 +2673,16 @@ bool DTVAL::SetValue_char(char *p, int n)
int ndv;
int dval[6];
if (n > 0) {
// Trim trailing blanks
for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--) ;
for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--);
if ((rc = (n = p2 - p + 1) > Len))
n = Len;
memcpy(Sdate, p, n);
} // endif n
Sdate[n] = '\0';
ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment