mariadb/storage/connect/tabtbl.cpp
Alexander Barkov 30c4b0ebc2 - Fixing TAB to 2 spaces
- Fixing line endings from "\r\n" to "\n"
2013-02-07 13:34:27 +04:00

777 lines
26 KiB
C++

/************* TabTbl C++ Program Source Code File (.CPP) **************/
/* PROGRAM NAME: TABTBL */
/* ------------- */
/* Version 1.3 */
/* */
/* COPYRIGHT: */
/* ---------- */
/* (C) Copyright to PlugDB Software Development 2008-2012 */
/* Author: Olivier BERTRAND */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
/* This program are the TDBTBL class DB routines. */
/* */
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
/* -------------------------------------- */
/* */
/* REQUIRED FILES: */
/* --------------- */
/* TABTBL.CPP - Source code */
/* PLGDBSEM.H - DB application declaration file */
/* TABDOS.H - TABDOS classes declaration file */
/* TABTBL.H - TABTBL classes declaration file */
/* GLOBAL.H - Global declaration file */
/* */
/* REQUIRED LIBRARIES: */
/* ------------------- */
/* Large model C library */
/* */
/* REQUIRED PROGRAMS: */
/* ------------------ */
/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
/* */
/***********************************************************************/
/***********************************************************************/
/* Include relevant section of system dependant header files. */
/***********************************************************************/
//#include "sql_base.h"
#include "my_global.h"
#if defined(WIN32)
#include <stdlib.h>
#include <stdio.h>
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif
//#include <windows.h>
#else
#if defined(UNIX)
#include <fnmatch.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "osutil.h"
#else
//#include <io.h>
#endif
//#include <fcntl.h>
#endif
/***********************************************************************/
/* Include application header files: */
/***********************************************************************/
#include "table.h" // MySQL table definitions
#include "global.h" // global declarations
#include "plgdbsem.h" // DB application declarations
#include "reldef.h" // DB definition declares
//#include "filter.h" // FILTER classes dcls
#include "filamtxt.h"
#include "tabcol.h"
#include "tabdos.h" // TDBDOS and DOSCOL class dcls
#include "tabtbl.h" // TDBTBL and TBLCOL classes dcls
#include "ha_connect.h"
#include "mycat.h" // For GetHandler
extern "C" int trace;
int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags);
/* ---------------------------- Class TBLDEF ---------------------------- */
/**************************************************************************/
/* Constructor. */
/**************************************************************************/
TBLDEF::TBLDEF(void)
{
To_Tables = NULL;
Ntables = 0;
Pseudo = 3;
} // end of TBLDEF constructor
/**************************************************************************/
/* DefineAM: define specific AM block values from XDB file. */
/**************************************************************************/
bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{
char *tablist, *dbname;
Desc = "Table list table";
tablist = Cat->GetStringCatInfo(g, Name, "Tablist", "");
dbname = Cat->GetStringCatInfo(g, Name, "Database", NULL);
Ntables = 0;
if (*tablist) {
char *p, *pn, *pdb;
PTBL *ptbl = &To_Tables, tbl;
for (pdb = tablist; ;) {
if ((p = strchr(pdb, ',')))
*p = 0;
// Analyze the table name, it has the format:
// [dbname.]tabname
if ((pn = strchr(pdb, '.'))) {
*pn++ = 0;
} else {
pn = pdb;
pdb = dbname;
} // endif p
// Allocate the TBLIST block for that table
tbl = (PTBL)PlugSubAlloc(g, NULL, sizeof(TBLIST));
tbl->Next = NULL;
tbl->Name = pn;
tbl->DB = pdb;
if (trace)
htrc("TBL: Name=%s db=%s\n", tbl->Name, SVP(tbl->DB));
// Link the blocks
*ptbl = tbl;
ptbl = &tbl->Next;
Ntables++;
if (p)
pdb = pn + strlen(pn) + 1;
else
break;
} // endfor pdb
Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0);
Accept = (Cat->GetBoolCatInfo(Name, "Accept", 0) != 0);
} // endif fsec || tablist
return FALSE;
} // end of DefineAM
/***********************************************************************/
/* GetTable: makes a new Table Description Block. */
/***********************************************************************/
PTDB TBLDEF::GetTable(PGLOBAL g, MODE m)
{
PTDB tdbp;
/*********************************************************************/
/* Allocate a TDB of the proper type. */
/* Column blocks will be allocated only when needed. */
/*********************************************************************/
tdbp = new(g) TDBTBL(this);
return tdbp;
} // end of GetTable
/* ------------------------- Class TDBTBL ---------------------------- */
/***********************************************************************/
/* TDBTBL constructors. */
/***********************************************************************/
TDBTBL::TDBTBL(PTBLDEF tdp) : TDBASE(tdp)
{
Tablist = NULL;
CurTable = NULL;
Tdbp = NULL;
Accept = tdp->Accept;
Maxerr = tdp->Maxerr;
Nbf = 0;
Rows = 0;
Crp = 0;
// NTables = 0;
// iTable = 0;
} // end of TDBTBL standard constructor
/***********************************************************************/
/* Allocate TBL column description block. */
/***********************************************************************/
PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
return new(g) TBLCOL(cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/
/* InsertSpecialColumn: Put a special column ahead of the column list.*/
/***********************************************************************/
PCOL TDBTBL::InsertSpecialColumn(PGLOBAL g, PCOL scp)
{
PCOL colp;
if (!scp->IsSpecial())
return NULL;
if (scp->GetAmType() == TYPE_AM_TABID)
// This special column is handled locally
colp = new((TIDBLK*)scp) TBTBLK(scp->GetValue());
else // Other special columns are treated normally
colp = scp;
colp->SetNext(Columns);
Columns = colp;
return colp;
} // end of InsertSpecialColumn
/***********************************************************************/
/* Get the PTDB of a table of the list. */
/***********************************************************************/
PTDB TDBTBL::GetSubTable(PGLOBAL g, PTBL tblp, PTABLE tabp)
{
char *db, key[128];
uint k, flags;
PTDB tdbp = NULL;
TABLE_LIST table_list;
TABLE_SHARE *s;
PCATLG cat = To_Def->GetCat();
PHC hc = ((MYCAT*)cat)->GetHandler();
THD *thd = (hc->GetTable())->in_use;
if (!thd)
return NULL; // Should not happen anymore
if (tblp->DB)
db = tblp->DB;
else
db = (char*)hc->GetDBName(NULL);
table_list.init_one_table(db, strlen(db),
tblp->Name, strlen(tblp->Name),
NULL, TL_IGNORE);
k = sprintf(key, "%s\0%s\0", db, tblp->Name);
if (!(s = alloc_table_share(&table_list, key, k))) {
strcpy(g->Message, "Error allocating share\n");
return NULL;
} // endif s
// 1 8 16
//flags = READ_ALL | DONT_OPEN_TABLES | DONT_OPEN_MASTER_REG;
//flags = 25;
flags = 24;
if (!open_table_def(thd, s, flags)) {
hc->tshp = s;
tdbp = cat->GetTable(g, tabp);
hc->tshp = NULL;
} else
sprintf(g->Message, "Error %d opening share\n", s->error);
if (trace && tdbp)
htrc("Subtable %s in %s\n",
tblp->Name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB()));
free_table_share(s);
return tdbp;
} // end of GetSubTable
/***********************************************************************/
/* Initializes the table table list. */
/***********************************************************************/
bool TDBTBL::InitTableList(PGLOBAL g)
{
char *colname;
int n, colpos;
PTBL tblp;
PTABLE tabp;
PTDB tdbp;
PCOL colp;
PTBLDEF tdp = (PTBLDEF)To_Def;
// PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
for (n = 0, tblp = tdp->GetTables(); tblp; tblp = tblp->Next) {
if (TestFil(g, To_Filter, tblp)) {
// Table or named view
tabp = new(g) XTAB(tblp->Name);
tabp->SetQualifier(tblp->DB);
// Get the table description block of this table
if (!(tdbp = GetSubTable(g, tblp, tabp))) {
if (++Nbf > Maxerr)
return TRUE; // Error return
else
continue; // Skip this table
} // endif tdbp
// We must allocate subtable columns before GetMaxSize is called
// because some (PLG, ODBC?) need to have their columns attached.
// Real initialization will be done later.
for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (!cp->IsSpecial()) {
colname = cp->GetName();
colpos = ((PTBLCOL)cp)->Colnum;
// We try first to get the column by name
if (!(colp = tdbp->ColDB(g, colname, 0)) && colpos)
// When unsuccessful, if a column number was specified
// try to get the column by its position in the table
colp = tdbp->ColDB(g, NULL, colpos);
if (!colp) {
if (!Accept) {
sprintf(g->Message, MSG(NO_MATCHING_COL),
colname, tdbp->GetName());
return TRUE; // Error return
} // endif !Accept
} else // this is needed in particular by PLG tables
colp->SetColUse(cp->GetColUse());
} // endif !special
if (Tablist)
Tablist->Link(tabp);
else
Tablist = tabp;
n++;
} // endif filp
} // endfor tblp
//NumTables = n;
To_Filter = NULL; // To avoid doing it several times
return FALSE;
} // end of InitTableList
/***********************************************************************/
/* Test the tablename against the pseudo "local" filter. */
/***********************************************************************/
bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp)
{
char *fil, op[8], tn[NAME_LEN];
bool neg;
if (!filp)
return TRUE;
else if (strstr(filp, " OR ") || strstr(filp, " AND "))
return TRUE; // Not handled yet
else
fil = filp + (*filp == '(' ? 1 : 0);
if (sscanf(fil, "TABID %s", op) != 1)
return TRUE; // ignore invalid filter
if ((neg = !strcmp(op, "NOT")))
strcpy(op, "IN");
if (!strcmp(op, "=")) {
// Temporarily, filter must be "TABID = 'value'" only
if (sscanf(fil, "TABID = '%[^']'", tn) != 1)
return TRUE; // ignore invalid filter
return !stricmp(tn, tblp->Name);
} else if (!strcmp(op, "IN")) {
char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10);
int n;
if (neg)
n = sscanf(fil, "TABID NOT IN (%[^)])", tnl);
else
n = sscanf(fil, "TABID IN (%[^)])", tnl);
if (n != 1)
return TRUE; // ignore invalid filter
while (tnl) {
if ((p = strchr(tnl, ',')))
*p++ = 0;
if (sscanf(tnl, "'%[^']'", tn) != 1)
return TRUE; // ignore invalid filter
else if (!stricmp(tn, tblp->Name))
return !neg; // Found
tnl = p;
} // endwhile
return neg; // Not found
} // endif op
return TRUE; // invalid operator
} // end of TestFil
/***********************************************************************/
/* TBL GetProgMax: get the max value for progress information. */
/***********************************************************************/
int TDBTBL::GetProgMax(PGLOBAL g)
{
PTABLE tblp;
int n, pmx = 0;
if (!Tablist && InitTableList(g))
return -1;
for (tblp = Tablist; tblp; tblp = tblp->GetNext())
if ((n = tblp->GetTo_Tdb()->GetProgMax(g)) > 0)
pmx += n;
return pmx;
} // end of GetProgMax
/***********************************************************************/
/* TBL GetProgCur: get the current value for progress information. */
/***********************************************************************/
int TDBTBL::GetProgCur(void)
{
return Crp + Tdbp->GetProgCur();
} // end of GetProgCur
#if 0
/***********************************************************************/
/* TBL Cardinality: returns table cardinality in number of rows. */
/* This function can be called with a null argument to test the */
/* availability of Cardinality implementation (1 yes, 0 no). */
/* Can be used on Multiple FIX table only. */
/***********************************************************************/
int TDBTBL::Cardinality(PGLOBAL g)
{
if (!g)
return Tdbp->Cardinality(g);
if (!Tablist && InitTableList(g))
return -1;
int n, card = 0;
for (int i = 0; i < NumFiles; i++) {
Tdbp->SetFile(g, Filenames[i]);
Tdbp->ResetSize();
if ((n = Tdbp->Cardinality(g)) < 0) {
// strcpy(g->Message, MSG(BAD_CARDINALITY));
return -1;
} // endif n
card += n;
} // endfor i
return card;
} // end of Cardinality
#endif // 0
/***********************************************************************/
/* Sum up the sizes of all sub-tables. */
/***********************************************************************/
int TDBTBL::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
PTABLE tblp;
int mxsz;
if (!Tablist && InitTableList(g))
return 0; // Cannot be calculated at this stage
// if (Use == USE_OPEN) {
// strcpy(g->Message, MSG(MAXSIZE_ERROR));
// return -1;
// } else
MaxSize = 0;
for (tblp = Tablist; tblp; tblp = tblp->GetNext()) {
if ((mxsz = tblp->GetTo_Tdb()->GetMaxSize(g)) < 0) {
MaxSize = -1;
return mxsz;
} // endif mxsz
MaxSize += mxsz;
} // endfor i
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* Reset read/write position values. */
/***********************************************************************/
void TDBTBL::ResetDB(void)
{
for (PCOL colp = Columns; colp; colp = colp->GetNext())
if (colp->GetAmType() == TYPE_AM_TABID)
colp->COLBLK::Reset();
for (PTABLE tblp = Tablist; tblp; tblp = tblp->GetNext())
((PTDBASE)tblp->GetTo_Tdb())->ResetDB();
Tdbp = (PTDBASE)Tablist->GetTo_Tdb();
Crp = 0;
} // end of ResetDB
/***********************************************************************/
/* Returns RowId if b is false or Rownum if b is true. */
/***********************************************************************/
int TDBTBL::RowNumber(PGLOBAL g, bool b)
{
return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
} // end of RowNumber
/***********************************************************************/
/* TBL Access Method opening routine. */
/* Open first file, other will be opened sequencially when reading. */
/***********************************************************************/
bool TDBTBL::OpenDB(PGLOBAL g)
{
if (trace)
htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
this, Tdb_No, Use, To_Key_Col, Mode);
if (Use == USE_OPEN) {
/*******************************************************************/
/* Table already open, replace it at its beginning. */
/*******************************************************************/
ResetDB();
return Tdbp->OpenDB(g); // Re-open fist table
} // endif use
#if 0
/*********************************************************************/
/* Direct access needed for join or sorting. */
/*********************************************************************/
if (NeedIndexing(g)) {
// Direct access of TBL tables is not implemented yet
strcpy(g->Message, MSG(NO_MUL_DIR_ACC));
return TRUE;
} // endif NeedIndexing
#endif // 0
/*********************************************************************/
/* When GetMaxsize was called, To_Filter was not set yet. */
/*********************************************************************/
if (To_Filter && Tablist) {
Tablist = NULL;
Nbf = 0;
} // endif To_Filter
/*********************************************************************/
/* Open the first table of the list. */
/*********************************************************************/
if (!Tablist && InitTableList(g)) // done in GetMaxSize
return TRUE;
if ((CurTable = Tablist)) {
Tdbp = (PTDBASE)CurTable->GetTo_Tdb();
Tdbp->SetMode(Mode);
// Tdbp->ResetDB();
// Tdbp->ResetSize();
// Check and initialize the subtable columns
for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (cp->GetAmType() == TYPE_AM_TABID)
cp->COLBLK::Reset();
else if (((PTBLCOL)cp)->Init(g))
return TRUE;
if (trace)
htrc("Opening subtable %s\n", Tdbp->GetName());
// Now we can safely open the table
if (Tdbp->OpenDB(g))
return TRUE;
} // endif *Tablist
Use = USE_OPEN;
return FALSE;
} // end of OpenDB
/***********************************************************************/
/* ReadDB: Data Base read routine for MUL access method. */
/***********************************************************************/
int TDBTBL::ReadDB(PGLOBAL g)
{
int rc;
if (!CurTable)
return RC_EF;
else if (To_Kindex) {
/*******************************************************************/
/* Reading is by an index table. */
/*******************************************************************/
strcpy(g->Message, MSG(NO_INDEX_READ));
rc = RC_FX;
} else {
/*******************************************************************/
/* Now start the reading process. */
/*******************************************************************/
retry:
rc = Tdbp->ReadDB(g);
if (rc == RC_EF) {
// Total number of rows met so far
Rows += Tdbp->RowNumber(g) - 1;
Crp += Tdbp->GetProgMax(g);
if ((CurTable = CurTable->GetNext())) {
/***************************************************************/
/* Continue reading from next table file. */
/***************************************************************/
Tdbp->CloseDB(g);
Tdbp = (PTDBASE)CurTable->GetTo_Tdb();
// Check and initialize the subtable columns
for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (cp->GetAmType() == TYPE_AM_TABID)
cp->COLBLK::Reset();
else if (((PTBLCOL)cp)->Init(g))
return RC_FX;
if (trace)
htrc("Opening subtable %s\n", Tdbp->GetName());
// Now we can safely open the table
if (Tdbp->OpenDB(g)) // Open next table
return RC_FX;
goto retry;
} // endif iFile
} else if (rc == RC_FX)
strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
} // endif To_Kindex
return rc;
} // end of ReadDB
/***********************************************************************/
/* Data Base write routine for MUL access method. */
/***********************************************************************/
int TDBTBL::WriteDB(PGLOBAL g)
{
strcpy(g->Message, MSG(TABMUL_READONLY));
return RC_FX; // NIY
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for MUL access method. */
/***********************************************************************/
int TDBTBL::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(TABMUL_READONLY));
return RC_FX; // NIY
} // end of DeleteDB
/***********************************************************************/
/* Data Base close routine for MUL access method. */
/***********************************************************************/
void TDBTBL::CloseDB(PGLOBAL g)
{
if (Tdbp)
Tdbp->CloseDB(g);
} // end of CloseDB
/* ---------------------------- TBLCOL ------------------------------- */
/***********************************************************************/
/* TBLCOL public constructor. */
/***********************************************************************/
TBLCOL::TBLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
: COLBLK(cdp, tdbp, i)
{
if (cprec) {
Next = cprec->GetNext();
cprec->SetNext(this);
} else {
Next = tdbp->GetColumns();
tdbp->SetColumns(this);
} // endif cprec
// Set additional Dos access method information for column.
Long = cdp->GetLong(); // ???
//strcpy(F_Date, cdp->F_Date);
Colp = NULL;
To_Val = NULL;
Pseudo = FALSE;
Colnum = cdp->GetOffset(); // If columns are retrieved by number
if (trace)
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
} // end of TBLCOL constructor
#if 0
/***********************************************************************/
/* TBLCOL public constructor. */
/***********************************************************************/
TBLCOL::TBLCOL(SPCBLK *scp, PTDB tdbp) : COLBLK(scp->GetName(), tdbp, 0)
{
// Set additional TBL access method information for pseudo column.
Is_Key = Was_Key = scp->IsKey();
Long = scp->GetLength();
Buf_Type = scp->GetResultType();
*Format.Type = (Buf_Type == TYPE_INT) ? 'N' : 'C';
Format.Length = Long;
Colp = NULL;
To_Val = NULL;
Pseudo = TRUE;
} // end of TBLCOL constructor
/***********************************************************************/
/* TBLCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
TBLCOL::TBLCOL(TBLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
{
Long = col1->Long;
Colp = col1->Colp;
To_Val = col1->To_Val;
Pseudo = col1->Pseudo;
} // end of TBLCOL copy constructor
#endif
/***********************************************************************/
/* TBLCOL initialization routine. */
/* Look for the matching column in the current table. */
/***********************************************************************/
bool TBLCOL::Init(PGLOBAL g)
{
PTDBTBL tdbp = (PTDBTBL)To_Tdb;
To_Val = NULL;
if (!(Colp = tdbp->Tdbp->ColDB(g, Name, 0)) && Colnum)
Colp = tdbp->Tdbp->ColDB(g, NULL, Colnum);
if (Colp) {
Colp->InitValue(g); // May not have been done elsewhere
To_Val = Colp->GetValue();
} else if (!tdbp->Accept) {
sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tdbp->Tdbp->GetName());
return TRUE;
} else
Value->Reset();
return FALSE;
} // end of Init
/***********************************************************************/
/* ReadColumn: */
/***********************************************************************/
void TBLCOL::ReadColumn(PGLOBAL g)
{
if (trace)
htrc("TBL ReadColumn: name=%s\n", Name);
if (Colp) {
Colp->ReadColumn(g);
Value->SetValue_pval(To_Val);
} // endif Colp
} // end of ReadColumn
/* ---------------------------- TBTBLK ------------------------------- */
/***********************************************************************/
/* ReadColumn: */
/***********************************************************************/
void TBTBLK::ReadColumn(PGLOBAL g)
{
if (trace)
htrc("TBT ReadColumn: name=%s\n", Name);
Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName());
} // end of ReadColumn
/* ------------------------------------------------------------------- */