mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	 0f18135ec8
			
		
	
	
	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 --------------------------- */
 |