1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

- 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
This commit is contained in:
Olivier Bertrand
2015-01-30 10:57:00 +01:00
parent 9a2dc7dfed
commit fd1ca70bb3
7 changed files with 327 additions and 233 deletions

View File

@@ -119,12 +119,12 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
Fpos = -1;
Spos = N = 0;
Limit = tdp->Limit;
Pretty = tdp->Pretty;
Strict = tdp->Strict;
NextSame = false;
Comma = false;
NextSame = 0;
SameRow = 0;
Xval = -1;
Pretty = tdp->Pretty;
Strict = tdp->Strict;
Comma = false;
} // 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());
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_BOOL:
if (vp->IsTypeNum())
vp->SetValue(val->GetInteger() ? 1 : 0);
else
vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
// } // endif Type
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
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);