mariadb/storage/connect/tabmul.cpp
Sergei Golubchik 5ae2656b69 Squashed commit of connect/10.0:
commit c545d544378483bf68c4fb713cd4ec872d0df2c4
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Tue Mar 27 23:13:14 2018 +0200

    - Fix MDEV-15577 CONNECT engine JDBC remote index prevents UPDATE
      Fixed in TDBJDBC::OpenDB because query can be null for updates
      modified:   storage/connect/tabjdbc.cpp

commit c4f1fe2e8e74566e9c3296f435448d9f5c718b23
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Wed Mar 14 12:21:17 2018 +0100

    - Fix MDEV-15429 CONNECT engine JDBC handling Postgresql UUID type
      Also handle Postgresql sending type VARCHAR for TEXT column and
      setting length to b x7FFFFFF when the length is unknown.
      modified:   storage/connect/Client.java
      modified:   storage/connect/JavaWrappers.jar
      modified:   storage/connect/JdbcInterface.java
      modified:   storage/connect/PostgresqlInterface.java
      modified:   storage/connect/global.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/jdbconn.cpp
      modified:   storage/connect/jdbconn.h
      modified:   storage/connect/mysql-test/connect/r/jdbc_postgresql.result
      modified:   storage/connect/mysql-test/connect/t/jdbc_postgresql.test
      modified:   storage/connect/mysql-test/connect/t/jdbconn.inc
      modified:   storage/connect/plgdbsem.h
      modified:   storage/connect/tabjdbc.cpp
      modified:   storage/connect/tabjdbc.h
      added:      storage/connect/mysql-test/connect/std_data/JavaWrappers.jar

commit 3068bb4882a316c6c32c624609db2bf24ae3ad40
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Mon Feb 26 19:40:27 2018 +0100

    Revert to old cmake file to avoid compile error

commit da8c1c0bd6a327fd03bd321be3170f468122ef67
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Mon Feb 26 16:13:39 2018 +0100

    - Remove warning on not used tabtyp variable in connect_assisted_discovery
      modified:   storage/connect/ha_connect.cc

    - Fix a bug causing CONNECT to loop when expanding a JSON column
      when the expanded column value is null or void array.
    - Adding the FullArray option to JSON tables.
    - Skipping expanded JSON lines when the expanded column value is null.
      modified:   storage/connect/connect.cc
      modified:   storage/connect/tabdos.h
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/tabjson.h

    - Fix MDEV-13353 No file privilege for ODBC, JDBC, MONGO, MAC, WMI file types.
      modified:   storage/connect/ha_connect.cc

    - Make some Json UDFs  to accept a non JSON item as 1st parameter.
      modified:   storage/connect/json.cpp
      modified:   storage/connect/json.h
      modified:   storage/connect/jsonudf.cpp
      modified:   storage/connect/jsonudf.h

    - Update Json UDF tests to cope with above changes.
      modified:   storage/connect/mysql-test/connect/r/json_udf.result
      modified:   storage/connect/mysql-test/connect/r/json_udf_bin.result
      modified:   storage/connect/mysql-test/connect/r/vcol.result
      modified:   storage/connect/mysql-test/connect/t/json_udf.test
      modified:   storage/connect/mysql-test/connect/t/vcol.test

    - Fix some compiler warning treated as error
      PlugSubAlloc no more exported because it does throw.
      modified:   storage/connect/global.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/jsonudf.cpp
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/tabjson.h

    - Other files modified (?) when going back to wrong merge
      modified:   storage/connect/CMakeLists.txt
      modified:   storage/connect/array.cpp
      modified:   storage/connect/colblk.cpp
      modified:   storage/connect/connect.cc
      modified:   storage/connect/csort.cpp
      modified:   storage/connect/domdoc.cpp
      modified:   storage/connect/filamap.cpp
      modified:   storage/connect/filamgz.cpp
      modified:   storage/connect/filamtxt.cpp
      modified:   storage/connect/filamzip.cpp
      modified:   storage/connect/filter.cpp
      modified:   storage/connect/fmdlex.c
      modified:   storage/connect/jdbconn.cpp
      modified:   storage/connect/macutil.cpp
      modified:   storage/connect/myconn.cpp
      modified:   storage/connect/odbconn.cpp
      modified:   storage/connect/plgdbutl.cpp
      modified:   storage/connect/plugutil.cpp
      modified:   storage/connect/preparse.h
      modified:   storage/connect/rcmsg.c
      modified:   storage/connect/rcmsg.h
      modified:   storage/connect/reldef.cpp
      modified:   storage/connect/tabdos.cpp
      modified:   storage/connect/tabfmt.cpp
      modified:   storage/connect/tabmac.cpp
      modified:   storage/connect/tabmul.cpp
      modified:   storage/connect/tabmysql.cpp
      modified:   storage/connect/tabmysql.h
      modified:   storage/connect/tabodbc.cpp
      modified:   storage/connect/tabtbl.cpp
      modified:   storage/connect/tabxml.cpp
      modified:   storage/connect/value.cpp
      modified:   storage/connect/xobject.cpp

