summaryrefslogtreecommitdiff
path: root/storage/connect/tabjson.cpp
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2015-01-30 10:57:00 +0100
committerOlivier Bertrand <bertrandop@gmail.com>2015-01-30 10:57:00 +0100
commitfd1ca70bb3710ae280bd11b3650820dd62002419 (patch)
tree4bf2d015e61dc83733c146a7cca4025ead296bde /storage/connect/tabjson.cpp
parent9a2dc7dfed6b56c529b2de865a15929bee2eceaf (diff)
downloadmariadb-git-fd1ca70bb3710ae280bd11b3650820dd62002419.tar.gz
- Enhance JSON tables handling.
modified: storage/connect/json.cpp storage/connect/json.h storage/connect/mysql-test/connect/r/json.result storage/connect/mysql-test/connect/t/json.test storage/connect/tabjson.cpp storage/connect/tabjson.h - Avoid crash when a partition table name pattern is ill formed (such as using place holder %i instead of %s) modified: storage/connect/ha_connect.cc
Diffstat (limited to 'storage/connect/tabjson.cpp')
-rw-r--r--storage/connect/tabjson.cpp477
1 files changed, 269 insertions, 208 deletions
diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp
index a22f490f398..f7723376598 100644
--- a/storage/connect/tabjson.cpp
+++ b/storage/connect/tabjson.cpp
@@ -119,12 +119,12 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
Fpos = -1;
Spos = N = 0;
Limit = tdp->Limit;
+ NextSame = 0;
+ SameRow = 0;
+ Xval = -1;
Pretty = tdp->Pretty;
Strict = tdp->Strict;
- NextSame = false;
Comma = false;
- SameRow = 0;
- Xval = -1;
} // end of TDBJSN standard constructor
TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
@@ -137,12 +137,12 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
Spos = tdbp->Spos;
N = tdbp->N;
Limit = tdbp->Limit;
- Pretty = tdbp->Pretty;
- Strict = tdbp->Strict;
NextSame = tdbp->NextSame;
- Comma = tdbp->Comma;
SameRow = tdbp->SameRow;
Xval = tdbp->Xval;
+ Pretty = tdbp->Pretty;
+ Strict = tdbp->Strict;
+ Comma = tdbp->Comma;
} // end of TDBJSN copy constructor
// Used for update
@@ -221,14 +221,9 @@ bool TDBJSN::OpenDB(PGLOBAL g)
/*******************************************************************/
/* Table already open replace it at its beginning. */
/*******************************************************************/
- for (PJCOL cp = (PJCOL)Columns; cp; cp = (PJCOL)cp->GetNext()) {
- cp->Nx = 0;
- cp->Arp = NULL;
- } // endfor cp
-
Fpos= -1;
Spos = 0;
- NextSame = false;
+ NextSame = 0;
SameRow = 0;
} else {
/*******************************************************************/
@@ -292,7 +287,8 @@ int TDBJSN::ReadDB(PGLOBAL g)
N++;
if (NextSame) {
- SameRow++;
+ SameRow = NextSame;
+ NextSame = 0;
return RC_OK;
} else if ((rc = TDBDOS::ReadDB(g)) == RC_OK)
if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK)) {
@@ -333,21 +329,20 @@ int TDBJSN::ReadDB(PGLOBAL g)
} // end of PrepareWriting
-/* ----------------------------- JSNCOL ------------------------------- */
+/* ---------------------------- JSONCOL ------------------------------ */
/***********************************************************************/
-/* JSNCOL public constructor. */
+/* JSONCOL public constructor. */
/***********************************************************************/
JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
: DOSCOL(g, cdp, tdbp, cprec, i, "DOS")
{
Tjp = (TDBJSN *)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
- Arp = NULL;
Jpath = cdp->GetFmt();
MulVal = NULL;
Nodes = NULL;
- Nod = Nx =0;
- Ival = -1;
+ Nod = 0;
+ Xnod = -1;
Xpd = false;
Parsed = false;
} // end of JSONCOL constructor
@@ -359,13 +354,11 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
{
Tjp = col1->Tjp;
- Arp = col1->Arp;
Jpath = col1->Jpath;
MulVal = col1->MulVal;
Nodes = col1->Nodes;
Nod = col1->Nod;
- Ival = col1->Ival;
- Nx = col1->Nx;
+ Xnod = col1->Xnod;
Xpd = col1->Xpd;
Parsed = col1->Parsed;
} // end of JSONCOL copy constructor
@@ -387,17 +380,16 @@ bool JSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
} // end of SetBuffer
/***********************************************************************/
-/* Analyse array processing options. */
+/* Check whether this object is expanded. */
/***********************************************************************/
bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b)
{
- if (Tjp->Xcol && nm && !strcmp(nm, Tjp->Xcol) &&
- (Tjp->Xval < 0 || Tjp->Xval == i)) {
+ if ((Tjp->Xcol && nm && !strcmp(nm, Tjp->Xcol) &&
+ (Tjp->Xval < 0 || Tjp->Xval == i)) || Xpd) {
Xpd = true; // Expandable object
Nodes[i].Op = OP_XX;
- Tjp->Xval = i;
} else if (b) {
- strcpy(g->Message, "Cannot expand more than one array");
+ strcpy(g->Message, "Cannot expand more than one branch");
return true;
} // endif Xcol
@@ -490,6 +482,38 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
return true;
} // endif's
+ // For calculated arrays, a local Value must be used
+ switch (jnp->Op) {
+ case OP_NUM:
+ jnp->Valp = AllocateValue(g, TYPE_INT);
+ break;
+ case OP_ADD:
+ case OP_MULT:
+ case OP_SEP:
+ if (!IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_DOUBLE);
+
+ break;
+ case OP_MIN:
+ case OP_MAX:
+ jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
+ break;
+ case OP_CNC:
+ if (IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
+
+ break;
+ default:
+ break;
+ } // endswitch Op
+
+ if (jnp->Valp)
+ MulVal = AllocateValue(g, jnp->Valp);
+
return false;
} // end of SetArrayOptions
@@ -507,8 +531,7 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
if (Parsed)
return false; // Already done
-
- if (InitValue(g))
+ else if (InitValue(g))
return true;
else if (!Jpath)
Jpath = Name;
@@ -552,47 +575,223 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
{
if (val) {
- if (Nodes[n].Op == OP_NUM)
- vp->SetValue(1);
- else {
- again:
- switch (val->GetValType()) {
- case TYPE_STRG:
- case TYPE_INTG:
- case TYPE_DBL:
- vp->SetValue_pval(val->GetValue());
- break;
- case TYPE_BOOL:
- if (vp->IsTypeNum())
- vp->SetValue(val->GetInteger() ? 1 : 0);
- else
- vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
-
+ switch (val->GetValType()) {
+ case TYPE_STRG:
+ case TYPE_INTG:
+ case TYPE_DBL:
+ vp->SetValue_pval(val->GetValue());
+ break;
+ case TYPE_BOOL:
+ if (vp->IsTypeNum())
+ vp->SetValue(val->GetInteger() ? 1 : 0);
+ else
+ vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
+
+ break;
+ case TYPE_JAR:
+ SetJsonValue(g, vp, val->GetArray()->GetValue(0), n);
+ break;
+ case TYPE_JOB:
+// if (!vp->IsTypeNum() || !Strict) {
+ vp->SetValue_psz(val->GetObject()->GetText(g));
break;
- case TYPE_JAR:
- val = val->GetArray()->GetValue(0);
- goto again;
- case TYPE_JOB:
- if (!vp->IsTypeNum()) {
- vp->SetValue_psz(val->GetObject()->GetText(g));
- break;
- } // endif Type
+// } // endif Type
- default:
- vp->Reset();
- } // endswitch Type
-
- } // endelse
+ default:
+ vp->Reset();
+ } // endswitch Type
} else
vp->Reset();
} // end of SetJsonValue
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void JSONCOL::ReadColumn(PGLOBAL g)
+ {
+ if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
+ Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* GetColumnValue: */
+/***********************************************************************/
+PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
+ {
+ int n = Nod - 1;
+ int nextsame = 0;
+ bool expd = false;
+ PJAR arp;
+ PJVAL val = NULL;
+
+//for (; i < Nod-1 && row; i++) {
+ for (; i < Nod && row; i++) {
+ if (Nodes[i].Op == OP_NUM) {
+ Value->SetValue(row->GetType() == TYPE_JAR ? row->size() : 1);
+ return(Value);
+ } else switch (row->GetType()) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key) {
+ // Expected Array was not there
+ if (i < Nod-1)
+ continue;
+ else
+ val = new(g) JVALUE(row);
+
+ } else
+ val = ((PJOB)row)->GetValue(Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ arp = (PJAR)row;
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op != OP_NULL) {
+ if (Nodes[i].Rank) {
+ val = arp->GetValue(Nodes[i].Rank - 1);
+ } else if (Nodes[i].Op == OP_XX) {
+ return ExpandArray(g, arp, i);
+ } else
+ return CalculateArray(g, arp, i);
+
+ } else
+ val = NULL;
+
+ } else if (i < Nod-1) {
+ strcpy(g->Message, "Unexpected array");
+ val = NULL; // Not an expected array
+ } else
+ val = arp->GetValue(0);
+
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ val = NULL;
+ } // endswitch Type
+
+ if (i < Nod-1)
+ row = (val) ? val->GetJson() : NULL;
+
+ } // endfor i
+
+ SetJsonValue(g, Value, val, n);
+ return Value;
+ } // end of GetColumnValue
+
+/***********************************************************************/
+/* ExpandArray: */
+/***********************************************************************/
+PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
+ {
+ int ars;
+ PJVAL jvp;
+ JVALUE jval;
+
+ ars = MY_MIN(Tjp->Limit, arp->size());
+ jvp = arp->GetValue(Nodes[n].Nx);
+
+ if (n < Nod - 1 && jvp->GetJson()) {
+ jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
+ jvp = &jval;
+ } // endif n
+
+ if (n >= Tjp->NextSame) {
+ if (++Nodes[n].Nx == ars) {
+ Nodes[n].Nx = 0;
+ Xnod = 0;
+ } else
+ Xnod = n;
+
+ Tjp->NextSame = Xnod;
+ } // endif NextSame
+
+ SetJsonValue(g, Value, jvp, n);
+ return Value;
+ } // end of ExpandArray
+
+/***********************************************************************/
+/* CalculateArray: */
+/***********************************************************************/
+PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
+ {
+ int i, ars;
+ bool err;
+ OPVAL op = Nodes[n].Op;
+ PVAL val[2], vp = Nodes[n].Valp;
+ PJVAL jvp;
+ JVALUE jval;
+
+ vp->Reset();
+ ars = MY_MIN(Tjp->Limit, arp->size());
+
+ for (i = 0; i < ars; i++) {
+ jvp = arp->GetValue(i);
+
+ if (n < Nod - 1 && jvp->GetJson()) {
+ jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
+ jvp = &jval;
+ } // endif n
+
+ if (!i) {
+ SetJsonValue(g, vp, jvp, n);
+ continue;
+ } else
+ SetJsonValue(g, MulVal, jvp, n);
+
+ if (!MulVal->IsZero()) {
+ switch (op) {
+ case OP_CNC:
+ if (Nodes[n].CncVal) {
+ val[0] = Nodes[n].CncVal;
+ err = vp->Compute(g, val, 1, op);
+ } // endif CncVal
+
+ val[0] = MulVal;
+ err = vp->Compute(g, val, 1, op);
+ break;
+ case OP_NUM:
+ case OP_SEP:
+ val[0] = Nodes[n].Valp;
+ val[1] = MulVal;
+ err = vp->Compute(g, val, 2, OP_ADD);
+ break;
+ default:
+ val[0] = Nodes[n].Valp;
+ val[1] = MulVal;
+ err = vp->Compute(g, val, 2, op);
+ } // endswitch Op
+
+ if (err)
+ vp->Reset();
+
+ } // endif Zero
+
+ } // endfor i
+
+ if (op == OP_SEP) {
+ // Calculate average
+ MulVal->SetValue(ars);
+ val[0] = vp;
+ val[1] = MulVal;
+
+ if (vp->Compute(g, val, 2, OP_DIV))
+ vp->Reset();
+
+ } // endif Op
+
+ return vp;
+ } // end of CalculateArray
+
/***********************************************************************/
/* GetRow: Get the object containing this column. */
/***********************************************************************/
-PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
+PJSON JSONCOL::GetRow(PGLOBAL g)
{
PJVAL val;
PJAR arp;
@@ -610,23 +809,15 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
case TYPE_JAR:
if (!Nodes[i].Key) {
if (Nodes[i].Op != OP_NULL) {
- Ival = i;
arp = (PJAR)row;
- if (mode < 2) // First pass
- Arp = arp;
-
- if (Nodes[i].Op != OP_XX) {
- if (Nodes[i].Rank)
- val = arp->GetValue(Nodes[i].Rank - 1);
- else
- val = arp->GetValue(arp == Arp ? Nx : 0);
-
- } else
- val = arp->GetValue(Tjp->SameRow);
-
- } else
- val = NULL;
+ if (Nodes[i].Rank)
+ val = arp->GetValue(Nodes[i].Rank - 1);
+ else
+ val = arp->GetValue(Nodes[i].Nx);
+
+ } else
+ val = NULL;
} else {
strcpy(g->Message, "Unexpected array");
@@ -644,7 +835,7 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
if (val) {
row = val->GetJson();
- } else if (mode == 1) { // mode write
+ } else {
// Construct missing objects
for (i++; row && i < Nod; i++) {
if (!Nodes[i].Key) {
@@ -668,8 +859,7 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
} // endfor i
break;
- } else
- row = NULL;
+ } // endelse
} // endfor i
@@ -677,131 +867,6 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
} // end of GetRow
/***********************************************************************/
-/* ReadColumn: */
-/***********************************************************************/
-void JSONCOL::ReadColumn(PGLOBAL g)
- {
- int mode = 0, n = Nod - 1;
- PJSON row;
- PJVAL val = NULL;
-
- evenmore:
- row = GetRow(g, mode);
-
- more:
- if (row) switch (row->GetType()) {
- case TYPE_JOB:
- if (Nodes[n].Key)
- val = row->GetValue(Nodes[n].Key);
- else
- val = new(g) JVALUE(row);
-
- break;
- case TYPE_JAR:
- // Multiple column ?
- if (Nodes[n].Op != OP_NULL) {
- Arp = (PJAR)row;
- val = Arp->GetValue(Nodes[n].Rank > 0 ?
- Nodes[n].Rank - 1 :
- Nodes[n].Op == OP_XX ? Tjp->SameRow : Nx);
- Ival = n;
- } else
- val = NULL;
-
- break;
- case TYPE_JVAL:
- val = (PJVAL)row;
- break;
- default:
- sprintf(g->Message, "Wrong return value type %d", row->GetType());
- Value->Reset();
- return;
- } // endswitch Type
-
- if (!Nx /*|| (Xpd)*/)
- SetJsonValue(g, Value, val, n);
-
- if (Arp) {
- // Multiple column
- int ars = (Nodes[Ival].Rank > 0) ? 1 : MY_MIN(Tjp->Limit, Arp->size());
-
- if (Nodes[Ival].Op == OP_XX) {
- if (ars > Tjp->SameRow + 1)
- Tjp->NextSame = true; // More to come
- else {
- Tjp->NextSame = false;
- Arp = NULL;
- } // endelse
-
- } else {
- if (Nx && val) {
- SetJsonValue(g, MulVal, val, Ival);
-
- if (!MulVal->IsZero()) {
- PVAL val[2];
- bool err;
-
- switch (Nodes[Ival].Op) {
- case OP_CNC:
- if (Nodes[Ival].CncVal) {
- val[0] = Nodes[Ival].CncVal;
- err = Value->Compute(g, val, 1, Nodes[Ival].Op);
- } // endif CncVal
-
- val[0] = MulVal;
- err = Value->Compute(g, val, 1, Nodes[Ival].Op);
- break;
- case OP_NUM:
- case OP_SEP:
- val[0] = Value;
- val[1] = MulVal;
- err = Value->Compute(g, val, 2, OP_ADD);
- break;
- default:
- val[0] = Value;
- val[1] = MulVal;
- err = Value->Compute(g, val, 2, Nodes[Ival].Op);
- } // endswitch Op
-
- if (err)
- Value->Reset();
-
- } // endif Zero
-
- } // endif Nx
-
- if (ars > ++Nx) {
- if (Ival != n) {
- mode = 2;
- goto evenmore;
- } else
- goto more;
-
- } else {
- if (Nodes[Ival].Op == OP_SEP) {
- // Calculate average
- PVAL val[2];
-
- MulVal->SetValue(ars);
- val[0] = Value;
- val[1] = MulVal;
-
- if (Value->Compute(g, val, 2, OP_DIV))
- Value->Reset();
-
- } // endif Op
-
- Arp = NULL;
- Nx = 0;
- } // endif ars
-
- } // endif Op
-
- } // endif Arp
-
- } // end of ReadColumn
-
-/***********************************************************************/
/* WriteColumn: */
/***********************************************************************/
void JSONCOL::WriteColumn(PGLOBAL g)
@@ -821,7 +886,7 @@ void JSONCOL::WriteColumn(PGLOBAL g)
PJOB objp = NULL;
PJAR arp = NULL;
PJVAL jvp = NULL;
- PJSON row = GetRow(g, 1);
+ PJSON row = GetRow(g);
JTYP type = row->GetType();
switch (row->GetType()) {
@@ -1176,11 +1241,6 @@ bool TDBJSON::OpenDB(PGLOBAL g)
/*******************************************************************/
/* Table already open replace it at its beginning. */
/*******************************************************************/
- for (PJCOL cp = (PJCOL)Columns; cp; cp = (PJCOL)cp->GetNext()) {
- cp->Nx = 0;
- cp->Arp = NULL;
- } // endfor cp
-
Fpos= -1;
Spos = 0;
NextSame = false;
@@ -1218,7 +1278,8 @@ int TDBJSON::ReadDB(PGLOBAL g)
N++;
if (NextSame) {
- SameRow++;
+ SameRow = NextSame;
+ NextSame = false;
rc = RC_OK;
} else if (++Fpos < (signed)Doc->size()) {
Row = Doc->GetValue(Fpos);