mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
dc3a693b70
Also add a new member Saved_Size in the Global structure. modified: storage/connect/global.h modified: storage/connect/plugutil.cpp modified: storage/connect/user_connect.cc modified: storage/connect/jsonudf.cpp - Add session variables json_all_path and default_depth modified: storage/connect/ha_connect.cc modified: storage/connect/mongo.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabxml.cpp - ADD column options JPATH and XPATH Work as FIELD_FORMAT but are more readable modified: storage/connect/ha_connect.cc modified: storage/connect/ha_connect.h modified: storage/connect/mysql-test/connect/r/json_java_2.result modified: storage/connect/mysql-test/connect/r/json_java_3.result modified: storage/connect/mysql-test/connect/r/json_mongo_c.result - Handle negative numbes in the option list modified: storage/connect/ha_connect.cc - Fix Json parse that could crash the server. Was because it could use THROW out of the TRY block. Also handle all error by THROW. It is now done by a new class JSON. modified: storage/connect/json.cpp modified: storage/connect/json.h - Add a new UDF function jfile_translate. It translate a Json file to pretty = 0. Fast because it does not a real parse of the file. modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h - Add a now options JSIZE and STRINGIFY to Json tables. STRINGIFY makes Objects or Arrays to be returned by their json representation instead of by their concatenated values. JSIZE allows to specify the LRECL (was 256) defaults to 1024. Also fix a bug about locating the sub-table by its path. modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h
449 lines
13 KiB
C++
449 lines
13 KiB
C++
/************** mongo C++ Program Source Code File (.CPP) **************/
|
|
/* PROGRAM NAME: mongo Version 1.0 */
|
|
/* (C) Copyright to the author Olivier BERTRAND 2017 */
|
|
/* These programs are the MGODEF class execution routines. */
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
/* Include relevant sections of the MariaDB header file. */
|
|
/***********************************************************************/
|
|
#include <my_global.h>
|
|
|
|
/***********************************************************************/
|
|
/* Include application header files: */
|
|
/* global.h is header containing all global declarations. */
|
|
/* plgdbsem.h is header containing the DB application declarations. */
|
|
/***********************************************************************/
|
|
#include "global.h"
|
|
#include "plgdbsem.h"
|
|
#include "xtable.h"
|
|
#include "tabext.h"
|
|
#include "filter.h"
|
|
#if defined(CMGO_SUPPORT)
|
|
#include "tabcmg.h"
|
|
#endif // CMGO_SUPPORT
|
|
#if defined(JAVA_SUPPORT)
|
|
#include "tabjmg.h"
|
|
#endif // JAVA_SUPPORT
|
|
#include "resource.h"
|
|
|
|
/***********************************************************************/
|
|
/* This should be an option. */
|
|
/***********************************************************************/
|
|
#define MAXCOL 200 /* Default max column nb in result */
|
|
#define TYPE_UNKNOWN 12 /* Must be greater than other types */
|
|
|
|
bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s);
|
|
bool IsNum(PSZ s);
|
|
int GetDefaultDepth(void);
|
|
|
|
/***********************************************************************/
|
|
/* Make selector json representation for Mongo tables. */
|
|
/***********************************************************************/
|
|
bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s)
|
|
{
|
|
OPVAL opc = fp->GetOpc();
|
|
|
|
s->Append('{');
|
|
|
|
if (opc == OP_AND || opc == OP_OR) {
|
|
if (fp->GetArgType(0) != TYPE_FILTER || fp->GetArgType(1) != TYPE_FILTER)
|
|
return true;
|
|
|
|
s->Append("\"$");
|
|
s->Append(opc == OP_AND ? "and" : "or");
|
|
s->Append("\":[");
|
|
|
|
if (MakeSelector(g, (PFIL)fp->Arg(0), s))
|
|
return true;
|
|
|
|
s->Append(',');
|
|
|
|
if (MakeSelector(g, (PFIL)fp->Arg(1), s))
|
|
return true;
|
|
|
|
s->Append(']');
|
|
} else {
|
|
if (fp->GetArgType(0) != TYPE_COLBLK)
|
|
return true;
|
|
|
|
s->Append('"');
|
|
s->Append(((PCOL)fp->Arg(0))->GetJpath(g, false));
|
|
s->Append("\":{\"$");
|
|
|
|
switch (opc) {
|
|
case OP_EQ:
|
|
s->Append("eq");
|
|
break;
|
|
case OP_NE:
|
|
s->Append("ne");
|
|
break;
|
|
case OP_GT:
|
|
s->Append("gt");
|
|
break;
|
|
case OP_GE:
|
|
s->Append("gte");
|
|
break;
|
|
case OP_LT:
|
|
s->Append("lt");
|
|
break;
|
|
case OP_LE:
|
|
s->Append("lte");
|
|
break;
|
|
case OP_NULL:
|
|
case OP_LIKE:
|
|
case OP_EXIST:
|
|
default:
|
|
return true;
|
|
} // endswitch Opc
|
|
|
|
s->Append("\":");
|
|
|
|
if (fp->GetArgType(1) == TYPE_COLBLK) {
|
|
s->Append("\"$");
|
|
s->Append(((PEXTCOL)fp->Arg(1))->GetJpath(g, false));
|
|
s->Append('"');
|
|
} else {
|
|
char buf[501];
|
|
|
|
fp->Arg(1)->Prints(g, buf, 500);
|
|
s->Append(buf);
|
|
} // endif Type
|
|
|
|
s->Append('}');
|
|
} // endif opc
|
|
|
|
s->Append('}');
|
|
return false;
|
|
} // end of MakeSelector
|
|
|
|
/***********************************************************************/
|
|
/* MGOColumns: construct the result blocks containing the description */
|
|
/* of all the columns of a document contained inside MongoDB. */
|
|
/***********************************************************************/
|
|
PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info)
|
|
{
|
|
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
|
|
TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
|
|
static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
|
|
FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
|
|
unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
|
|
int ncol = sizeof(buftyp) / sizeof(int);
|
|
int i, n = 0;
|
|
PCSZ drv;
|
|
PBCOL bcp;
|
|
MGODISC *cmgd = NULL;
|
|
PQRYRES qrp;
|
|
PCOLRES crp;
|
|
|
|
if (info) {
|
|
length[0] = 128;
|
|
length[7] = 256;
|
|
goto skipit;
|
|
} // endif info
|
|
|
|
/*********************************************************************/
|
|
/* Open MongoDB. */
|
|
/*********************************************************************/
|
|
drv = GetStringTableOption(g, topt, "Driver", NULL);
|
|
|
|
if (drv && toupper(*drv) == 'C') {
|
|
#if defined(CMGO_SUPPORT)
|
|
cmgd = new(g) CMGDISC(g, (int*)length);
|
|
#else
|
|
sprintf(g->Message, "Mongo %s Driver not available", "C");
|
|
goto err;
|
|
#endif
|
|
} else if (drv && toupper(*drv) == 'J') {
|
|
#if defined(JAVA_SUPPORT)
|
|
cmgd = new(g) JMGDISC(g, (int*)length);
|
|
#else
|
|
sprintf(g->Message, "Mongo %s Driver not available", "Java");
|
|
goto err;
|
|
#endif
|
|
} else { // Driver not specified
|
|
#if defined(CMGO_SUPPORT)
|
|
cmgd = new(g) CMGDISC(g, (int*)length);
|
|
#else
|
|
cmgd = new(g) JMGDISC(g, (int*)length);
|
|
#endif
|
|
} // endif drv
|
|
|
|
if ((n = cmgd->GetColumns(g, db, uri, topt)) < 0)
|
|
goto err;
|
|
|
|
skipit:
|
|
if (trace(1))
|
|
htrc("MGOColumns: 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 = "Bpath";
|
|
|
|
if (info || !qrp)
|
|
return qrp;
|
|
|
|
qrp->Nblin = n;
|
|
|
|
/*********************************************************************/
|
|
/* Now get the results into blocks. */
|
|
/*********************************************************************/
|
|
for (i = 0, bcp = cmgd->fbcp; bcp; i++, bcp = bcp->Next) {
|
|
if (bcp->Type == TYPE_UNKNOWN) // Void column
|
|
bcp->Type = TYPE_STRING;
|
|
|
|
crp = qrp->Colresp; // Column Name
|
|
crp->Kdata->SetValue(bcp->Name, i);
|
|
crp = crp->Next; // Data Type
|
|
crp->Kdata->SetValue(bcp->Type, i);
|
|
crp = crp->Next; // Type Name
|
|
crp->Kdata->SetValue(GetTypeName(bcp->Type), i);
|
|
crp = crp->Next; // Precision
|
|
crp->Kdata->SetValue(bcp->Len, i);
|
|
crp = crp->Next; // Length
|
|
crp->Kdata->SetValue(bcp->Len, i);
|
|
crp = crp->Next; // Scale (precision)
|
|
crp->Kdata->SetValue(bcp->Scale, i);
|
|
crp = crp->Next; // Nullable
|
|
crp->Kdata->SetValue(bcp->Cbn ? 1 : 0, i);
|
|
crp = crp->Next; // Field format
|
|
|
|
if (crp->Kdata)
|
|
crp->Kdata->SetValue(bcp->Fmt, i);
|
|
|
|
} // endfor i
|
|
|
|
/*********************************************************************/
|
|
/* Return the result pointer. */
|
|
/*********************************************************************/
|
|
return qrp;
|
|
|
|
err:
|
|
if (cmgd && cmgd->tmgp)
|
|
cmgd->tmgp->CloseDB(g);
|
|
|
|
return NULL;
|
|
} // end of MGOColumns
|
|
|
|
/***********************************************************************/
|
|
/* Class used to get the columns of a mongo collection. */
|
|
/***********************************************************************/
|
|
MGODISC::MGODISC(PGLOBAL g, int *lg) {
|
|
length = lg;
|
|
fbcp = NULL;
|
|
pbcp = NULL;
|
|
tmgp = NULL;
|
|
drv = NULL;
|
|
i = ncol = lvl = 0;
|
|
all = false;
|
|
} // end of MGODISC constructor
|
|
|
|
/***********************************************************************/
|
|
/* Class used to get the columns of a mongo collection. */
|
|
/***********************************************************************/
|
|
int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt)
|
|
{
|
|
PMGODEF tdp;
|
|
|
|
lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
|
|
lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
|
|
all = GetBooleanTableOption(g, topt, "Fullarray", false);
|
|
|
|
/*********************************************************************/
|
|
/* Open the MongoDB collection. */
|
|
/*********************************************************************/
|
|
tdp = new(g) MGODEF;
|
|
tdp->Uri = (uri && *uri) ? uri : "mongodb://localhost:27017";
|
|
tdp->Driver = drv;
|
|
tdp->Tabname = GetStringTableOption(g, topt, "Name", NULL);
|
|
tdp->Tabname = GetStringTableOption(g, topt, "Tabname", tdp->Tabname);
|
|
tdp->Tabschema = GetStringTableOption(g, topt, "Dbname", db);
|
|
tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
|
|
tdp->Colist = GetStringTableOption(g, topt, "Colist", "all");
|
|
tdp->Filter = GetStringTableOption(g, topt, "Filter", NULL);
|
|
tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
|
|
tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
|
|
tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
|
|
(tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
|
|
|
|
if (trace(1))
|
|
htrc("Uri %s coll=%s db=%s colist=%s filter=%s lvl=%d\n",
|
|
tdp->Uri, tdp->Tabname, tdp->Tabschema, tdp->Colist, tdp->Filter, lvl);
|
|
|
|
tmgp = tdp->GetTable(g, MODE_READ);
|
|
tmgp->SetMode(MODE_READ);
|
|
|
|
if (tmgp->OpenDB(g))
|
|
return -1;
|
|
|
|
bcol.Next = NULL;
|
|
bcol.Name = bcol.Fmt = NULL;
|
|
bcol.Type = TYPE_UNKNOWN;
|
|
bcol.Len = bcol.Scale = 0;
|
|
bcol.Found = true;
|
|
bcol.Cbn = false;
|
|
|
|
if (Init(g))
|
|
return -1;
|
|
|
|
/*********************************************************************/
|
|
/* Analyse the BSON tree and define columns. */
|
|
/*********************************************************************/
|
|
for (i = 1; ; i++) {
|
|
switch (tmgp->ReadDB(g)) {
|
|
case RC_EF:
|
|
return ncol;
|
|
case RC_FX:
|
|
return -1;
|
|
default:
|
|
GetDoc();
|
|
} // endswitch ReadDB
|
|
|
|
if (Find(g))
|
|
return -1;
|
|
|
|
// Missing columns can be null
|
|
for (bcp = fbcp; bcp; bcp = bcp->Next) {
|
|
bcp->Cbn |= !bcp->Found;
|
|
bcp->Found = false;
|
|
} // endfor bcp
|
|
|
|
} // endfor i
|
|
|
|
return ncol;
|
|
} // end of GetColumns
|
|
|
|
/***********************************************************************/
|
|
/* Add a new column in the column list. */
|
|
/***********************************************************************/
|
|
void MGODISC::AddColumn(PGLOBAL g, PCSZ colname, PCSZ fmt, int k)
|
|
{
|
|
// Check whether this column was already found
|
|
for (bcp = fbcp; bcp; bcp = bcp->Next)
|
|
if (!strcmp(colname, bcp->Name))
|
|
break;
|
|
|
|
if (bcp) {
|
|
if (bcp->Type != bcol.Type)
|
|
bcp->Type = TYPE_STRING;
|
|
|
|
if (k && *fmt && (!bcp->Fmt || strlen(bcp->Fmt) < strlen(fmt))) {
|
|
bcp->Fmt = PlugDup(g, fmt);
|
|
length[7] = MY_MAX(length[7], (signed)strlen(fmt));
|
|
} // endif *fmt
|
|
|
|
bcp->Len = MY_MAX(bcp->Len, bcol.Len);
|
|
bcp->Scale = MY_MAX(bcp->Scale, bcol.Scale);
|
|
bcp->Cbn |= bcol.Cbn;
|
|
bcp->Found = true;
|
|
} else {
|
|
// New column
|
|
bcp = (PBCOL)PlugSubAlloc(g, NULL, sizeof(BCOL));
|
|
*bcp = bcol;
|
|
bcp->Cbn |= (i > 1);
|
|
bcp->Name = PlugDup(g, colname);
|
|
length[0] = MY_MAX(length[0], (signed)strlen(colname));
|
|
|
|
if (k) {
|
|
bcp->Fmt = PlugDup(g, fmt);
|
|
length[7] = MY_MAX(length[7], (signed)strlen(fmt));
|
|
} else
|
|
bcp->Fmt = NULL;
|
|
|
|
if (pbcp) {
|
|
bcp->Next = pbcp->Next;
|
|
pbcp->Next = bcp;
|
|
} else
|
|
fbcp = bcp;
|
|
|
|
ncol++;
|
|
} // endif jcp
|
|
|
|
pbcp = bcp;
|
|
} // end of AddColumn
|
|
|
|
/* -------------------------- Class MGODEF --------------------------- */
|
|
|
|
MGODEF::MGODEF(void)
|
|
{
|
|
Driver = NULL;
|
|
Uri = NULL;
|
|
Colist = NULL;
|
|
Filter = NULL;
|
|
Base = 0;
|
|
Version = 0;
|
|
Pipe = false;
|
|
} // end of MGODEF constructor
|
|
|
|
/***********************************************************************/
|
|
/* DefineAM: define specific AM block values. */
|
|
/***********************************************************************/
|
|
bool MGODEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
|
|
{
|
|
if (EXTDEF::DefineAM(g, "MGO", poff))
|
|
return true;
|
|
else if (!Tabschema)
|
|
Tabschema = GetStringCatInfo(g, "Dbname", "*");
|
|
|
|
Driver = GetStringCatInfo(g, "Driver", NULL);
|
|
Uri = GetStringCatInfo(g, "Connect", "mongodb://localhost:27017");
|
|
Colist = GetStringCatInfo(g, "Colist", NULL);
|
|
Filter = GetStringCatInfo(g, "Filter", NULL);
|
|
Base = GetIntCatInfo("Base", 0) ? 1 : 0;
|
|
Version = GetIntCatInfo("Version", 3);
|
|
|
|
if (Version == 2)
|
|
Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
|
|
else
|
|
Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
|
|
|
|
Pipe = GetBoolCatInfo("Pipeline", false);
|
|
return false;
|
|
} // end of DefineAM
|
|
|
|
/***********************************************************************/
|
|
/* GetTable: makes a new Table Description Block. */
|
|
/***********************************************************************/
|
|
PTDB MGODEF::GetTable(PGLOBAL g, MODE m)
|
|
{
|
|
if (Driver && toupper(*Driver) == 'C') {
|
|
#if defined(CMGO_SUPPORT)
|
|
if (Catfunc == FNC_COL)
|
|
return new(g) TDBGOL(this);
|
|
else
|
|
return new(g) TDBCMG(this);
|
|
#else
|
|
sprintf(g->Message, "Mongo %s Driver not available", "C");
|
|
return NULL;
|
|
#endif
|
|
} else if (Driver && toupper(*Driver) == 'J') {
|
|
#if defined(JAVA_SUPPORT)
|
|
if (Catfunc == FNC_COL)
|
|
return new(g) TDBJGL(this);
|
|
else
|
|
return new(g) TDBJMG(this);
|
|
#else
|
|
sprintf(g->Message, "Mongo %s Driver not available", "Java");
|
|
return NULL;
|
|
#endif
|
|
} else { // Driver not specified
|
|
#if defined(CMGO_SUPPORT)
|
|
if (Catfunc == FNC_COL)
|
|
return new(g) TDBGOL(this);
|
|
else
|
|
return new(g) TDBCMG(this);
|
|
#else
|
|
if (Catfunc == FNC_COL)
|
|
return new(g) TDBJGL(this);
|
|
else
|
|
return new(g) TDBJMG(this);
|
|
#endif
|
|
} // endif Driver
|
|
|
|
} // end of GetTable
|