commit 5095628b31ed8c94bd7c794c6b0162894a9040b1
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Tue Feb 13 14:29:00 2018 +0100

    - Fix a bug causing CONNECT to loop when expanding a JSON column
      when the expanded column value is null or void array.
    - Adding the FullArray option to JSON tables.
    - Skipping expanded JSON lines when the expanded column value is null.
      modified:   storage/connect/connect.cc
      modified:   storage/connect/tabdos.h
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/tabjson.h

commit 9896174328da42016735630c893fd09eb128b48e
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Fri Feb 2 15:48:57 2018 +0100

    - Remove warning on not used tabtyp variable in connect_assisted_discovery
      modified:   storage/connect/ha_connect.cc

commit d7e254c05f88173eb04d8dafc813013eb42ccdbe
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Wed Jan 31 14:42:45 2018 +0100

    - Use delayed load for the MongoDB C Drive on Windows
      modified:   storage/connect/CMakeLists.txt
      modified:   storage/connect/cmgoconn.cpp
      modified:   storage/connect/ha_connect.cc

    - Add FORCE to the connect_type_conv enum values
      This will translate binary values to TYPE_STRING
      modified:   storage/connect/checklvl.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/odbconn.cpp

    - Change the connect_xtrace variable to from int to set
      modified:   storage/connect/array.cpp
      modified:   storage/connect/blkfil.cpp
      modified:   storage/connect/block.h
      modified:   storage/connect/cmgoconn.cpp
      modified:   storage/connect/colblk.cpp
      modified:   storage/connect/connect.cc
      modified:   storage/connect/filamap.cpp
      modified:   storage/connect/filamdbf.cpp
      modified:   storage/connect/filamfix.cpp
      modified:   storage/connect/filamgz.cpp
      modified:   storage/connect/filamtxt.cpp
      modified:   storage/connect/filamvct.cpp
      modified:   storage/connect/filamzip.cpp
      modified:   storage/connect/filter.cpp
      modified:   storage/connect/global.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/inihandl.cpp
      modified:   storage/connect/javaconn.cpp
      modified:   storage/connect/jdbconn.cpp
      modified:   storage/connect/jmgfam.cpp
      modified:   storage/connect/jmgoconn.cpp
      modified:   storage/connect/json.cpp
      modified:   storage/connect/jsonudf.cpp
      modified:   storage/connect/libdoc.cpp
      modified:   storage/connect/mongo.cpp
      modified:   storage/connect/mycat.cc
      modified:   storage/connect/myconn.cpp
      modified:   storage/connect/odbconn.cpp
      modified:   storage/connect/plgdbutl.cpp
      modified:   storage/connect/plugutil.cpp
      modified:   storage/connect/reldef.cpp
      modified:   storage/connect/tabcol.cpp
      modified:   storage/connect/tabdos.cpp
      modified:   storage/connect/tabext.cpp
      modified:   storage/connect/tabfix.cpp
      modified:   storage/connect/tabfmt.cpp
      modified:   storage/connect/tabjdbc.cpp
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/table.cpp
      modified:   storage/connect/tabmul.cpp
      modified:   storage/connect/tabmysql.cpp
      modified:   storage/connect/tabodbc.cpp
      modified:   storage/connect/tabpivot.cpp
      modified:   storage/connect/tabsys.cpp
      modified:   storage/connect/tabtbl.cpp
      modified:   storage/connect/tabutil.cpp
      modified:   storage/connect/tabvct.cpp
      modified:   storage/connect/tabwmi.cpp
      modified:   storage/connect/tabxml.cpp
      modified:   storage/connect/user_connect.cc
      modified:   storage/connect/valblk.cpp
      modified:   storage/connect/value.cpp
      modified:   storage/connect/xindex.cpp

    - Restore connect_enable_mongo variable (but undocumented)
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/mycat.cc
      modified:   storage/connect/mysql-test/connect/r/json_java_2.result
      modified:   storage/connect/mysql-test/connect/r/json_java_3.result
      modified:   storage/connect/mysql-test/connect/r/json_mongo_c.result
      modified:   storage/connect/mysql-test/connect/r/mongo_c.result
      modified:   storage/connect/mysql-test/connect/r/mongo_java_2.result
      modified:   storage/connect/mysql-test/connect/r/mongo_java_3.result
      modified:   storage/connect/mysql-test/connect/r/tbl_thread.result
      modified:   storage/connect/mysql-test/connect/t/mongo.inc
      modified:   storage/connect/mysql-test/connect/t/mongo_test.inc
      modified:   storage/connect/mysql-test/connect/t/tbl_thread.test
