mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
0f18135ec8
modified: storage/connect/bsonudf.cpp modified: storage/connect/jsonudf.cpp - Stringify option is now a ; separated list of columns modified: storage/connect/json.cpp modified: storage/connect/json.h modified: storage/connect/mongo.h modified: storage/connect/tabbson.cpp modified: storage/connect/tabcmg.cpp modified: storage/connect/tabcmg.h modified: storage/connect/tabjmg.cpp modified: storage/connect/tabjmg.h modified: storage/connect/tabjson.cpp - PrepareColist not a static function anymore (+ typo) modified: storage/connect/taboccur.cpp - JDVC: Recognize schema (database) from a wrapper server modified: storage/connect/tabjdbc.cpp
506 lines
15 KiB
C++
506 lines
15 KiB
C++
/************** tabcmg C++ Program Source Code File (.CPP) *************/
|
|
/* PROGRAM NAME: tabcmg Version 1.3 */
|
|
/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
|
|
/* This program are the C MongoDB class DB 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. */
|
|
/* tdbdos.h is header containing the TDBDOS declarations. */
|
|
/* json.h is header containing the JSON classes declarations. */
|
|
/***********************************************************************/
|
|
#include "global.h"
|
|
#include "plgdbsem.h"
|
|
#include "xtable.h"
|
|
#include "maputil.h"
|
|
#include "filamtxt.h"
|
|
#include "tabext.h"
|
|
#include "tabcmg.h"
|
|
#include "tabmul.h"
|
|
#include "filter.h"
|
|
|
|
PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info);
|
|
bool Stringified(PCSZ, char*);
|
|
|
|
/* -------------------------- Class CMGDISC -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* Get document. */
|
|
/***********************************************************************/
|
|
void CMGDISC::GetDoc(void)
|
|
{
|
|
doc = ((TDBCMG*)tmgp)->Cmgp->Document;
|
|
} // end of GetDoc
|
|
|
|
/***********************************************************************/
|
|
/* Analyse passed document. */
|
|
/***********************************************************************/
|
|
//bool CMGDISC::Find(PGLOBAL g, int i, int k, bool b)
|
|
bool CMGDISC::Find(PGLOBAL g)
|
|
{
|
|
return FindInDoc(g, &iter, doc, NULL, NULL, 0, false);
|
|
} // end of Find
|
|
|
|
/***********************************************************************/
|
|
/* Analyse passed document. */
|
|
/***********************************************************************/
|
|
bool CMGDISC::FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc,
|
|
char *pcn, char *pfmt, int k, bool b)
|
|
{
|
|
if (!doc || bson_iter_init(iter, doc)) {
|
|
const char *key;
|
|
char colname[65];
|
|
char fmt[129];
|
|
bool newcol;
|
|
size_t n;
|
|
|
|
while (bson_iter_next(iter)) {
|
|
key = bson_iter_key(iter);
|
|
newcol = true;
|
|
|
|
if (pcn) {
|
|
n = sizeof(colname) - 1;
|
|
strncpy(colname, pcn, n);
|
|
colname[n] = 0;
|
|
n -= strlen(colname);
|
|
strncat(strncat(colname, "_", n), key, n - 1);
|
|
} else
|
|
strcpy(colname, key);
|
|
|
|
if (pfmt) {
|
|
n = sizeof(fmt) - 1;
|
|
strncpy(fmt, pfmt, n);
|
|
fmt[n] = 0;
|
|
n -= strlen(fmt);
|
|
strncat(strncat(fmt, ".", n), key, n - 1);
|
|
} else
|
|
strcpy(fmt, key);
|
|
|
|
bcol.Cbn = false;
|
|
|
|
switch (bson_iter_type(iter)) {
|
|
case BSON_TYPE_UTF8:
|
|
bcol.Type = TYPE_STRING;
|
|
bcol.Len = strlen(bson_iter_utf8(iter, NULL));
|
|
break;
|
|
case BSON_TYPE_INT32:
|
|
bcol.Type = TYPE_INT;
|
|
bcol.Len = 11; // bson_iter_int32(iter)
|
|
break;
|
|
case BSON_TYPE_INT64:
|
|
bcol.Type = TYPE_BIGINT;
|
|
bcol.Len = 22; // bson_iter_int64(iter)
|
|
break;
|
|
case BSON_TYPE_DOUBLE:
|
|
bcol.Type = TYPE_DOUBLE;
|
|
bcol.Len = 12;
|
|
bcol.Scale = 6; // bson_iter_double(iter)
|
|
break;
|
|
case BSON_TYPE_DATE_TIME:
|
|
bcol.Type = TYPE_DATE;
|
|
bcol.Len = 19; // bson_iter_date_time(iter)
|
|
break;
|
|
case BSON_TYPE_BOOL:
|
|
bcol.Type = TYPE_TINY;
|
|
bcol.Len = 1;
|
|
break;
|
|
case BSON_TYPE_OID:
|
|
bcol.Type = TYPE_STRING;
|
|
bcol.Len = 24; // bson_iter_oid(iter)
|
|
break;
|
|
case BSON_TYPE_DECIMAL128:
|
|
bcol.Type = TYPE_DECIM;
|
|
bcol.Len = 32; // bson_iter_decimal128(iter, &dec)
|
|
break;
|
|
case BSON_TYPE_DOCUMENT:
|
|
if (lvl < 0)
|
|
continue;
|
|
else if (lvl <= k) {
|
|
bcol.Type = TYPE_STRING;
|
|
bcol.Len = 512;
|
|
} else {
|
|
bson_iter_t child;
|
|
|
|
if (bson_iter_recurse(iter, &child))
|
|
if (FindInDoc(g, &child, NULL, colname, fmt, k + 1, false))
|
|
return true;
|
|
|
|
newcol = false;
|
|
} // endif lvl
|
|
|
|
break;
|
|
case BSON_TYPE_ARRAY:
|
|
if (lvl < 0)
|
|
continue;
|
|
else if (lvl <= k) {
|
|
bcol.Type = TYPE_STRING;
|
|
bcol.Len = 512;
|
|
} else {
|
|
bson_t* arr;
|
|
bson_iter_t itar;
|
|
const uint8_t* data = NULL;
|
|
uint32_t len = 0;
|
|
|
|
bson_iter_array(iter, &len, &data);
|
|
arr = bson_new_from_data(data, len);
|
|
|
|
if (FindInDoc(g, &itar, arr, colname, fmt, k + 1, !all))
|
|
return true;
|
|
|
|
newcol = false;
|
|
} // endif lvl
|
|
|
|
break;
|
|
} // endswitch iter
|
|
|
|
if (newcol)
|
|
AddColumn(g, colname, fmt, k);
|
|
|
|
if (b)
|
|
break; // Test only first element of arrays
|
|
|
|
} // endwhile iter
|
|
|
|
} // endif doc
|
|
|
|
return false;
|
|
} // end of FindInDoc
|
|
|
|
/* --------------------------- Class TDBCMG -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* Implementation of the TDBCMG class. */
|
|
/***********************************************************************/
|
|
TDBCMG::TDBCMG(MGODEF *tdp) : TDBEXT(tdp)
|
|
{
|
|
Cmgp = NULL;
|
|
Cnd = NULL;
|
|
Pcg.Tdbp = this;
|
|
|
|
if (tdp) {
|
|
Pcg.Uristr = tdp->Uri;
|
|
Pcg.Db_name = tdp->Tabschema;
|
|
Pcg.Coll_name = tdp->Tabname;
|
|
Pcg.Options = tdp->Colist;
|
|
Pcg.Filter = tdp->Filter;
|
|
Pcg.Line = NULL;
|
|
Pcg.Pipe = tdp->Pipe && tdp->Colist != NULL;
|
|
B = tdp->Base ? 1 : 0;
|
|
Strfy = tdp->Strfy;
|
|
} else {
|
|
Pcg.Uristr = NULL;
|
|
Pcg.Db_name = NULL;
|
|
Pcg.Coll_name = NULL;
|
|
Pcg.Options = NULL;
|
|
Pcg.Filter = NULL;
|
|
Pcg.Line = NULL;
|
|
Pcg.Pipe = false;
|
|
Strfy = NULL;
|
|
B = 0;
|
|
} // endif tdp
|
|
|
|
Fpos = -1;
|
|
N = 0;
|
|
Done = false;
|
|
} // end of TDBCMG standard constructor
|
|
|
|
TDBCMG::TDBCMG(TDBCMG *tdbp) : TDBEXT(tdbp)
|
|
{
|
|
Cmgp = tdbp->Cmgp;
|
|
Cnd = tdbp->Cnd;
|
|
Pcg = tdbp->Pcg;
|
|
Strfy = tdbp->Strfy;
|
|
B = tdbp->B;
|
|
Fpos = tdbp->Fpos;
|
|
N = tdbp->N;
|
|
Done = tdbp->Done;
|
|
} // end of TDBCMG copy constructor
|
|
|
|
// Used for update
|
|
PTDB TDBCMG::Clone(PTABS t)
|
|
{
|
|
PTDB tp;
|
|
PMGOCOL cp1, cp2;
|
|
PGLOBAL g = t->G;
|
|
|
|
tp = new(g) TDBCMG(this);
|
|
|
|
for (cp1 = (PMGOCOL)Columns; cp1; cp1 = (PMGOCOL)cp1->GetNext())
|
|
if (!cp1->IsSpecial()) {
|
|
cp2 = new(g) MGOCOL(cp1, tp); // Make a copy
|
|
NewPointer(t, cp1, cp2);
|
|
} // endif cp1
|
|
|
|
return tp;
|
|
} // end of Clone
|
|
|
|
/***********************************************************************/
|
|
/* Allocate JSN column description block. */
|
|
/***********************************************************************/
|
|
PCOL TDBCMG::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
|
{
|
|
PMGOCOL colp = new(g) MGOCOL(g, cdp, this, cprec, n);
|
|
|
|
return colp;
|
|
} // end of MakeCol
|
|
|
|
/***********************************************************************/
|
|
/* InsertSpecialColumn: Put a special column ahead of the column list.*/
|
|
/***********************************************************************/
|
|
PCOL TDBCMG::InsertSpecialColumn(PCOL colp)
|
|
{
|
|
if (!colp->IsSpecial())
|
|
return NULL;
|
|
|
|
colp->SetNext(Columns);
|
|
Columns = colp;
|
|
return colp;
|
|
} // end of InsertSpecialColumn
|
|
|
|
/***********************************************************************/
|
|
/* Init: initialize MongoDB processing. */
|
|
/***********************************************************************/
|
|
bool TDBCMG::Init(PGLOBAL g)
|
|
{
|
|
if (Done)
|
|
return false;
|
|
|
|
/*********************************************************************/
|
|
/* Open an C connection for this table. */
|
|
/*********************************************************************/
|
|
if (!Cmgp)
|
|
Cmgp = new(g) CMgoConn(g, &Pcg);
|
|
else if (Cmgp->IsConnected())
|
|
Cmgp->Close();
|
|
|
|
if (Cmgp->Connect(g))
|
|
return true;
|
|
|
|
Done = true;
|
|
return false;
|
|
} // end of Init
|
|
|
|
/***********************************************************************/
|
|
/* MONGO Cardinality: returns table size in number of rows. */
|
|
/***********************************************************************/
|
|
int TDBCMG::Cardinality(PGLOBAL g)
|
|
{
|
|
if (!g)
|
|
return 1;
|
|
else if (Cardinal < 0)
|
|
Cardinal = (!Init(g)) ? Cmgp->CollSize(g) : 0;
|
|
|
|
return Cardinal;
|
|
} // end of Cardinality
|
|
|
|
/***********************************************************************/
|
|
/* MONGO GetMaxSize: returns collection size estimate. */
|
|
/***********************************************************************/
|
|
int TDBCMG::GetMaxSize(PGLOBAL g)
|
|
{
|
|
if (MaxSize < 0)
|
|
MaxSize = Cardinality(g);
|
|
|
|
return MaxSize;
|
|
} // end of GetMaxSize
|
|
|
|
/***********************************************************************/
|
|
/* OpenDB: Data Base open routine for MONGO access method. */
|
|
/***********************************************************************/
|
|
bool TDBCMG::OpenDB(PGLOBAL g)
|
|
{
|
|
if (Use == USE_OPEN) {
|
|
/*******************************************************************/
|
|
/* Table already open replace it at its beginning. */
|
|
/*******************************************************************/
|
|
Cmgp->Rewind();
|
|
Fpos = -1;
|
|
return false;
|
|
} // endif Use
|
|
|
|
/*********************************************************************/
|
|
/* First opening. */
|
|
/*********************************************************************/
|
|
if (Pcg.Pipe && Mode != MODE_READ) {
|
|
strcpy(g->Message, "Pipeline tables are read only");
|
|
return true;
|
|
} // endif Pipe
|
|
|
|
Use = USE_OPEN; // Do it now in case we are recursively called
|
|
|
|
if (Init(g))
|
|
return true;
|
|
|
|
if (Mode == MODE_DELETE && !Next)
|
|
// Delete all documents
|
|
return Cmgp->DocDelete(g);
|
|
else if (Mode == MODE_INSERT)
|
|
Cmgp->MakeColumnGroups(g);
|
|
|
|
return false;
|
|
} // end of OpenDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base indexed read routine for ODBC access method. */
|
|
/***********************************************************************/
|
|
bool TDBCMG::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
|
|
{
|
|
strcpy(g->Message, "MONGO tables are not indexable");
|
|
return true;
|
|
} // end of ReadKey
|
|
|
|
/***********************************************************************/
|
|
/* ReadDB: Get next document from a collection. */
|
|
/***********************************************************************/
|
|
int TDBCMG::ReadDB(PGLOBAL g)
|
|
{
|
|
return Cmgp->ReadNext(g);
|
|
} // end of ReadDB
|
|
|
|
/***********************************************************************/
|
|
/* WriteDB: Data Base write routine for MGO access method. */
|
|
/***********************************************************************/
|
|
int TDBCMG::WriteDB(PGLOBAL g)
|
|
{
|
|
return Cmgp->Write(g);
|
|
} // end of WriteDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base delete line routine for MGO access method. */
|
|
/***********************************************************************/
|
|
int TDBCMG::DeleteDB(PGLOBAL g, int irc)
|
|
{
|
|
return (irc == RC_OK) ? WriteDB(g) : RC_OK;
|
|
} // end of DeleteDB
|
|
|
|
/***********************************************************************/
|
|
/* Table close routine for MONGO tables. */
|
|
/***********************************************************************/
|
|
void TDBCMG::CloseDB(PGLOBAL g)
|
|
{
|
|
Cmgp->Close();
|
|
Done = false;
|
|
} // end of CloseDB
|
|
|
|
/* ----------------------------- MGOCOL ------------------------------ */
|
|
|
|
/***********************************************************************/
|
|
/* MGOCOL public constructor. */
|
|
/***********************************************************************/
|
|
MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
|
|
: EXTCOL(cdp, tdbp, cprec, i, "MGO")
|
|
{
|
|
Tmgp = (PTDBCMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
|
|
Sgfy = Stringified(Tmgp->Strfy, Name);
|
|
|
|
if ((Jpath = cdp->GetFmt())) {
|
|
int n = strlen(Jpath) - 1;
|
|
|
|
if (Jpath[n] == '*') {
|
|
Jpath = PlugDup(g, cdp->GetFmt());
|
|
if (Jpath[n - 1] == '.') n--;
|
|
Jpath[n] = 0;
|
|
Sgfy = true;
|
|
} // endif Jpath
|
|
|
|
} else
|
|
Jpath = cdp->GetName();
|
|
|
|
} // end of MGOCOL constructor
|
|
|
|
/***********************************************************************/
|
|
/* MGOCOL constructor used for copying columns. */
|
|
/* tdbp is the pointer to the new table descriptor. */
|
|
/***********************************************************************/
|
|
MGOCOL::MGOCOL(MGOCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
|
|
{
|
|
Tmgp = col1->Tmgp;
|
|
Jpath = col1->Jpath;
|
|
Sgfy = col1->Sgfy;
|
|
} // end of MGOCOL copy constructor
|
|
|
|
/***********************************************************************/
|
|
/* Get path when proj is false or projection path when proj is true. */
|
|
/***********************************************************************/
|
|
PSZ MGOCOL::GetJpath(PGLOBAL g, bool proj)
|
|
{
|
|
if (Jpath) {
|
|
if (proj) {
|
|
char *p1, *p2, *projpath = PlugDup(g, Jpath);
|
|
int i = 0;
|
|
|
|
for (p1 = p2 = projpath; *p1; p1++)
|
|
if (*p1 == '.') {
|
|
if (!i)
|
|
*p2++ = *p1;
|
|
|
|
i = 1;
|
|
} else if (i) {
|
|
if (!isdigit(*p1)) {
|
|
*p2++ = *p1;
|
|
i = 0;
|
|
} // endif p1
|
|
|
|
} else
|
|
*p2++ = *p1;
|
|
|
|
if (*(p2 - 1) == '.')
|
|
p2--;
|
|
|
|
*p2 = 0;
|
|
return projpath;
|
|
} else
|
|
return Jpath;
|
|
|
|
} else
|
|
return Name;
|
|
|
|
} // end of GetJpath
|
|
|
|
/***********************************************************************/
|
|
/* ReadColumn: */
|
|
/***********************************************************************/
|
|
void MGOCOL::ReadColumn(PGLOBAL g)
|
|
{
|
|
Tmgp->Cmgp->GetColumnValue(g, this);
|
|
} // end of ReadColumn
|
|
|
|
/***********************************************************************/
|
|
/* WriteColumn: */
|
|
/***********************************************************************/
|
|
void MGOCOL::WriteColumn(PGLOBAL g)
|
|
{
|
|
// Check whether this node must be written
|
|
if (Value != To_Val)
|
|
Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
|
|
|
|
} // end of WriteColumn
|
|
|
|
/* ---------------------------TDBGOL class --------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* TDBGOL class constructor. */
|
|
/***********************************************************************/
|
|
TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp)
|
|
{
|
|
Topt = tdp->GetTopt();
|
|
Uri = tdp->Uri;
|
|
Db = tdp->GetTabschema();
|
|
} // end of TDBJCL constructor
|
|
|
|
/***********************************************************************/
|
|
/* GetResult: Get the list the JSON file columns. */
|
|
/***********************************************************************/
|
|
PQRYRES TDBGOL::GetResult(PGLOBAL g)
|
|
{
|
|
return MGOColumns(g, Db, Uri, Topt, false);
|
|
} // end of GetResult
|
|
|
|
/* -------------------------- End of mongo --------------------------- */
|