diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2015-01-30 10:57:00 +0100 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2015-01-30 10:57:00 +0100 |
commit | fd1ca70bb3710ae280bd11b3650820dd62002419 (patch) | |
tree | 4bf2d015e61dc83733c146a7cca4025ead296bde /storage/connect/tabjson.cpp | |
parent | 9a2dc7dfed6b56c529b2de865a15929bee2eceaf (diff) | |
download | mariadb-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.cpp | 477 |
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); |