mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
1624 lines
50 KiB
C++
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
|
|
|