mariadb/storage/connect/tabmul.cpp
2022-07-27 11:02:57 +02:00

1624 lines
50 KiB
C++

/************* TabMul C++ Program Source Code File (.CPP) **************/
/* PROGRAM NAME: TABMUL */
/* ------------- */
/* Version 1.9 */
/* */
/* COPYRIGHT: */
/* ---------- */
/* (C) Copyright to PlugDB Software Development 2003 - 2017 */
/* 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>
#if defined(PATHMATCHSPEC)
#include "Shlwapi.h"
//using namespace std;
#pragma comment(lib,"shlwapi.lib")
#endif // PATHMATCHSPEC
#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
/* ------------------------- Class TDBMUL ---------------------------- */
/***********************************************************************/
/* TABMUL constructors. */
/***********************************************************************/
TDBMUL::TDBMUL(PTDB 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::Clone(PTABS t)
{
PTDBMUL tp;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBMUL(this);
tp->Tdbp = Tdbp->Clone(t);
tp->Columns = tp->Tdbp->GetColumns();
return tp;
} // end of Clone
PTDB TDBMUL::Duplicate(PGLOBAL g)
{
PTDBMUL tmup = new(g) TDBMUL(this);
tmup->Tdbp = 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)
PTDBDIR dirp;
PSZ pfn[PFNZ];
PSZ filename;
int rc, n = 0;
if (trace(1))
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(1))
htrc("InitFileName: fn='%s'\n", filename);
if (Mul != 2) {
/*******************************************************************/
/* To_File is a multiple name with special characters */
/*******************************************************************/
if (Mul == 1)
dirp = new(g) TDBDIR(PlugDup(g, filename));
else // Mul == 3 (Subdir)
dirp = new(g) TDBSDR(PlugDup(g, filename));
if (dirp->OpenDB(g))
return true;
if (trace(1) && Mul == 3) {
int nf = ((PTDBSDR)dirp)->FindInDir(g);
htrc("Number of files = %d\n", nf);
} // endif trace
while (true)
if ((rc = dirp->ReadDB(g)) == RC_OK) {
#if defined(_WIN32)
strcat(strcpy(filename, dirp->Drive), dirp->Direc);
#else // !_WIN32
strcpy(filename, dirp->Direc);
#endif // !_WIN32
strcat(strcat(filename, dirp->Fname), dirp->Ftype);
pfn[n++] = PlugDup(g, filename);
} else
break;
dirp->CloseDB(g);
if (rc == RC_FX)
return true;
} 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(_WIN32)
// 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++] = PlugDup(g, filename);
} // endfor n
} // endif Mul
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(1))
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(1))
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)
{
// 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
#if 0
/* ------------------------- Class TDBMSD ---------------------------- */
// Method
PTDB TDBMSD::Clone(PTABS t)
{
PTDBMSD tp;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBMSD(this);
tp->Tdbp = Tdbp->Clone(t);
tp->Columns = tp->Tdbp->GetColumns();
return tp;
} // end of Clone
PTDB TDBMSD::Duplicate(PGLOBAL g)
{
PTDBMSD tmup = new(g) TDBMSD(this);
tmup->Tdbp = 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 TDBMSD::InitFileNames(PGLOBAL g)
{
#define PFNZ 4096
#define FNSZ (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
PTDBSDR dirp;
PSZ pfn[PFNZ];
PSZ filename;
int rc, n = 0;
if (trace(1))
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(1))
htrc("InitFileName: fn='%s'\n", filename);
dirp = new(g) TDBSDR(filename);
if (dirp->OpenDB(g))
return true;
while (true)
if ((rc = dirp->ReadDB(g)) == RC_OK) {
#if defined(_WIN32)
strcat(strcpy(filename, dirp->Drive), dirp->Direc);
#else // !_WIN32
strcpy(filename, dirp->Direc);
#endif // !_WIN32
strcat(strcat(filename, dirp->Fname), dirp->Ftype);
pfn[n++] = PlugDup(g, filename);
} else
break;
if (rc == RC_FX)
return true;
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
#endif // 0
/* --------------------------- Class DIRDEF -------------------------- */
/***********************************************************************/
/* DefineAM: define specific AM block values from XDB file. */
/***********************************************************************/
bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR, int)
{
Desc = Fn = GetStringCatInfo(g, "Filename", NULL);
Incl = GetBoolCatInfo("Subdir", false);
Huge = GetBoolCatInfo("Huge", false);
Nodir = GetBoolCatInfo("Nodir", true);
return false;
} // end of DefineAM
/***********************************************************************/
/* GetTable: makes a new Table Description Block. */
/***********************************************************************/
PTDB DIRDEF::GetTable(PGLOBAL g, MODE)
{
#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. */
/***********************************************************************/
void TDBDIR::Init(void)
{
iFile = 0;
#if defined(_WIN32)
Dvalp = NULL;
memset(&FileData, 0, sizeof(_finddata_t));
hSearch = INVALID_HANDLE_VALUE;
*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 Init
TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
{
To_File = tdp->Fn;
Nodir = tdp->Nodir;
Init();
} // end of TDBDIR standard constructor
TDBDIR::TDBDIR(PSZ fpat) : TDBASE((PTABDEF)NULL)
{
To_File = fpat;
Nodir = true;
Init();
} // end of TDBDIR constructor
/***********************************************************************/
/* Initialize/get the components of the search file pattern. */
/***********************************************************************/
char* TDBDIR::Path(PGLOBAL g)
{
PCATLG cat __attribute__((unused))= PlgGetCatalog(g);
PTABDEF defp = (PTABDEF)To_Def;
#if defined(_WIN32)
if (!*Drive) {
PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
_splitpath(Fpath, Drive, Direc, Fname, Ftype);
} else
_makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull for TDBSDR
return Fpath;
#else // !_WIN32
if (!Done) {
PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
_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 rc;
// Start searching files in the target directory.
hSearch = FindFirstFile(Path(g), &FileData);
if (hSearch == INVALID_HANDLE_VALUE) {
rc = GetLastError();
if (rc != ERROR_FILE_NOT_FOUND) {
char buf[512];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), buf);
return -1;
} // endif rc
return 0;
} // endif hSearch
while (true) {
if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
n++;
if (!FindNextFile(hSearch, &FileData)) {
rc = GetLastError();
if (rc != ERROR_NO_MORE_FILES) {
snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), rc);
FindClose(hSearch);
return -1;
} // endif rc
break;
} // endif Next
} // endwhile
// Close the search handle.
FindClose(hSearch);
#else // !_WIN32
Path(g);
// Start searching files in the target directory.
if (!(Dir = opendir(Direc))) {
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(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(1))
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)
do {
if (hSearch == INVALID_HANDLE_VALUE) {
/*****************************************************************/
/* Start searching files in the target directory. The use of */
/* the Path function is required when called from TDBSDR. */
/*****************************************************************/
hSearch = FindFirstFile(Path(g), &FileData);
if (hSearch == INVALID_HANDLE_VALUE) {
rc = RC_EF;
break;
} else
iFile++;
} else {
if (!FindNextFile(hSearch, &FileData)) {
// Restore file name and type pattern
_splitpath(To_File, NULL, NULL, Fname, Ftype);
rc = RC_EF;
break;
} else
iFile++;
} // endif hSearch
} while (Nodir && FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
if (rc == RC_OK)
_splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
#else // !Win32
rc = RC_NF;
if (!Dir)
// Start searching files in the target directory.
if (!(Dir = opendir(Direc))) {
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(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)
{
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)
{
#if defined(_WIN32)
// Close the search handle.
FindClose(hSearch);
hSearch = INVALID_HANDLE_VALUE;
#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, PCSZ)
: 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.
Tdbp = (PTDBDIR)tdbp;
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)
{
Tdbp = (PTDBDIR)tdbp;
N = col1->N;
} // end of DIRCOL copy constructor
#if defined(_WIN32)
/***********************************************************************/
/* Retrieve time information from FileData. */
/***********************************************************************/
void DIRCOL::SetTimeValue(PGLOBAL g, FILETIME& ftime)
{
char tsp[24];
SYSTEMTIME stp;
if (FileTimeToSystemTime(&ftime, &stp)) {
sprintf(tsp, "%04d-%02d-%02d %02d:%02d:%02d",
stp.wYear, stp.wMonth, stp.wDay, stp.wHour, stp.wMinute, stp.wSecond);
if (Value->GetType() != TYPE_STRING) {
if (!Tdbp->Dvalp)
Tdbp->Dvalp = AllocateValue(g, TYPE_DATE, 20, 0, false,
"YYYY-MM-DD hh:mm:ss");
Tdbp->Dvalp->SetValue_psz(tsp);
Value->SetValue_pval(Tdbp->Dvalp);
} else
Value->SetValue_psz(tsp);
} else
Value->Reset();
} // end of SetTimeValue
#endif // _WIN32
/***********************************************************************/
/* 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)
{
if (trace(1))
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.dwFileAttributes); break;
case 5: Value->SetValue((int)Tdbp->FileData.nFileSizeLow); break;
case 6: SetTimeValue(g, Tdbp->FileData.ftLastWriteTime); break;
case 7: SetTimeValue(g, Tdbp->FileData.ftCreationTime); break;
case 8: SetTimeValue(g, Tdbp->FileData.ftLastAccessTime); 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:
snprintf(g->Message, sizeof(g->Message), MSG(INV_DIRCOL_OFST), N);
throw GetAmType();
} // endswitch N
} // end of ReadColumn
/* ------------------------- Class TDBSDR ---------------------------- */
/***********************************************************************/
/* 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 FindInDir: 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)
HANDLE h;
int rc;
#if defined(PATHMATCHSPEC)
if (!*Drive)
Path(g);
_makepath(Fpath, Drive, Direc, "*", "*");
h = FindFirstFile(Fpath, &FileData);
if (h == INVALID_HANDLE_VALUE) {
rc = GetLastError();
if (rc != ERROR_FILE_NOT_FOUND) {
char buf[512];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), buf);
return -1;
} // endif rc
return 0;
} // endif h
while (true) {
if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
*FileData.cFileName != '.') {
// Look in the name sub-directory
strcat(strcat(Direc, FileData.cFileName), "/");
n += FindInDir(g);
Direc[m] = '\0'; // Restore path
} else if (PathMatchSpec(FileData.cFileName, Fpath))
n++;
if (!FindNextFile(h, &FileData)) {
rc = GetLastError();
if (rc != ERROR_NO_MORE_FILES) {
snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), rc);
FindClose(h);
return -1;
} // endif rc
break;
} // endif Next
} // endwhile
#else // !PATHMATCHSPEC
h = FindFirstFile(Path(g), &FileData);
if (h == INVALID_HANDLE_VALUE) {
rc = GetLastError();
if (rc != ERROR_FILE_NOT_FOUND) {
char buf[512];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), buf);
return -1;
} // endif rc
return 0;
} // endif hSearch
while (true) {
n++;
if (!FindNextFile(h, &FileData)) {
rc = GetLastError();
if (rc != ERROR_NO_MORE_FILES) {
snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), rc);
FindClose(h);
return -1;
} // endif rc
break;
} // endif Next
} // endwhile
// Now search files in sub-directories.
_makepath(Fpath, Drive, Direc, "*", ".");
h = FindFirstFile(Fpath, &FileData);
if (h != INVALID_HANDLE_VALUE) {
while (true) {
if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
*FileData.cFileName != '.') {
// Look in the name sub-directory
strcat(strcat(Direc, FileData.cFileName), "/");
n += FindInDir(g);
Direc[m] = '\0'; // Restore path
} // endif SUBDIR
if (!FindNextFile(h, &FileData))
break;
} // endwhile
} // endif h
#endif // !PATHMATCHSPEC
// Close the search handle.
FindClose(h);
#else // !_WIN32
int k;
DIR *dir = opendir(Direc);
if (!dir) {
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(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 = INVALID_HANDLE_VALUE;
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 == INVALID_HANDLE_VALUE) {
// _makepath(Fpath, Drive, Direc, "*", "."); why was this made?
_makepath(Fpath, Drive, Direc, "*", NULL);
Sub->H = FindFirstFile(Fpath, &FileData);
} else if (!FindNextFile(Sub->H, &FileData)) {
FindClose(Sub->H);
Sub->H = INVALID_HANDLE_VALUE;
*FileData.cFileName= '\0';
break;
} // endif findnext
} while(!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
(*FileData.cFileName == '.' &&
(!FileData.cFileName[1] || FileData.cFileName[1] == '.')));
if (Sub->H == INVALID_HANDLE_VALUE) {
// 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 = INVALID_HANDLE_VALUE;
Sub->Next = sup;
} // endif Next
Sub = Sub->Next;
strcat(strcat(Direc, FileData.cFileName), "/");
Sub->Len = strlen(Direc);
// Reset Hsearch used by TDBDIR::ReadDB
FindClose(hSearch);
hSearch = INVALID_HANDLE_VALUE;
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))) {
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(g->Message), "%s: %s", Fpath, strerror(errno));
rc = RC_FX;
} else if (S_ISDIR(Fileinfo.st_mode) && strcmp(Entry->d_name, ".")
&& strcmp(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::Clone(PTABS t)
{
PTDB tp;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBDHR(this);
tp->Columns = Columns;
return tp;
} // end of Clone
/***********************************************************************/
/* 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);
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(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(1))
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
snprintf(g->Message, sizeof(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);
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(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));
throw 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, PCSZ 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(1))
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