mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
957 lines
31 KiB
C++
957 lines
31 KiB
C++
/************* RelDef CPP Program Source Code File (.CPP) **************/
|
|
/* PROGRAM NAME: RELDEF */
|
|
/* ------------- */
|
|
/* Version 1.7 */
|
|
/* */
|
|
/* COPYRIGHT: */
|
|
/* ---------- */
|
|
/* (C) Copyright to the author Olivier BERTRAND 2004-2019 */
|
|
/* */
|
|
/* WHAT THIS PROGRAM DOES: */
|
|
/* ----------------------- */
|
|
/* This program are the DB definition related routines. */
|
|
/* */
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
/* Include relevant MariaDB header file. */
|
|
/***********************************************************************/
|
|
#include "my_global.h"
|
|
#if defined(_WIN32)
|
|
#include <sqlext.h>
|
|
#else
|
|
//#include <dlfcn.h> // dlopen(), dlclose(), dlsym() ...
|
|
#include "osutil.h"
|
|
//#include "sqlext.h"
|
|
#endif
|
|
#include "handler.h"
|
|
|
|
/***********************************************************************/
|
|
/* Include application header files */
|
|
/* */
|
|
/* global.h is header containing all global declarations. */
|
|
/* plgdbsem.h is header containing DB application declarations. */
|
|
/* catalog.h is header containing DB description declarations. */
|
|
/***********************************************************************/
|
|
#include "global.h"
|
|
#include "plgdbsem.h"
|
|
#include "reldef.h"
|
|
#include "colblk.h"
|
|
#include "tabcol.h"
|
|
#include "filamap.h"
|
|
#include "filamfix.h"
|
|
#if defined(VCT_SUPPORT)
|
|
#include "filamvct.h"
|
|
#endif // VCT_SUPPORT
|
|
#if defined(GZ_SUPPORT)
|
|
#include "filamgz.h"
|
|
#endif // GZ_SUPPORT
|
|
#include "tabdos.h"
|
|
#include "valblk.h"
|
|
#include "tabmul.h"
|
|
#include "ha_connect.h"
|
|
#include "mycat.h"
|
|
|
|
#if !defined(_WIN32)
|
|
extern handlerton *connect_hton;
|
|
#endif // !_WIN32
|
|
|
|
/***********************************************************************/
|
|
/* External function. */
|
|
/***********************************************************************/
|
|
USETEMP UseTemp(void);
|
|
char *GetPluginDir(void);
|
|
PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char* tab, char* db, bool info);
|
|
|
|
/***********************************************************************/
|
|
/* OEMColumns: Get table column info for an OEM table. */
|
|
/***********************************************************************/
|
|
PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char* tab, char* db, bool info)
|
|
{
|
|
typedef PQRYRES(__stdcall* XCOLDEF) (PGLOBAL, void*, char*, char*, bool);
|
|
const char* module, * subtype;
|
|
char c, soname[_MAX_PATH], getname[40] = "Col";
|
|
#if defined(_WIN32)
|
|
HANDLE hdll; /* Handle to the external DLL */
|
|
#else // !_WIN32
|
|
void* hdll; /* Handle for the loaded shared library */
|
|
#endif // !_WIN32
|
|
XCOLDEF coldef = NULL;
|
|
PQRYRES qrp = NULL;
|
|
|
|
module = topt->module;
|
|
subtype = topt->subtype;
|
|
|
|
if (!module || !subtype)
|
|
return NULL;
|
|
|
|
/*********************************************************************/
|
|
/* Ensure that the .dll doesn't have a path. */
|
|
/* This is done to ensure that only approved dll from the system */
|
|
/* directories are used (to make this even remotely secure). */
|
|
/*********************************************************************/
|
|
if (check_valid_path(module, strlen(module))) {
|
|
safe_strcpy(g->Message, sizeof(g->Message), "Module cannot contain a path");
|
|
return NULL;
|
|
}
|
|
else if (strlen(subtype)+1+3 >= sizeof(getname)) {
|
|
safe_strcpy(g->Message, sizeof(g->Message), "Subtype string too long");
|
|
return NULL;
|
|
}
|
|
else
|
|
PlugSetPath(soname, module, GetPluginDir());
|
|
|
|
// The exported name is always in uppercase
|
|
for (int i = 0; ; i++) {
|
|
c = subtype[i];
|
|
getname[i + 3] = toupper(c);
|
|
if (!c) break;
|
|
} // endfor i
|
|
|
|
#if defined(_WIN32)
|
|
// Load the Dll implementing the table
|
|
if (!(hdll = LoadLibrary(soname))) {
|
|
char buf[256];
|
|
DWORD rc = GetLastError();
|
|
|
|
snprintf(g->Message, sizeof(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);
|
|
safe_strcat(g->Message, sizeof(g->Message), ": ");
|
|
safe_strcat(g->Message, sizeof(g->Message), buf);
|
|
return NULL;
|
|
} // endif hDll
|
|
|
|
// Get the function returning an instance of the external DEF class
|
|
if (!(coldef = (XCOLDEF)GetProcAddress((HINSTANCE)hdll, getname))) {
|
|
snprintf(g->Message, sizeof(g->Message), MSG(PROCADD_ERROR), GetLastError(), getname);
|
|
FreeLibrary((HMODULE)hdll);
|
|
return NULL;
|
|
} // endif coldef
|
|
#else // !_WIN32
|
|
const char* error = NULL;
|
|
|
|
// Load the desired shared library
|
|
if (!(hdll = dlopen(soname, RTLD_LAZY))) {
|
|
error = dlerror();
|
|
snprintf(g->Message, sizeof(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 (!(coldef = (XCOLDEF)dlsym(hdll, getname))) {
|
|
error = dlerror();
|
|
snprintf(g->Message, sizeof(g->Message), MSG(GET_FUNC_ERR), getname, SVP(error));
|
|
dlclose(hdll);
|
|
return NULL;
|
|
} // endif coldef
|
|
#endif // !_WIN32
|
|
|
|
// Just in case the external Get function does not set error messages
|
|
snprintf(g->Message, sizeof(g->Message), "Error getting column info from %s", subtype);
|
|
|
|
// Get the table column definition
|
|
qrp = coldef(g, topt, tab, db, info);
|
|
|
|
#if defined(_WIN32)
|
|
FreeLibrary((HMODULE)hdll);
|
|
#else // !_WIN32
|
|
dlclose(hdll);
|
|
#endif // !_WIN32
|
|
|
|
return qrp;
|
|
} // end of OEMColumns
|
|
|
|
/* --------------------------- Class RELDEF -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* RELDEF Constructor. */
|
|
/***********************************************************************/
|
|
RELDEF::RELDEF(void)
|
|
{
|
|
Next = NULL;
|
|
To_Cols = NULL;
|
|
Name = NULL;
|
|
Database = NULL;
|
|
Cat = NULL;
|
|
Hc = NULL;
|
|
} // end of RELDEF constructor
|
|
|
|
/***********************************************************************/
|
|
/* This function return a pointer to the Table Option Struct. */
|
|
/***********************************************************************/
|
|
PTOS RELDEF::GetTopt(void)
|
|
{
|
|
return Hc->GetTableOptionStruct();
|
|
} // end of GetTopt
|
|
|
|
/***********************************************************************/
|
|
/* This function sets an integer table information. */
|
|
/***********************************************************************/
|
|
bool RELDEF::SetIntCatInfo(PCSZ what, int n)
|
|
{
|
|
return Hc->SetIntegerOption(what, n);
|
|
} // end of SetIntCatInfo
|
|
|
|
/***********************************************************************/
|
|
/* This function returns integer table information. */
|
|
/***********************************************************************/
|
|
int RELDEF::GetIntCatInfo(PCSZ what, int idef)
|
|
{
|
|
int n= Hc->GetIntegerOption(what);
|
|
|
|
return (n == NO_IVAL) ? idef : n;
|
|
} // end of GetIntCatInfo
|
|
|
|
/***********************************************************************/
|
|
/* This function returns Boolean table information. */
|
|
/***********************************************************************/
|
|
bool RELDEF::GetBoolCatInfo(PCSZ what, bool bdef)
|
|
{
|
|
bool b= Hc->GetBooleanOption(what, bdef);
|
|
|
|
return b;
|
|
} // end of GetBoolCatInfo
|
|
|
|
/***********************************************************************/
|
|
/* This function returns size catalog information. */
|
|
/***********************************************************************/
|
|
int RELDEF::GetSizeCatInfo(PCSZ what, PCSZ sdef)
|
|
{
|
|
char c;
|
|
PCSZ s;
|
|
int i, n= 0;
|
|
|
|
if (!(s= Hc->GetStringOption(what)))
|
|
s= sdef;
|
|
|
|
if ((i= sscanf(s, " %d %c ", &n, &c)) == 2)
|
|
switch (toupper(c)) {
|
|
case 'M':
|
|
n *= 1024;
|
|
// fall through
|
|
case 'K':
|
|
n *= 1024;
|
|
} // endswitch c
|
|
|
|
return n;
|
|
} // end of GetSizeCatInfo
|
|
|
|
/***********************************************************************/
|
|
/* This function sets char table information in buf. */
|
|
/***********************************************************************/
|
|
int RELDEF::GetCharCatInfo(PCSZ what, PCSZ sdef, char *buf, int size)
|
|
{
|
|
PCSZ s= Hc->GetStringOption(what);
|
|
|
|
strncpy(buf, ((s) ? s : sdef), size);
|
|
return size;
|
|
} // end of GetCharCatInfo
|
|
|
|
/***********************************************************************/
|
|
/* To be used by any TDB's. */
|
|
/***********************************************************************/
|
|
bool RELDEF::Partitioned(void)
|
|
{
|
|
return Hc->IsPartitioned();
|
|
} // end of Partitioned
|
|
|
|
/***********************************************************************/
|
|
/* This function returns string table information. */
|
|
/* Default parameter is "*" to get the handler default. */
|
|
/***********************************************************************/
|
|
char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef)
|
|
{
|
|
char *sval = NULL;
|
|
PCSZ name, s= Hc->GetStringOption(what, sdef);
|
|
|
|
if (s) {
|
|
if (!Hc->IsPartitioned() ||
|
|
(stricmp(what, "filename") && stricmp(what, "tabname")
|
|
&& stricmp(what, "connect")))
|
|
sval= PlugDup(g, s);
|
|
else
|
|
sval= (char*)s;
|
|
|
|
} else if (!stricmp(what, "filename")) {
|
|
// Return default file name
|
|
PCSZ ftype= Hc->GetStringOption("Type", "*");
|
|
int i, n;
|
|
|
|
if (IsFileType(GetTypeID(ftype))) {
|
|
name= Hc->GetPartName();
|
|
sval= (char*)PlugSubAlloc(g, NULL, strlen(name) + 12);
|
|
snprintf(sval, strlen(name) + 12, "%s.", name);
|
|
n= strlen(sval);
|
|
|
|
// Fold ftype to lower case
|
|
for (i= 0; i < 12; i++)
|
|
if (!ftype[i]) {
|
|
sval[n+i]= 0;
|
|
break;
|
|
} else
|
|
sval[n+i]= tolower(ftype[i]);
|
|
|
|
} // endif FileType
|
|
|
|
} // endif s
|
|
|
|
return sval;
|
|
} // end of GetStringCatInfo
|
|
|
|
/* --------------------------- Class TABDEF -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* TABDEF Constructor. */
|
|
/***********************************************************************/
|
|
TABDEF::TABDEF(void)
|
|
{
|
|
Schema = NULL;
|
|
Desc = NULL;
|
|
Recfm = RECFM_DFLT;
|
|
Catfunc = FNC_NO;
|
|
Card = 0;
|
|
Elemt = 0;
|
|
Sort = 0;
|
|
Multiple = 0;
|
|
Degree = 0;
|
|
Pseudo = 0;
|
|
Read_Only = false;
|
|
m_data_charset = NULL;
|
|
csname = NULL;
|
|
} // end of TABDEF constructor
|
|
|
|
/***********************************************************************/
|
|
/* Return the table format. */
|
|
/***********************************************************************/
|
|
RECFM TABDEF::GetTableFormat(const char* type)
|
|
{
|
|
RECFM recfm = Recfm;
|
|
|
|
if (Catfunc != FNC_NO)
|
|
recfm = RECFM_NAF;
|
|
else if (recfm == RECFM_DFLT)
|
|
// Default format depends on the table type
|
|
switch (GetTypeID(type)) {
|
|
case TAB_DOS: recfm = RECFM_VAR; break;
|
|
case TAB_CSV: recfm = RECFM_CSV; break;
|
|
case TAB_FMT: recfm = RECFM_FMT; break;
|
|
case TAB_FIX: recfm = RECFM_FIX; break;
|
|
case TAB_BIN: recfm = RECFM_BIN; break;
|
|
case TAB_VEC: recfm = RECFM_VCT; break;
|
|
case TAB_DBF: recfm = RECFM_DBF; break;
|
|
case TAB_XML: recfm = RECFM_XML; break;
|
|
case TAB_DIR: recfm = RECFM_DIR; break;
|
|
default: recfm = RECFM_NAF; break;
|
|
} // endswitch type
|
|
|
|
return recfm;
|
|
} // end of GetTableFormat
|
|
|
|
/***********************************************************************/
|
|
/* Define: initialize the table definition block from XDB file. */
|
|
/***********************************************************************/
|
|
bool TABDEF::Define(PGLOBAL g, PCATLG cat,
|
|
LPCSTR name, LPCSTR schema, LPCSTR am)
|
|
{
|
|
Hc = ((MYCAT*)cat)->GetHandler();
|
|
Name = (PSZ)name;
|
|
Schema = (PSZ)Hc->GetDBName(schema);
|
|
Cat = cat;
|
|
Catfunc = GetFuncID(GetStringCatInfo(g, "Catfunc", NULL));
|
|
Elemt = GetIntCatInfo("Elements", 0);
|
|
Multiple = GetIntCatInfo("Multiple", 0);
|
|
Degree = GetIntCatInfo("Degree", 0);
|
|
Read_Only = GetBoolCatInfo("ReadOnly", false);
|
|
const char *data_charset_name= GetStringCatInfo(g, "Data_charset", NULL);
|
|
m_data_charset= data_charset_name ?
|
|
get_charset_by_csname(data_charset_name, MY_CS_PRIMARY,
|
|
MYF(MY_UTF8_IS_UTF8MB3)):
|
|
NULL;
|
|
csname = GetStringCatInfo(g, "Table_charset", NULL);
|
|
|
|
// Do the definition of AM specific fields
|
|
if (DefineAM(g, am, 0))
|
|
return true;
|
|
|
|
// Get The column definitions
|
|
if (stricmp(am, "OEM") && GetColCatInfo(g) < 0)
|
|
return true;
|
|
|
|
Hc->tshp = NULL; // TO BE CHECKED
|
|
return false;
|
|
} // end of Define
|
|
|
|
/***********************************************************************/
|
|
/* This function returns the database data path. */
|
|
/***********************************************************************/
|
|
PCSZ TABDEF::GetPath(void)
|
|
{
|
|
return (Database) ? Database : (Hc) ? Hc->GetDataPath() : NULL;
|
|
} // end of GetPath
|
|
|
|
/***********************************************************************/
|
|
/* This function returns column table information. */
|
|
/***********************************************************************/
|
|
int TABDEF::GetColCatInfo(PGLOBAL g)
|
|
{
|
|
char *type = GetStringCatInfo(g, "Type", "*");
|
|
char c, fty, eds;
|
|
int i, n, loff, poff, nof, nlg;
|
|
void *field = NULL;
|
|
RECFM trf;
|
|
PCOLDEF cdp, lcdp = NULL, tocols= NULL;
|
|
PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO));
|
|
|
|
memset(pcf, 0, sizeof(COLINFO));
|
|
|
|
// Get the table format
|
|
trf = GetTableFormat(type);
|
|
|
|
// Take care of the column definitions
|
|
i= poff= nof= nlg= 0;
|
|
|
|
#if defined(_WIN32)
|
|
// Offsets of HTML and DIR tables start from 0, DBF at 1
|
|
loff= (trf == RECFM_DBF) ? 1 : (trf == RECFM_XML || trf == RECFM_DIR) ? -1 : 0;
|
|
#else // !_WIN32
|
|
// Offsets of HTML tables start from 0, DIR and DBF at 1
|
|
loff = (trf == RECFM_DBF || trf == RECFM_DIR) ? 1 : (trf == RECFM_XML) ? -1 : 0;
|
|
#endif // !_WIN32
|
|
|
|
while (true) {
|
|
// Default Offset depends on table format
|
|
switch (trf ) {
|
|
case RECFM_VAR:
|
|
case RECFM_FIX:
|
|
case RECFM_BIN:
|
|
case RECFM_VCT:
|
|
case RECFM_DBF:
|
|
poff= loff + nof; // Default next offset
|
|
nlg= MY_MAX(nlg, poff); // Default lrecl
|
|
break;
|
|
case RECFM_CSV:
|
|
case RECFM_FMT:
|
|
nlg+= nof;
|
|
/* falls through */
|
|
case RECFM_DIR:
|
|
case RECFM_XML:
|
|
poff= loff + (pcf->Flags & U_VIRTUAL ? 0 : 1);
|
|
break;
|
|
//case RECFM_INI:
|
|
//case RECFM_MAC:
|
|
//case RECFM_TBL:
|
|
//case RECFM_XCL:
|
|
//case RECFM_OCCUR:
|
|
//case RECFM_PRX:
|
|
case RECFM_OEM:
|
|
poff = 0; // Offset represents an independant flag
|
|
break;
|
|
default: // PLG ODBC JDBC MYSQL WMI...
|
|
poff = 0; // NA
|
|
break;
|
|
} // endswitch trf
|
|
|
|
// do {
|
|
field= Hc->GetColumnOption(g, field, pcf);
|
|
// } while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/));
|
|
|
|
if (trf == RECFM_DBF && pcf->Type == TYPE_DATE && !pcf->Datefmt) {
|
|
// DBF date format defaults to 'YYYMMDD'
|
|
pcf->Datefmt= "YYYYMMDD";
|
|
pcf->Length= 8;
|
|
} // endif trf
|
|
|
|
if (!field)
|
|
break;
|
|
|
|
// Allocate the column description block
|
|
cdp= new(g) COLDEF;
|
|
|
|
if ((nof= cdp->Define(g, NULL, pcf, poff)) < 0)
|
|
return -1; // Error, probably unhandled type
|
|
else
|
|
loff= cdp->GetOffset();
|
|
|
|
switch (trf ) {
|
|
case RECFM_VCT:
|
|
cdp->SetOffset(0); // Not to have shift
|
|
/* falls through */
|
|
case RECFM_BIN:
|
|
// BIN/VEC are packed by default
|
|
if (nof) {
|
|
// Field width is the internal representation width
|
|
// that can also depend on the column format
|
|
fty = cdp->Decode ? 'C' : 'X';
|
|
eds = 0;
|
|
n = 0;
|
|
|
|
if (cdp->Fmt && !cdp->Decode) {
|
|
for (i = 0; cdp->Fmt[i]; i++) {
|
|
c = toupper(cdp->Fmt[i]);
|
|
|
|
if (isdigit(c))
|
|
n = (n * 10 + (c - '0'));
|
|
else if (c == 'L' || c == 'B' || c == 'H')
|
|
eds = c;
|
|
else
|
|
fty = c;
|
|
|
|
} // endfor i
|
|
|
|
} // endif Fmt
|
|
|
|
if (n)
|
|
nof = n;
|
|
else switch (fty) {
|
|
case 'X':
|
|
if (eds && IsTypeChar(cdp->Buf_Type))
|
|
nof = sizeof(longlong);
|
|
else
|
|
nof= cdp->Clen;
|
|
|
|
break;
|
|
case 'C': break;
|
|
case 'R':
|
|
case 'F': nof = sizeof(float); break;
|
|
case 'I': nof = sizeof(int); break;
|
|
case 'D': nof = sizeof(double); break;
|
|
case 'S': nof = sizeof(short); break;
|
|
case 'T': nof = sizeof(char); break;
|
|
case 'G': nof = sizeof(longlong); break;
|
|
default: /* Wrong format */
|
|
snprintf(g->Message, sizeof(g->Message), "Invalid format %c", fty);
|
|
return -1;
|
|
} // endswitch fty
|
|
|
|
} // endif nof
|
|
|
|
default:
|
|
break;
|
|
} // endswitch trf
|
|
|
|
if (lcdp)
|
|
lcdp->SetNext(cdp);
|
|
else
|
|
tocols= cdp;
|
|
|
|
lcdp= cdp;
|
|
i++;
|
|
} // endwhile
|
|
|
|
// Degree is the the number of defined columns (informational)
|
|
if (i != GetDegree())
|
|
SetDegree(i);
|
|
|
|
if (GetDefType() == TYPE_AM_DOS) {
|
|
int ending, recln= 0;
|
|
|
|
ending = Hc->GetIntegerOption("Ending");
|
|
|
|
// Calculate the default record size
|
|
switch (trf ) {
|
|
case RECFM_FIX:
|
|
case RECFM_BIN:
|
|
recln= nlg + ending; // + length of line ending
|
|
break;
|
|
case RECFM_VCT:
|
|
recln= nlg;
|
|
|
|
// if ((k= (pak < 0) ? 8 : pak) > 1)
|
|
// See above for detailed comment
|
|
// Round up lrecl to multiple of 8 or pak
|
|
// recln= ((recln + k - 1) / k) * k;
|
|
|
|
break;
|
|
case RECFM_VAR:
|
|
case RECFM_DBF:
|
|
recln= nlg;
|
|
break;
|
|
case RECFM_CSV:
|
|
case RECFM_FMT:
|
|
// The number of separators (assuming an extra one can exist)
|
|
// recln= poff * ((qotd) ? 3 : 1); to be investigated
|
|
recln= nlg + poff * 3; // To be safe
|
|
default:
|
|
break;
|
|
} // endswitch trf
|
|
|
|
// lrecl must be at least recln to avoid buffer overflow
|
|
if (trace(1))
|
|
htrc("Lrecl: Calculated=%d defined=%d\n",
|
|
recln, Hc->GetIntegerOption("Lrecl"));
|
|
|
|
recln = MY_MAX(recln, Hc->GetIntegerOption("Lrecl"));
|
|
Hc->SetIntegerOption("Lrecl", recln);
|
|
((PDOSDEF)this)->SetLrecl(recln);
|
|
|
|
if (trace(1))
|
|
htrc("Lrecl set to %d\n", recln);
|
|
|
|
} // endif TYPE
|
|
|
|
// Attach the column definition to the tabdef
|
|
SetCols(tocols);
|
|
return poff;
|
|
} // end of GetColCatInfo
|
|
|
|
/***********************************************************************/
|
|
/* SetIndexInfo: retrieve index description from the table structure. */
|
|
/***********************************************************************/
|
|
void TABDEF::SetIndexInfo(void)
|
|
{
|
|
// Attach new index(es)
|
|
SetIndx(Hc->GetIndexInfo());
|
|
} // end of SetIndexInfo
|
|
|
|
/* --------------------------- Class OEMDEF -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* GetXdef: get the external TABDEF from OEM module. */
|
|
/***********************************************************************/
|
|
PTABDEF OEMDEF::GetXdef(PGLOBAL g)
|
|
{
|
|
typedef PTABDEF (__stdcall *XGETDEF) (PGLOBAL, void *);
|
|
char c, soname[_MAX_PATH], getname[40] = "Get";
|
|
PTABDEF xdefp;
|
|
XGETDEF getdef = NULL;
|
|
PCATLG cat = Cat;
|
|
|
|
/*********************************************************************/
|
|
/* Ensure that the module name doesn't have a path. */
|
|
/* This is done to ensure that only approved libs from the system */
|
|
/* directories are used (to make this even remotely secure). */
|
|
/*********************************************************************/
|
|
if (check_valid_path(Module, strlen(Module))) {
|
|
safe_strcpy(g->Message, sizeof(g->Message), "Module cannot contain a path");
|
|
return NULL;
|
|
} else
|
|
// PlugSetPath(soname, Module, GetPluginDir()); // Crashes on Fedora
|
|
snprintf(soname, sizeof(soname), "%s%s", GetPluginDir(), Module);
|
|
|
|
#if defined(_WIN32)
|
|
// Is the DLL already loaded?
|
|
if (!Hdll && !(Hdll = GetModuleHandle(soname)))
|
|
// No, load the Dll implementing the function
|
|
if (!(Hdll = LoadLibrary(soname))) {
|
|
char buf[256];
|
|
DWORD rc = GetLastError();
|
|
|
|
snprintf(g->Message, sizeof(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);
|
|
safe_strcat(g->Message, sizeof(g->Message), ": ");
|
|
safe_strcat(g->Message, sizeof(g->Message), buf);
|
|
return NULL;
|
|
} // endif hDll
|
|
|
|
// The exported name is always in uppercase
|
|
for (int i = 0; ; i++) {
|
|
c = Subtype[i];
|
|
getname[i + 3] = toupper(c);
|
|
if (!c) break;
|
|
} // endfor i
|
|
|
|
// Get the function returning an instance of the external DEF class
|
|
if (!(getdef = (XGETDEF)GetProcAddress((HINSTANCE)Hdll, getname))) {
|
|
char buf[256];
|
|
DWORD rc = GetLastError();
|
|
|
|
snprintf(g->Message, sizeof(g->Message), MSG(PROCADD_ERROR), rc, getname);
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
|
|
(LPTSTR)buf, sizeof(buf), NULL);
|
|
safe_strcat(g->Message, sizeof(g->Message), ": ");
|
|
safe_strcat(g->Message, sizeof(g->Message), buf);
|
|
FreeLibrary((HMODULE)Hdll);
|
|
return NULL;
|
|
} // endif getdef
|
|
#else // !_WIN32
|
|
const char *error = NULL;
|
|
|
|
#if 0 // Don't know what all this stuff does
|
|
Dl_info dl_info;
|
|
|
|
// The OEM lib must retrieve exported CONNECT variables
|
|
if (dladdr(&connect_hton, &dl_info)) {
|
|
if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0) {
|
|
error = dlerror();
|
|
snprintf(g->Message, sizeof(g->Message), "dlopen failed: %s, OEM not supported", SVP(error));
|
|
return NULL;
|
|
} // endif dlopen
|
|
|
|
} else {
|
|
error = dlerror();
|
|
snprintf(g->Message, sizeof(g->Message), "dladdr failed: %s, OEM not supported", SVP(error));
|
|
return NULL;
|
|
} // endif dladdr
|
|
#endif // 0
|
|
|
|
// Load the desired shared library
|
|
if (!Hdll && !(Hdll = dlopen(soname, RTLD_LAZY))) {
|
|
error = dlerror();
|
|
snprintf(g->Message, sizeof(g->Message), MSG(SHARED_LIB_ERR), soname, SVP(error));
|
|
return NULL;
|
|
} // endif Hdll
|
|
|
|
// The exported name is always in uppercase
|
|
for (int i = 0; ; i++) {
|
|
c = Subtype[i];
|
|
getname[i + 3] = toupper(c);
|
|
if (!c) break;
|
|
} // endfor i
|
|
|
|
// Get the function returning an instance of the external DEF class
|
|
if (!(getdef = (XGETDEF)dlsym(Hdll, getname))) {
|
|
error = dlerror();
|
|
snprintf(g->Message, sizeof(g->Message), MSG(GET_FUNC_ERR), getname, SVP(error));
|
|
dlclose(Hdll);
|
|
return NULL;
|
|
} // endif getdef
|
|
#endif // !_WIN32
|
|
|
|
// Just in case the external Get function does not set error messages
|
|
snprintf(g->Message, sizeof(g->Message), MSG(DEF_ALLOC_ERROR), Subtype);
|
|
|
|
// Get the table definition block
|
|
if (!(xdefp = getdef(g, NULL)))
|
|
return NULL;
|
|
|
|
// Have the external class do its complete definition
|
|
if (!cat->Cbuf) {
|
|
// Suballocate a temporary buffer for the entire column section
|
|
cat->Cblen = GetSizeCatInfo("Colsize", "8K");
|
|
cat->Cbuf = (char*)PlugSubAlloc(g, NULL, cat->Cblen);
|
|
} // endif Cbuf
|
|
|
|
// Ok, return external block
|
|
return xdefp;
|
|
} // end of GetXdef
|
|
|
|
#if 0
|
|
/***********************************************************************/
|
|
/* DeleteTableFile: Delete an OEM table file if applicable. */
|
|
/***********************************************************************/
|
|
bool OEMDEF::DeleteTableFile(PGLOBAL g)
|
|
{
|
|
if (!Pxdef)
|
|
Pxdef = GetXdef(g);
|
|
|
|
return (Pxdef) ? Pxdef->DeleteTableFile(g) : true;
|
|
} // end of DeleteTableFile
|
|
#endif // 0
|
|
|
|
/***********************************************************************/
|
|
/* Define: initialize the table definition block from XDB file. */
|
|
/***********************************************************************/
|
|
bool OEMDEF::DefineAM(PGLOBAL g, LPCSTR, int)
|
|
{
|
|
Module = GetStringCatInfo(g, "Module", "");
|
|
Subtype = GetStringCatInfo(g, "Subtype", Module);
|
|
|
|
if (!*Module)
|
|
Module = Subtype;
|
|
|
|
char *desc = (char*)PlugSubAlloc(g, NULL, strlen(Module)
|
|
+ strlen(Subtype) + 3);
|
|
sprintf(desc, "%s(%s)", Module, Subtype);
|
|
Desc = desc;
|
|
|
|
// If define block not here yet, get it now
|
|
if (!Pxdef && !(Pxdef = GetXdef(g)))
|
|
return true; // Error
|
|
|
|
// Here "OEM" should be replace by a more useful value
|
|
return Pxdef->Define(g, Cat, Name, Schema, Subtype);
|
|
} // end of DefineAM
|
|
|
|
/***********************************************************************/
|
|
/* GetTable: makes a new Table Description Block. */
|
|
/***********************************************************************/
|
|
PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode)
|
|
{
|
|
PTDB tdbp = NULL;
|
|
|
|
// If define block not here yet, get it now
|
|
if (!Pxdef && !(Pxdef = GetXdef(g)))
|
|
return NULL; // Error
|
|
|
|
/*********************************************************************/
|
|
/* Allocate a TDB of the proper type. */
|
|
/* Column blocks will be allocated only when needed. */
|
|
/*********************************************************************/
|
|
if (!(tdbp = Pxdef->GetTable(g, mode)))
|
|
return NULL;
|
|
else if (Multiple && tdbp->GetFtype() == RECFM_OEM)
|
|
tdbp = new(g) TDBMUL(tdbp); // No block optimization yet
|
|
|
|
#if 0
|
|
/*********************************************************************/
|
|
/* The OEM table is based on a file type (currently DOS+ only) */
|
|
/*********************************************************************/
|
|
assert (rfm == RECFM_VAR || rfm == RECFM_FIX ||
|
|
rfm == RECFM_BIN || rfm == RECFM_VCT);
|
|
|
|
PTXF txfp = NULL;
|
|
PDOSDEF defp = (PDOSDEF)Pxdef;
|
|
bool map = defp->Mapped && mode != MODE_INSERT &&
|
|
!(UseTemp() == TMP_FORCE &&
|
|
(mode == MODE_UPDATE || mode == MODE_DELETE));
|
|
int cmpr = defp->Compressed;
|
|
|
|
/*********************************************************************/
|
|
/* Allocate table and file processing class of the proper type. */
|
|
/* Column blocks will be allocated only when needed. */
|
|
/*********************************************************************/
|
|
if (!((PTDBDOS)tdbp)->GetTxfp()) {
|
|
if (cmpr) {
|
|
#if defined(GZ_SUPPORT)
|
|
if (cmpr == 1)
|
|
txfp = new(g) GZFAM(defp);
|
|
else
|
|
txfp = new(g) ZLBFAM(defp);
|
|
#else // !GZ_SUPPORT
|
|
safe_strcpy(g->Message, sizeof(g->Message), "Compress not supported");
|
|
return NULL;
|
|
#endif // !GZ_SUPPORT
|
|
} else if (rfm == RECFM_VAR) {
|
|
if (map)
|
|
txfp = new(g) MAPFAM(defp);
|
|
else
|
|
txfp = new(g) DOSFAM(defp);
|
|
|
|
} else if (rfm == RECFM_FIX || rfm == RECFM_BIN) {
|
|
if (map)
|
|
txfp = new(g) MPXFAM(defp);
|
|
else
|
|
txfp = new(g) FIXFAM(defp);
|
|
} else if (rfm == RECFM_VCT) {
|
|
#if defined(VCT_SUPPORT)
|
|
assert(Pxdef->GetDefType() == TYPE_AM_VCT);
|
|
|
|
if (map)
|
|
txfp = new(g) VCMFAM((PVCTDEF)defp);
|
|
else
|
|
txfp = new(g) VCTFAM((PVCTDEF)defp);
|
|
#else // !VCT_SUPPORT
|
|
safe_strcpy(g->Message, sizeof(g->Message), "VCT no more supported");
|
|
return NULL;
|
|
#endif // !VCT_SUPPORT
|
|
} // endif's
|
|
|
|
((PTDBDOS)tdbp)->SetTxfp(txfp);
|
|
} // endif Txfp
|
|
|
|
if (Multiple)
|
|
tdbp = new(g) TDBMUL(tdbp);
|
|
#endif // 0
|
|
return tdbp;
|
|
} // end of GetTable
|
|
|
|
/* --------------------------- Class COLCRT -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* COLCRT Constructors. */
|
|
/***********************************************************************/
|
|
COLCRT::COLCRT(PSZ name)
|
|
{
|
|
Next = NULL;
|
|
Name = name;
|
|
Desc = NULL;
|
|
Decode = NULL;
|
|
Fmt = NULL;
|
|
Offset = -1;
|
|
Long = -1;
|
|
Precision = -1;
|
|
Freq = -1;
|
|
Key = -1;
|
|
Scale = -1;
|
|
Opt = -1;
|
|
DataType = '*';
|
|
} // end of COLCRT constructor for table creation
|
|
|
|
COLCRT::COLCRT(void)
|
|
{
|
|
Next = NULL;
|
|
Name = NULL;
|
|
Desc = NULL;
|
|
Decode = NULL;
|
|
Fmt = NULL;
|
|
Offset = 0;
|
|
Long = 0;
|
|
Precision = 0;
|
|
Freq = 0;
|
|
Key = 0;
|
|
Scale = 0;
|
|
Opt = 0;
|
|
DataType = '*';
|
|
} // end of COLCRT constructor for table & view definition
|
|
|
|
/* --------------------------- Class COLDEF -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* COLDEF Constructor. */
|
|
/***********************************************************************/
|
|
COLDEF::COLDEF(void) : COLCRT()
|
|
{
|
|
To_Min = NULL;
|
|
To_Max = NULL;
|
|
To_Pos = NULL;
|
|
Xdb2 = FALSE;
|
|
To_Bmap = NULL;
|
|
To_Dval = NULL;
|
|
Ndv = 0;
|
|
Nbm = 0;
|
|
Buf_Type = TYPE_ERROR;
|
|
Clen = 0;
|
|
Poff = 0;
|
|
memset(&F, 0, sizeof(FORMAT));
|
|
Flags = 0;
|
|
} // end of COLDEF constructor
|
|
|
|
/***********************************************************************/
|
|
/* Define: initialize a column definition from a COLINFO structure. */
|
|
/***********************************************************************/
|
|
int COLDEF::Define(PGLOBAL g, void *, PCOLINFO cfp, int poff)
|
|
{
|
|
Name = (PSZ)PlugDup(g, cfp->Name);
|
|
|
|
if (!(cfp->Flags & U_SPECIAL)) {
|
|
Poff = poff;
|
|
Buf_Type = cfp->Type;
|
|
|
|
if ((Clen = GetTypeSize(Buf_Type, cfp->Length)) < 0) {
|
|
snprintf(g->Message, sizeof(g->Message), MSG(BAD_COL_TYPE), GetTypeName(Buf_Type), Name);
|
|
return -1;
|
|
} // endswitch
|
|
|
|
safe_strcpy(F.Type, sizeof(F.Type), GetFormatType(Buf_Type));
|
|
F.Length = cfp->Length;
|
|
F.Prec = cfp->Scale;
|
|
Offset = (cfp->Offset < 0) ? poff : cfp->Offset;
|
|
Precision = cfp->Precision;
|
|
Scale = cfp->Scale;
|
|
Long = cfp->Length;
|
|
Opt = cfp->Opt;
|
|
Key = cfp->Key;
|
|
Freq = cfp->Freq;
|
|
|
|
if (cfp->Remark && *cfp->Remark)
|
|
Desc = (PSZ)PlugDup(g, cfp->Remark);
|
|
|
|
if (cfp->Datefmt)
|
|
Decode = (PSZ)PlugDup(g, cfp->Datefmt);
|
|
|
|
} else
|
|
Offset = poff;
|
|
|
|
if (cfp->Fieldfmt)
|
|
Fmt = (PSZ)PlugDup(g, cfp->Fieldfmt);
|
|
|
|
Flags = cfp->Flags;
|
|
return (Flags & (U_VIRTUAL|U_SPECIAL)) ? 0 : Long;
|
|
} // end of Define
|
|
|
|
/* ------------------------- End of RelDef --------------------------- */
|