2018-04-26 14:15:18 +02:00

1622 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(__WIN__)
#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(__WIN__)
strcat(strcpy(filename, dirp->Drive), dirp->Direc);
#else // !__WIN__
strcpy(filename, dirp->Direc);
#endif // !__WIN__
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(__WIN__)
// 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(__WIN__)
strcat(strcpy(filename, dirp->Drive), dirp->Direc);
#else // !__WIN__
strcpy(filename, dirp->Direc);
#endif // !__WIN__
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(__WIN__)
Dvalp = NULL;
memset(&FileData, 0, sizeof(_finddata_t));
hSearch = INVALID_HANDLE_VALUE;
*Drive = '\0';
#else // !__WIN__
memset(&Fileinfo, 0, sizeof(struct stat));
Entry = NULL;
Dir = NULL;
Done = false;
*Pattern = '\0';
#endif // !__WIN__
*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 = PlgGetCatalog(g);
PTABDEF defp = (PTABDEF)To_Def;
#if defined(__WIN__)
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 // !__WIN__
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 // !__WIN__
} // 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 rc, n = -1;
#if defined(__WIN__)
// 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);
sprintf(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) {
sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
FindClose(hSearch);
return -1;
} // endif rc
break;
} // endif Next
} // endwhile
// Close the search handle.
FindClose(hSearch);
#else // !__WIN__
Path(g);
// Start searching files in the target directory.
if (!(Dir = opendir(Direc))) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
return -1;
} // endif dir
while ((Entry = readdir(Dir))) {
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
return -1;
} else if (S_ISREG(Fileinfo.st_mode))
// Test whether the file name matches the table name filter
if (!fnmatch(Pattern, Entry->d_name, 0))
n++; // We have a match
} // endwhile Entry
// Close the DIR handle.
closedir(Dir);
#endif // !__WIN__
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(__WIN__)
Path(g); // Be sure it is done
Dir = NULL; // For ReadDB
#endif // !__WIN__
return false;
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for DIR access method. */
/***********************************************************************/
int TDBDIR::ReadDB(PGLOBAL g)
{
int rc = RC_OK;
#if defined(__WIN__)
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))) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
rc = RC_FX;
} // endif dir
while (rc == RC_NF)
if ((Entry = readdir(Dir))) {
// We need the Fileinfo structure to get info about the file
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
rc = RC_FX;
} else if (S_ISREG(Fileinfo.st_mode))
// Test whether the file name matches the table name filter
if (!fnmatch(Pattern, Entry->d_name, 0)) {
iFile++; // We have a match
_splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
rc = RC_OK;
} // endif fnmatch
} else {
// Restore file name and type pattern
_splitpath(To_File, NULL, NULL, Fname, Ftype);
rc = RC_EF;
} // endif Entry
#endif // !__WIN__
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(__WIN__)
// Close the search handle.
FindClose(hSearch);
hSearch = INVALID_HANDLE_VALUE;
#else // !__WIN__
// Close the DIR handle
if (Dir) {
closedir(Dir);
Dir = NULL;
} // endif dir
#endif // !__WIN__
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(__WIN__)
/***********************************************************************/
/* 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 // __WIN__
/***********************************************************************/
/* 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(__WIN__)
case 0: Value->SetValue_psz(Tdbp->Drive); break;
#endif // __WIN__
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(__WIN__)
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 // !__WIN__
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 // !__WIN__
default:
sprintf(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 rc, n = 0;
size_t m = strlen(Direc);
// Start searching files in the target directory.
#if defined(__WIN__)
HANDLE h;
#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);
sprintf(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) {
sprintf(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);
sprintf(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) {
sprintf(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 // !__WIN__
int k;
DIR *dir = opendir(Direc);
if (!dir) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
return -1;
} // endif dir
while ((Entry = readdir(dir))) {
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
return -1;
} else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
// Look in the name sub-directory
strcat(strcat(Direc, Entry->d_name), "/");
if ((k = FindInDir(g)) < 0)
return k;
else
n += k;
Direc[m] = '\0'; // Restore path
} else if (S_ISREG(Fileinfo.st_mode))
// Test whether the file name matches the table name filter
if (!fnmatch(Pattern, Entry->d_name, 0))
n++; // We have a match
} // endwhile readdir
// Close the DIR handle.
closedir(dir);
#endif // !__WIN__
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(__WIN__)
Sub->H = INVALID_HANDLE_VALUE;
Sub->Len = strlen(Direc);
#else // !__WIN__
Sub->D = NULL;
Sub->Len = 0;
#endif // !__WIN__
} // 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(__WIN__)
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 // !__WIN__
rc = RC_NF;
again:
if (!Sub->D)
// Start searching files in the target directory.
if (!(Sub->D = opendir(Direc))) {
sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
rc = RC_FX;
} // endif dir
while (rc == RC_NF)
if ((Entry = readdir(Sub->D))) {
// We need the Fileinfo structure to get info about the file
strcat(strcpy(Fpath, Direc), Entry->d_name);
if (lstat(Fpath, &Fileinfo) < 0) {
sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
rc = RC_FX;
} else if (S_ISDIR(Fileinfo.st_mode) && 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 // !__WIN__
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);
sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
} // endswitch rc
} else {
for (n = 1;; n++)
if (!FindNextFile(h, &FileData)) {
rc = GetLastError();
if (rc != ERROR_NO_MORE_FILES) {
sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
n = -1;
} // endif rc
break;
} // endif FindNextFile
// Close the search handle.
if (!FindClose(h) && n != -1)
strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
} // endif Hsearch
MaxSize = n;
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* DHR Access Method opening routine. */
/* Open first file, other will be opened sequencially when reading. */
/***********************************************************************/
bool TDBDHR::OpenDB(PGLOBAL g)
{
if (trace(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
sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
return true;
} // endif NeedIndexing
Use = USE_OPEN;
return false;
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for DHR access method. */
/***********************************************************************/
int TDBDHR::ReadDB(PGLOBAL g)
{
int rc = RC_OK;
DWORD erc;
if (Hsearch == INVALID_HANDLE_VALUE) {
char *filename[_MAX_PATH];
PDBUSER dup = PlgGetUser(g);
PlugSetPath(filename, To_File, dup->Path);
_splitpath(filename, Drive, Direc, NULL, NULL);
/*******************************************************************/
/* Start searching files in the target directory. */
/*******************************************************************/
Hsearch = FindFirstFile(filename, &FileData);
if (Hsearch != INVALID_HANDLE_VALUE)
iFile = 1;
else switch (erc = GetLastError()) {
case ERROR_NO_MORE_FILES:
case ERROR_FILE_NOT_FOUND:
// case ERROR_PATH_NOT_FOUND: ???????
rc = RC_EF;
break;
default:
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, erc, 0,
(LPTSTR)&filename, sizeof(filename), NULL);
sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
rc = RC_FX;
} // endswitch erc
} else {
if (!FindNextFile(Hsearch, &FileData)) {
DWORD erc = GetLastError();
if (erc != ERROR_NO_MORE_FILES) {
sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
FindClose(Hsearch);
rc = RC_FX;
} else
rc = RC_EF;
} else
iFile++;
} // endif Hsearch
if (rc == RC_OK)
_splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
return rc;
} // end of ReadDB
/***********************************************************************/
/* Data Base close routine for MUL access method. */
/***********************************************************************/
void TDBDHR::CloseDB(PGLOBAL g)
{
// Close the search handle.
if (!FindClose(Hsearch)) {
strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
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