mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
- Fix a bug causing CONNECT to loop when expanding a JSON column
when the expanded column value is null or void array. - Adding the FullArray option to JSON tables. - Skipping expanded JSON lines when the expanded column value is null. modified: storage/connect/connect.cc modified: storage/connect/tabdos.h modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h
This commit is contained in:
@@ -404,6 +404,7 @@ RCODE EvalColumns(PGLOBAL g, PTDB tdbp, bool reset, bool mrr)
|
|||||||
rc = RC_FX;
|
rc = RC_FX;
|
||||||
} catch (const char *msg) {
|
} catch (const char *msg) {
|
||||||
strcpy(g->Message, msg);
|
strcpy(g->Message, msg);
|
||||||
|
rc = RC_NF;
|
||||||
} // end catch
|
} // end catch
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@@ -29,6 +29,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */
|
|||||||
friend class TXTFAM;
|
friend class TXTFAM;
|
||||||
friend class DBFBASE;
|
friend class DBFBASE;
|
||||||
friend class UNZIPUTL;
|
friend class UNZIPUTL;
|
||||||
|
friend class JSONCOL;
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
DOSDEF(void);
|
DOSDEF(void);
|
||||||
|
@@ -54,16 +54,16 @@
|
|||||||
USETEMP UseTemp(void);
|
USETEMP UseTemp(void);
|
||||||
char *GetJsonNull(void);
|
char *GetJsonNull(void);
|
||||||
|
|
||||||
typedef struct _jncol {
|
//typedef struct _jncol {
|
||||||
struct _jncol *Next;
|
// struct _jncol *Next;
|
||||||
char *Name;
|
// char *Name;
|
||||||
char *Fmt;
|
// char *Fmt;
|
||||||
int Type;
|
// int Type;
|
||||||
int Len;
|
// int Len;
|
||||||
int Scale;
|
// int Scale;
|
||||||
bool Cbn;
|
// bool Cbn;
|
||||||
bool Found;
|
// bool Found;
|
||||||
} JCOL, *PJCL;
|
//} JCOL, *PJCL;
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
/* JSONColumns: construct the result blocks containing the description */
|
/* JSONColumns: construct the result blocks containing the description */
|
||||||
@@ -76,26 +76,13 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
|
static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
|
||||||
FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
|
FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
|
||||||
static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
|
static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
|
||||||
char *p, colname[65], fmt[129];
|
int i, n = 0;
|
||||||
int i, j, lvl, n = 0;
|
|
||||||
int ncol = sizeof(buftyp) / sizeof(int);
|
int ncol = sizeof(buftyp) / sizeof(int);
|
||||||
bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
|
PJCL jcp;
|
||||||
PCSZ sep, level;
|
JSONDISC *pjdc = NULL;
|
||||||
PVAL valp;
|
|
||||||
JCOL jcol;
|
|
||||||
PJCL jcp, fjcp = NULL, pjcp = NULL;
|
|
||||||
PJPR *jrp, jpp;
|
|
||||||
PJSON jsp;
|
|
||||||
PJVAL jvp;
|
|
||||||
PJOB row;
|
|
||||||
PJDEF tdp;
|
|
||||||
TDBJSN *tjnp = NULL;
|
|
||||||
PJTDB tjsp = NULL;
|
|
||||||
PQRYRES qrp;
|
PQRYRES qrp;
|
||||||
PCOLRES crp;
|
PCOLRES crp;
|
||||||
|
|
||||||
jcol.Name = jcol.Fmt = NULL;
|
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
length[0] = 128;
|
length[0] = 128;
|
||||||
length[7] = 256;
|
length[7] = 256;
|
||||||
@@ -107,10 +94,87 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
return NULL;
|
return NULL;
|
||||||
} // endif Multiple
|
} // endif Multiple
|
||||||
|
|
||||||
|
pjdc = new(g) JSONDISC(g, (int*)length);
|
||||||
|
|
||||||
|
if (!(n = pjdc->GetColumns(g, db, dsn, topt)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
skipit:
|
||||||
|
if (trace(1))
|
||||||
|
htrc("JSONColumns: n=%d len=%d\n", n, length[0]);
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
/* Open the input file. */
|
/* Allocate the structures used to refer to the result set. */
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
level = GetStringTableOption(g, topt, "Level", NULL);
|
qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
|
||||||
|
buftyp, fldtyp, length, false, false);
|
||||||
|
|
||||||
|
crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
|
||||||
|
crp->Name = "Nullable";
|
||||||
|
crp->Next->Name = "Jpath";
|
||||||
|
|
||||||
|
if (info || !qrp)
|
||||||
|
return qrp;
|
||||||
|
|
||||||
|
qrp->Nblin = n;
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Now get the results into blocks. */
|
||||||
|
/*********************************************************************/
|
||||||
|
for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) {
|
||||||
|
if (jcp->Type == TYPE_UNKNOWN)
|
||||||
|
jcp->Type = TYPE_STRING; // Void column
|
||||||
|
|
||||||
|
crp = qrp->Colresp; // Column Name
|
||||||
|
crp->Kdata->SetValue(jcp->Name, i);
|
||||||
|
crp = crp->Next; // Data Type
|
||||||
|
crp->Kdata->SetValue(jcp->Type, i);
|
||||||
|
crp = crp->Next; // Type Name
|
||||||
|
crp->Kdata->SetValue(GetTypeName(jcp->Type), i);
|
||||||
|
crp = crp->Next; // Precision
|
||||||
|
crp->Kdata->SetValue(jcp->Len, i);
|
||||||
|
crp = crp->Next; // Length
|
||||||
|
crp->Kdata->SetValue(jcp->Len, i);
|
||||||
|
crp = crp->Next; // Scale (precision)
|
||||||
|
crp->Kdata->SetValue(jcp->Scale, i);
|
||||||
|
crp = crp->Next; // Nullable
|
||||||
|
crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i);
|
||||||
|
crp = crp->Next; // Field format
|
||||||
|
|
||||||
|
if (crp->Kdata)
|
||||||
|
crp->Kdata->SetValue(jcp->Fmt, i);
|
||||||
|
|
||||||
|
} // endfor i
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Return the result pointer. */
|
||||||
|
/*********************************************************************/
|
||||||
|
return qrp;
|
||||||
|
} // end of JSONColumns
|
||||||
|
|
||||||
|
/* -------------------------- Class JSONDISC ------------------------- */
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* Class used to get the columns of a JSON table. */
|
||||||
|
/***********************************************************************/
|
||||||
|
JSONDISC::JSONDISC(PGLOBAL g, int *lg)
|
||||||
|
{
|
||||||
|
length = lg;
|
||||||
|
jcp = fjcp = pjcp = NULL;
|
||||||
|
tjnp = NULL;
|
||||||
|
jpp = NULL;
|
||||||
|
tjsp = NULL;
|
||||||
|
jsp = NULL;
|
||||||
|
row = NULL;
|
||||||
|
sep = NULL;
|
||||||
|
i = n = bf = ncol = lvl = 0;
|
||||||
|
all = false;
|
||||||
|
} // end of JSONDISC constructor
|
||||||
|
|
||||||
|
int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
|
||||||
|
{
|
||||||
|
bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
|
||||||
|
PCSZ level = GetStringTableOption(g, topt, "Level", NULL);
|
||||||
|
|
||||||
if (level) {
|
if (level) {
|
||||||
lvl = atoi(level);
|
lvl = atoi(level);
|
||||||
@@ -120,6 +184,9 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
|
|
||||||
sep = GetStringTableOption(g, topt, "Separator", ".");
|
sep = GetStringTableOption(g, topt, "Separator", ".");
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
/* Open the input file. */
|
||||||
|
/*********************************************************************/
|
||||||
tdp = new(g) JSONDEF;
|
tdp = new(g) JSONDEF;
|
||||||
#if defined(ZIP_SUPPORT)
|
#if defined(ZIP_SUPPORT)
|
||||||
tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
|
tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
|
||||||
@@ -139,7 +206,7 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
|
|
||||||
if (!tdp->Fn && !tdp->Uri) {
|
if (!tdp->Fn && !tdp->Uri) {
|
||||||
strcpy(g->Message, MSG(MISSING_FNAME));
|
strcpy(g->Message, MSG(MISSING_FNAME));
|
||||||
return NULL;
|
return 0;
|
||||||
} // endif Fn
|
} // endif Fn
|
||||||
|
|
||||||
if (trace(1))
|
if (trace(1))
|
||||||
@@ -160,7 +227,7 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
tdp->Pretty = 0;
|
tdp->Pretty = 0;
|
||||||
#else // !MONGO_SUPPORT
|
#else // !MONGO_SUPPORT
|
||||||
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
|
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
|
||||||
return NULL;
|
return 0;
|
||||||
#endif // !MONGO_SUPPORT
|
#endif // !MONGO_SUPPORT
|
||||||
} // endif Uri
|
} // endif Uri
|
||||||
|
|
||||||
@@ -170,7 +237,7 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp));
|
tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp));
|
||||||
#else // !ZIP_SUPPORT
|
#else // !ZIP_SUPPORT
|
||||||
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
|
sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
|
||||||
return NULL;
|
return 0;
|
||||||
#endif // !ZIP_SUPPORT
|
#endif // !ZIP_SUPPORT
|
||||||
} else
|
} else
|
||||||
tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp));
|
tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp));
|
||||||
@@ -255,140 +322,28 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
goto err;
|
goto err;
|
||||||
} // endif row
|
} // endif row
|
||||||
|
|
||||||
|
all = GetBooleanTableOption(g, topt, "Fullarray", false);
|
||||||
|
jcol.Name = jcol.Fmt = NULL;
|
||||||
jcol.Next = NULL;
|
jcol.Next = NULL;
|
||||||
jcol.Found = true;
|
jcol.Found = true;
|
||||||
colname[64] = 0;
|
colname[0] = 0;
|
||||||
fmt[128] = 0;
|
|
||||||
|
|
||||||
if (!tdp->Uri) {
|
if (!tdp->Uri) {
|
||||||
*fmt = '$';
|
fmt[0] = '$';
|
||||||
fmt[1] = '.';
|
fmt[1] = '.';
|
||||||
p = fmt + 2;
|
bf = 2;
|
||||||
} else
|
} // endif Uri
|
||||||
p = fmt;
|
|
||||||
|
|
||||||
jrp = (PJPR*)PlugSubAlloc(g, NULL, sizeof(PJPR) * MY_MAX(lvl, 0));
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
/* Analyse the JSON tree and define columns. */
|
/* Analyse the JSON tree and define columns. */
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
for (i = 1; ; i++) {
|
for (i = 1; ; i++) {
|
||||||
for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) {
|
for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) {
|
||||||
for (j = 0; j < lvl; j++)
|
|
||||||
jrp[j] = NULL;
|
|
||||||
|
|
||||||
more:
|
|
||||||
strncpy(colname, jpp->GetKey(), 64);
|
strncpy(colname, jpp->GetKey(), 64);
|
||||||
*p = 0;
|
fmt[bf] = 0;
|
||||||
j = 0;
|
|
||||||
jvp = jpp->GetVal();
|
|
||||||
|
|
||||||
retry:
|
if (Find(g, jpp->GetVal(), MY_MIN(lvl, 0)))
|
||||||
if ((valp = jvp ? jvp->GetValue() : NULL)) {
|
|
||||||
jcol.Type = valp->GetType();
|
|
||||||
jcol.Len = valp->GetValLen();
|
|
||||||
jcol.Scale = valp->GetValPrec();
|
|
||||||
jcol.Cbn = valp->IsNull();
|
|
||||||
} else if (!jvp || jvp->IsNull()) {
|
|
||||||
jcol.Type = TYPE_UNKNOWN;
|
|
||||||
jcol.Len = jcol.Scale = 0;
|
|
||||||
jcol.Cbn = true;
|
|
||||||
} else if (j < lvl) {
|
|
||||||
if (!*p)
|
|
||||||
strcat(fmt, colname);
|
|
||||||
|
|
||||||
jsp = jvp->GetJson();
|
|
||||||
|
|
||||||
switch (jsp->GetType()) {
|
|
||||||
case TYPE_JOB:
|
|
||||||
if (!jrp[j])
|
|
||||||
jrp[j] = jsp->GetFirst();
|
|
||||||
|
|
||||||
if (*jrp[j]->GetKey() != '$') {
|
|
||||||
strncat(strncat(fmt, sep, 128), jrp[j]->GetKey(), 128);
|
|
||||||
strncat(strncat(colname, "_", 64), jrp[j]->GetKey(), 64);
|
|
||||||
} // endif Key
|
|
||||||
|
|
||||||
jvp = jrp[j]->GetVal();
|
|
||||||
j++;
|
|
||||||
break;
|
|
||||||
case TYPE_JAR:
|
|
||||||
if (!tdp->Xcol || stricmp(tdp->Xcol, colname)) {
|
|
||||||
if (tdp->Uri)
|
|
||||||
strncat(strncat(fmt, sep, 128), "0", 128);
|
|
||||||
else
|
|
||||||
strncat(fmt, "[0]", 128);
|
|
||||||
|
|
||||||
} else
|
|
||||||
strncat(fmt, (tdp->Uri ? sep : "[]"), 128);
|
|
||||||
|
|
||||||
jvp = jsp->GetValue(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sprintf(g->Message, "Logical error after %s", fmt);
|
|
||||||
goto err;
|
goto err;
|
||||||
} // endswitch jsp
|
|
||||||
|
|
||||||
goto retry;
|
|
||||||
} else if (lvl >= 0) {
|
|
||||||
jcol.Type = TYPE_STRING;
|
|
||||||
jcol.Len = 256;
|
|
||||||
jcol.Scale = 0;
|
|
||||||
jcol.Cbn = true;
|
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check whether this column was already found
|
|
||||||
for (jcp = fjcp; jcp; jcp = jcp->Next)
|
|
||||||
if (!strcmp(colname, jcp->Name))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (jcp) {
|
|
||||||
if (jcp->Type != jcol.Type) {
|
|
||||||
if (jcp->Type == TYPE_UNKNOWN)
|
|
||||||
jcp->Type = jcol.Type;
|
|
||||||
else if (jcol.Type != TYPE_UNKNOWN)
|
|
||||||
jcp->Type = TYPE_STRING;
|
|
||||||
|
|
||||||
} // endif Type
|
|
||||||
|
|
||||||
if (*p && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) {
|
|
||||||
jcp->Fmt = PlugDup(g, fmt);
|
|
||||||
length[7] = MY_MAX(length[7], strlen(fmt));
|
|
||||||
} // endif fmt
|
|
||||||
|
|
||||||
jcp->Len = MY_MAX(jcp->Len, jcol.Len);
|
|
||||||
jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale);
|
|
||||||
jcp->Cbn |= jcol.Cbn;
|
|
||||||
jcp->Found = true;
|
|
||||||
} else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) {
|
|
||||||
// New column
|
|
||||||
jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL));
|
|
||||||
*jcp = jcol;
|
|
||||||
jcp->Cbn |= (i > 1);
|
|
||||||
jcp->Name = PlugDup(g, colname);
|
|
||||||
length[0] = MY_MAX(length[0], strlen(colname));
|
|
||||||
|
|
||||||
if (*p) {
|
|
||||||
jcp->Fmt = PlugDup(g, fmt);
|
|
||||||
length[7] = MY_MAX(length[7], strlen(fmt));
|
|
||||||
} else
|
|
||||||
jcp->Fmt = NULL;
|
|
||||||
|
|
||||||
if (pjcp) {
|
|
||||||
jcp->Next = pjcp->Next;
|
|
||||||
pjcp->Next = jcp;
|
|
||||||
} else
|
|
||||||
fjcp = jcp;
|
|
||||||
|
|
||||||
n++;
|
|
||||||
} // endif jcp
|
|
||||||
|
|
||||||
pjcp = jcp;
|
|
||||||
|
|
||||||
for (j = lvl - 1; j >= 0; j--)
|
|
||||||
if (jrp[j] && (jrp[j] = jrp[j]->GetNext()))
|
|
||||||
goto more;
|
|
||||||
|
|
||||||
} // endfor jpp
|
} // endfor jpp
|
||||||
|
|
||||||
@@ -416,69 +371,160 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
|
|||||||
if (!(row = (jsp) ? jsp->GetObject() : NULL))
|
if (!(row = (jsp) ? jsp->GetObject() : NULL))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} // endor i
|
} // endfor i
|
||||||
|
|
||||||
if (tdp->Pretty != 2)
|
if (tdp->Pretty != 2)
|
||||||
tjnp->CloseDB(g);
|
tjnp->CloseDB(g);
|
||||||
|
|
||||||
skipit:
|
return n;
|
||||||
if (trace(1))
|
|
||||||
htrc("JSONColumns: n=%d len=%d\n", n, length[0]);
|
|
||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
/* Allocate the structures used to refer to the result set. */
|
|
||||||
/*********************************************************************/
|
|
||||||
qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
|
|
||||||
buftyp, fldtyp, length, false, false);
|
|
||||||
|
|
||||||
crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
|
|
||||||
crp->Name = "Nullable";
|
|
||||||
crp->Next->Name = "Jpath";
|
|
||||||
|
|
||||||
if (info || !qrp)
|
|
||||||
return qrp;
|
|
||||||
|
|
||||||
qrp->Nblin = n;
|
|
||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
/* Now get the results into blocks. */
|
|
||||||
/*********************************************************************/
|
|
||||||
for (i = 0, jcp = fjcp; jcp; i++, jcp = jcp->Next) {
|
|
||||||
if (jcp->Type == TYPE_UNKNOWN)
|
|
||||||
jcp->Type = TYPE_STRING; // Void column
|
|
||||||
|
|
||||||
crp = qrp->Colresp; // Column Name
|
|
||||||
crp->Kdata->SetValue(jcp->Name, i);
|
|
||||||
crp = crp->Next; // Data Type
|
|
||||||
crp->Kdata->SetValue(jcp->Type, i);
|
|
||||||
crp = crp->Next; // Type Name
|
|
||||||
crp->Kdata->SetValue(GetTypeName(jcp->Type), i);
|
|
||||||
crp = crp->Next; // Precision
|
|
||||||
crp->Kdata->SetValue(jcp->Len, i);
|
|
||||||
crp = crp->Next; // Length
|
|
||||||
crp->Kdata->SetValue(jcp->Len, i);
|
|
||||||
crp = crp->Next; // Scale (precision)
|
|
||||||
crp->Kdata->SetValue(jcp->Scale, i);
|
|
||||||
crp = crp->Next; // Nullable
|
|
||||||
crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i);
|
|
||||||
crp = crp->Next; // Field format
|
|
||||||
|
|
||||||
if (crp->Kdata)
|
|
||||||
crp->Kdata->SetValue(jcp->Fmt, i);
|
|
||||||
|
|
||||||
} // endfor i
|
|
||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
/* Return the result pointer. */
|
|
||||||
/*********************************************************************/
|
|
||||||
return qrp;
|
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (tdp->Pretty != 2)
|
if (tdp->Pretty != 2)
|
||||||
tjnp->CloseDB(g);
|
tjnp->CloseDB(g);
|
||||||
|
|
||||||
return NULL;
|
return 0;
|
||||||
} // end of JSONColumns
|
} // end of GetColumns
|
||||||
|
|
||||||
|
bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, int j)
|
||||||
|
{
|
||||||
|
char *p, *pc = colname + strlen(colname);
|
||||||
|
int ars;
|
||||||
|
PJOB job;
|
||||||
|
PJAR jar;
|
||||||
|
|
||||||
|
if ((valp = jvp ? jvp->GetValue() : NULL)) {
|
||||||
|
jcol.Type = valp->GetType();
|
||||||
|
jcol.Len = valp->GetValLen();
|
||||||
|
jcol.Scale = valp->GetValPrec();
|
||||||
|
jcol.Cbn = valp->IsNull();
|
||||||
|
} else if (!jvp || jvp->IsNull()) {
|
||||||
|
jcol.Type = TYPE_UNKNOWN;
|
||||||
|
jcol.Len = jcol.Scale = 0;
|
||||||
|
jcol.Cbn = true;
|
||||||
|
} else if (j < lvl) {
|
||||||
|
if (!fmt[bf])
|
||||||
|
strcat(fmt, colname);
|
||||||
|
|
||||||
|
p = fmt + strlen(fmt);
|
||||||
|
jsp = jvp->GetJson();
|
||||||
|
|
||||||
|
switch (jsp->GetType()) {
|
||||||
|
case TYPE_JOB:
|
||||||
|
job = (PJOB)jsp;
|
||||||
|
|
||||||
|
for (PJPR jrp = job->GetFirst(); jrp; jrp = jrp->GetNext()) {
|
||||||
|
if (*jrp->GetKey() != '$') {
|
||||||
|
strncat(strncat(fmt, sep, 128), jrp->GetKey(), 128);
|
||||||
|
strncat(strncat(colname, "_", 64), jrp->GetKey(), 64);
|
||||||
|
} // endif Key
|
||||||
|
|
||||||
|
if (Find(g, jrp->GetVal(), j + 1))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*p = *pc = 0;
|
||||||
|
} // endfor jrp
|
||||||
|
|
||||||
|
return false;
|
||||||
|
case TYPE_JAR:
|
||||||
|
jar = (PJAR)jsp;
|
||||||
|
|
||||||
|
if (all || (tdp->Xcol && !stricmp(tdp->Xcol, colname)))
|
||||||
|
ars = jar->GetSize(false);
|
||||||
|
else
|
||||||
|
ars = MY_MIN(jar->GetSize(false), 1);
|
||||||
|
|
||||||
|
for (int k = 0; k < ars; k++) {
|
||||||
|
if (!tdp->Xcol || stricmp(tdp->Xcol, colname)) {
|
||||||
|
sprintf(buf, "%d", k);
|
||||||
|
|
||||||
|
if (tdp->Uri)
|
||||||
|
strncat(strncat(fmt, sep, 128), buf, 128);
|
||||||
|
else
|
||||||
|
strncat(strncat(strncat(fmt, "[", 128), buf, 128), "]", 128);
|
||||||
|
|
||||||
|
if (all)
|
||||||
|
strncat(strncat(colname, "_", 64), buf, 64);
|
||||||
|
|
||||||
|
} else
|
||||||
|
strncat(fmt, (tdp->Uri ? sep : "[*]"), 128);
|
||||||
|
|
||||||
|
if (Find(g, jar->GetValue(k), j))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*p = *pc = 0;
|
||||||
|
} // endfor k
|
||||||
|
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
sprintf(g->Message, "Logical error after %s", fmt);
|
||||||
|
return true;
|
||||||
|
} // endswitch Type
|
||||||
|
|
||||||
|
} else if (lvl >= 0) {
|
||||||
|
jcol.Type = TYPE_STRING;
|
||||||
|
jcol.Len = 256;
|
||||||
|
jcol.Scale = 0;
|
||||||
|
jcol.Cbn = true;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AddColumn(g);
|
||||||
|
return false;
|
||||||
|
} // end of Find
|
||||||
|
|
||||||
|
void JSONDISC::AddColumn(PGLOBAL g)
|
||||||
|
{
|
||||||
|
bool b = fmt[bf] != 0; // True if formatted
|
||||||
|
|
||||||
|
// Check whether this column was already found
|
||||||
|
for (jcp = fjcp; jcp; jcp = jcp->Next)
|
||||||
|
if (!strcmp(colname, jcp->Name))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (jcp) {
|
||||||
|
if (jcp->Type != jcol.Type) {
|
||||||
|
if (jcp->Type == TYPE_UNKNOWN)
|
||||||
|
jcp->Type = jcol.Type;
|
||||||
|
else if (jcol.Type != TYPE_UNKNOWN)
|
||||||
|
jcp->Type = TYPE_STRING;
|
||||||
|
|
||||||
|
} // endif Type
|
||||||
|
|
||||||
|
if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) {
|
||||||
|
jcp->Fmt = PlugDup(g, fmt);
|
||||||
|
length[7] = MY_MAX(length[7], strlen(fmt));
|
||||||
|
} // endif fmt
|
||||||
|
|
||||||
|
jcp->Len = MY_MAX(jcp->Len, jcol.Len);
|
||||||
|
jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale);
|
||||||
|
jcp->Cbn |= jcol.Cbn;
|
||||||
|
jcp->Found = true;
|
||||||
|
} else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) {
|
||||||
|
// New column
|
||||||
|
jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL));
|
||||||
|
*jcp = jcol;
|
||||||
|
jcp->Cbn |= (i > 1);
|
||||||
|
jcp->Name = PlugDup(g, colname);
|
||||||
|
length[0] = MY_MAX(length[0], strlen(colname));
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
jcp->Fmt = PlugDup(g, fmt);
|
||||||
|
length[7] = MY_MAX(length[7], strlen(fmt));
|
||||||
|
} else
|
||||||
|
jcp->Fmt = NULL;
|
||||||
|
|
||||||
|
if (pjcp) {
|
||||||
|
jcp->Next = pjcp->Next;
|
||||||
|
pjcp->Next = jcp;
|
||||||
|
} else
|
||||||
|
fjcp = jcp;
|
||||||
|
|
||||||
|
n++;
|
||||||
|
} // endif jcp
|
||||||
|
|
||||||
|
pjcp = jcp;
|
||||||
|
} // end of AddColumn
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------- Class JSONDEF -------------------------- */
|
/* -------------------------- Class JSONDEF -------------------------- */
|
||||||
|
|
||||||
@@ -513,6 +559,7 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
|
|||||||
Limit = GetIntCatInfo("Limit", 10);
|
Limit = GetIntCatInfo("Limit", 10);
|
||||||
Base = GetIntCatInfo("Base", 0) ? 1 : 0;
|
Base = GetIntCatInfo("Base", 0) ? 1 : 0;
|
||||||
Sep = *GetStringCatInfo(g, "Separator", ".");
|
Sep = *GetStringCatInfo(g, "Separator", ".");
|
||||||
|
Accept = GetBoolCatInfo("Accept", false);
|
||||||
|
|
||||||
if (Uri = GetStringCatInfo(g, "Connect", NULL)) {
|
if (Uri = GetStringCatInfo(g, "Connect", NULL)) {
|
||||||
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
|
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
|
||||||
@@ -1471,6 +1518,9 @@ void JSONCOL::ReadColumn(PGLOBAL g)
|
|||||||
if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
|
if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
|
||||||
Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
|
Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
|
||||||
|
|
||||||
|
if (Xpd && Value->IsNull() && !((PJDEF)Tjp->To_Def)->Accept)
|
||||||
|
throw("Null expandable JSON value");
|
||||||
|
|
||||||
// Set null when applicable
|
// Set null when applicable
|
||||||
if (!Nullable)
|
if (!Nullable)
|
||||||
Value->SetNull(false);
|
Value->SetNull(false);
|
||||||
@@ -1546,11 +1596,16 @@ PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
|
|||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
|
PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
|
||||||
{
|
{
|
||||||
int ars;
|
int ars = MY_MIN(Tjp->Limit, arp->size());
|
||||||
PJVAL jvp;
|
PJVAL jvp;
|
||||||
JVALUE jval;
|
JVALUE jval;
|
||||||
|
|
||||||
ars = MY_MIN(Tjp->Limit, arp->size());
|
if (!ars) {
|
||||||
|
Value->Reset();
|
||||||
|
Value->SetNull(true);
|
||||||
|
Tjp->NextSame = 0;
|
||||||
|
return Value;
|
||||||
|
} // endif ars
|
||||||
|
|
||||||
if (!(jvp = arp->GetValue((Nodes[n].Rx = Nodes[n].Nx)))) {
|
if (!(jvp = arp->GetValue((Nodes[n].Rx = Nodes[n].Nx)))) {
|
||||||
strcpy(g->Message, "Logical error expanding array");
|
strcpy(g->Message, "Logical error expanding array");
|
||||||
|
@@ -15,6 +15,7 @@ enum JMODE {MODE_OBJECT, MODE_ARRAY, MODE_VALUE};
|
|||||||
typedef class JSONDEF *PJDEF;
|
typedef class JSONDEF *PJDEF;
|
||||||
typedef class TDBJSON *PJTDB;
|
typedef class TDBJSON *PJTDB;
|
||||||
typedef class JSONCOL *PJCOL;
|
typedef class JSONCOL *PJCOL;
|
||||||
|
class TDBJSN;
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
/* The JSON tree node. Can be an Object or an Array. */
|
/* The JSON tree node. Can be an Object or an Array. */
|
||||||
@@ -29,6 +30,47 @@ typedef struct _jnode {
|
|||||||
int Nx; // Next to read row number
|
int Nx; // Next to read row number
|
||||||
} JNODE, *PJNODE;
|
} JNODE, *PJNODE;
|
||||||
|
|
||||||
|
typedef struct _jncol {
|
||||||
|
struct _jncol *Next;
|
||||||
|
char *Name;
|
||||||
|
char *Fmt;
|
||||||
|
int Type;
|
||||||
|
int Len;
|
||||||
|
int Scale;
|
||||||
|
bool Cbn;
|
||||||
|
bool Found;
|
||||||
|
} JCOL, *PJCL;
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* Class used to get the columns of a mongo collection. */
|
||||||
|
/***********************************************************************/
|
||||||
|
class JSONDISC : public BLOCK {
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
JSONDISC(PGLOBAL g, int *lg);
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
int GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt);
|
||||||
|
bool Find(PGLOBAL g, PJVAL jvp, int j);
|
||||||
|
void AddColumn(PGLOBAL g);
|
||||||
|
|
||||||
|
// Members
|
||||||
|
JCOL jcol;
|
||||||
|
PJCL jcp, fjcp, pjcp;
|
||||||
|
PVAL valp;
|
||||||
|
PJDEF tdp;
|
||||||
|
TDBJSN *tjnp;
|
||||||
|
PJTDB tjsp;
|
||||||
|
PJPR jpp;
|
||||||
|
PJSON jsp;
|
||||||
|
PJOB row;
|
||||||
|
PCSZ sep;
|
||||||
|
char colname[65], fmt[129], buf[16];
|
||||||
|
int *length;
|
||||||
|
int i, n, bf, ncol, lvl;
|
||||||
|
bool all;
|
||||||
|
}; // end of JSONDISC
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
/* JSON table. */
|
/* JSON table. */
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
@@ -36,13 +78,13 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */
|
|||||||
friend class TDBJSON;
|
friend class TDBJSON;
|
||||||
friend class TDBJSN;
|
friend class TDBJSN;
|
||||||
friend class TDBJCL;
|
friend class TDBJCL;
|
||||||
|
friend class JSONDISC;
|
||||||
#if defined(CMGO_SUPPORT)
|
#if defined(CMGO_SUPPORT)
|
||||||
friend class CMGFAM;
|
friend class CMGFAM;
|
||||||
#endif // CMGO_SUPPORT
|
#endif // CMGO_SUPPORT
|
||||||
#if defined(JAVA_SUPPORT)
|
#if defined(JAVA_SUPPORT)
|
||||||
friend class JMGFAM;
|
friend class JMGFAM;
|
||||||
#endif // JAVA_SUPPORT
|
#endif // JAVA_SUPPORT
|
||||||
friend PQRYRES JSONColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
JSONDEF(void);
|
JSONDEF(void);
|
||||||
|
Reference in New Issue
Block a user