mariadb/storage/connect/mycat.cc
Olivier Bertrand 38edf74a3c 1) Fix bug on strange sprintf
2) Fix bug on bad sprintf
3) Fix bug on cast from pointer to int

4) Begin implementing the "info" tables.
Already existing were the ODBC sata source table and the
WMI column info table.

A common way to handle them will permit to develop many
other such tables. Implemented:

The ODBC column info table.

Modified:
ha_connect.cc  (4)
odbconn.cpp    (4)
tabodbc.h      (4)
tabodbc.cpp    (4)
tabsys.h       (3)
rcmsg.c        (4)
tabfmt.cpp     (2)
tabtbl.cpp     (1)
resource.h     (4)
mycat.h        (4)
2013-02-08 00:46:10 +01:00

657 lines
22 KiB
C++

/* Copyright (C) Olivier Bertrand 2004 - 2012
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*************** Mycat CC Program Source Code File (.CC) ***************/
/* PROGRAM NAME: MYCAT */
/* ------------- */
/* Version 1.3 */
/* */
/* Author: Olivier Bertrand 2012 - 2013 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
/* This program are the DB description related routines. */
/***********************************************************************/
/***********************************************************************/
/* Include relevant MariaDB header file. */
/***********************************************************************/
#if defined(WIN32)
//#include <windows.h>
//#include <sqlext.h>
#elif defined(UNIX)
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#endif
#define DONT_DEFINE_VOID
//#include <mysql/plugin.h>
#include "handler.h"
#undef OFFSET
/***********************************************************************/
/* Include application header files */
/* */
/* global.h is header containing all global declarations. */
/* plgdbsem.h is header containing DB application declarations. */
/* tabdos.h is header containing TDBDOS classes declarations. */
/* MYCAT.h is header containing DB description declarations. */
/***********************************************************************/
#if defined(UNIX)
#include "osutil.h"
#endif // UNIX
#include "global.h"
#include "plgdbsem.h"
#include "reldef.h"
#include "tabcol.h"
#include "xtable.h"
#include "filamtxt.h"
#include "tabdos.h"
#include "tabfmt.h"
#include "tabvct.h"
#include "tabsys.h"
#if defined(WIN32)
#include "tabmac.h"
#include "tabwmi.h"
#endif // WIN32
#include "tabtbl.h"
#if defined(XML_SUPPORT)
#include "tabxml.h"
#endif // XML_SUPPORT
#include "tabmul.h"
#if defined(MYSQL_SUPPORT)
#include "tabmysql.h"
#endif // MYSQL_SUPPORT
#if defined(ODBC_SUPPORT)
#define NODBC
#include "tabodbc.h"
#endif // ODBC_SUPPORT
#if defined(PIVOT_SUPPORT)
#include "tabpivot.h"
#endif // PIVOT_SUPPORT
#include "ha_connect.h"
#include "mycat.h"
/**************************************************************************/
/* Extern static variables. */
/**************************************************************************/
#if defined(WIN32)
extern "C" HINSTANCE s_hModule; // Saved module handle
#endif // !WIN32
extern int xtrace;
/**************************************************************************/
/* General DB routines. */
/**************************************************************************/
//bool PlugCheckPattern(PGLOBAL, LPCSTR, LPCSTR);
//#if !defined(WIN32)
extern "C" int GetRcString(int id, char *buf, int bufsize);
//#endif // !WIN32
//void ptrc(char const *fmt, ...);
/**************************************************************************/
/* Allocate the result structure that will contain result data. */
/**************************************************************************/
PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
int *dbtype, int *buftyp, unsigned int *length,
bool blank = false, bool nonull = false)
{
char cname[NAM_LEN+1];
int i;
PCOLRES *pcrp, crp;
PQRYRES qrp;
/************************************************************************/
/* Allocate the structure used to contain the result set. */
/************************************************************************/
qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
pcrp = &qrp->Colresp;
qrp->Continued = false;
qrp->Truncated = false;
qrp->Info = false;
qrp->Suball = true;
qrp->Maxres = maxres;
qrp->Maxsize = 0;
qrp->Nblin = 0;
qrp->Nbcol = 0; // will be ncol
qrp->Cursor = 0;
qrp->BadLines = 0;
for (i = 0; i < ncol; i++) {
*pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
crp = *pcrp;
pcrp = &crp->Next;
crp->Colp = NULL;
crp->Ncol = ++qrp->Nbcol;
crp->Type = buftyp[i];
crp->Length = length[i];
crp->Clen = GetTypeSize(crp->Type, length[i]);
crp->Prec = 0;
crp->DBtype = dbtype[i];
if (ids > 0) {
#if defined(XMSG)
// Get header from message file
strncpy(cname, PlugReadMessage(g, ids + crp->Ncol, NULL), NAM_LEN);
cname[NAM_LEN] = 0; // for truncated long names
//#elif defined(WIN32)
// Get header from ressource file
// LoadString(s_hModule, ids + crp->Ncol, cname, sizeof(cname));
#else // !WIN32
GetRcString(ids + crp->Ncol, cname, sizeof(cname));
#endif // !WIN32
crp->Name = (PSZ)PlugSubAlloc(g, NULL, strlen(cname) + 1);
strcpy(crp->Name, cname);
} else
crp->Name = NULL; // Will be set by caller
// Allocate the Value Block that will contain data
if (crp->Length || nonull)
crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
crp->Length, 0, true, blank);
else
crp->Kdata = NULL;
if (g->Trace)
htrc("Column(%d) %s type=%d len=%d value=%p\n",
crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);
} // endfor i
*pcrp = NULL;
return qrp;
} // end of PlgAllocResult
/***********************************************************************/
/* Get a unique char identifier for types. The letter used are: */
/* ABCDEF..I.KLM.O..R.T.VWXY.. */
/***********************************************************************/
char GetTypeID(char *type)
{
return (!type) ? 'D' // DOS (default)
: (!stricmp(type, "FMT")) ? 'T' // CSV
: (!stricmp(type, "DIR")) ? 'R' // diR
: (!stricmp(type, "DBF")) ? 'A' // dbAse
: (!stricmp(type, "SYS")) ? 'I' // INI
: (!stricmp(type, "TBL")) ? 'L' // tbL
: (!stricmp(type, "MYSQL")) ? 'Y' // mYsql
: (!stricmp(type, "OEM")) ? 'E' : toupper(*type);
} // end of GetTypeID
/* ------------------------- Class CATALOG --------------------------- */
/***********************************************************************/
/* CATALOG Constructor. */
/***********************************************************************/
CATALOG::CATALOG(void)
{
To_Desc= NULL;
//*DescFile= '\0';
#if defined(WIN32)
DataPath= ".\\";
#else // !WIN32
DataPath= "./";
#endif // !WIN32
Descp= NULL;
//memset(&DescArea, 0, sizeof(AREADEF));
memset(&Ctb, 0, sizeof(CURTAB));
Cbuf= NULL;
Cblen= 0;
DefHuge= false;
} // end of CATALOG constructor
/* -------------------------- Class MYCAT ---------------------------- */
/***********************************************************************/
/* MYCAT Constructor. */
/***********************************************************************/
MYCAT::MYCAT(PHC hc) : CATALOG()
{
Hc= hc;
To_Desc= NULL;
DefHuge= false;
SepIndex= true; // Temporay until we can store offet and size
} // end of MYCAT constructor
/***********************************************************************/
/* When using volatile storage, reset values pointing to Sarea. */
/***********************************************************************/
void MYCAT::Reset(void)
{
To_Desc= NULL;
} // end of Reset
/***********************************************************************/
/* This function sets the current database path. */
/***********************************************************************/
void MYCAT::SetPath(PGLOBAL g, LPCSTR *datapath, const char *path)
{
if (path) {
size_t len= strlen(path) + (*path != '.' ? 4 : 1);
char *buf= (char*)PlugSubAlloc(g, NULL, len);
if (*path != '.') {
#if defined(WIN32)
char *s= "\\";
#else // !WIN32
char *s= "/";
#endif // !WIN32
strcat(strcat(strcat(strcpy(buf, "."), s), path), s);
} else
strcpy(buf, path);
*datapath= buf;
} // endif path
} // end of SetDataPath
/***********************************************************************/
/* This function sets an integer MYCAT information. */
/***********************************************************************/
bool MYCAT::SetIntCatInfo(LPCSTR name, PSZ what, int n)
{
return Hc->SetIntegerOption(what, n);
} // end of SetIntCatInfo
/***********************************************************************/
/* This function returns integer MYCAT information. */
/***********************************************************************/
int MYCAT::GetIntCatInfo(LPCSTR name, PSZ what, int idef)
{
int n= Hc->GetIntegerOption(what);
return (n == NO_IVAL) ? idef : n;
} // end of GetIntCatInfo
/***********************************************************************/
/* This function returns Boolean MYCAT information. */
/***********************************************************************/
bool MYCAT::GetBoolCatInfo(LPCSTR name, PSZ what, bool bdef)
{
bool b= Hc->GetBooleanOption(what, bdef);
return b;
} // end of GetBoolCatInfo
/***********************************************************************/
/* This function returns size catalog information. */
/***********************************************************************/
int MYCAT::GetSizeCatInfo(LPCSTR name, PSZ what, PSZ sdef)
{
char * s, c;
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;
case 'K':
n *= 1024;
} // endswitch c
return n;
} // end of GetSizeCatInfo
/***********************************************************************/
/* This function sets char MYCAT information in buf. */
/***********************************************************************/
int MYCAT::GetCharCatInfo(LPCSTR name, PSZ what,
PSZ sdef, char *buf, int size)
{
char *s= Hc->GetStringOption(what);
strncpy(buf, ((s) ? s : sdef), size);
return size;
} // end of GetCharCatInfo
/***********************************************************************/
/* This function returns string MYCAT information. */
/* Default parameter is "*" to get the handler default. */
/***********************************************************************/
char *MYCAT::GetStringCatInfo(PGLOBAL g, PSZ name, PSZ what, PSZ sdef)
{
char *sval, *s= Hc->GetStringOption(what, sdef);
if (s) {
sval= (char*)PlugSubAlloc(g, NULL, strlen(s) + 1);
strcpy(sval, s);
} else
sval = NULL;
return sval;
} // end of GetStringCatInfo
/***********************************************************************/
/* This function returns column MYCAT information. */
/***********************************************************************/
int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp)
{
char *type= GetStringCatInfo(g, NULL, "Type", "DOS");
int i, loff, poff, nof, nlg;
void *field= NULL;
PCOLDEF cdp, lcdp= NULL, tocols= NULL;
PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO));
// Get a unique char identifier for type
char tc= GetTypeID(type);
// Take care of the column definitions
i= poff= nof= nlg= 0;
// Offsets of HTML and DIR tables start from 0, DBF at 1
loff= (tc == 'A') ? 1 : (tc == 'X' || tc == 'R') ? -1 : 0;
while (true) {
// Default Offset depends on table type
switch (tc) {
case 'D': // DOS
case 'F': // FIX
case 'B': // BIN
case 'V': // VEC
case 'A': // DBF
poff= loff + nof; // Default next offset
nlg= max(nlg, poff); // Default lrecl
break;
case 'C': // CSV
case 'T': // FMT
nlg+= nof;
case 'R': // DIR
case 'X': // XML
poff= loff + 1;
break;
case 'I': // INI
case 'M': // MAC
case 'L': // TBL
case 'E': // OEM
poff = 0; // Offset represents an independant flag
break;
default: // VCT PLG ODBC MYSQL WMI...
poff = 0; // NA
break;
} // endswitch tc
do {
field= Hc->GetColumnOption(field, pcf);
} while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/));
if (tc == 'A' && pcf->Type == TYPE_DATE && !pcf->Datefmt) {
// DBF date format defaults to 'YYYMMDD'
pcf->Datefmt= "YYYYMMDD";
pcf->Length= 8;
} // endif tc
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 if (nof)
loff= cdp->GetOffset();
switch (tc) {
case 'V':
cdp->SetOffset(0); // Not to have shift
case 'B':
// BIN/VEC are packed by default
if (nof)
// Field width is the internal representation width
// that can also depend on the column format
switch (cdp->Fmt ? *cdp->Fmt : 'X') {
case 'C': break;
case 'R':
case 'F':
case 'L':
case 'I': nof= 4; break;
case 'D': nof= 8; break;
case 'S': nof= 2; break;
case 'T': nof= 1; break;
default: nof= cdp->Clen;
} // endswitch Fmt
break;
} // endswitch tc
if (lcdp)
lcdp->SetNext(cdp);
else
tocols= cdp;
lcdp= cdp;
i++;
} // endwhile
// Degree is the the number of defined columns (informational)
if (i != defp->GetDegree())
defp->SetDegree(i);
if (defp->GetDefType() == TYPE_AM_DOS) {
int ending, recln= 0;
PDOSDEF ddp= (PDOSDEF)defp;
// Was commented because sometimes ending is 0 even when
// not specified (for instance if quoted is specified)
// if ((ending= Hc->GetIntegerOption("Ending")) < 0) {
if ((ending= Hc->GetIntegerOption("Ending")) <= 0) {
#if defined(WIN32)
ending= 2;
#else
ending= 1;
#endif
Hc->SetIntegerOption("Ending", ending);
} // endif ending
// Calculate the default record size
switch (tc) {
case 'F':
recln= nlg + ending; // + length of line ending
break;
case 'B':
case 'V':
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 'D':
case 'A':
recln= nlg;
break;
case 'T':
case 'C':
// 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
break;
} // endswitch tc
// lrecl must be at least recln to avoid buffer overflow
recln= max(recln, Hc->GetIntegerOption("Lrecl"));
Hc->SetIntegerOption("Lrecl", recln);
ddp->SetLrecl(recln);
} // endif Lrecl
// Attach the column definition to the tabdef
defp->SetCols(tocols);
return poff;
} // end of GetColCatInfo
/***********************************************************************/
/* GetIndexInfo: retrieve index description from the table structure. */
/***********************************************************************/
bool MYCAT::GetIndexInfo(PGLOBAL g, PTABDEF defp)
{
PIXDEF xdp, pxd= NULL, toidx= NULL;
// Now take care of the index definitions
for (int n= 0; ; n++) {
if (xtrace)
printf("Getting index %d info\n", n + 1);
if (!(xdp= Hc->GetIndexInfo(n)))
break;
if (pxd)
pxd->SetNext(xdp);
else
toidx= xdp;
pxd= xdp;
} // endfor n
// All is correct, attach new index(es)
defp->SetIndx(toidx);
return false;
} // end of GetIndexInfo
/***********************************************************************/
/* GetTableDesc: retrieve a table descriptor. */
/* Look for a table descriptor matching the name and type. If found */
/* in storage, return a pointer to it, else look in the XDB file. If */
/* found, make and add the descriptor and return a pointer to it. */
/***********************************************************************/
PRELDEF MYCAT::GetTableDesc(PGLOBAL g, LPCSTR name,
LPCSTR am, PRELDEF *prp)
{
LPCSTR type;
if (xtrace)
printf("GetTableDesc: name=%s am=%s\n", name, SVP(am));
// Firstly check whether this table descriptor is in memory
if (To_Desc)
return To_Desc;
// Here get the type of this table
if (!(type= Hc->GetStringOption("Type")))
type= "DOS";
return MakeTableDesc(g, name, type);
} // end of GetTableDesc
/***********************************************************************/
/* MakeTableDesc: make a table/view description. */
/* Note: caller must check if name already exists before calling it. */
/***********************************************************************/
PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am)
{
char tc;
PRELDEF tdp= NULL;
if (xtrace)
printf("MakeTableDesc: name=%s am=%s\n", name, SVP(am));
/*********************************************************************/
/* Get a unique char identifier for types. The letter used are: */
/* ABCDEF..IJKLM.OPQRSTUVWXYZ and Allocate table definition class */
/*********************************************************************/
tc= GetTypeID((char*)am);
switch (tc) {
case 'F':
case 'B':
case 'A':
case 'D': tdp= new(g) DOSDEF; break;
case 'T':
case 'C': tdp= new(g) CSVDEF; break;
case 'I': tdp= new(g) INIDEF; break;
case 'R': tdp= new(g) DIRDEF; break;
#if defined(XML_SUPPORT)
case 'X': tdp= new(g) XMLDEF; break;
#endif // XML_SUPPORT
case 'V': tdp= new(g) VCTDEF; break;
#if defined(ODBC_SUPPORT)
case 'O': tdp= new(g) ODBCDEF; break;
#endif // ODBC_SUPPORT
#if defined(WIN32)
case 'M': tdp= new(g) MACDEF; break;
case 'W': tdp= new(g) WMIDEF; break;
#endif // WIN32
case 'E': tdp= new(g) OEMDEF; break;
case 'L': tdp= new(g) TBLDEF; break;
#if defined(MYSQL_SUPPORT)
case 'Y': tdp= new(g) MYSQLDEF; break;
#endif // MYSQL_SUPPORT
#if defined(PIVOT_SUPPORT)
case 'P': tdp= new(g) PIVOTDEF; break;
#endif // PIVOT_SUPPORT
default:
sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name);
} // endswitch
// Do make the table/view definition from XDB file information
if (tdp && tdp->Define(g, this, name, am))
tdp= NULL;
return tdp;
} // end of MakeTableDesc
/***********************************************************************/
/* Initialize a Table Description Block construction. */
/***********************************************************************/
PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode)
{
PRELDEF tdp;
PTDB tdbp= NULL;
LPCSTR name= tablep->GetName();
if (xtrace)
printf("GetTableDB: name=%s\n", name);
// Look for the description of the requested table
tdp= GetTableDesc(g, name, NULL);
if (tdp) {
if (xtrace)
printf("tdb=%p type=%s\n", tdp, tdp->GetType());
if (tablep->GetQualifier())
SetPath(g, &tdp->Database, tablep->GetQualifier());
tdbp= tdp->GetTable(g, mode);
} // endif tdp
if (tdbp) {
if (xtrace)
printf("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(),
tdbp->GetAmType());
tablep->SetTo_Tdb(tdbp);
tdbp->SetTable(tablep);
} // endif tdbp
return (tdbp);
} // end of GetTable
/***********************************************************************/
/* ClearDB: Terminates Database usage. */
/***********************************************************************/
void MYCAT::ClearDB(PGLOBAL g)
{
To_Desc= NULL;
} // end of ClearDB
/* ------------------------ End of MYCAT --------------------------- */