mariadb/storage/connect/tabmul.cpp
Olivier Bertrand 213ecbbb4f - In info, the file length sometimes could not be caculated because the
catalog data path had not been set. This was added into ha_connect::info.
modified:
  storage/connect/ha_connect.cc

- All the functions querying table options could return information from the wrong
  table when several CONNECT tables were used in the same query (for instance joined
  together) This was because they belonged to the catalog class that is shared between
  all tables in the same query. They have been moved from the catalog class to the
  TABDEF/RELDEF class that is attached to each table. This was a major potential bug.
modified:
  storage/connect/catalog.h
  storage/connect/filamvct.cpp
  storage/connect/filamzip.cpp
  storage/connect/mycat.cc
  storage/connect/mycat.h
  storage/connect/reldef.cpp
  storage/connect/reldef.h
  storage/connect/tabdos.cpp
  storage/connect/tabfmt.cpp
  storage/connect/tabmul.cpp
  storage/connect/tabmysql.cpp
  storage/connect/taboccur.cpp
  storage/connect/tabodbc.cpp
  storage/connect/tabpivot.cpp
  storage/connect/tabsys.cpp
  storage/connect/tabtbl.cpp
  storage/connect/tabutil.cpp
  storage/connect/tabvct.cpp
  storage/connect/tabwmi.cpp
  storage/connect/tabxcl.cpp
  storage/connect/tabxml.cpp
  storage/connect/xindex.cpp

- Prepare indexing of MYSQL/ODBC tables (as does FEDERATED) (Not implemented yet)
modified:
  storage/connect/ha_connect.cc
  storage/connect/ha_connect.h
  storage/connect/mycat.cc
  storage/connect/mycat.h

- Typo
modified:
  storage/connect/plgdbutl.cpp
2014-04-14 14:26:48 +02:00

1504 lines
48 KiB
C++
Executable file

