Commit 4e8af8a6 authored by Olivier Bertrand's avatar Olivier Bertrand

- Fix memory leak for the JSON table type

  (and continue BSON implementatio)
  modified:   storage/connect/bson.cpp
  modified:   storage/connect/bson.h
  modified:   storage/connect/bsonudf.cpp
  modified:   storage/connect/connect.cc
  modified:   storage/connect/global.h
  modified:   storage/connect/ha_connect.cc
  modified:   storage/connect/jsonudf.cpp
  modified:   storage/connect/mycat.cc
  modified:   storage/connect/plgdbsem.h
  modified:   storage/connect/plugutil.cpp
  modified:   storage/connect/tabjson.cpp
  modified:   storage/connect/tabjson.h
  modified:   storage/connect/user_connect.cc

- Desesperatly trying to fix xml.test failure
  modified:   storage/connect/mysql-test/connect/r/xml.result
parent 950bf6ab
This diff is collapsed.
...@@ -69,54 +69,64 @@ DllExport bool IsNum(PSZ s); ...@@ -69,54 +69,64 @@ DllExport bool IsNum(PSZ s);
class BJSON : public BLOCK { class BJSON : public BLOCK {
public: public:
// Constructor // Constructor
BJSON(void* base, PBVAL vp = NULL) { Base = base; Bvp = vp; } BJSON(PGLOBAL g, PBVAL vp = NULL) { G = g, Base = G->Sarea; Bvp = vp; }
void* GetBase(void) { return Base; } void* GetBase(void) { return Base; }
void SubSet(bool b = false);
void MemSave(void) {G->Saved_Size = ((PPOOLHEADER)G->Sarea)->To_Free;}
void GetMsg(PGLOBAL g) { if (g != G) strcpy(g->Message, G->Message); }
// SubAlloc functions // SubAlloc functions
void* BsonSubAlloc(PGLOBAL g, size_t size); void* BsonSubAlloc(size_t size);
PBPR SubAllocPair(PGLOBAL g, OFFSET key, OFFSET val = 0); PBPR SubAllocPair(OFFSET key, OFFSET val = 0);
PBPR SubAllocPair(PGLOBAL g, PSZ key, OFFSET val = 0) PBPR SubAllocPair(PSZ key, OFFSET val = 0)
{return SubAllocPair(g, MOF(key), val);} {return SubAllocPair(MOF(key), val);}
PBVAL SubAllocVal(PGLOBAL g); PBVAL NewVal(int type = TYPE_NULL);
PBVAL SubAllocVal(PGLOBAL g, OFFSET toval, int type = TYPE_NULL, short nd = 0); PBVAL SubAllocVal(OFFSET toval, int type = TYPE_NULL, short nd = 0);
PBVAL SubAllocVal(PGLOBAL g, PBVAL toval, int type = TYPE_NULL, short nd = 0) PBVAL SubAllocVal(PBVAL toval, int type = TYPE_NULL, short nd = 0)
{return SubAllocVal(g, MOF(toval), type, nd);} {return SubAllocVal(MOF(toval), type, nd);}
PBVAL SubAllocVal(PGLOBAL g, PSZ str, int type = TYPE_STRG, short nd = 0) PBVAL SubAllocStr(OFFSET str, short nd = 0);
{return SubAllocVal(g, MOF(str), type, nd);} PBVAL SubAllocStr(PSZ str, short nd = 0)
PBVAL SubAllocVal(PGLOBAL g, PVAL valp); {return SubAllocStr(MOF(str), nd);}
PBVAL DupVal(PGLOBAL g, PBVAL bvp); PBVAL SubAllocVal(PVAL valp);
PBVAL DupVal(PBVAL bvp);
// Array functions // Array functions
int GetArraySize(PBVAL bap, bool b = false); int GetArraySize(PBVAL bap, bool b = false);
PBVAL GetArrayValue(PBVAL bap, int i); PBVAL GetArrayValue(PBVAL bap, int i);
PSZ GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text); PSZ GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text);
PBVAL MergeArray(PGLOBAL g, PBVAL bap1,PBVAL bap2); PBVAL MergeArray(PBVAL bap1,PBVAL bap2);
PBVAL DeleteValue(PBVAL bap, int n); PBVAL DeleteValue(PBVAL bap, int n);
PBVAL AddArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp = NULL, int* x = NULL); PBVAL AddArrayValue(PBVAL bap, PBVAL nvp = NULL, int* x = NULL);
PBVAL SetArrayValue(PGLOBAL g, PBVAL bap, PBVAL nvp, int n); PBVAL SetArrayValue(PBVAL bap, PBVAL nvp, int n);
bool IsArrayNull(PBVAL bap); bool IsArrayNull(PBVAL bap);
// Object functions // Object functions
int GetObjectSize(PBPR bop, bool b = false); int GetObjectSize(PBPR bop, bool b = false);
PBPR GetNext(PBPR prp) {return MPP(prp->Next);}
PSZ GetObjectText(PGLOBAL g, PBPR bop, PSTRG text); PSZ GetObjectText(PGLOBAL g, PBPR bop, PSTRG text);
PBPR MergeObject(PGLOBAL g, PBPR bop1, PBPR bop2); PBPR MergeObject(PBPR bop1, PBPR bop2);
PBPR AddPair(PGLOBAL g, PBPR bop, PSZ key, OFFSET val = 0); PBPR AddPair(PBPR bop, PSZ key, OFFSET val = 0);
PSZ GetKey(PBPR prp) {return MZP(prp->Key);}
PBVAL GetVal(PBPR prp) {return MVP(prp->Vlp);}
PBVAL GetKeyValue(PBPR bop, PSZ key); PBVAL GetKeyValue(PBPR bop, PSZ key);
PBVAL GetKeyList(PGLOBAL g, PBPR bop); PBVAL GetKeyList(PBPR bop);
PBVAL GetObjectValList(PGLOBAL g, PBPR bop); PBVAL GetObjectValList(PBPR bop);
PBPR SetKeyValue(PGLOBAL g, PBPR bop, OFFSET bvp, PSZ key); PBPR SetKeyValue(PBPR bop, OFFSET bvp, PSZ key);
inline PBPR SetKeyValue(PBPR bop, PBVAL vlp, PSZ key)
{return SetKeyValue(bop, MOF(vlp), key);}
PBPR DeleteKey(PBPR bop, PCSZ k); PBPR DeleteKey(PBPR bop, PCSZ k);
bool IsObjectNull(PBPR bop); bool IsObjectNull(PBPR bop);
// Value functions // Value functions
int GetSize(PBVAL vlp, bool b = false); int GetSize(PBVAL vlp, bool b = false);
PBVAL GetNext(PBVAL vlp) {return MVP(vlp->Next);}
PBPR GetObject(PBVAL vlp); PBPR GetObject(PBVAL vlp);
PBVAL GetArray(PBVAL vlp); PBVAL GetArray(PBVAL vlp);
//PJSON GetJsp(void) { return (DataType == TYPE_JSON ? Jsp : NULL); } //PJSON GetJsp(void) { return (DataType == TYPE_JSON ? Jsp : NULL); }
PSZ GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text); PSZ GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text);
//inline PJSON GetJson(void) { return (DataType == TYPE_JSON ? Jsp : this); } inline PBVAL GetBson(PBVAL bvp) { return IsJson(bvp) ? MVP(bvp->To_Val) : bvp; }
PSZ GetString(PGLOBAL g, PBVAL vp, char* buff = NULL); PSZ GetString(PBVAL vp, char* buff = NULL);
int GetInteger(PBVAL vp); int GetInteger(PBVAL vp);
long long GetBigint(PBVAL vp); long long GetBigint(PBVAL vp);
double GetDouble(PBVAL vp); double GetDouble(PBVAL vp);
...@@ -124,17 +134,20 @@ class BJSON : public BLOCK { ...@@ -124,17 +134,20 @@ class BJSON : public BLOCK {
void SetValueObj(PBVAL vlp, PBPR bop); void SetValueObj(PBVAL vlp, PBPR bop);
void SetValueArr(PBVAL vlp, PBVAL bap); void SetValueArr(PBVAL vlp, PBVAL bap);
void SetValueVal(PBVAL vlp, PBVAL vp); void SetValueVal(PBVAL vlp, PBVAL vp);
void SetValue(PGLOBAL g, PBVAL vlp, PVAL valp); void SetValue(PBVAL vlp, PVAL valp);
void SetString(PBVAL vlp, PSZ s, int ci = 0); void SetString(PBVAL vlp, PSZ s, int ci = 0);
void SetInteger(PBVAL vlp, int n); void SetInteger(PBVAL vlp, int n);
void SetBigint(PGLOBAL g, PBVAL vlp, longlong ll); void SetBigint(PBVAL vlp, longlong ll);
void SetFloat(PBVAL vlp, double f); void SetFloat(PBVAL vlp, double f);
void SetBool(PBVAL vlp, bool b); void SetBool(PBVAL vlp, bool b);
void Clear(PBVAL vlp) { vlp->N = 0; vlp->Nd = 0; vlp->Next = 0; vlp->Type = TYPE_NULL; }
bool IsValueNull(PBVAL vlp); bool IsValueNull(PBVAL vlp);
bool IsJson(PBVAL vlp) {return (vlp->Type == TYPE_JAR || vlp->Type == TYPE_JOB);}
// Members // Members
PBVAL Bvp; PGLOBAL G;
void* Base; PBVAL Bvp;
void *Base;
protected: protected:
// Default constructor not to be used // Default constructor not to be used
...@@ -146,18 +159,18 @@ class BJSON : public BLOCK { ...@@ -146,18 +159,18 @@ class BJSON : public BLOCK {
/***********************************************************************/ /***********************************************************************/
class BDOC : public BJSON { class BDOC : public BJSON {
public: public:
BDOC(void *); BDOC(PGLOBAL G);
PBVAL ParseJson(PGLOBAL g, char* s, size_t n, int* prty = NULL, bool* b = NULL); PBVAL ParseJson(PGLOBAL g, char* s, size_t n, int* prty = NULL, bool* b = NULL);
PSZ Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty); PSZ Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty);
protected: protected:
OFFSET ParseArray(PGLOBAL g, int& i); OFFSET ParseArray(int& i);
OFFSET ParseObject(PGLOBAL g, int& i); OFFSET ParseObject(int& i);
PBVAL ParseValue(PGLOBAL g, int& i); PBVAL ParseValue(int& i);
OFFSET ParseString(PGLOBAL g, int& i); OFFSET ParseString(int& i);
void ParseNumeric(PGLOBAL g, int& i, PBVAL bvp); void ParseNumeric(int& i, PBVAL bvp);
OFFSET ParseAsArray(PGLOBAL g, int& i, int pretty, int* ptyp); OFFSET ParseAsArray(int& i, int pretty, int* ptyp);
bool SerializeArray(OFFSET arp, bool b); bool SerializeArray(OFFSET arp, bool b);
bool SerializeObject(OFFSET obp); bool SerializeObject(OFFSET obp);
bool SerializeValue(PBVAL vp); bool SerializeValue(PBVAL vp);
...@@ -166,7 +179,7 @@ class BDOC : public BJSON { ...@@ -166,7 +179,7 @@ class BDOC : public BJSON {
JOUT* jp; // Used with serialize JOUT* jp; // Used with serialize
char* s; // The Json string to parse char* s; // The Json string to parse
int len; // The Json string length int len; // The Json string length
bool pty[3]; // Used to guess what pretty is bool pty[3]; // Used to guess what pretty is
// Default constructor not to be used // Default constructor not to be used
BDOC(void) {} BDOC(void) {}
......
...@@ -41,7 +41,7 @@ inline void JsonMemSave(PGLOBAL g) { ...@@ -41,7 +41,7 @@ inline void JsonMemSave(PGLOBAL g) {
/*********************************************************************************/ /*********************************************************************************/
inline void JsonFreeMem(PGLOBAL g) { inline void JsonFreeMem(PGLOBAL g) {
g->Activityp = NULL; g->Activityp = NULL;
PlugExit(g); g = PlugExit(g);
} /* end of JsonFreeMem */ } /* end of JsonFreeMem */
/* --------------------------- New Testing BJSON Stuff --------------------------*/ /* --------------------------- New Testing BJSON Stuff --------------------------*/
...@@ -71,8 +71,7 @@ static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len) ...@@ -71,8 +71,7 @@ static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len)
/*********************************************************************************/ /*********************************************************************************/
/* BSNX public constructor. */ /* BSNX public constructor. */
/*********************************************************************************/ /*********************************************************************************/
BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) : BDOC(g)
: BDOC(g->Sarea)
{ {
Row = row; Row = row;
Bvalp = NULL; Bvalp = NULL;
...@@ -361,7 +360,7 @@ void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp) ...@@ -361,7 +360,7 @@ void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp)
} else switch (vlp->Type) { } else switch (vlp->Type) {
case TYPE_DTM: case TYPE_DTM:
case TYPE_STRG: case TYPE_STRG:
vp->SetValue_psz(GetString(g, vlp)); vp->SetValue_psz(GetString(vlp));
break; break;
case TYPE_INTG: case TYPE_INTG:
case TYPE_BINT: case TYPE_BINT:
...@@ -371,14 +370,14 @@ void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp) ...@@ -371,14 +370,14 @@ void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp)
if (vp->IsTypeNum()) if (vp->IsTypeNum())
vp->SetValue(GetDouble(vlp)); vp->SetValue(GetDouble(vlp));
else // Get the proper number of decimals else // Get the proper number of decimals
vp->SetValue_psz(GetString(g, vlp)); vp->SetValue_psz(GetString(vlp));
break; break;
case TYPE_BOOL: case TYPE_BOOL:
if (vp->IsTypeNum()) if (vp->IsTypeNum())
vp->SetValue(GetInteger(vlp) ? 1 : 0); vp->SetValue(GetInteger(vlp) ? 1 : 0);
else else
vp->SetValue_psz(GetString(g, vlp)); vp->SetValue_psz(GetString(vlp));
break; break;
case TYPE_JAR: case TYPE_JAR:
...@@ -439,7 +438,7 @@ PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b) ...@@ -439,7 +438,7 @@ PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b)
for (; i < Nod && row; i++) { for (; i < Nod && row; i++) {
if (Nodes[i].Op == OP_NUM) { if (Nodes[i].Op == OP_NUM) {
Value->SetValue(row->Type == TYPE_JAR ? GetArraySize(MVP(row->To_Val)) : 1); Value->SetValue(row->Type == TYPE_JAR ? GetArraySize(MVP(row->To_Val)) : 1);
vlp = SubAllocVal(g, Value); vlp = SubAllocVal(Value);
return vlp; return vlp;
} else if (Nodes[i].Op == OP_XX) { } else if (Nodes[i].Op == OP_XX) {
Jb = b; Jb = b;
...@@ -473,7 +472,7 @@ PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b) ...@@ -473,7 +472,7 @@ PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i, my_bool b)
else if (Nodes[i].Op == OP_EXP) else if (Nodes[i].Op == OP_EXP)
return (PBVAL)ExpandArray(g, bap, i); return (PBVAL)ExpandArray(g, bap, i);
else else
return SubAllocVal(g, CalculateArray(g, bap, i)); return SubAllocVal(CalculateArray(g, bap, i));
} else { } else {
// Unexpected array, unwrap it as [0] // Unexpected array, unwrap it as [0]
...@@ -701,12 +700,12 @@ PBVAL BJNX::GetRow(PGLOBAL g) ...@@ -701,12 +700,12 @@ PBVAL BJNX::GetRow(PGLOBAL g)
// nwr = SubAllocPair(g); // nwr = SubAllocPair(g);
// Construct new row // Construct new row
nwr = SubAllocVal(g); nwr = NewVal();
if (row->Type == TYPE_JOB) { if (row->Type == TYPE_JOB) {
SetKeyValue(g, MPP(row->To_Val), MOF(nwr), Nodes[i - 1].Key); SetKeyValue(MPP(row->To_Val), MOF(nwr), Nodes[i - 1].Key);
} else if (row->Type == TYPE_JAR) { } else if (row->Type == TYPE_JAR) {
AddArrayValue(g, MVP(row->To_Val), nwr); AddArrayValue(MVP(row->To_Val), nwr);
} else { } else {
strcpy(g->Message, "Wrong type when writing new row"); strcpy(g->Message, "Wrong type when writing new row");
nwr = NULL; nwr = NULL;
...@@ -748,15 +747,15 @@ my_bool BJNX::WriteValue(PGLOBAL g, PBVAL jvalp) ...@@ -748,15 +747,15 @@ my_bool BJNX::WriteValue(PGLOBAL g, PBVAL jvalp)
if (arp) { if (arp) {
if (!Nodes[Nod - 1].Key) { if (!Nodes[Nod - 1].Key) {
if (Nodes[Nod - 1].Op == OP_EQ) if (Nodes[Nod - 1].Op == OP_EQ)
SetArrayValue(g, arp, jvalp, Nodes[Nod - 1].Rank); SetArrayValue(arp, jvalp, Nodes[Nod - 1].Rank);
else else
AddArrayValue(g, arp, jvalp); AddArrayValue(arp, jvalp);
} // endif Key } // endif Key
} else if (objp) { } else if (objp) {
if (Nodes[Nod - 1].Key) if (Nodes[Nod - 1].Key)
SetKeyValue(g, objp, MOF(jvalp), Nodes[Nod - 1].Key); SetKeyValue(objp, MOF(jvalp), Nodes[Nod - 1].Key);
} else if (jvp) } else if (jvp)
SetValueVal(jvp, jvalp); SetValueVal(jvp, jvalp);
...@@ -1159,8 +1158,8 @@ static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i) ...@@ -1159,8 +1158,8 @@ static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i)
int n, len; int n, len;
int ci; int ci;
longlong bigint; longlong bigint;
BDOC doc(g->Sarea); BDOC doc(g);
PBVAL bp, bvp = doc.SubAllocVal(g); PBVAL bp, bvp = doc.NewVal();
if (sap) { if (sap) {
if (args->arg_type[i] == STRING_RESULT) { if (args->arg_type[i] == STRING_RESULT) {
...@@ -1209,7 +1208,7 @@ static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i) ...@@ -1209,7 +1208,7 @@ static PBVAL MakeBinValue(PGLOBAL g, UDF_ARGS* args, uint i)
(bigint == 1LL && !strcmp(args->attributes[i], "TRUE"))) (bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
doc.SetBool(bvp, (bool)bigint); doc.SetBool(bvp, (bool)bigint);
else else
doc.SetBigint(g, bvp, bigint); doc.SetBigint(bvp, bigint);
break; break;
case REAL_RESULT: case REAL_RESULT:
...@@ -1256,7 +1255,7 @@ char* bsonvalue(UDF_INIT* initid, UDF_ARGS* args, char* result, ...@@ -1256,7 +1255,7 @@ char* bsonvalue(UDF_INIT* initid, UDF_ARGS* args, char* result,
if (!g->Xchk) { if (!g->Xchk) {
if (!CheckMemory(g, initid, args, 1, false)) { if (!CheckMemory(g, initid, args, 1, false)) {
BDOC doc(g->Sarea); BDOC doc(g);
PBVAL bvp = MakeBinValue(g, args, 0); PBVAL bvp = MakeBinValue(g, args, 0);
if (!(str = doc.Serialize(g, bvp, NULL, 0))) if (!(str = doc.Serialize(g, bvp, NULL, 0)))
...@@ -1297,13 +1296,13 @@ char* bson_make_array(UDF_INIT* initid, UDF_ARGS* args, char* result, ...@@ -1297,13 +1296,13 @@ char* bson_make_array(UDF_INIT* initid, UDF_ARGS* args, char* result,
if (!g->Xchk) { if (!g->Xchk) {
if (!CheckMemory(g, initid, args, args->arg_count, false)) { if (!CheckMemory(g, initid, args, args->arg_count, false)) {
BDOC doc(g->Sarea); BDOC doc(g);
PBVAL bvp = NULL, arp = NULL; PBVAL bvp = NULL, arp = NULL;
for (uint i = 0; i < args->arg_count; i++) for (uint i = 0; i < args->arg_count; i++)
bvp = doc.AddArrayValue(g, bvp, MakeBinValue(g, args, i)); bvp = doc.AddArrayValue(bvp, MakeBinValue(g, args, i));
arp = doc.SubAllocVal(g, bvp, TYPE_JAR); arp = doc.SubAllocVal(bvp, TYPE_JAR);
if (!(str = doc.Serialize(g, arp, NULL, 0))) if (!(str = doc.Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message); str = strcpy(result, g->Message);
...@@ -1364,7 +1363,7 @@ char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result, ...@@ -1364,7 +1363,7 @@ char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result,
if (!CheckMemory(g, initid, args, args->arg_count, true)) { if (!CheckMemory(g, initid, args, args->arg_count, true)) {
uint n = 1; uint n = 1;
bool b = false; bool b = false;
BDOC doc(g->Sarea); BDOC doc(g);
PBVAL bvp = NULL, arp = MakeBinValue(g, args, 0); PBVAL bvp = NULL, arp = MakeBinValue(g, args, 0);
if (arp->Type == TYPE_JAR) { if (arp->Type == TYPE_JAR) {
...@@ -1374,10 +1373,10 @@ char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result, ...@@ -1374,10 +1373,10 @@ char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result,
n = 0; n = 0;
for (uint i = n; i < args->arg_count; i++) for (uint i = n; i < args->arg_count; i++)
bvp = doc.AddArrayValue(g, bvp, MakeBinValue(g, args, i)); bvp = doc.AddArrayValue(bvp, MakeBinValue(g, args, i));
if (!n) if (!n)
arp = doc.SubAllocVal(g, bvp, TYPE_JAR); arp = doc.SubAllocVal(bvp, TYPE_JAR);
else if (b) else if (b)
doc.SetValueArr(arp, bvp); doc.SetValueArr(arp, bvp);
......
...@@ -73,8 +73,7 @@ PGLOBAL CntExit(PGLOBAL g) ...@@ -73,8 +73,7 @@ PGLOBAL CntExit(PGLOBAL g)
g->Activityp = NULL; g->Activityp = NULL;
} // endif Activityp } // endif Activityp
PlugExit(g); g= PlugExit(g);
g= NULL;
} // endif g } // endif g
return g; return g;
......
...@@ -208,7 +208,7 @@ DllExport char *PlugGetMessage(PGLOBAL, int); ...@@ -208,7 +208,7 @@ DllExport char *PlugGetMessage(PGLOBAL, int);
DllExport short GetLineLength(PGLOBAL); // Console line length DllExport short GetLineLength(PGLOBAL); // Console line length
#endif // __WIN__ #endif // __WIN__
DllExport PGLOBAL PlugInit(LPCSTR, size_t); // Plug global initialization DllExport PGLOBAL PlugInit(LPCSTR, size_t); // Plug global initialization
DllExport int PlugExit(PGLOBAL); // Plug global termination DllExport PGLOBAL PlugExit(PGLOBAL); // Plug global termination
DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR); DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR);
DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir); DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir);
DllExport BOOL PlugIsAbsolutePath(LPCSTR path); DllExport BOOL PlugIsAbsolutePath(LPCSTR path);
......
...@@ -170,7 +170,7 @@ ...@@ -170,7 +170,7 @@
#define JSONMAX 10 // JSON Default max grp size #define JSONMAX 10 // JSON Default max grp size
extern "C" { extern "C" {
char version[]= "Version 1.07.0002 November 13, 2020"; char version[]= "Version 1.07.0002 November 30, 2020";
#if defined(__WIN__) #if defined(__WIN__)
char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__; char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__;
char slash= '\\'; char slash= '\\';
...@@ -230,6 +230,9 @@ char *GetUserVariable(PGLOBAL g, const uchar *varname) ...@@ -230,6 +230,9 @@ char *GetUserVariable(PGLOBAL g, const uchar *varname)
PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
PQRYRES VirColumns(PGLOBAL g, bool info); PQRYRES VirColumns(PGLOBAL g, bool info);
PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info); PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info);
#ifdef DEVELOPMENT
PQRYRES BSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info);
#endif // DEVEOPMENT
PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info); PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info);
#if defined(REST_SUPPORT) #if defined(REST_SUPPORT)
PQRYRES RESTColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); PQRYRES RESTColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
...@@ -4513,7 +4516,10 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) ...@@ -4513,7 +4516,10 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick)
case TAB_VEC: case TAB_VEC:
case TAB_REST: case TAB_REST:
case TAB_JSON: case TAB_JSON:
if (options->filename && *options->filename) { #if defined DEVELOPMENT
case TAB_BSON:
#endif // DEVELOPMENT
if (options->filename && *options->filename) {
if (!quick) { if (!quick) {
char path[FN_REFLEN], dbpath[FN_REFLEN]; char path[FN_REFLEN], dbpath[FN_REFLEN];
...@@ -5679,7 +5685,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5679,7 +5685,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
} else if (topt->http) { } else if (topt->http) {
switch (ttp) { switch (ttp) {
case TAB_JSON: case TAB_JSON:
case TAB_XML: #ifdef DEVELOPMENT
case TAB_BSON:
#endif // DEVELOPMENT
case TAB_XML:
case TAB_CSV: case TAB_CSV:
ttp = TAB_REST; ttp = TAB_REST;
break; break;
...@@ -5863,6 +5872,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -5863,6 +5872,9 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
case TAB_XML: case TAB_XML:
#endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT #endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT
case TAB_JSON: case TAB_JSON:
#ifdef DEVELOPMENT
case TAB_BSON:
#endif // DEVELOPMENT
dsn= strz(g, create_info->connect_string); dsn= strz(g, create_info->connect_string);
if (!fn && !zfn && !mul && !dsn) if (!fn && !zfn && !mul && !dsn)
...@@ -6029,6 +6041,11 @@ static int connect_assisted_discovery(handlerton *, THD* thd, ...@@ -6029,6 +6041,11 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
case TAB_JSON: case TAB_JSON:
qrp= JSONColumns(g, db, dsn, topt, fnc == FNC_COL); qrp= JSONColumns(g, db, dsn, topt, fnc == FNC_COL);
break; break;
#ifdef DEVELOPMENT
case TAB_BSON:
qrp= BSONColumns(g, db, dsn, topt, fnc == FNC_COL);
break;
#endif // DEVELOPMENT
#if defined(JAVA_SUPPORT) #if defined(JAVA_SUPPORT)
case TAB_MONGO: case TAB_MONGO:
url= strz(g, create_info->connect_string); url= strz(g, create_info->connect_string);
......
...@@ -1178,7 +1178,7 @@ my_bool JsonSubSet(PGLOBAL g) ...@@ -1178,7 +1178,7 @@ my_bool JsonSubSet(PGLOBAL g)
{ {
PPOOLHEADER pph = (PPOOLHEADER)g->Sarea; PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
pph->To_Free = (g->Saved_Size) ? g->Saved_Size : (size_t)sizeof(POOLHEADER); pph->To_Free = (g->Saved_Size) ? g->Saved_Size : sizeof(POOLHEADER);
pph->FreeBlk = g->Sarea_Size - pph->To_Free; pph->FreeBlk = g->Sarea_Size - pph->To_Free;
g->Saved_Size = 0; g->Saved_Size = 0;
return FALSE; return FALSE;
...@@ -1198,7 +1198,7 @@ inline void JsonMemSave(PGLOBAL g) ...@@ -1198,7 +1198,7 @@ inline void JsonMemSave(PGLOBAL g)
inline void JsonFreeMem(PGLOBAL g) inline void JsonFreeMem(PGLOBAL g)
{ {
g->Activityp = NULL; g->Activityp = NULL;
PlugExit(g); g = PlugExit(g);
} /* end of JsonFreeMem */ } /* end of JsonFreeMem */
/*********************************************************************************/ /*********************************************************************************/
...@@ -1281,7 +1281,7 @@ my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args, char *message, my_bool mbn, ...@@ -1281,7 +1281,7 @@ my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args, char *message, my_bool mbn,
return true; return true;
} else if (g->Sarea_Size == 0) { } else if (g->Sarea_Size == 0) {
strcpy(message, g->Message); strcpy(message, g->Message);
PlugExit(g); g = PlugExit(g);
return true; return true;
} // endif g } // endif g
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
/*************** Mycat CC Program Source Code File (.CC) ***************/ /*************** Mycat CC Program Source Code File (.CC) ***************/
/* PROGRAM NAME: MYCAT */ /* PROGRAM NAME: MYCAT */
/* ------------- */ /* ------------- */
/* Version 1.7 */ /* Version 1.8 */
/* */ /* */
/* Author: Olivier Bertrand 2012 - 2019 */ /* Author: Olivier Bertrand 2012 - 2020 */
/* */ /* */
/* WHAT THIS PROGRAM DOES: */ /* WHAT THIS PROGRAM DOES: */
/* ----------------------- */ /* ----------------------- */
...@@ -82,7 +82,11 @@ ...@@ -82,7 +82,11 @@
#endif // JAVA_SUPPORT #endif // JAVA_SUPPORT
#include "tabpivot.h" #include "tabpivot.h"
#include "tabvir.h" #include "tabvir.h"
#if defined(DEVELOPMENT)
#include "tabbson.h"
#else
#include "tabjson.h" #include "tabjson.h"
#endif // DEVELOPMENT
#include "ha_connect.h" #include "ha_connect.h"
#if defined(XML_SUPPORT) #if defined(XML_SUPPORT)
#include "tabxml.h" #include "tabxml.h"
...@@ -157,6 +161,9 @@ TABTYPE GetTypeID(const char *type) ...@@ -157,6 +161,9 @@ TABTYPE GetTypeID(const char *type)
: (!stricmp(type, "PIVOT")) ? TAB_PIVOT : (!stricmp(type, "PIVOT")) ? TAB_PIVOT
: (!stricmp(type, "VIR")) ? TAB_VIR : (!stricmp(type, "VIR")) ? TAB_VIR
: (!stricmp(type, "JSON")) ? TAB_JSON : (!stricmp(type, "JSON")) ? TAB_JSON
#if defined(DEVELOPMENT)
: (!stricmp(type, "BSON")) ? TAB_BSON
#endif
#if defined(ZIP_SUPPORT) #if defined(ZIP_SUPPORT)
: (!stricmp(type, "ZIP")) ? TAB_ZIP : (!stricmp(type, "ZIP")) ? TAB_ZIP
#endif #endif
...@@ -181,6 +188,9 @@ bool IsFileType(TABTYPE type) ...@@ -181,6 +188,9 @@ bool IsFileType(TABTYPE type)
case TAB_INI: case TAB_INI:
case TAB_VEC: case TAB_VEC:
case TAB_JSON: case TAB_JSON:
#if defined(DEVELOPMENT)
case TAB_BSON:
#endif
case TAB_REST: case TAB_REST:
// case TAB_ZIP: // case TAB_ZIP:
isfile= true; isfile= true;
...@@ -276,6 +286,9 @@ bool IsTypeIndexable(TABTYPE type) ...@@ -276,6 +286,9 @@ bool IsTypeIndexable(TABTYPE type)
case TAB_VEC: case TAB_VEC:
case TAB_DBF: case TAB_DBF:
case TAB_JSON: case TAB_JSON:
#if defined(DEVELOPMENT)
case TAB_BSON:
#endif
idx= true; idx= true;
break; break;
default: default:
...@@ -302,6 +315,9 @@ int GetIndexType(TABTYPE type) ...@@ -302,6 +315,9 @@ int GetIndexType(TABTYPE type)
case TAB_VEC: case TAB_VEC:
case TAB_DBF: case TAB_DBF:
case TAB_JSON: case TAB_JSON:
#if defined(DEVELOPMENT)
case TAB_BSON:
#endif
xtyp= 1; xtyp= 1;
break; break;
case TAB_MYSQL: case TAB_MYSQL:
...@@ -445,7 +461,7 @@ PTABDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) ...@@ -445,7 +461,7 @@ PTABDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am)
case TAB_XML: tdp= new(g) XMLDEF; break; case TAB_XML: tdp= new(g) XMLDEF; break;
#endif // XML_SUPPORT #endif // XML_SUPPORT
#if defined(VCT_SUPPORT) #if defined(VCT_SUPPORT)
case TAB_VEC: tdp = new(g) VCTDEF; break; case TAB_VEC: tdp= new(g) VCTDEF; break;
#endif // VCT_SUPPORT #endif // VCT_SUPPORT
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
case TAB_ODBC: tdp= new(g) ODBCDEF; break; case TAB_ODBC: tdp= new(g) ODBCDEF; break;
...@@ -466,8 +482,11 @@ PTABDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) ...@@ -466,8 +482,11 @@ PTABDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am)
case TAB_PIVOT: tdp= new(g) PIVOTDEF; break; case TAB_PIVOT: tdp= new(g) PIVOTDEF; break;
case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_VIR: tdp= new(g) VIRDEF; break;
case TAB_JSON: tdp= new(g) JSONDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break;
#if defined(DEVELOPMENT)
case TAB_BSON: tdp= new(g) BSONDEF; break;
#endif
#if defined(ZIP_SUPPORT) #if defined(ZIP_SUPPORT)
case TAB_ZIP: tdp = new(g) ZIPDEF; break; case TAB_ZIP: tdp= new(g) ZIPDEF; break;
#endif // ZIP_SUPPORT #endif // ZIP_SUPPORT
#if defined(REST_SUPPORT) #if defined(REST_SUPPORT)
case TAB_REST: tdp= new (g) RESTDEF; break; case TAB_REST: tdp= new (g) RESTDEF; break;
......
...@@ -323,7 +323,7 @@ HEX(c) 3F3F3F3F3F3F3F ...@@ -323,7 +323,7 @@ HEX(c) 3F3F3F3F3F3F3F
Warnings: Warnings:
Level Warning Level Warning
Code 1366 Code 1366
Message Incorrect string value: '\xC3\x81\xC3\x82\xC3\x83...' for column 'c' at row 1 Message Incorrect string value: '\xC3\x81\xC3\x82\xC3\x83...' for column `test`.`t1`.`c` at row 1
Level Warning Level Warning
Code 1105 Code 1105
Message Out of range value ÁÂÃÄÅÆÇ for column 'c' at row 1 Message Out of range value ÁÂÃÄÅÆÇ for column 'c' at row 1
...@@ -374,7 +374,7 @@ INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3); ...@@ -374,7 +374,7 @@ INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3);
Warnings: Warnings:
Level Warning Level Warning
Code 1105 Code 1105
Message Com error: Unable to save character to 'iso-8859-1' encoding. Message Com error: Impossible d'enregistrer le caractre dans le codage iso-8859-1.
INSERT INTO t1 VALUES ('&<>"\''); INSERT INTO t1 VALUES ('&<>"\'');
SELECT node, hex(node) FROM t1; SELECT node, hex(node) FROM t1;
......
...@@ -83,7 +83,8 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ ...@@ -83,7 +83,8 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */
TAB_ZIP = 27, /* ZIP file info table */ TAB_ZIP = 27, /* ZIP file info table */
TAB_MONGO = 28, /* Table retrieved from MongoDB */ TAB_MONGO = 28, /* Table retrieved from MongoDB */
TAB_REST = 29, /* Table retrieved from Rest */ TAB_REST = 29, /* Table retrieved from Rest */
TAB_NIY = 30}; /* Table not implemented yet */ TAB_BSON = 30, /* BSON Table (development) */
TAB_NIY = 31}; /* Table not implemented yet */
enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
TYPE_AM_ROWID = 1, /* ROWID type (special column) */ TYPE_AM_ROWID = 1, /* ROWID type (special column) */
......
...@@ -184,7 +184,7 @@ PGLOBAL PlugInit(LPCSTR Language, size_t worksize) ...@@ -184,7 +184,7 @@ PGLOBAL PlugInit(LPCSTR Language, size_t worksize)
/***********************************************************************/ /***********************************************************************/
/* PlugExit: Terminate Plug operations. */ /* PlugExit: Terminate Plug operations. */
/***********************************************************************/ /***********************************************************************/
int PlugExit(PGLOBAL g) PGLOBAL PlugExit(PGLOBAL g)
{ {
if (g) { if (g) {
PDBUSER dup = PlgGetUser(g); PDBUSER dup = PlgGetUser(g);
...@@ -196,7 +196,7 @@ int PlugExit(PGLOBAL g) ...@@ -196,7 +196,7 @@ int PlugExit(PGLOBAL g)
delete g; delete g;
} // endif g } // endif g
return 0; return NULL;
} // end of PlugExit } // end of PlugExit
/***********************************************************************/ /***********************************************************************/
...@@ -483,9 +483,10 @@ bool AllocSarea(PGLOBAL g, size_t size) ...@@ -483,9 +483,10 @@ bool AllocSarea(PGLOBAL g, size_t size)
#else #else
if (trace(8)) { if (trace(8)) {
#endif #endif
if (g->Sarea) if (g->Sarea) {
htrc("Work area of %zd allocated at %p\n", size, g->Sarea); htrc("Work area of %zd allocated at %p\n", size, g->Sarea);
else PlugSubSet(g->Sarea, size);
} else
htrc("SareaAlloc: %s\n", g->Message); htrc("SareaAlloc: %s\n", g->Message);
} // endif trace } // endif trace
......
This diff is collapsed.
This diff is collapsed.
...@@ -165,8 +165,9 @@ JSONDISC::JSONDISC(PGLOBAL g, uint *lg) ...@@ -165,8 +165,9 @@ JSONDISC::JSONDISC(PGLOBAL g, uint *lg)
int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
{ {
char filename[_MAX_PATH]; char filename[_MAX_PATH];
bool mgo = (GetTypeID(topt->type) == TAB_MONGO); bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
PGLOBAL G = NULL;
lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth()); lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
lvl = GetIntegerTableOption(g, topt, "Depth", lvl); lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
...@@ -296,12 +297,15 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) ...@@ -296,12 +297,15 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
tjnp->SetMode(MODE_READ); tjnp->SetMode(MODE_READ);
// Allocate the parse work memory // Allocate the parse work memory
#if 0
PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
memset(G, 0, sizeof(GLOBAL)); memset(G, 0, sizeof(GLOBAL));
G->Sarea_Size = (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 10 : 2); G->Sarea_Size = (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 10 : 2);
G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size);
PlugSubSet(G->Sarea, G->Sarea_Size); PlugSubSet(G->Sarea, G->Sarea_Size);
G->jump_level = 0; G->jump_level = 0;
#endif // 0
G = PlugInit(NULL, (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 10 : 2));
tjnp->SetG(G); tjnp->SetG(G);
if (tjnp->OpenDB(g)) if (tjnp->OpenDB(g))
...@@ -738,6 +742,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ...@@ -738,6 +742,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
if (Lrecl) { if (Lrecl) {
// Allocate the parse work memory // Allocate the parse work memory
#if 0
PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
memset(G, 0, sizeof(GLOBAL)); memset(G, 0, sizeof(GLOBAL));
G->Sarea_Size = (size_t)Lrecl * 10; G->Sarea_Size = (size_t)Lrecl * 10;
...@@ -745,6 +750,8 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ...@@ -745,6 +750,8 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
PlugSubSet(G->Sarea, G->Sarea_Size); PlugSubSet(G->Sarea, G->Sarea_Size);
G->jump_level = 0; G->jump_level = 0;
((TDBJSN*)tdbp)->G = G; ((TDBJSN*)tdbp)->G = G;
#endif // 0
((TDBJSN*)tdbp)->G = PlugInit(NULL, (size_t)Lrecl * (Pretty >= 0 ? 10 : 2));
} else { } else {
strcpy(g->Message, "LRECL is not defined"); strcpy(g->Message, "LRECL is not defined");
return NULL; return NULL;
...@@ -1226,7 +1233,16 @@ int TDBJSN::WriteDB(PGLOBAL g) ...@@ -1226,7 +1233,16 @@ int TDBJSN::WriteDB(PGLOBAL g)
return rc; return rc;
} // end of WriteDB } // end of WriteDB
/* ---------------------------- JSONCOL ------------------------------ */ /***********************************************************************/
/* Data Base close routine for JSON access method. */
/***********************************************************************/
void TDBJSN::CloseDB(PGLOBAL g)
{
TDBDOS::CloseDB(g);
G = PlugExit(G);
} // end of CloseDB
/* ---------------------------- JSONCOL ------------------------------ */
/***********************************************************************/ /***********************************************************************/
/* JSONCOL public constructor. */ /* JSONCOL public constructor. */
...@@ -1608,7 +1624,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp) ...@@ -1608,7 +1624,7 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
strcpy(g->Message, "Column size too small"); strcpy(g->Message, "Column size too small");
Value->SetValue_char(NULL, 0); Value->SetValue_char(NULL, 0);
} // endif Clen } // endif Clen
#endif 0 #endif // 0
} else } else
Value->SetValue_psz(Serialize(g, jsp, NULL, 0)); Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
/* */ /* */
/* This file contains the JSON classes declares. */ /* This file contains the JSON classes declares. */
/***********************************************************************/ /***********************************************************************/
#pragma once
//#include "osutil.h" // Unuseful and bad for OEM //#include "osutil.h" // Unuseful and bad for OEM
#include "block.h" #include "block.h"
#include "colblk.h" #include "colblk.h"
...@@ -161,6 +162,7 @@ class DllExport TDBJSN : public TDBDOS { ...@@ -161,6 +162,7 @@ class DllExport TDBJSN : public TDBDOS {
virtual int ReadDB(PGLOBAL g); virtual int ReadDB(PGLOBAL g);
virtual bool PrepareWriting(PGLOBAL g); virtual bool PrepareWriting(PGLOBAL g);
virtual int WriteDB(PGLOBAL g); virtual int WriteDB(PGLOBAL g);
virtual void CloseDB(PGLOBAL g);
// Specific routine // Specific routine
virtual int EstimatedLength(void); virtual int EstimatedLength(void);
......
...@@ -112,8 +112,7 @@ bool user_connect::user_init() ...@@ -112,8 +112,7 @@ bool user_connect::user_init()
if (g) if (g)
printf("%s\n", g->Message); printf("%s\n", g->Message);
int rc= PlugExit(g); g= PlugExit(g);
g= NULL;
if (dup) if (dup)
free(dup); free(dup);
......
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