From fd1ca70bb3710ae280bd11b3650820dd62002419 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 30 Jan 2015 10:57:00 +0100 Subject: - 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 --- storage/connect/tabjson.cpp | 477 +++++++++++++++++++++++++------------------- 1 file changed, 269 insertions(+), 208 deletions(-) (limited to 'storage/connect/tabjson.cpp') 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,139 +859,13 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode) } // endfor i break; - } else - row = NULL; + } // endelse } // endfor i return row; } // 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: */ /***********************************************************************/ @@ -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); -- cgit v1.2.1