2019-07-30 22:45:04 +02:00
|
|
|
/*************** Rest C++ Program Source Code File (.CPP) **************/
|
2019-11-16 14:59:54 +01:00
|
|
|
/* PROGRAM NAME: Rest Version 1.6 */
|
2019-07-30 22:45:04 +02:00
|
|
|
/* (C) Copyright to the author Olivier BERTRAND 2018 - 2019 */
|
2019-08-17 16:58:58 +02:00
|
|
|
/* This program is the REST Web API support for MariaDB. */
|
|
|
|
/* When compiled without MARIADB defined, it is the EOM module code. */
|
2019-07-30 22:45:04 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Definitions needed by the included files. */
|
|
|
|
/***********************************************************************/
|
2019-08-17 16:58:58 +02:00
|
|
|
#if defined(MARIADB)
|
2019-11-30 19:03:29 +01:00
|
|
|
#include <my_global.h> // All MariaDB stuff
|
2019-08-17 16:58:58 +02:00
|
|
|
#else // !MARIADB OEM module
|
|
|
|
#include "mini-global.h"
|
|
|
|
#define _MAX_PATH 260
|
|
|
|
#if !defined(__WIN__)
|
|
|
|
#define __stdcall
|
2019-12-01 01:16:23 +01:00
|
|
|
//#if !defined(REST_SOURCE)
|
|
|
|
//#include <dlfcn.h> // dlopen(), dlclose(), dlsym() ...
|
|
|
|
//#endif
|
2019-08-17 16:58:58 +02:00
|
|
|
#endif // !__WIN__
|
|
|
|
#define _OS_H_INCLUDED // Prevent os.h to be called
|
|
|
|
#endif // !MARIADB
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Include application header files: */
|
|
|
|
/* global.h is header containing all global declarations. */
|
|
|
|
/* plgdbsem.h is header containing the DB application declarations. */
|
|
|
|
/* (x)table.h is header containing the TDBASE declarations. */
|
|
|
|
/***********************************************************************/
|
|
|
|
#include "global.h"
|
|
|
|
#include "plgdbsem.h"
|
|
|
|
#include "xtable.h"
|
|
|
|
#include "filamtxt.h"
|
|
|
|
#include "tabdos.h"
|
2019-08-17 16:58:58 +02:00
|
|
|
#include "plgxml.h"
|
|
|
|
#include "tabxml.h"
|
2019-07-30 22:45:04 +02:00
|
|
|
#include "tabjson.h"
|
2019-08-17 16:58:58 +02:00
|
|
|
#include "tabfmt.h"
|
2019-07-30 22:45:04 +02:00
|
|
|
#include "tabrest.h"
|
|
|
|
|
2019-11-16 14:59:54 +01:00
|
|
|
static XGETREST getRestFnc = NULL;
|
|
|
|
|
2019-08-17 16:58:58 +02:00
|
|
|
#if !defined(MARIADB)
|
|
|
|
/***********************************************************************/
|
|
|
|
/* DB static variables. */
|
|
|
|
/***********************************************************************/
|
|
|
|
int TDB::Tnum;
|
|
|
|
int DTVAL::Shift;
|
|
|
|
int CSORT::Limit = 0;
|
|
|
|
double CSORT::Lg2 = log(2.0);
|
|
|
|
size_t CSORT::Cpn[1000] = { 0 };
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* These functions are exported from the REST library. */
|
|
|
|
/***********************************************************************/
|
|
|
|
extern "C" {
|
|
|
|
PTABDEF __stdcall GetREST(PGLOBAL, void*);
|
|
|
|
PQRYRES __stdcall ColREST(PGLOBAL, PTOS, char*, char*, bool);
|
|
|
|
} // extern "C"
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* This function returns a table definition class. */
|
|
|
|
/***********************************************************************/
|
|
|
|
PTABDEF __stdcall GetREST(PGLOBAL g, void *memp)
|
|
|
|
{
|
|
|
|
return new(g, memp) RESTDEF;
|
|
|
|
} // end of GetREST
|
|
|
|
#endif // !MARIADB
|
|
|
|
|
2019-11-16 14:59:54 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* GetREST: get the external TABDEF from OEM module. */
|
|
|
|
/***********************************************************************/
|
|
|
|
XGETREST GetRestFunction(PGLOBAL g)
|
|
|
|
{
|
|
|
|
if (getRestFnc)
|
|
|
|
return getRestFnc;
|
|
|
|
|
|
|
|
#if !defined(REST_SOURCE)
|
|
|
|
if (trace(515))
|
|
|
|
htrc("Looking for GetRest library\n");
|
|
|
|
|
|
|
|
#if defined(__WIN__)
|
|
|
|
HANDLE Hdll;
|
|
|
|
const char* soname = "GetRest.dll"; // Module name
|
|
|
|
|
|
|
|
if (!(Hdll = LoadLibrary(soname))) {
|
|
|
|
char buf[256];
|
|
|
|
DWORD rc = GetLastError();
|
|
|
|
|
|
|
|
sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname);
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
|
|
|
|
(LPTSTR)buf, sizeof(buf), NULL);
|
|
|
|
strcat(strcat(g->Message, ": "), buf);
|
|
|
|
return NULL;
|
|
|
|
} // endif Hdll
|
|
|
|
|
|
|
|
// Get the function returning an instance of the external DEF class
|
|
|
|
if (!(getRestFnc = (XGETREST)GetProcAddress((HINSTANCE)Hdll, "restGetFile"))) {
|
|
|
|
char buf[256];
|
|
|
|
DWORD rc = GetLastError();
|
|
|
|
|
|
|
|
sprintf(g->Message, MSG(PROCADD_ERROR), rc, "restGetFile");
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
|
|
|
|
(LPTSTR)buf, sizeof(buf), NULL);
|
|
|
|
strcat(strcat(g->Message, ": "), buf);
|
|
|
|
FreeLibrary((HMODULE)Hdll);
|
|
|
|
return NULL;
|
|
|
|
} // endif getRestFnc
|
|
|
|
#else // !__WIN__
|
|
|
|
void* Hso;
|
|
|
|
const char* error = NULL;
|
|
|
|
const char* soname = "GetRest.so"; // Module name
|
|
|
|
|
|
|
|
// Load the desired shared library
|
|
|
|
if (!(Hso = dlopen(soname, RTLD_LAZY))) {
|
|
|
|
error = dlerror();
|
|
|
|
sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
|
|
|
|
return NULL;
|
|
|
|
} // endif Hdll
|
|
|
|
|
|
|
|
// Get the function returning an instance of the external DEF class
|
2019-11-16 15:59:16 +01:00
|
|
|
if (!(getRestFnc = (XGETREST)dlsym(Hso, "restGetFile"))) {
|
2019-11-16 14:59:54 +01:00
|
|
|
error = dlerror();
|
|
|
|
sprintf(g->Message, MSG(GET_FUNC_ERR), "restGetFile", SVP(error));
|
|
|
|
dlclose(Hso);
|
|
|
|
return NULL;
|
|
|
|
} // endif getdef
|
|
|
|
#endif // !__WIN__
|
|
|
|
#else
|
|
|
|
getRestFnc = restGetFile;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return getRestFnc;
|
|
|
|
} // end of GetRestFunction
|
|
|
|
|
2019-07-30 22:45:04 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Return the columns definition to MariaDB. */
|
|
|
|
/***********************************************************************/
|
2019-08-17 16:58:58 +02:00
|
|
|
#if defined(MARIADB)
|
2019-07-30 22:45:04 +02:00
|
|
|
PQRYRES RESTColumns(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
|
2019-08-17 16:58:58 +02:00
|
|
|
#else // !MARIADB
|
|
|
|
PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
|
|
|
|
#endif // !MARIADB
|
2019-07-30 22:45:04 +02:00
|
|
|
{
|
|
|
|
PQRYRES qrp= NULL;
|
2019-08-17 16:58:58 +02:00
|
|
|
char filename[_MAX_PATH + 1]; // MAX PATH ???
|
2019-07-30 22:45:04 +02:00
|
|
|
PCSZ http, uri, fn, ftype;
|
2019-11-16 14:59:54 +01:00
|
|
|
XGETREST grf = GetRestFunction(g);
|
|
|
|
|
|
|
|
if (!grf)
|
|
|
|
return NULL;
|
2019-07-30 22:45:04 +02:00
|
|
|
|
2019-08-17 16:58:58 +02:00
|
|
|
http = GetStringTableOption(g, tp, "Http", NULL);
|
|
|
|
uri = GetStringTableOption(g, tp, "Uri", NULL);
|
|
|
|
fn = GetStringTableOption(g, tp, "Filename", "rest.json");
|
|
|
|
#if defined(MARIADB)
|
2019-08-19 18:06:34 +02:00
|
|
|
ftype = GetStringTableOption(g, tp, "Type", "JSON");
|
2019-08-17 16:58:58 +02:00
|
|
|
#else // !MARIADB
|
2019-08-19 18:06:34 +02:00
|
|
|
// OEM tables must specify the file type
|
|
|
|
ftype = GetStringTableOption(g, tp, "Ftype", "JSON");
|
2019-08-17 16:58:58 +02:00
|
|
|
#endif // !MARIADB
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
// We used the file name relative to recorded datapath
|
|
|
|
strcat(strcat(strcat(strcpy(filename, "."), slash), db), slash);
|
2019-11-26 19:22:46 +01:00
|
|
|
strncat(filename, fn, _MAX_PATH - strlen(filename));
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
// Retrieve the file from the web and copy it locally
|
2019-11-16 14:59:54 +01:00
|
|
|
if (http && grf(g->Message, trace(515), http, uri, filename)) {
|
|
|
|
// sprintf(g->Message, "Failed to get file at %s", http);
|
2019-07-30 22:45:04 +02:00
|
|
|
} else if (!stricmp(ftype, "XML"))
|
2019-08-17 16:58:58 +02:00
|
|
|
qrp = XMLColumns(g, db, tab, tp, info);
|
2019-07-30 22:45:04 +02:00
|
|
|
else if (!stricmp(ftype, "JSON"))
|
2019-08-17 16:58:58 +02:00
|
|
|
qrp = JSONColumns(g, db, NULL, tp, info);
|
2019-07-30 22:45:04 +02:00
|
|
|
else if (!stricmp(ftype, "CSV"))
|
2019-08-17 16:58:58 +02:00
|
|
|
qrp = CSVColumns(g, NULL, tp, info);
|
2019-07-30 22:45:04 +02:00
|
|
|
else
|
|
|
|
sprintf(g->Message, "Usupported file type %s", ftype);
|
|
|
|
|
|
|
|
return qrp;
|
|
|
|
} // end of RESTColumns
|
|
|
|
|
|
|
|
/* -------------------------- Class RESTDEF -------------------------- */
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* DefineAM: define specific AM block values. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
|
|
|
{
|
2019-11-16 14:59:54 +01:00
|
|
|
char filename[_MAX_PATH + 1];
|
2019-08-17 16:58:58 +02:00
|
|
|
int rc = 0, n;
|
2019-11-16 14:59:54 +01:00
|
|
|
bool xt = trace(515);
|
|
|
|
LPCSTR ftype;
|
|
|
|
XGETREST grf = GetRestFunction(g);
|
|
|
|
|
|
|
|
if (!grf)
|
|
|
|
return true;
|
2019-08-17 16:58:58 +02:00
|
|
|
|
|
|
|
#if defined(MARIADB)
|
2019-08-19 18:06:34 +02:00
|
|
|
ftype = GetStringCatInfo(g, "Type", "JSON");
|
2019-08-17 16:58:58 +02:00
|
|
|
#else // !MARIADB
|
|
|
|
// OEM tables must specify the file type
|
|
|
|
ftype = GetStringCatInfo(g, "Ftype", "JSON");
|
|
|
|
#endif // !MARIADB
|
|
|
|
|
2019-11-16 14:59:54 +01:00
|
|
|
if (xt)
|
2019-08-19 18:06:34 +02:00
|
|
|
htrc("ftype = %s am = %s\n", ftype, SVP(am));
|
2019-08-17 16:58:58 +02:00
|
|
|
|
2019-08-19 18:06:34 +02:00
|
|
|
n = (!stricmp(ftype, "JSON")) ? 1
|
|
|
|
: (!stricmp(ftype, "XML")) ? 2
|
|
|
|
: (!stricmp(ftype, "CSV")) ? 3 : 0;
|
2019-08-17 16:58:58 +02:00
|
|
|
|
|
|
|
if (n == 0) {
|
|
|
|
htrc("DefineAM: Unsupported REST table type %s", am);
|
|
|
|
sprintf(g->Message, "Unsupported REST table type %s", am);
|
|
|
|
return true;
|
|
|
|
} // endif n
|
|
|
|
|
|
|
|
Http = GetStringCatInfo(g, "Http", NULL);
|
|
|
|
Uri = GetStringCatInfo(g, "Uri", NULL);
|
|
|
|
Fn = GetStringCatInfo(g, "Filename", "rest.json");
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
// We used the file name relative to recorded datapath
|
2019-08-17 16:58:58 +02:00
|
|
|
//PlugSetPath(filename, Fn, GetPath());
|
2019-11-26 19:22:46 +01:00
|
|
|
strcpy(filename, GetPath());
|
|
|
|
strncat(filename, Fn, _MAX_PATH - strlen(filename));
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
// Retrieve the file from the web and copy it locally
|
2019-11-16 14:59:54 +01:00
|
|
|
rc = grf(g->Message, xt, Http, Uri, filename);
|
2019-08-17 16:58:58 +02:00
|
|
|
|
2019-11-16 14:59:54 +01:00
|
|
|
if (xt)
|
2019-08-19 18:06:34 +02:00
|
|
|
htrc("Return from restGetFile: rc=%d\n", rc);
|
2019-08-17 16:58:58 +02:00
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return true;
|
2019-08-19 18:06:34 +02:00
|
|
|
else switch (n) {
|
|
|
|
case 1: Tdp = new (g) JSONDEF; break;
|
|
|
|
case 2: Tdp = new (g) XMLDEF; break;
|
|
|
|
case 3: Tdp = new (g) CSVDEF; break;
|
|
|
|
default: Tdp = NULL;
|
|
|
|
} // endswitch n
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
// Do make the table/view definition
|
|
|
|
if (Tdp && Tdp->Define(g, Cat, Name, Schema, "REST"))
|
2019-08-17 16:58:58 +02:00
|
|
|
Tdp = NULL; // Error occured
|
|
|
|
|
2019-11-16 14:59:54 +01:00
|
|
|
if (xt)
|
2019-08-19 18:06:34 +02:00
|
|
|
htrc("Tdp defined\n", rc);
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
// Return true in case of error
|
|
|
|
return (Tdp == NULL);
|
|
|
|
} // end of DefineAM
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* GetTable: makes a new Table Description Block. */
|
|
|
|
/***********************************************************************/
|
|
|
|
PTDB RESTDEF::GetTable(PGLOBAL g, MODE m)
|
|
|
|
{
|
2019-08-19 18:06:34 +02:00
|
|
|
if (trace(515))
|
|
|
|
htrc("REST GetTable mode=%d\n", m);
|
2019-08-17 16:58:58 +02:00
|
|
|
|
|
|
|
if (m != MODE_READ && m != MODE_READX) {
|
|
|
|
strcpy(g->Message, "REST tables are currently read only");
|
|
|
|
return NULL;
|
|
|
|
} // endif m
|
2019-07-30 22:45:04 +02:00
|
|
|
|
|
|
|
return Tdp->GetTable(g, m); // Leave file type do the job
|
|
|
|
} // end of GetTable
|
|
|
|
|
|
|
|
/* ---------------------- End of Class RESTDEF ----------------------- */
|