mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 02:51:44 +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
609 lines
20 KiB
C++
609 lines
20 KiB
C++
/************** PlugUtil C Program Source Code File (.C) ***************/
|
|
/* */
|
|
/* PROGRAM NAME: PLUGUTIL */
|
|
/* ------------- */
|
|
/* Version 3.1 */
|
|
/* */
|
|
/* COPYRIGHT: */
|
|
/* ---------- */
|
|
/* (C) Copyright to the author Olivier BERTRAND 1993-2020 */
|
|
/* */
|
|
/* WHAT THIS PROGRAM DOES: */
|
|
/* ----------------------- */
|
|
/* This program are initialization and utility Plug routines. */
|
|
/* */
|
|
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
|
/* -------------------------------------- */
|
|
/* */
|
|
/* REQUIRED FILES: */
|
|
/* --------------- */
|
|
/* See Readme.C for a list and description of required SYSTEM files. */
|
|
/* */
|
|
/* PLUG.C - Source code */
|
|
/* GLOBAL.H - Global declaration file */
|
|
/* OPTION.H - Option declaration file */
|
|
/* */
|
|
/* REQUIRED LIBRARIES: */
|
|
/* ------------------- */
|
|
/* */
|
|
/* OS2.LIB - OS2 libray */
|
|
/* LLIBCE.LIB - Protect mode/standard combined large model C */
|
|
/* library */
|
|
/* */
|
|
/* REQUIRED PROGRAMS: */
|
|
/* ------------------ */
|
|
/* */
|
|
/* IBM C Compiler */
|
|
/* IBM Linker */
|
|
/* */
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
/* */
|
|
/* Include relevant MariaDB header file. */
|
|
/* */
|
|
/***********************************************************************/
|
|
#include "my_global.h"
|
|
#if defined(__WIN__)
|
|
//#include <windows.h>
|
|
#else
|
|
#if defined(UNIX) || defined(UNIV_LINUX)
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
//#define __stdcall
|
|
#else
|
|
#include <dir.h>
|
|
#endif
|
|
#include <stdarg.h>
|
|
#endif
|
|
|
|
#if defined(WIN)
|
|
#include <alloc.h>
|
|
#endif
|
|
#include <errno.h> /* definitions of ERANGE ENOMEM */
|
|
#if !defined(UNIX) && !defined(UNIV_LINUX)
|
|
#include <direct.h> /* Directory management library */
|
|
#endif
|
|
|
|
/***********************************************************************/
|
|
/* */
|
|
/* Include application header files */
|
|
/* */
|
|
/* global.h is header containing all global declarations. */
|
|
/* */
|
|
/***********************************************************************/
|
|
#define STORAGE /* Initialize global variables */
|
|
|
|
#include "osutil.h"
|
|
#include "global.h"
|
|
#include "plgdbsem.h"
|
|
#if defined(NEWMSG)
|
|
#include "rcmsg.h"
|
|
#endif // NEWMSG
|
|
|
|
#if defined(__WIN__)
|
|
extern HINSTANCE s_hModule; /* Saved module handle */
|
|
#endif // __WIN__
|
|
|
|
#if defined(XMSG)
|
|
extern char *msg_path;
|
|
char *msglang(void);
|
|
#endif // XMSG
|
|
|
|
/***********************************************************************/
|
|
/* Local Definitions and static variables */
|
|
/***********************************************************************/
|
|
typedef struct {
|
|
ushort Segsize;
|
|
ushort Size;
|
|
} AREASIZE;
|
|
|
|
ACTIVITY defActivity = { /* Describes activity and language */
|
|
NULL, /* Points to user work area(s) */
|
|
"Unknown"}; /* Application name */
|
|
|
|
#if defined(XMSG) || defined(NEWMSG)
|
|
static char stmsg[200];
|
|
#endif // XMSG || NEWMSG
|
|
|
|
#if defined(UNIX) || defined(UNIV_LINUX)
|
|
#include "rcmsg.h"
|
|
#endif // UNIX
|
|
|
|
/**************************************************************************/
|
|
/* Conditional tracing output function. */
|
|
/**************************************************************************/
|
|
void xtrc(uint x, char const *fmt, ...)
|
|
{
|
|
if (GetTraceValue() & x) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
} // endif x
|
|
|
|
} // end of xtrc
|
|
|
|
/**************************************************************************/
|
|
/* Tracing output function. */
|
|
/**************************************************************************/
|
|
void htrc(char const* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
} // end of htrc
|
|
|
|
/***********************************************************************/
|
|
/* Plug initialization routine. */
|
|
/* Language points on initial language name and eventual path. */
|
|
/* Return value is the pointer to the Global structure. */
|
|
/***********************************************************************/
|
|
PGLOBAL PlugInit(LPCSTR Language, size_t worksize)
|
|
{
|
|
PGLOBAL g;
|
|
|
|
if (trace(2))
|
|
htrc("PlugInit: Language='%s'\n",
|
|
((!Language) ? "Null" : (char*)Language));
|
|
|
|
try {
|
|
g = new GLOBAL;
|
|
} catch (...) {
|
|
fprintf(stderr, MSG(GLOBAL_ERROR), (int)sizeof(GLOBAL));
|
|
return NULL;
|
|
} // end try/catch
|
|
|
|
g->Sarea = NULL;
|
|
g->Createas = false;
|
|
g->Alchecked = 0;
|
|
g->Mrr = 0;
|
|
g->Activityp = NULL;
|
|
g->Xchk = NULL;
|
|
g->N = 0;
|
|
g->More = 0;
|
|
g->Saved_Size = 0;
|
|
strcpy(g->Message, "");
|
|
|
|
/*******************************************************************/
|
|
/* Allocate the main work segment. */
|
|
/*******************************************************************/
|
|
if (worksize && AllocSarea(g, worksize)) {
|
|
char errmsg[MAX_STR];
|
|
snprintf(errmsg, sizeof(errmsg) - 1, MSG(WORK_AREA), g->Message);
|
|
strcpy(g->Message, errmsg);
|
|
} // endif Sarea
|
|
|
|
g->jump_level = -1; /* New setting to allow recursive call of Plug */
|
|
return(g);
|
|
} /* end of PlugInit */
|
|
|
|
/***********************************************************************/
|
|
/* PlugExit: Terminate Plug operations. */
|
|
/***********************************************************************/
|
|
int PlugExit(PGLOBAL g)
|
|
{
|
|
if (g) {
|
|
PDBUSER dup = PlgGetUser(g);
|
|
|
|
if (dup)
|
|
free(dup);
|
|
|
|
FreeSarea(g);
|
|
delete g;
|
|
} // endif g
|
|
|
|
return 0;
|
|
} // end of PlugExit
|
|
|
|
/***********************************************************************/
|
|
/* Remove the file type from a file name. */
|
|
/* Note: this routine is not really implemented for Unix. */
|
|
/***********************************************************************/
|
|
LPSTR PlugRemoveType(LPSTR pBuff, LPCSTR FileName)
|
|
{
|
|
#if defined(__WIN__)
|
|
char drive[_MAX_DRIVE];
|
|
#else
|
|
char *drive = NULL;
|
|
#endif
|
|
char direc[_MAX_DIR];
|
|
char fname[_MAX_FNAME];
|
|
char ftype[_MAX_EXT];
|
|
|
|
_splitpath(FileName, drive, direc, fname, ftype);
|
|
|
|
if (trace(2)) {
|
|
htrc("after _splitpath: FileName=%s\n", FileName);
|
|
htrc("drive=%s dir=%s fname=%s ext=%s\n",
|
|
SVP(drive), direc, fname, ftype);
|
|
} // endif trace
|
|
|
|
_makepath(pBuff, drive, direc, fname, "");
|
|
|
|
if (trace(2))
|
|
htrc("buff='%s'\n", pBuff);
|
|
|
|
return pBuff;
|
|
} // end of PlugRemoveType
|
|
|
|
|
|
BOOL PlugIsAbsolutePath(LPCSTR path)
|
|
{
|
|
#if defined(__WIN__)
|
|
return ((path[0] >= 'a' && path[0] <= 'z') ||
|
|
(path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':';
|
|
#else
|
|
return path[0] == '/';
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Set the full path of a file relatively to a given path. */
|
|
/* Note: this routine is not really implemented for Unix. */
|
|
/***********************************************************************/
|
|
LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath)
|
|
{
|
|
char newname[_MAX_PATH];
|
|
char direc[_MAX_DIR], defdir[_MAX_DIR], tmpdir[_MAX_DIR];
|
|
char fname[_MAX_FNAME];
|
|
char ftype[_MAX_EXT];
|
|
#if defined(__WIN__)
|
|
char drive[_MAX_DRIVE], defdrv[_MAX_DRIVE];
|
|
#else
|
|
char *drive = NULL, *defdrv = NULL;
|
|
#endif
|
|
|
|
if (trace(2))
|
|
htrc("prefix=%s fn=%s path=%s\n", prefix, FileName, defpath);
|
|
|
|
if (!strncmp(FileName, "//", 2) || !strncmp(FileName, "\\\\", 2)) {
|
|
strcpy(pBuff, FileName); // Remote file
|
|
return pBuff;
|
|
} // endif
|
|
|
|
if (PlugIsAbsolutePath(FileName))
|
|
{
|
|
strcpy(pBuff, FileName); // FileName includes absolute path
|
|
return pBuff;
|
|
} // endif
|
|
|
|
#if !defined(__WIN__)
|
|
if (*FileName == '~') {
|
|
if (_fullpath(pBuff, FileName, _MAX_PATH)) {
|
|
if (trace(2))
|
|
htrc("pbuff='%s'\n", pBuff);
|
|
|
|
return pBuff;
|
|
} else
|
|
return FileName; // Error, return unchanged name
|
|
|
|
} // endif FileName
|
|
#endif // !__WIN__
|
|
|
|
if (prefix && strcmp(prefix, ".") && !PlugIsAbsolutePath(defpath))
|
|
{
|
|
char tmp[_MAX_PATH];
|
|
int len= snprintf(tmp, sizeof(tmp) - 1, "%s%s%s",
|
|
prefix, defpath, FileName);
|
|
memcpy(pBuff, tmp, (size_t) len);
|
|
pBuff[len]= '\0';
|
|
return pBuff;
|
|
}
|
|
|
|
_splitpath(FileName, drive, direc, fname, ftype);
|
|
|
|
if (defpath) {
|
|
char c = defpath[strlen(defpath) - 1];
|
|
|
|
strcpy(tmpdir, defpath);
|
|
|
|
if (c != '/' && c != '\\')
|
|
strcat(tmpdir, "/");
|
|
|
|
} else
|
|
strcpy(tmpdir, "./");
|
|
|
|
_splitpath(tmpdir, defdrv, defdir, NULL, NULL);
|
|
|
|
if (trace(2)) {
|
|
htrc("after _splitpath: FileName=%s\n", FileName);
|
|
#if defined(__WIN__)
|
|
htrc("drive=%s dir=%s fname=%s ext=%s\n", drive, direc, fname, ftype);
|
|
htrc("defdrv=%s defdir=%s\n", defdrv, defdir);
|
|
#else
|
|
htrc("dir=%s fname=%s ext=%s\n", direc, fname, ftype);
|
|
#endif
|
|
} // endif trace
|
|
|
|
if (drive && !*drive)
|
|
strcpy(drive, defdrv);
|
|
|
|
switch (*direc) {
|
|
case '\0':
|
|
strcpy(direc, defdir);
|
|
break;
|
|
case '\\':
|
|
case '/':
|
|
break;
|
|
default:
|
|
// This supposes that defdir ends with a SLASH
|
|
strcpy(direc, strcat(defdir, direc));
|
|
} // endswitch
|
|
|
|
_makepath(newname, drive, direc, fname, ftype);
|
|
|
|
if (trace(2))
|
|
htrc("newname='%s'\n", newname);
|
|
|
|
if (_fullpath(pBuff, newname, _MAX_PATH)) {
|
|
if (trace(2))
|
|
htrc("pbuff='%s'\n", pBuff);
|
|
|
|
return pBuff;
|
|
} else
|
|
return FileName; // Error, return unchanged name
|
|
|
|
} // end of PlugSetPath
|
|
|
|
#if defined(XMSG)
|
|
/***********************************************************************/
|
|
/* PlugGetMessage: get a message from the message file. */
|
|
/***********************************************************************/
|
|
char *PlugReadMessage(PGLOBAL g, int mid, char *m)
|
|
{
|
|
char msgfile[_MAX_PATH], msgid[32], buff[256];
|
|
char *msg;
|
|
FILE *mfile = NULL;
|
|
|
|
//GetPrivateProfileString("Message", msglang, "Message\\english.msg",
|
|
// msgfile, _MAX_PATH, plgini);
|
|
//strcat(strcat(strcpy(msgfile, msg_path), msglang()), ".msg");
|
|
strcat(strcpy(buff, msglang()), ".msg");
|
|
PlugSetPath(msgfile, NULL, buff, msg_path);
|
|
|
|
if (!(mfile = fopen(msgfile, "rt"))) {
|
|
sprintf(stmsg, "Fail to open message file %s", msgfile);
|
|
goto err;
|
|
} // endif mfile
|
|
|
|
for (;;)
|
|
if (!fgets(buff, 256, mfile)) {
|
|
sprintf(stmsg, "Cannot get message %d %s", mid, SVP(m));
|
|
goto fin;
|
|
} else
|
|
if (atoi(buff) == mid)
|
|
break;
|
|
|
|
if (sscanf(buff, " %*d %s \"%[^\"]", msgid, stmsg) < 2) {
|
|
// Old message file
|
|
if (!sscanf(buff, " %*d \"%[^\"]", stmsg)) {
|
|
sprintf(stmsg, "Bad message file for %d %s", mid, SVP(m));
|
|
goto fin;
|
|
} else
|
|
m = NULL;
|
|
|
|
} // endif sscanf
|
|
|
|
if (m && strcmp(m, msgid)) {
|
|
// Message file is out of date
|
|
strcpy(stmsg, m);
|
|
goto fin;
|
|
} // endif m
|
|
|
|
fin:
|
|
fclose(mfile);
|
|
|
|
err:
|
|
if (g) {
|
|
// Called by STEP
|
|
msg = PlugDup(g, stmsg);
|
|
} else // Called by MSG or PlgGetErrorMsg
|
|
msg = stmsg;
|
|
|
|
return msg;
|
|
} // end of PlugReadMessage
|
|
|
|
#elif defined(NEWMSG)
|
|
/***********************************************************************/
|
|
/* PlugGetMessage: get a message from the resource string table. */
|
|
/***********************************************************************/
|
|
char *PlugGetMessage(PGLOBAL g, int mid)
|
|
{
|
|
char *msg;
|
|
|
|
#if 0 // was !defined(UNIX) && !defined(UNIV_LINUX)
|
|
int n = LoadString(s_hModule, (uint)mid, (LPTSTR)stmsg, 200);
|
|
|
|
if (n == 0) {
|
|
DWORD rc = GetLastError();
|
|
msg = (char*)PlugSubAlloc(g, NULL, 512); // Extend buf allocation
|
|
n = sprintf(msg, "Message %d, rc=%d: ", mid, rc);
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
|
|
(LPTSTR)(msg + n), 512 - n, NULL);
|
|
return msg;
|
|
} // endif n
|
|
|
|
#else // ALL
|
|
if (!GetRcString(mid, stmsg, 200))
|
|
sprintf(stmsg, "Message %d not found", mid);
|
|
#endif // ALL
|
|
|
|
if (g) {
|
|
// Called by STEP
|
|
msg = PlugDup(g, stmsg);
|
|
} else // Called by MSG or PlgGetErrorMsg
|
|
msg = stmsg;
|
|
|
|
return msg;
|
|
} // end of PlugGetMessage
|
|
#endif // NEWMSG
|
|
|
|
#if defined(__WIN__)
|
|
/***********************************************************************/
|
|
/* Return the line length of the console screen buffer. */
|
|
/***********************************************************************/
|
|
short GetLineLength(PGLOBAL g)
|
|
{
|
|
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
|
HANDLE hcons = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
BOOL b = GetConsoleScreenBufferInfo(hcons, &coninfo);
|
|
|
|
return (b) ? coninfo.dwSize.X : 0;
|
|
} // end of GetLineLength
|
|
#endif // __WIN__
|
|
|
|
/***********************************************************************/
|
|
/* Program for memory allocation of work and language areas. */
|
|
/***********************************************************************/
|
|
bool AllocSarea(PGLOBAL g, size_t size)
|
|
{
|
|
/*********************************************************************/
|
|
/* This is the allocation routine for the WIN32/UNIX/AIX version. */
|
|
/*********************************************************************/
|
|
#if defined(__WIN__)
|
|
if (size >= 1048576) // 1M
|
|
g->Sarea = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
else
|
|
#endif
|
|
g->Sarea = malloc(size);
|
|
|
|
if (!g->Sarea) {
|
|
sprintf(g->Message, MSG(MALLOC_ERROR), "malloc");
|
|
g->Sarea_Size = 0;
|
|
} else
|
|
g->Sarea_Size = size;
|
|
|
|
#if defined(DEVELOPMENT)
|
|
if (true) {
|
|
#else
|
|
if (trace(8)) {
|
|
#endif
|
|
if (g->Sarea)
|
|
htrc("Work area of %zd allocated at %p\n", size, g->Sarea);
|
|
else
|
|
htrc("SareaAlloc: %s\n", g->Message);
|
|
|
|
} // endif trace
|
|
|
|
return (!g->Sarea);
|
|
} // end of AllocSarea
|
|
|
|
/***********************************************************************/
|
|
/* Program for memory freeing the work area. */
|
|
/***********************************************************************/
|
|
void FreeSarea(PGLOBAL g)
|
|
{
|
|
if (g->Sarea) {
|
|
#if defined(__WIN__)
|
|
if (g->Sarea_Size >= 1048576) // 1M
|
|
VirtualFree(g->Sarea, 0, MEM_RELEASE);
|
|
else
|
|
#endif
|
|
free(g->Sarea);
|
|
|
|
#if defined(DEVELOPMENT)
|
|
if (true)
|
|
#else
|
|
if (trace(8))
|
|
#endif
|
|
htrc("Freeing Sarea at %p size = %zd\n", g->Sarea, g->Sarea_Size);
|
|
|
|
g->Sarea = NULL;
|
|
g->Sarea_Size = 0;
|
|
} // endif Sarea
|
|
|
|
return;
|
|
} // end of FreeSarea
|
|
|
|
/***********************************************************************/
|
|
/* Program for SubSet initialization of memory pools. */
|
|
/* Here there should be some verification done such as validity of */
|
|
/* the address and size not larger than memory size. */
|
|
/***********************************************************************/
|
|
BOOL PlugSubSet(void *memp, size_t size)
|
|
{
|
|
PPOOLHEADER pph = (PPOOLHEADER)memp;
|
|
|
|
pph->To_Free = (size_t)sizeof(POOLHEADER);
|
|
pph->FreeBlk = size - pph->To_Free;
|
|
return FALSE;
|
|
} /* end of PlugSubSet */
|
|
|
|
/***********************************************************************/
|
|
/* Use it to export a function that do throwing. */
|
|
/***********************************************************************/
|
|
static void *DoThrow(int n)
|
|
{
|
|
throw n;
|
|
} /* end of DoThrow */
|
|
|
|
/***********************************************************************/
|
|
/* Program for sub-allocating one item in a storage area. */
|
|
/* The simple way things are done here is based on the fact */
|
|
/* that no freeing of suballocated blocks is permitted in CONNECT. */
|
|
/***********************************************************************/
|
|
void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
|
|
{
|
|
PPOOLHEADER pph; /* Points on area header. */
|
|
|
|
if (!memp)
|
|
/*******************************************************************/
|
|
/* Allocation is to be done in the Sarea. */
|
|
/*******************************************************************/
|
|
memp = g->Sarea;
|
|
|
|
size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */
|
|
pph = (PPOOLHEADER)memp;
|
|
|
|
if (trace(16))
|
|
htrc("SubAlloc in %p size=%zd used=%zd free=%zd\n",
|
|
memp, size, pph->To_Free, pph->FreeBlk);
|
|
|
|
if (size > pph->FreeBlk) { /* Not enough memory left in pool */
|
|
PCSZ pname = "Work";
|
|
|
|
sprintf(g->Message,
|
|
"Not enough memory in %s area for request of %zd (used=%zd free=%zd)",
|
|
pname, size, pph->To_Free, pph->FreeBlk);
|
|
|
|
if (trace(1))
|
|
htrc("PlugSubAlloc: %s\n", g->Message);
|
|
|
|
DoThrow(1234);
|
|
} /* endif size OS32 code */
|
|
|
|
/*********************************************************************/
|
|
/* Do the suballocation the simplest way. */
|
|
/*********************************************************************/
|
|
memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
|
|
pph->To_Free += size; /* New offset of pool free block */
|
|
pph->FreeBlk -= size; /* New size of pool free block */
|
|
|
|
if (trace(16))
|
|
htrc("Done memp=%p used=%zd free=%zd\n",
|
|
memp, pph->To_Free, pph->FreeBlk);
|
|
|
|
return (memp);
|
|
} /* end of PlugSubAlloc */
|
|
|
|
/***********************************************************************/
|
|
/* Program for sub-allocating and copying a string in a storage area. */
|
|
/***********************************************************************/
|
|
char *PlugDup(PGLOBAL g, const char *str)
|
|
{
|
|
if (str) {
|
|
char *sm = (char*)PlugSubAlloc(g, NULL, strlen(str) + 1);
|
|
|
|
strcpy(sm, str);
|
|
return sm;
|
|
} else
|
|
return NULL;
|
|
|
|
} // end of PlugDup
|
|
|
|
/*--------------------- End of PLUGUTIL program -----------------------*/
|