summaryrefslogtreecommitdiff
path: root/storage/connect/tabrest.cpp
blob: 7e0d736f4e75e9522c6443dd451869e62add371d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/*************** Rest C++ Program Source Code File (.CPP) **************/
/* PROGRAM NAME: Rest   Version 1.6                                    */
/*  (C) Copyright to the author Olivier BERTRAND          2018 - 2019  */
/*  This program is the REST Web API support for MariaDB.              */
/*  When compiled without MARIADB defined, it is the EOM module code.  */
/***********************************************************************/

/***********************************************************************/
/*  Definitions needed by the included files.                          */
/***********************************************************************/
#if defined(MARIADB)
#include <my_global.h>    // All MariaDB stuff
#else   // !MARIADB       OEM module
#include "mini-global.h"
#define _MAX_PATH 260
#if !defined(__WIN__)
#define __stdcall
#if !defined(REST_SOURCE)
#include <dlfcn.h>         // dlopen(), dlclose(), dlsym() ...
#endif
#endif   // !__WIN__
#define _OS_H_INCLUDED     // Prevent os.h to be called
#endif  // !MARIADB

/***********************************************************************/
/*  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"
#include "plgxml.h"
#include "tabxml.h"
#include "tabjson.h"
#include "tabfmt.h"
#include "tabrest.h"

static XGETREST getRestFnc = NULL;

#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

/***********************************************************************/
/*  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
	if (!(getRestFnc = (XGETREST)dlsym(Hso, "restGetFile"))) {
		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

/***********************************************************************/
/*  Return the columns definition to MariaDB.                          */
/***********************************************************************/
#if defined(MARIADB)
PQRYRES RESTColumns(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
#else   // !MARIADB
PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
#endif  // !MARIADB
{
  PQRYRES qrp= NULL;
  char filename[_MAX_PATH + 1];  // MAX PATH ???
  PCSZ http, uri, fn, ftype;
	XGETREST grf = GetRestFunction(g);

	if (!grf)
		return NULL;

  http = GetStringTableOption(g, tp, "Http", NULL);
  uri = GetStringTableOption(g, tp, "Uri", NULL);
  fn = GetStringTableOption(g, tp, "Filename", "rest.json");
#if defined(MARIADB)
  ftype = GetStringTableOption(g, tp, "Type", "JSON");
#else   // !MARIADB
  // OEM tables must specify the file type
  ftype = GetStringTableOption(g, tp, "Ftype", "JSON");
#endif  // !MARIADB

  //  We used the file name relative to recorded datapath
  strcat(strcat(strcat(strcpy(filename, "."), slash), db), slash);
  strncat(filename, fn, _MAX_PATH - strlen(filename));

  // Retrieve the file from the web and copy it locally
	if (http && grf(g->Message, trace(515), http, uri, filename)) {
			// sprintf(g->Message, "Failed to get file at %s", http);
  } else if (!stricmp(ftype, "XML"))
    qrp = XMLColumns(g, db, tab, tp, info);
  else if (!stricmp(ftype, "JSON"))
    qrp = JSONColumns(g, db, NULL, tp, info);
  else if (!stricmp(ftype, "CSV"))
    qrp = CSVColumns(g, NULL, tp, info);
  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)
{
	char    filename[_MAX_PATH + 1];
  int     rc = 0, n;
	bool    xt = trace(515);
	LPCSTR  ftype;
	XGETREST grf = GetRestFunction(g);

	if (!grf)
		return true;

#if defined(MARIADB)
  ftype = GetStringCatInfo(g, "Type", "JSON");
#else   // !MARIADB
  // OEM tables must specify the file type
  ftype = GetStringCatInfo(g, "Ftype", "JSON");
#endif  // !MARIADB

  if (xt)
    htrc("ftype = %s am = %s\n", ftype, SVP(am));

  n = (!stricmp(ftype, "JSON")) ? 1
    : (!stricmp(ftype, "XML"))  ? 2
    : (!stricmp(ftype, "CSV"))  ? 3 : 0;

  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");

  //  We used the file name relative to recorded datapath
  //PlugSetPath(filename, Fn, GetPath());
  strcpy(filename, GetPath());
	strncat(filename, Fn, _MAX_PATH - strlen(filename));

  // Retrieve the file from the web and copy it locally
	rc = grf(g->Message, xt, Http, Uri, filename);

  if (xt)
    htrc("Return from restGetFile: rc=%d\n", rc);

  if (rc)
    return true;
  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

  // Do make the table/view definition
  if (Tdp && Tdp->Define(g, Cat, Name, Schema, "REST"))
    Tdp = NULL; // Error occured

  if (xt)
    htrc("Tdp defined\n", rc);

  // 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)
{
  if (trace(515))
    htrc("REST GetTable mode=%d\n", m);

  if (m != MODE_READ && m != MODE_READX) {
    strcpy(g->Message, "REST tables are currently read only");
    return NULL;
  } // endif m

  return Tdp->GetTable(g, m); // Leave file type do the job
} // end of GetTable

/* ---------------------- End of Class RESTDEF ----------------------- */