/************* TabMul C++ Program Source Code File (.CPP) **************/
/* PROGRAM NAME: TABMUL */
/* ------------- */
/* Version 1.7 */
/* */
/* COPYRIGHT: */
/* ---------- */
/* (C) Copyright to PlugDB Software Development 2003 - 2012 */
/* Author: Olivier BERTRAND */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
/* This program are the TDBMUL class DB routines. */
/* */
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
/* -------------------------------------- */
/* */
/* REQUIRED FILES: */
/* --------------- */
/* TABMUL.CPP - Source code */
/* PLGDBSEM.H - DB application declaration file */
/* TABDOS.H - TABDOS classes declaration file */
/* TABMUL.H - TABFIX 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 "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 "global.h" // global declarations
#include "plgdbsem.h" // DB application declarations
#include "reldef.h" // DB definition declares
#include "filamtxt.h"
#include "tabdos.h" // TDBDOS and DOSCOL class dcls
#include "tabmul.h" // TDBMUL and MULCOL classes dcls
extern "C" int trace;
/* ------------------------- Class TDBMUL ---------------------------- */
/***********************************************************************/
/* TABMUL constructors. */
/***********************************************************************/
TDBMUL::TDBMUL(PTDBASE tdbp) : TDBASE(tdbp->GetDef())
{
Tdbp = tdbp;
Filenames = NULL;
Rows = 0;
Mul = tdbp->GetDef()->GetMultiple();
NumFiles = 0;
iFile = 0;
} // end of TDBMUL standard constructor
TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp)
{
Tdbp = tdbp->Tdbp;
Filenames = tdbp->Filenames;
Rows = tdbp->Rows;
Mul = tdbp->Mul;
NumFiles = tdbp->NumFiles;
iFile = tdbp->iFile;
} // end of TDBMUL copy constructor
// Method
PTDB TDBMUL::CopyOne(PTABS t)
{
PTDBMUL tp;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBMUL(this);
tp->Tdbp = (PTDBASE)Tdbp->CopyOne(t);
tp->Columns = tp->Tdbp->GetColumns();
return tp;
} // end of CopyOne
PTDB TDBMUL::Duplicate(PGLOBAL g)
{
PTDBMUL tmup = new(g) TDBMUL(this);
tmup->Tdbp = (PTDBASE)Tdbp->Duplicate(g);
return tmup;
} // end of Duplicate
/***********************************************************************/
/* Initializes the table filename list. */
/* Note: tables created by concatenating the file components without */
/* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
/* have a LRECL that is the sum of the lengths of all components. */
/* This is why we use a big filename array to take care of that. */
/***********************************************************************/
bool TDBMUL::InitFileNames(PGLOBAL g)
{
#define PFNZ 4096
#define FNSZ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT
char *pfn[PFNZ];
char *filename;
int rc, n = 0;
if (trace)
htrc("in InitFileName: fn[]=%d\n", FNSZ);
filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
// The sub table may need to refer to the Table original block
Tdbp->SetTable(To_Table); // Was not set at construction
PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
if (trace)
htrc("InitFileName: fn='%s'\n", filename);
if (Mul == 1) {
/*******************************************************************/
/* To_File is a multiple name with special characters */
/*******************************************************************/
#if defined(WIN32)
char drive[_MAX_DRIVE], direc[_MAX_DIR];
WIN32_FIND_DATA FileData;
HANDLE hSearch;
_splitpath(filename, drive, direc, NULL, NULL);
// Start searching files in the target directory.
hSearch = FindFirstFile(filename, &FileData);
if (hSearch == INVALID_HANDLE_VALUE) {
rc = GetLastError();
if (rc != ERROR_FILE_NOT_FOUND) {
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), 0,
(LPTSTR)&filename, sizeof(filename), NULL);
sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
return true;
} // endif rc
goto suite;
} // endif hSearch
while (n < PFNZ) {
strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName);
pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
strcpy(pfn[n++], filename);
if (!FindNextFile(hSearch, &FileData)) {
rc = GetLastError();
if (rc != ERROR_NO_MORE_FILES) {
sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
FindClose(hSearch);
return true;
} // endif rc
break;
} // endif FindNextFile
} // endwhile n
// Close the search handle.
if (!FindClose(hSearch)) {
strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
return true;
} // endif FindClose
#else // !WIN32
struct stat fileinfo;
char fn[PATH_MAX], direc[PATH_MAX], pattern[256], ftype[8];
DIR *dir;
struct dirent *entry;
_splitpath(filename, NULL, direc, pattern, ftype);
strcat(pattern, ftype);
if (trace)
htrc("direc=%s pattern=%s ftype=%s\n", direc, pattern, ftype);
// Start searching files in the target directory.
if (!(dir = opendir(direc))) {
sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno));
if (trace)
htrc("%s\n", g->Message);
return true;
} // endif dir
if (trace)
htrc("dir opened: reading files\n");
while ((entry = readdir(dir)) && n < PFNZ) {
strcat(strcpy(fn, direc), entry->d_name);
if (trace)
htrc("%s read\n", fn);
if (lstat(fn, &fileinfo) < 0) {
sprintf(g->Message, "%s: %s", fn, strerror(errno));
return true;
} else if (!S_ISREG(fileinfo.st_mode))
continue; // Not a regular file (should test for links)
/*******************************************************************/
/* Test whether the file name matches the table name filter. */
/*******************************************************************/
if (fnmatch(pattern, entry->d_name, 0))
continue; // Not a match
strcat(strcpy(filename, direc), entry->d_name);
pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
strcpy(pfn[n++], filename);
if (trace)
htrc("Adding pfn[%d] %s\n", n, filename);
} // endwhile readdir
// Close the dir handle.
closedir(dir);
#endif // !WIN32
} else {
/*******************************************************************/
/* To_File is the name of a file containing the file name list */
/*******************************************************************/
char *p;
FILE *stream;
if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r")))
return true;
while (n < PFNZ) {
if (!fgets(filename, FNSZ, stream)) {
fclose(stream);
break;
} // endif fgets
p = filename + strlen(filename) - 1;
#if defined(UNIX)
// Data files can be imported from Windows (having CRLF)
if (*p == '\n' || *p == '\r') {
// is this enough for Unix ???
*p--; // Eliminate ending CR or LF character
if (p >= filename)
// is this enough for Unix ???
if (*p == '\n' || *p == '\r')
*p--; // Eliminate ending CR or LF character
} // endif p
#else
if (*p == '\n')
p--; // Eliminate ending new-line character
#endif
// Trim rightmost blanks
for (; p >= filename && *p == ' '; p--) ;
*(++p) = '\0';
// Suballocate the file name
pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
strcpy(pfn[n++], filename);
} // endfor n
} // endif Mul
#if defined(WIN32)
suite:
#endif
if (n) {
Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
for (int i = 0; i < n; i++)
Filenames[i] = pfn[i];
} else {
Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
Filenames[0] = NULL;
} // endif n
NumFiles = n;
return false;
} // end of InitFileNames
/***********************************************************************/
/* The table column list is the sub-table column list. */
/***********************************************************************/
PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num)
{
PCOL cp;
/*********************************************************************/
/* Because special columns are directly added to the MUL block, */
/* make sure that the sub-table has the same column list, before */
/* and after the call to the ColDB function. */
/*********************************************************************/
Tdbp->SetColumns(Columns);
cp = Tdbp->ColDB(g, name, num);
Columns = Tdbp->GetColumns();
return cp;
} // end of ColDB
/***********************************************************************/
/* MUL GetProgMax: get the max value for progress information. */
/***********************************************************************/
int TDBMUL::GetProgMax(PGLOBAL g)
{
if (!Filenames && InitFileNames(g))
return -1;
return NumFiles; // This is a temporary setting
} // end of GetProgMax
/***********************************************************************/
/* MUL GetProgCur: get the current value for progress information. */
/***********************************************************************/
int TDBMUL::GetProgCur(void)
{
return iFile; // This is a temporary setting
} // end of GetProgMax
/***********************************************************************/
/* MUL 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 TDBMUL::Cardinality(PGLOBAL g)
{
if (!g)
return Tdbp->Cardinality(g);
if (!Filenames && InitFileNames(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
/***********************************************************************/
/* Sum up the sizes of all sub-tables. */
/***********************************************************************/
int TDBMUL::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
int i;
int mxsz;
if (trace)
htrc("TDBMUL::GetMaxSize: Filenames=%p\n", Filenames);
if (!Filenames && InitFileNames(g))
return -1;
if (Use == USE_OPEN) {
strcpy(g->Message, MSG(MAXSIZE_ERROR));
return -1;
} else
MaxSize = 0;
for (i = 0; i < NumFiles; i++) {
Tdbp->SetFile(g, Filenames[i]);
Tdbp->ResetSize();
if ((mxsz = Tdbp->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 TDBMUL::ResetDB(void)
{
for (PCOL colp = Columns; colp; colp = colp->GetNext())
if (colp->GetAmType() == TYPE_AM_FILID)
colp->COLBLK::Reset();
Tdbp->ResetDB();
} // end of ResetDB
/***********************************************************************/
/* Returns RowId if b is false or Rownum if b is true. */
/***********************************************************************/
int TDBMUL::RowNumber(PGLOBAL g, bool b)
{
return ((b) ? 0 : Rows)
+ ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1);
} // end of RowNumber
/***********************************************************************/
/* MUL Access Method opening routine. */
/* Open first file, other will be opened sequencially when reading. */
/***********************************************************************/
bool TDBMUL::OpenDB(PGLOBAL g)
{
if (trace)
htrc("MUL 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. */
/*******************************************************************/
if (Filenames[iFile = 0]) {
Tdbp->CloseDB(g);
Tdbp->SetUse(USE_READY);
Tdbp->SetFile(g, Filenames[iFile = 0]);
Tdbp->ResetSize();
Rows = 0;
ResetDB();
return Tdbp->OpenDB(g); // Re-open with new file name
} else
return false;
} // endif use
/*********************************************************************/
/* We need to calculate MaxSize before opening the query. */
/*********************************************************************/
if (GetMaxSize(g) < 0)
return true;
/*********************************************************************/
/* Open the first table file of the list. */
/*********************************************************************/
//if (!Filenames && InitFileNames(g)) // was done in GetMaxSize
// return true;
if (Filenames[iFile = 0]) {
Tdbp->SetFile(g, Filenames[0]);
Tdbp->SetMode(Mode);
Tdbp->ResetDB();
Tdbp->ResetSize();
if (Tdbp->OpenDB(g))
return true;
} // endif *Filenames
Use = USE_OPEN;
return false;
} // end of OpenDB
/***********************************************************************/
/* ReadDB: Data Base read routine for MUL access method. */
/***********************************************************************/
int TDBMUL::ReadDB(PGLOBAL g)
{
int rc;
if (NumFiles == 0)
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) {
if (Tdbp->GetDef()->GetPseudo() & 1)
// Total number of rows met so far
Rows += Tdbp->RowNumber(g) - 1;
if (++iFile < NumFiles) {
/***************************************************************/
/* Continue reading from next table file. */
/***************************************************************/
Tdbp->CloseDB(g);
Tdbp->SetUse(USE_READY);
Tdbp->SetFile(g, Filenames[iFile]);
Tdbp->ResetSize();
ResetDB();
if (Tdbp->OpenDB(g)) // Re-open with new file name
return RC_FX;
goto retry;
} // endif iFile
} else if (rc == RC_FX)
strcat(strcat(strcat(g->Message, " ("), Tdbp->GetFile(g)), ")");
} // endif To_Kindex
return rc;
} // end of ReadDB
/***********************************************************************/
/* Data Base write routine for MUL access method. */
/***********************************************************************/
int TDBMUL::WriteDB(PGLOBAL g)
{
return Tdbp->WriteDB(g);
// strcpy(g->Message, MSG(TABMUL_READONLY));
// return RC_FX; // NIY
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for MUL access method. */
/***********************************************************************/
int TDBMUL::DeleteDB(PGLOBAL g, int irc)
{
// When implementing DELETE_MODE InitFileNames must be updated to
// eliminate CRLF under Windows if the file is read in binary.
strcpy(g->Message, MSG(TABMUL_READONLY));
return RC_FX; // NIY
} // end of DeleteDB
/***********************************************************************/
/* Data Base close routine for MUL access method. */
/***********************************************************************/
void TDBMUL::CloseDB(PGLOBAL g)
{
if (NumFiles > 0) {
Tdbp->CloseDB(g);
iFile = NumFiles;
} // endif NumFiles
} // end of CloseDB
/* --------------------------- Class DIRDEF -------------------------- */
/***********************************************************************/
/* DefineAM: define specific AM block values from XDB file. */
/***********************************************************************/
bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
{
Desc = Fn = GetStringCatInfo(g, "Filename", NULL);
Incl = (GetIntCatInfo("Subdir", 0) != 0);
Huge = (GetIntCatInfo("Huge", 0) != 0);
return false;
} // end of DefineAM
/***********************************************************************/
/* GetTable: makes a new Table Description Block. */
/***********************************************************************/
PTDB DIRDEF::GetTable(PGLOBAL g, MODE m)
{
#if 0
if (Huge)
return new(g) TDBDHR(this); // Not implemented yet
else
#endif
if (Incl)
return new(g) TDBSDR(this); // Including sub-directory files
else
return new(g) TDBDIR(this); // Not Including sub-directory files
} // end of GetTable
/* ------------------------- Class TDBDIR ---------------------------- */
/***********************************************************************/
/* TABDIR constructors. */
/***********************************************************************/
TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
{
To_File = tdp->Fn;
iFile = 0;
#if defined(WIN32)
memset(&FileData, 0, sizeof(_finddata_t));
Hsearch = -1;
*Drive = '\0';
#else // !WIN32
memset(&Fileinfo, 0, sizeof(struct stat));
Entry = NULL;
Dir = NULL;
Done = false;
*Pattern = '\0';
#endif // !WIN32
*Fpath = '\0';
*Direc = '\0';
*Fname = '\0';
*Ftype = '\0';
} // end of TDBDIR standard constructor
TDBDIR::TDBDIR(PTDBDIR tdbp) : TDBASE(tdbp)
{
To_File = tdbp->To_File;
iFile = tdbp->iFile;
#if defined(WIN32)
FileData = tdbp->FileData;
Hsearch = tdbp->Hsearch;
strcpy(Drive, tdbp->Drive);
#else // !WIN32
Fileinfo = tdbp->Fileinfo;
Entry = tdbp->Entry;
Dir = tdbp->Dir;
Done = tdbp->Done;
strcpy(Pattern, tdbp->Pattern);
#endif // !WIN32
strcpy(Direc, tdbp->Direc);
strcpy(Fname, tdbp->Fname);
strcpy(Ftype, tdbp->Ftype);
} // end of TDBDIR copy constructor
// Method
PTDB TDBDIR::CopyOne(PTABS t)
{
PTDB tp;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBDIR(this);
tp->SetColumns(Columns);
return tp;
} // end of CopyOne
/***********************************************************************/
/* Initialize/get the components of the search file pattern. */
/***********************************************************************/
char* TDBDIR::Path(PGLOBAL g)
{
PCATLG cat = PlgGetCatalog(g);
#if defined(WIN32)
if (!*Drive) {
PlugSetPath(Fpath, To_File, cat->GetDataPath());
_splitpath(Fpath, Drive, Direc, Fname, Ftype);
} else
_makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull ???
return Fpath;
#else // !WIN32
if (!Done) {
PlugSetPath(Fpath, To_File, cat->GetDataPath());
_splitpath(Fpath, NULL, Direc, Fname, Ftype);
strcat(strcpy(Pattern, Fname), Ftype);
Done = true;
} // endif Done
return Pattern;
#endif // !WIN32
} // end of Path
/***********************************************************************/
/* Allocate DIR column description block. */
/***********************************************************************/
PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
return new(g) DIRCOL(cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/
/* DIR GetMaxSize: returns the number of retrieved files. */
/***********************************************************************/
int TDBDIR::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
int n = -1;
#if defined(WIN32)
int h;
// Start searching files in the target directory.
h = _findfirst(Path(g), &FileData);
if (h != -1) {
for (n = 1;; n++)
if (_findnext(h, &FileData))
break;
// Close the search handle.
_findclose(h);
} else
n = 0;
#else // !WIN32
Path(g);
// Start searching files in the target directory.
if (!(Dir = opendir(Direc))) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
return -1;
} // endif dir
while ((Entry = readdir(Dir))) {
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
return -1;
} else if (S_ISREG(Fileinfo.st_mode))
// Test whether the file name matches the table name filter
if (!fnmatch(Pattern, Entry->d_name, 0))
n++; // We have a match
} // endwhile Entry
// Close the DIR handle.
closedir(Dir);
#endif // !WIN32
MaxSize = n;
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* DIR Access Method opening routine. */
/* Open first file, other will be opened sequencially when reading. */
/***********************************************************************/
bool TDBDIR::OpenDB(PGLOBAL g)
{
if (trace)
htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
this, Tdb_No, Use, Mode);
if (Use == USE_OPEN) {
/*******************************************************************/
/* Table already open, reopen it. */
/*******************************************************************/
CloseDB(g);
SetUse(USE_READY);
} // endif use
Use = USE_OPEN;
#if !defined(WIN32)
Path(g); // Be sure it is done
Dir = NULL; // For ReadDB
#endif // !WIN32
return false;
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for DIR access method. */
/***********************************************************************/
int TDBDIR::ReadDB(PGLOBAL g)
{
int rc = RC_OK;
#if defined(WIN32)
if (Hsearch == -1) {
/*******************************************************************/
/* Start searching files in the target directory. The use of the */
/* Path function is required when called from TDBSDR. */
/*******************************************************************/
Hsearch = _findfirst(Path(g), &FileData);
if (Hsearch == -1)
rc = RC_EF;
else
iFile++;
} else {
if (_findnext(Hsearch, &FileData)) {
// Restore file name and type pattern
_splitpath(To_File, NULL, NULL, Fname, Ftype);
rc = RC_EF;
} else
iFile++;
} // endif Hsearch
if (rc == RC_OK)
_splitpath(FileData.name, NULL, NULL, Fname, Ftype);
#else // !Win32
rc = RC_NF;
if (!Dir)
// Start searching files in the target directory.
if (!(Dir = opendir(Direc))) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
rc = RC_FX;
} // endif dir
while (rc == RC_NF)
if ((Entry = readdir(Dir))) {
// We need the Fileinfo structure to get info about the file
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
rc = RC_FX;
} else if (S_ISREG(Fileinfo.st_mode))
// Test whether the file name matches the table name filter
if (!fnmatch(Pattern, Entry->d_name, 0)) {
iFile++; // We have a match
_splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
rc = RC_OK;
} // endif fnmatch
} else {
// Restore file name and type pattern
_splitpath(To_File, NULL, NULL, Fname, Ftype);
rc = RC_EF;
} // endif Entry
#endif // !WIN32
return rc;
} // end of ReadDB
/***********************************************************************/
/* Data Base write routine for DIR access method. */
/***********************************************************************/
int TDBDIR::WriteDB(PGLOBAL g)
{
strcpy(g->Message, MSG(TABDIR_READONLY));
return RC_FX; // NIY
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for DIR access method. */
/***********************************************************************/
int TDBDIR::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, MSG(TABDIR_READONLY));
return RC_FX; // NIY
} // end of DeleteDB
/***********************************************************************/
/* Data Base close routine for MUL access method. */
/***********************************************************************/
void TDBDIR::CloseDB(PGLOBAL g)
{
#if defined(WIN32)
// Close the search handle.
_findclose(Hsearch);
Hsearch = -1;
#else // !WIN32
// Close the DIR handle
if (Dir) {
closedir(Dir);
Dir = NULL;
} // endif dir
#endif // !WIN32
iFile = 0;
} // end of CloseDB
// ------------------------ DIRCOL functions ----------------------------
/***********************************************************************/
/* DIRCOL public constructor. */
/***********************************************************************/
DIRCOL::DIRCOL(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 DIR access method information for column.
N = cdp->GetOffset();
} // end of DIRCOL constructor
/***********************************************************************/
/* DIRCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
{
N = col1->N;
} // end of DIRCOL copy constructor
/***********************************************************************/
/* ReadColumn: what this routine does is to access the information */
/* corresponding to this column and convert it to buffer type. */
/***********************************************************************/
void DIRCOL::ReadColumn(PGLOBAL g)
{
PTDBDIR tdbp = (PTDBDIR)To_Tdb;
if (trace)
htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
/*********************************************************************/
/* Retrieve the information corresponding to the column number. */
/*********************************************************************/
switch (N) {
#if defined(WIN32)
case 0: Value->SetValue_psz(tdbp->Drive); break;
#endif // WIN32
case 1: Value->SetValue_psz(tdbp->Direc); break;
case 2: Value->SetValue_psz(tdbp->Fname); break;
case 3: Value->SetValue_psz(tdbp->Ftype); break;
#if defined(WIN32)
case 4: Value->SetValue((int)tdbp->FileData.attrib); break;
case 5: Value->SetValue((int)tdbp->FileData.size); break;
case 6: Value->SetValue((int)tdbp->FileData.time_write); break;
case 7: Value->SetValue((int)tdbp->FileData.time_create); break;
case 8: Value->SetValue((int)tdbp->FileData.time_access); break;
#else // !WIN32
case 4: Value->SetValue((int)tdbp->Fileinfo.st_mode); break;
case 5: Value->SetValue((int)tdbp->Fileinfo.st_size); break;
case 6: Value->SetValue((int)tdbp->Fileinfo.st_mtime); break;
case 7: Value->SetValue((int)tdbp->Fileinfo.st_ctime); break;
case 8: Value->SetValue((int)tdbp->Fileinfo.st_atime); break;
case 9: Value->SetValue((int)tdbp->Fileinfo.st_uid); break;
case 10: Value->SetValue((int)tdbp->Fileinfo.st_gid); break;
#endif // !WIN32
default:
sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
longjmp(g->jumper[g->jump_level], GetAmType());
} // endswitch N
} // end of ReadColumn
/* ------------------------- Class TDBSDR ---------------------------- */
/***********************************************************************/
/* TABSDR copy constructors. */
/***********************************************************************/
TDBSDR::TDBSDR(PTDBSDR tdbp) : TDBDIR(tdbp)
{
Sub = tdbp->Sub;
} // end of TDBSDR copy constructor
// Method
PTDB TDBSDR::CopyOne(PTABS t)
{
PTDB tp;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBSDR(this);
tp->SetColumns(Columns);
return tp;
} // end of CopyOne
/***********************************************************************/
/* SDR GetMaxSize: returns the number of retrieved files. */
/***********************************************************************/
int TDBSDR::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
Path(g);
MaxSize = FindInDir(g);
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* SDR GetMaxSize: returns the number of retrieved files. */
/***********************************************************************/
int TDBSDR::FindInDir(PGLOBAL g)
{
int n = 0;
size_t m = strlen(Direc);
// Start searching files in the target directory.
#if defined(WIN32)
int h = _findfirst(Path(g), &FileData);
if (h != -1) {
for (n = 1;; n++)
if (_findnext(h, &FileData))
break;
// Close the search handle.
_findclose(h);
} // endif h
// Now search files in sub-directories.
_makepath(Fpath, Drive, Direc, "*", "");
h = _findfirst(Fpath, &FileData);
if (h != -1) {
while (true) {
if (FileData.attrib & _A_SUBDIR && *FileData.name != '.') {
// Look in the name sub-directory
strcat(strcat(Direc, FileData.name), "\\");
n += FindInDir(g);
Direc[m] = '\0'; // Restore path
} // endif SUBDIR
if (_findnext(h, &FileData))
break;
} // endwhile
// Close the search handle.
_findclose(h);
} // endif h
#else // !WIN32
int k;
DIR *dir = opendir(Direc);
if (!dir) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
return -1;
} // endif dir
while ((Entry = readdir(dir))) {
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
return -1;
} else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
// Look in the name sub-directory
strcat(strcat(Direc, Entry->d_name), "/");
if ((k = FindInDir(g)) < 0)
return k;
else
n += k;
Direc[m] = '\0'; // Restore path
} else if (S_ISREG(Fileinfo.st_mode))
// Test whether the file name matches the table name filter
if (!fnmatch(Pattern, Entry->d_name, 0))
n++; // We have a match
} // endwhile readdir
// Close the DIR handle.
closedir(dir);
#endif // !WIN32
return n;
} // end of FindInDir
/***********************************************************************/
/* DIR Access Method opening routine. */
/* Open first file, other will be opened sequencially when reading. */
/***********************************************************************/
bool TDBSDR::OpenDB(PGLOBAL g)
{
if (!Sub) {
Path(g);
Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
Sub->Next = NULL;
Sub->Prev = NULL;
#if defined(WIN32)
Sub->H = -1;
Sub->Len = strlen(Direc);
#else // !WIN32
Sub->D = NULL;
Sub->Len = 0;
#endif // !WIN32
} // endif To_Sub
return TDBDIR::OpenDB(g);
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for SDR access method. */
/***********************************************************************/
int TDBSDR::ReadDB(PGLOBAL g)
{
int rc;
#if defined(WIN32)
again:
rc = TDBDIR::ReadDB(g);
if (rc == RC_EF) {
// Are there more files in sub-directories
retry:
do {
if (Sub->H == -1) {
_makepath(Fpath, Drive, Direc, "*", "");
Sub->H = _findfirst(Fpath, &FileData);
} else if (_findnext(Sub->H, &FileData)) {
_findclose(Sub->H);
Sub->H = -1;
*FileData.name = '\0';
} // endif findnext
} while(*FileData.name == '.');
if (Sub->H == -1) {
// No more sub-directories. Are we in a sub-directory?
if (!Sub->Prev)
return rc; // No, all is finished
// here we must continue in the parent directory
Sub = Sub->Prev;
goto retry;
} else {
// Search next sub-directory
Direc[Sub->Len] = '\0';
if (!Sub->Next) {
PSUBDIR sup;
sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
sup->Next = NULL;
sup->Prev = Sub;
sup->H = -1;
Sub->Next = sup;
} // endif Next
Sub = Sub->Next;
strcat(strcat(Direc, FileData.name), "\\");
Sub->Len = strlen(Direc);
// Reset Hsearch used by TDBDIR::ReadDB
_findclose(Hsearch);
Hsearch = -1;
goto again;
} // endif H
} // endif rc
#else // !WIN32
rc = RC_NF;
again:
if (!Sub->D)
// Start searching files in the target directory.
if (!(Sub->D = opendir(Direc))) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
rc = RC_FX;
} // endif dir
while (rc == RC_NF)
if ((Entry = readdir(Sub->D))) {
// We need the Fileinfo structure to get info about the file
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
rc = RC_FX;
} else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
// Look in the name sub-directory
if (!Sub->Next) {
PSUBDIR sup;
sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
sup->Next = NULL;
sup->Prev = Sub;
Sub->Next = sup;
} // endif Next
Sub = Sub->Next;
Sub->D = NULL;
Sub->Len = strlen(Direc);
strcat(strcat(Direc, Entry->d_name), "/");
goto again;
} else if (S_ISREG(Fileinfo.st_mode))
// Test whether the file name matches the table name filter
if (!fnmatch(Pattern, Entry->d_name, 0)) {
iFile++; // We have a match
_splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
rc = RC_OK;
} // endif fnmatch
} else {
// No more files. Close the DIR handle.
closedir(Sub->D);
// Are we in a sub-directory?
if (Sub->Prev) {
// Yes, we must continue in the parent directory
Direc[Sub->Len] = '\0';
Sub = Sub->Prev;
} else
rc = RC_EF; // No, all is finished
} // endif Entry
#endif // !WIN32
return rc;
} // end of ReadDB
#if 0
/* ------------------------- Class TDBDHR ---------------------------- */
/***********************************************************************/
/* TABDHR constructors. */
/***********************************************************************/
TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
{
memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
Hsearch = INVALID_HANDLE_VALUE;
iFile = 0;
*Drive = '\0';
*Direc = '\0';
*Fname = '\0';
*Ftype = '\0';
} // end of TDBDHR standard constructor
TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
{
FileData = tdbp->FileData;
Hsearch = tdbp->Hsearch;
iFile = tdbp->iFile;
strcpy(Drive, tdbp->Drive);
strcpy(Direc, tdbp->Direc);
strcpy(Fname, tdbp->Fname);
strcpy(Ftype, tdbp->Ftype);
} // end of TDBDHR copy constructor
// Method
PTDB TDBDHR::CopyOne(PTABS t)
{
PTDB tp;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBDHR(this);
tp->Columns = Columns;
return tp;
} // end of CopyOne
/***********************************************************************/
/* Allocate DHR column description block. */
/***********************************************************************/
PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
return new(g) DHRCOL(cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/
/* DHR GetMaxSize: returns the number of retrieved files. */
/***********************************************************************/
int TDBDHR::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
char filename[_MAX_PATH];
int i, rc;
int n = -1;
HANDLE h;
PDBUSER dup = PlgGetUser(g);
PlugSetPath(filename, To_File, dup->Path);
// Start searching files in the target directory.
h = FindFirstFile(filename, &FileData);
if (h == INVALID_HANDLE_VALUE) {
switch (rc = GetLastError()) {
case ERROR_NO_MORE_FILES:
case ERROR_FILE_NOT_FOUND:
n = 0;
break;
default:
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, rc, 0,
(LPTSTR)&filename, sizeof(filename), NULL);
sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
} // endswitch rc
} else {
for (n = 1;; n++)
if (!FindNextFile(h, &FileData)) {
rc = GetLastError();
if (rc != ERROR_NO_MORE_FILES) {
sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
n = -1;
} // endif rc
break;
} // endif FindNextFile
// Close the search handle.
if (!FindClose(h) && n != -1)
strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
} // endif Hsearch
MaxSize = n;
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* DHR Access Method opening routine. */
/* Open first file, other will be opened sequencially when reading. */
/***********************************************************************/
bool TDBDHR::OpenDB(PGLOBAL g)
{
if (trace)
htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
this, Tdb_No, Use, Mode);
if (Use == USE_OPEN) {
/*******************************************************************/
/* Table already open, reopen it. */
/*******************************************************************/
CloseDB(g);
SetUse(USE_READY);
} // endif use
/*********************************************************************/
/* Direct access needed for join or sorting. */
/*********************************************************************/
if (NeedIndexing(g)) {
// Direct access of DHR tables is not implemented yet
sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
return true;
} // endif NeedIndexing
Use = USE_OPEN;
return false;
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for DHR access method. */
/***********************************************************************/
int TDBDHR::ReadDB(PGLOBAL g)
{
int rc = RC_OK;
DWORD erc;
if (Hsearch == INVALID_HANDLE_VALUE) {
char *filename[_MAX_PATH];
PDBUSER dup = PlgGetUser(g);
PlugSetPath(filename, To_File, dup->Path);
_splitpath(filename, Drive, Direc, NULL, NULL);
/*******************************************************************/
/* Start searching files in the target directory. */
/*******************************************************************/
Hsearch = FindFirstFile(filename, &FileData);
if (Hsearch != INVALID_HANDLE_VALUE)
iFile = 1;
else switch (erc = GetLastError()) {
case ERROR_NO_MORE_FILES:
case ERROR_FILE_NOT_FOUND:
// case ERROR_PATH_NOT_FOUND: ???????
rc = RC_EF;
break;
default:
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, erc, 0,
(LPTSTR)&filename, sizeof(filename), NULL);
sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
rc = RC_FX;
} // endswitch erc
} else {
if (!FindNextFile(Hsearch, &FileData)) {
DWORD erc = GetLastError();
if (erc != ERROR_NO_MORE_FILES) {
sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
FindClose(Hsearch);
rc = RC_FX;
} else
rc = RC_EF;
} else
iFile++;
} // endif Hsearch
if (rc == RC_OK)
_splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
return rc;
} // end of ReadDB
/***********************************************************************/
/* Data Base close routine for MUL access method. */
/***********************************************************************/
void TDBDHR::CloseDB(PGLOBAL g)
{
// Close the search handle.
if (!FindClose(Hsearch)) {
strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
longjmp(g->jumper[g->jump_level], GetAmType());
} // endif FindClose
iFile = 0;
Hsearch = INVALID_HANDLE_VALUE;
} // end of CloseDB
// ------------------------ DHRCOL functions ----------------------------
/***********************************************************************/
/* DHRCOL public constructor. */
/***********************************************************************/
DHRCOL::DHRCOL(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 DHR access method information for column.
N = cdp->GetOffset();
} // end of DOSCOL constructor
/***********************************************************************/
/* DHRCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
{
N = col1->N;
} // end of DHRCOL copy constructor
/***********************************************************************/
/* ReadColumn: what this routine does is to access the information */
/* corresponding to this column and convert it to buffer type. */
/***********************************************************************/
void DHRCOL::ReadColumn(PGLOBAL g)
{
int rc;
PTDBDHR tdbp = (PTDBDHR)To_Tdb;
if (trace)
htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
/*********************************************************************/
/* Retrieve the information corresponding to the column number. */
/*********************************************************************/
switch (N) {
case 0: // Drive
Value->SetValue(Drive, _MAX_DRIVE);
break;
case 1: // Path
Value->SetValue(Direc, _MAX_DHR);
break;
case 2: // Name
Value->SetValue(Fname, _MAX_FNAME);
break;
case 3: // Extention
Value->SetValue(Ftype, _MAX_EXT);
break;
case 4: // Extention
Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
break;
case 5:
Value->SetValue(tdbp->FileData.dwFileAttributes);
break;
case 6:
Value->SetValue(..................
} // end of ReadColumn
#endif // 0