mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
Adding the CONNECT storage engine sources.
This commit is contained in:
65
storage/connect/CMakeLists.txt
Normal file
65
storage/connect/CMakeLists.txt
Normal file
@@ -0,0 +1,65 @@
|
||||
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
if( WITH_WARNINGS )
|
||||
add_definitions(-Wall -Wfatal-errors -Wextra)
|
||||
message(STATUS "GCC: All warnings enabled")
|
||||
else()
|
||||
add_definitions(--no-warnings)
|
||||
message(STATUS "GCC: All warnings disabled")
|
||||
endif()
|
||||
|
||||
add_definitions( -DUNIX -DLINUX -DUBUNTU -DMARIADB -DFORCE_INIT_OF_VARS -DMYSQL_DYNAMIC_PLUGIN )
|
||||
add_definitions( -DHUGE_SUPPORT -DXML_SUPPORT -DMYSQL_SUPPORT -DZIP_SUPPORT -DODBC_SUPPORT )
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -fexceptions -fPIC ")
|
||||
INCLUDE_DIRECTORIES(/usr/include/libxml2)
|
||||
INCLUDE_DIRECTORIES(/usr/include/i386-linux-gnu)
|
||||
INCLUDE_DIRECTORIES()
|
||||
get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
|
||||
message("inc_dirs = ${inc_dirs}")
|
||||
|
||||
SET(CONNECT_PLUGIN_STATIC "connect")
|
||||
SET(CONNECT_PLUGIN_DYNAMIC "connect")
|
||||
|
||||
SET(CONNECT_SOURCES
|
||||
ha_connect.cc connect.cc user_connect.cc mycat.cc
|
||||
fmdlex.c inihandl.c osutil.c plugutil.c rcmsg.c
|
||||
csort.cpp maputil.cpp plgdbutl.cpp
|
||||
colblk.cpp reldef.cpp tabcol.cpp table.cpp
|
||||
filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp
|
||||
tabdos.cpp tabfix.cpp tabfmt.cpp tabmul.cpp tabsys.cpp tabvct.cpp
|
||||
valblk.cpp value.cpp xindex.cpp xobject.cpp
|
||||
tabodbc.cpp odbconn.cpp
|
||||
filamzip.cpp tabtbl.cpp myconn.cpp myutil.cpp tabmysql.cpp
|
||||
tabxml.cpp plgxml.cpp libdoc.cpp)
|
||||
|
||||
|
||||
SET(XML_LIBRARY "-L/usr/lib/i386-linux-gnu -lxml2")
|
||||
#SET(MYSQL_LIBRARY "-L/usr/local/mysql/lib -lmysqlclient")
|
||||
#SET(MYSQL_LIBRARY "-L/ ../../libmysql/libmysqlclient.a")
|
||||
|
||||
# For static linking
|
||||
SET(MYSQL_LIBRARY mysqlclient)
|
||||
|
||||
# For dynaric linking
|
||||
#SET(MYSQL_LIBRARY libmysql)
|
||||
|
||||
SET(ODBC_LIBRARY "-L/usr/lib -lodbc")
|
||||
|
||||
MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
|
||||
STORAGE_ENGINE MODULE_ONLY
|
||||
MODULE_OUTPUT_NAME "ha_connect"
|
||||
LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${MYSQL_LIBRARY} ${ODBC_LIBRARY})
|
||||
57
storage/connect/block.h
Normal file
57
storage/connect/block.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/**************** Block H Declares Source Code File (.H) ***************/
|
||||
/* Name: BLOCK.H Version 2.0 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998 */
|
||||
/* */
|
||||
/* This file contains the BLOCK pure virtual class definition. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* Note: one of the main purpose of this base class is to take care */
|
||||
/* of the very specific way Plug handles memory allocation. */
|
||||
/* Instead of allocating small chunks of storage via new or malloc */
|
||||
/* Plug works in its private memory pool in which it does the sub- */
|
||||
/* allocation using the function PlugSubAlloc. These are never freed */
|
||||
/* separately but when a transaction is terminated, the entire pool */
|
||||
/* is set to empty, resulting in a very fast and efficient allocate */
|
||||
/* process, no garbage collection problem, and an automatic recovery */
|
||||
/* procedure (via LongJump) when the memory is exhausted. */
|
||||
/* For this to work new must be given two parameters, first the */
|
||||
/* global pointer of the Plug application, and an optional pointer to */
|
||||
/* the memory pool to use, defaulting to NULL meaning using the Plug */
|
||||
/* standard default memory pool, example: */
|
||||
/* tabp = new(g) XTAB("EMPLOYEE"); */
|
||||
/* allocates a XTAB class object in the standard Plug memory pool. */
|
||||
/***********************************************************************/
|
||||
#if !defined(BLOCK_DEFINED)
|
||||
#define BLOCK_DEFINED
|
||||
|
||||
#if defined(WIN32) && !defined(NOEX)
|
||||
#define DllExport __declspec( dllexport )
|
||||
#else // !WIN32
|
||||
#define DllExport
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definition of class BLOCK with its method function new. */
|
||||
/***********************************************************************/
|
||||
typedef class BLOCK *PBLOCK;
|
||||
|
||||
class DllExport BLOCK {
|
||||
public:
|
||||
void * operator new(size_t size, PGLOBAL g, void *p = NULL) {
|
||||
#ifdef DEBTRACE
|
||||
if (debug != NULL)
|
||||
htrc("New BLOCK: size=%d g=%p p=%p\n", size, g, p);
|
||||
#endif
|
||||
return (PlugSubAlloc(g, p, size));
|
||||
} // end of new
|
||||
|
||||
virtual void Print(PGLOBAL, FILE *, uint) {} // Produce file desc
|
||||
virtual void Print(PGLOBAL, char *, uint) {} // Produce string desc
|
||||
|
||||
#if !defined(__BORLANDC__)
|
||||
// Avoid warning C4291 by defining a matching dummy delete operator
|
||||
void operator delete(void *, PGLOBAL, void *) {}
|
||||
#endif
|
||||
}; // end of class BLOCK
|
||||
|
||||
#endif // !BLOCK_DEFINED
|
||||
150
storage/connect/catalog.h
Normal file
150
storage/connect/catalog.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/*************** Catalog H Declares Source Code File (.H) **************/
|
||||
/* Name: CATALOG.H Version 3.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2000-2012 */
|
||||
/* */
|
||||
/* This file contains the CATALOG PlugDB classes definitions. */
|
||||
/***********************************************************************/
|
||||
#ifndef __CATALOG__H
|
||||
#define __CATALOG__H
|
||||
|
||||
#include "block.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Defines the length of a buffer to contain entire table section. */
|
||||
/***********************************************************************/
|
||||
#define PLG_MAX_PATH 144 /* Must be the same across systems */
|
||||
#define PLG_BUFF_LEN 100 /* Number of lines in binary file buffer */
|
||||
|
||||
#if !defined(WIN32)
|
||||
/**************************************************************************/
|
||||
/* Defines specific to Windows and ODBC. */
|
||||
/**************************************************************************/
|
||||
#define SQL_CHAR 1
|
||||
#define SQL_NUMERIC 2
|
||||
#define SQL_DECIMAL 3
|
||||
#define SQL_INTEGER 4
|
||||
#define SQL_SMALLINT 5
|
||||
#define SQL_FLOAT 6
|
||||
#define SQL_REAL 7
|
||||
#define SQL_DOUBLE 8
|
||||
#define SQL_TIMESTAMP 11
|
||||
#define SQL_VARCHAR 12
|
||||
#define SQL_NULLABLE_UNKNOWN 2
|
||||
#define SQL_ALL_EXCEPT_LIKE 2
|
||||
#define SQL_SEARCHABLE 3
|
||||
#define SQL_ALL_TYPES 0
|
||||
#define SQL_TABLE_STAT 0
|
||||
#define SQL_BEST_ROWID 1
|
||||
#define SQL_PC_NOT_PSEUDO 1
|
||||
#define SQL_PC_PSEUDO 2
|
||||
#define SQL_SCOPE_CURROW 0
|
||||
#endif // !WIN32
|
||||
|
||||
//typedef class INDEXDEF *PIXDEF;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Defines the structure used to enumerate tables or views. */
|
||||
/***********************************************************************/
|
||||
typedef struct _curtab {
|
||||
PRELDEF CurTdb;
|
||||
char *Curp;
|
||||
char *Tabpat;
|
||||
bool Ispat;
|
||||
bool NoView;
|
||||
int Nt;
|
||||
char *Type[16];
|
||||
} CURTAB, *PCURTAB;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Defines the structure used to get column catalog info. */
|
||||
/***********************************************************************/
|
||||
typedef struct _colinfo {
|
||||
char *Name;
|
||||
int Type;
|
||||
int Offset;
|
||||
int Length;
|
||||
int Key;
|
||||
int Prec;
|
||||
int Opt;
|
||||
char *Remark;
|
||||
char *Datefmt;
|
||||
char *Fieldfmt;
|
||||
ushort Flags; // Used by MariaDB CONNECT handlers
|
||||
} COLINFO, *PCOLINFO;
|
||||
|
||||
/***********************************************************************/
|
||||
/* CATALOG: base class for catalog classes. */
|
||||
/***********************************************************************/
|
||||
class DllExport CATALOG {
|
||||
friend class RELDEF;
|
||||
friend class TABDEF;
|
||||
friend class DIRDEF;
|
||||
friend class OEMDEF;
|
||||
public:
|
||||
CATALOG(void); // Constructor
|
||||
|
||||
// Implementation
|
||||
void *GetDescp(void) {return Descp;}
|
||||
PRELDEF GetTo_Desc(void) {return To_Desc;}
|
||||
//PSZ GetDescFile(void) {return DescFile;}
|
||||
int GetCblen(void) {return Cblen;}
|
||||
bool GetDefHuge(void) {return DefHuge;}
|
||||
void SetDefHuge(bool b) {DefHuge = b;}
|
||||
bool GetSepIndex(void) {return SepIndex;}
|
||||
void SetSepIndex(bool b) {SepIndex = b;}
|
||||
char *GetCbuf(void) {return Cbuf;}
|
||||
char *GetDataPath(void) {return (char*)DataPath;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void) {}
|
||||
virtual void SetDataPath(PGLOBAL g, const char *path) {}
|
||||
virtual bool GetBoolCatInfo(LPCSTR name, PSZ what, bool bdef) {return bdef;}
|
||||
virtual bool SetIntCatInfo(LPCSTR name, PSZ what, int ival) {return false;}
|
||||
virtual int GetIntCatInfo(LPCSTR name, PSZ what, int idef) {return idef;}
|
||||
virtual int GetSizeCatInfo(LPCSTR name, PSZ what, PSZ sdef) {return 0;}
|
||||
virtual int GetCharCatInfo(LPCSTR name, PSZ what, PSZ sdef, char *buf, int size)
|
||||
{strncpy(buf, sdef, size); return size;}
|
||||
virtual char *GetStringCatInfo(PGLOBAL g, PSZ name, PSZ what, PSZ sdef)
|
||||
{return sdef;}
|
||||
virtual int GetColCatInfo(PGLOBAL g, PTABDEF defp) {return -1;}
|
||||
virtual bool GetIndexInfo(PGLOBAL g, PTABDEF defp) {return true;}
|
||||
virtual bool CheckName(PGLOBAL g, char *name) {return true;}
|
||||
virtual bool ClearName(PGLOBAL g, PSZ name) {return true;}
|
||||
virtual PRELDEF MakeOneTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am) {return NULL;}
|
||||
virtual PRELDEF GetTableDescEx(PGLOBAL g, PTABLE tablep) {return NULL;}
|
||||
virtual PRELDEF GetTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am,
|
||||
PRELDEF *prp = NULL) {return NULL;}
|
||||
virtual PRELDEF GetFirstTable(PGLOBAL g) {return NULL;}
|
||||
virtual PRELDEF GetNextTable(PGLOBAL g) {return NULL;}
|
||||
virtual bool TestCond(PGLOBAL g, const char *name, const char *type) {return true;}
|
||||
virtual bool DropTable(PGLOBAL g, PSZ name, bool erase) {return true;}
|
||||
virtual PTDB GetTable(PGLOBAL g, PTABLE tablep, MODE mode = MODE_READ) {return NULL;}
|
||||
virtual void TableNames(PGLOBAL g, char *buffer, int maxbuf, int info[]) {}
|
||||
virtual void ColumnNames(PGLOBAL g, char *tabname, char *buffer,
|
||||
int maxbuf, int info[]) {}
|
||||
virtual void ColumnDefs(PGLOBAL g, char *tabname, char *buffer,
|
||||
int maxbuf, int info[]) {}
|
||||
virtual void *DecodeValues(PGLOBAL g, char *tabname, char *colname,
|
||||
char *buffer, int maxbuf, int info[]) {return NULL;}
|
||||
virtual int ColumnType(PGLOBAL g, char *tabname, char *colname) {return 0;}
|
||||
virtual void ClearDB(PGLOBAL g) {}
|
||||
|
||||
protected:
|
||||
virtual bool ClearSection(PGLOBAL g, const char *key, const char *section) {return true;}
|
||||
virtual PRELDEF MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am) {return NULL;}
|
||||
|
||||
// Members
|
||||
PRELDEF To_Desc; /* To chain of relation desc. */
|
||||
void *Descp; /* To DB description area */
|
||||
//AREADEF DescArea; /* Table desc. area size */
|
||||
char *Cbuf; /* Buffer used for col section */
|
||||
int Cblen; /* Length of suballoc. buffer */
|
||||
CURTAB Ctb; /* Used to enumerate tables */
|
||||
bool DefHuge; /* true: tables default to huge */
|
||||
bool SepIndex; /* true: separate index files */
|
||||
//char DescFile[_MAX_PATH]; /* DB description filename */
|
||||
LPCSTR DataPath; /* Is the Path of DB data dir */
|
||||
}; // end of class CATALOG
|
||||
|
||||
#endif // __CATALOG__H
|
||||
42
storage/connect/checklvl.h
Normal file
42
storage/connect/checklvl.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/************** PlgDBSem H Declares Source Code File (.H) **************/
|
||||
/* Name: CHKLVL.H Version 1.1 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2009 */
|
||||
/* */
|
||||
/* This file contains the definition of the checking level constants. */
|
||||
/***********************************************************************/
|
||||
|
||||
#if !defined(_CHKLVL_DEFINED_)
|
||||
#define _CHKLVL_DEFINED_
|
||||
/***********************************************************************/
|
||||
/* Following definitions are used to indicate the level of checking. */
|
||||
/***********************************************************************/
|
||||
enum CHKLVL {CHK_NO = 0x00, /* No checking */
|
||||
CHK_TYPE = 0x01, /* Check types for Insert/Update */
|
||||
CHK_UPDATE = 0x02, /* Two pass checking of Update */
|
||||
CHK_DELETE = 0x04, /* Indexed checking of Delete */
|
||||
CHK_JOIN = 0x08, /* Check types joining tables */
|
||||
CHK_OPT = 0x10, /* Automatic optimize on changes */
|
||||
CHK_MANY = 0x20, /* Check many-to-many joins */
|
||||
CHK_ALL = 0x3F, /* All of the above */
|
||||
CHK_STD = 0x1E, /* Standard level of checking */
|
||||
CHK_MAXRES = 0x40, /* Prevent Maxres recalculation */
|
||||
CHK_ONLY = 0x100}; /* Just check, no action (NIY) */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Following definitions are used to indicate the execution mode. */
|
||||
/***********************************************************************/
|
||||
enum XMOD {XMOD_EXECUTE = 0, /* DOS execution mode */
|
||||
XMOD_PREPARE = 1, /* Prepare mode */
|
||||
XMOD_TEST = 2, /* Test mode */
|
||||
XMOD_CONVERT = 3}; /* HQL conversion mode */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Following definitions indicate the use of a temporay file. */
|
||||
/***********************************************************************/
|
||||
enum USETEMP {TMP_AUTO = 0, /* Best choice */
|
||||
TMP_NO = 1, /* Never */
|
||||
TMP_YES = 2, /* Always */
|
||||
TMP_FORCE = 3}; /* Forced for MAP tables */
|
||||
|
||||
#endif // _CHKLVL_DEFINED_
|
||||
379
storage/connect/colblk.cpp
Normal file
379
storage/connect/colblk.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/************* Colblk C++ Functions Source Code File (.CPP) ************/
|
||||
/* Name: COLBLK.CPP Version 1.9 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
|
||||
/* */
|
||||
/* This file contains the COLBLK class functions. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/* global.h is header containing all global Plug declarations. */
|
||||
/* plgdbsem.h is header containing the DB applic. declarations. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "tabcol.h"
|
||||
#include "colblk.h"
|
||||
#include "xindex.h"
|
||||
#include "xtable.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* COLBLK protected constructor. */
|
||||
/***********************************************************************/
|
||||
COLBLK::COLBLK(PCOLDEF cdp, PTDB tdbp, int i)
|
||||
{
|
||||
Next = NULL;
|
||||
Index = i;
|
||||
//Number = 0;
|
||||
ColUse = 0;
|
||||
|
||||
if ((Cdp = cdp)) {
|
||||
Name = cdp->Name;
|
||||
Format = cdp->F;
|
||||
Opt = cdp->Opt;
|
||||
Long = cdp->Long;
|
||||
Buf_Type = cdp->Buf_Type;
|
||||
ColUse |= cdp->Flags; // Used by CONNECT
|
||||
} else {
|
||||
Name = NULL;
|
||||
memset(&Format, 0, sizeof(FORMAT));
|
||||
Opt = 0;
|
||||
Long = 0;
|
||||
Buf_Type = TYPE_ERROR;
|
||||
} // endif cdp
|
||||
|
||||
To_Tdb = tdbp;
|
||||
Status = BUF_NO;
|
||||
//Value = NULL; done in XOBJECT constructor
|
||||
To_Kcol = NULL;
|
||||
} // end of COLBLK constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* COLBLK constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
COLBLK::COLBLK(PCOL col1, PTDB tdbp)
|
||||
{
|
||||
PCOL colp;
|
||||
|
||||
// Copy the old column block to the new one
|
||||
*this = *col1;
|
||||
Next = NULL;
|
||||
//To_Orig = col1;
|
||||
To_Tdb = tdbp;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" copying COLBLK %s from %p to %p\n", Name, col1, this);
|
||||
#endif
|
||||
|
||||
if (tdbp)
|
||||
// Attach the new column to the table block
|
||||
if (!tdbp->GetColumns())
|
||||
tdbp->SetColumns(this);
|
||||
else {
|
||||
for (colp = tdbp->GetColumns(); colp->Next; colp = colp->Next) ;
|
||||
|
||||
colp->Next = this;
|
||||
} // endelse
|
||||
|
||||
} // end of COLBLK copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset the column descriptor to non evaluated yet. */
|
||||
/***********************************************************************/
|
||||
void COLBLK::Reset(void)
|
||||
{
|
||||
Status &= ~BUF_READ;
|
||||
} // end of Reset
|
||||
|
||||
/***********************************************************************/
|
||||
/* Compare: compares itself to an (expression) object and returns */
|
||||
/* true if it is equivalent. */
|
||||
/***********************************************************************/
|
||||
bool COLBLK::Compare(PXOB xp)
|
||||
{
|
||||
return (this == xp);
|
||||
} // end of Compare
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetFormat: function used to set SELECT output format. */
|
||||
/***********************************************************************/
|
||||
bool COLBLK::SetFormat(PGLOBAL g, FORMAT& fmt)
|
||||
{
|
||||
fmt = Format;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("COLBLK: %p format=%c(%d,%d)\n",
|
||||
this, *fmt.Type, fmt.Length, fmt.Prec);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
} // end of SetFormat
|
||||
|
||||
/***********************************************************************/
|
||||
/* CheckColumn: a column descriptor is found, say it by returning 1. */
|
||||
/***********************************************************************/
|
||||
int COLBLK::CheckColumn(PGLOBAL g, PSQL sqlp, PXOB &p, int &ag)
|
||||
{
|
||||
return 1;
|
||||
} // end of CheckColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* Eval: get the column value from the last read record or from a */
|
||||
/* matching Index column if there is one. */
|
||||
/***********************************************************************/
|
||||
bool COLBLK::Eval(PGLOBAL g)
|
||||
{
|
||||
#ifdef DEBTRACE
|
||||
htrc("Col Eval: %s status=%.4X\n", Name, Status);
|
||||
#endif
|
||||
|
||||
if (!GetStatus(BUF_READ)) {
|
||||
// if (To_Tdb->IsNull())
|
||||
// Value->Reset();
|
||||
if (To_Kcol)
|
||||
To_Kcol->FillValue(Value);
|
||||
else
|
||||
ReadColumn(g);
|
||||
|
||||
AddStatus(BUF_READ);
|
||||
} // endif
|
||||
|
||||
return false;
|
||||
} // end of Eval
|
||||
|
||||
/***********************************************************************/
|
||||
/* CheckSort: */
|
||||
/* Used to check that a table is involved in the sort list items. */
|
||||
/***********************************************************************/
|
||||
bool COLBLK::CheckSort(PTDB tdbp)
|
||||
{
|
||||
return (tdbp == To_Tdb);
|
||||
} // end of CheckSort
|
||||
|
||||
/***********************************************************************/
|
||||
/* MarkCol: see PlugMarkCol for column references to mark. */
|
||||
/***********************************************************************/
|
||||
void COLBLK::MarkCol(ushort bits)
|
||||
{
|
||||
ColUse |= bits;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" column R%d.%s marked as %04X\n",
|
||||
To_Tdb->GetTdb_No(), Name, ColUse);
|
||||
#endif
|
||||
} // end of MarkCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* InitValue: prepare a column block for read operation. */
|
||||
/* Now we use Format.Length for the len parameter to avoid strings */
|
||||
/* to be truncated when converting from string to coded string. */
|
||||
/* Added in version 1.5 is the arguments GetPrecision() and Domain */
|
||||
/* in calling AllocateValue. Domain is used for TYPE_TOKEN only, */
|
||||
/* but why was GetPrecision() not specified ? To be checked. */
|
||||
/***********************************************************************/
|
||||
bool COLBLK::InitValue(PGLOBAL g)
|
||||
{
|
||||
if (Value)
|
||||
return false; // Already done
|
||||
|
||||
// Allocate a Value object
|
||||
if (!(Value = AllocateValue(g, Buf_Type, Format.Length,
|
||||
GetPrecision(), GetDomain(),
|
||||
(To_Tdb) ? To_Tdb->GetCat() : NULL)))
|
||||
return true;
|
||||
|
||||
Status = BUF_READY;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" colp=%p type=%d value=%p coluse=%.4X status=%.4X\n",
|
||||
this, Buf_Type, Value, ColUse, Status);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
} // end of InitValue
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetBuffer: prepare a column block for write operation. */
|
||||
/***********************************************************************/
|
||||
bool COLBLK::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
|
||||
{
|
||||
sprintf(g->Message, MSG(UNDEFINED_AM), "SetBuffer");
|
||||
return true;
|
||||
} // end of SetBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetLength: returns an evaluation of the column string length. */
|
||||
/***********************************************************************/
|
||||
int COLBLK::GetLengthEx(void)
|
||||
{
|
||||
return Long;
|
||||
} // end of GetLengthEx
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to access the last line */
|
||||
/* read from the corresponding table, extract from it the field */
|
||||
/* corresponding to this column and convert it to buffer type. */
|
||||
/***********************************************************************/
|
||||
void COLBLK::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
sprintf(g->Message, MSG(UNDEFINED_AM), "ReadColumn");
|
||||
longjmp(g->jumper[g->jump_level], TYPE_COLBLK);
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteColumn: what this routine does is to access the last line */
|
||||
/* read from the corresponding table, and rewrite the field */
|
||||
/* corresponding to this column from the column buffer and type. */
|
||||
/***********************************************************************/
|
||||
void COLBLK::WriteColumn(PGLOBAL g)
|
||||
{
|
||||
sprintf(g->Message, MSG(UNDEFINED_AM), "WriteColumn");
|
||||
longjmp(g->jumper[g->jump_level], TYPE_COLBLK);
|
||||
} // end of WriteColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make file output of a column descriptor block. */
|
||||
/***********************************************************************/
|
||||
void COLBLK::Print(PGLOBAL g, FILE *f, uint n)
|
||||
{
|
||||
char m[64];
|
||||
int i;
|
||||
PCOL colp;
|
||||
|
||||
memset(m, ' ', n); // Make margin string
|
||||
m[n] = '\0';
|
||||
|
||||
for (colp = To_Tdb->GetColumns(), i = 1; colp; colp = colp->Next, i++)
|
||||
if (colp == this)
|
||||
break;
|
||||
|
||||
fprintf(f, "%sR%dC%d type=%d F=%.2s(%d,%d)", m, To_Tdb->GetTdb_No(),
|
||||
i, GetAmType(), Format.Type, Format.Length, Format.Prec);
|
||||
fprintf(f,
|
||||
" coluse=%04X status=%04X buftyp=%d value=%p name=%s\n",
|
||||
ColUse, Status, Buf_Type, Value, Name);
|
||||
} // end of Print
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make string output of a column descriptor block. */
|
||||
/***********************************************************************/
|
||||
void COLBLK::Print(PGLOBAL g, char *ps, uint z)
|
||||
{
|
||||
sprintf(ps, "R%d.%s", To_Tdb->GetTdb_No(), Name);
|
||||
} // end of Print
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* SPCBLK constructor. */
|
||||
/***********************************************************************/
|
||||
SPCBLK::SPCBLK(PCOLUMN cp)
|
||||
: COLBLK((PCOLDEF)NULL, cp->GetTo_Table()->GetTo_Tdb(), 0)
|
||||
{
|
||||
Name = (char*)cp->GetName();
|
||||
Long = 0;
|
||||
Buf_Type = TYPE_ERROR;
|
||||
} // end of SPCBLK constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteColumn: what this routine does is to access the last line */
|
||||
/* read from the corresponding table, and rewrite the field */
|
||||
/* corresponding to this column from the column buffer and type. */
|
||||
/***********************************************************************/
|
||||
void SPCBLK::WriteColumn(PGLOBAL g)
|
||||
{
|
||||
sprintf(g->Message, MSG(SPCOL_READONLY), Name);
|
||||
longjmp(g->jumper[g->jump_level], TYPE_COLBLK);
|
||||
} // end of WriteColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* RIDBLK constructor for the ROWID special column. */
|
||||
/***********************************************************************/
|
||||
RIDBLK::RIDBLK(PCOLUMN cp, bool rnm) : SPCBLK(cp)
|
||||
{
|
||||
Long = 10;
|
||||
Buf_Type = TYPE_INT;
|
||||
Rnm = rnm;
|
||||
*Format.Type = 'N';
|
||||
Format.Length = 10;
|
||||
} // end of RIDBLK constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to return the ordinal */
|
||||
/* number of the current row in the table (if Rnm is true) or in the */
|
||||
/* current file (if Rnm is false) the same except for multiple tables.*/
|
||||
/***********************************************************************/
|
||||
void RIDBLK::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
Value->SetValue(To_Tdb->RowNumber(g, Rnm));
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIDBLK constructor for the FILEID special column. */
|
||||
/***********************************************************************/
|
||||
FIDBLK::FIDBLK(PCOLUMN cp) : SPCBLK(cp)
|
||||
{
|
||||
//Is_Key = 2; for when the MUL table indexed reading will be implemented.
|
||||
Long = _MAX_PATH;
|
||||
Buf_Type = TYPE_STRING;
|
||||
*Format.Type = 'C';
|
||||
Format.Length = Long;
|
||||
#if defined(WIN32)
|
||||
Format.Prec = 1; // Case insensitive
|
||||
#endif // WIN32
|
||||
Constant = (!((PTDBASE)To_Tdb)->GetDef()->GetMultiple() &&
|
||||
To_Tdb->GetAmType() != TYPE_AM_PLG &&
|
||||
To_Tdb->GetAmType() != TYPE_AM_PLM);
|
||||
Fn = NULL;
|
||||
} // end of FIDBLK constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to return the current */
|
||||
/* file ID of the table (can change for Multiple tables). */
|
||||
/***********************************************************************/
|
||||
void FIDBLK::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
if (Fn != ((PTDBASE)To_Tdb)->GetFile(g)) {
|
||||
char filename[_MAX_PATH];
|
||||
|
||||
Fn = ((PTDBASE)To_Tdb)->GetFile(g);
|
||||
PlugSetPath(filename, Fn, ((PTDBASE)To_Tdb)->GetPath());
|
||||
Value->SetValue_psz(filename);
|
||||
} // endif Fn
|
||||
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* TIDBLK constructor for the TABID special column. */
|
||||
/***********************************************************************/
|
||||
TIDBLK::TIDBLK(PCOLUMN cp) : SPCBLK(cp)
|
||||
{
|
||||
//Is_Key = 2; for when the MUL table indexed reading will be implemented.
|
||||
Long = 64;
|
||||
Buf_Type = TYPE_STRING;
|
||||
*Format.Type = 'C';
|
||||
Format.Length = Long;
|
||||
Format.Prec = 1; // Case insensitive
|
||||
Constant = (To_Tdb->GetAmType() != TYPE_AM_PLG &&
|
||||
To_Tdb->GetAmType() != TYPE_AM_PLM);
|
||||
Tname = NULL;
|
||||
} // end of TIDBLK constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to return the table ID. */
|
||||
/***********************************************************************/
|
||||
void TIDBLK::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
if (Tname == NULL) {
|
||||
Tname = (char*)To_Tdb->GetName();
|
||||
Value->SetValue_psz(Tname);
|
||||
} // endif Tname
|
||||
|
||||
} // end of ReadColumn
|
||||
|
||||
180
storage/connect/colblk.h
Normal file
180
storage/connect/colblk.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/*************** Colblk H Declares Source Code File (.H) ***************/
|
||||
/* Name: COLBLK.H Version 1.5 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the COLBLK and derived classes declares. */
|
||||
/***********************************************************************/
|
||||
#ifndef __COLBLK__H
|
||||
#define __COLBLK__H
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/***********************************************************************/
|
||||
#include "xobject.h"
|
||||
#include "reldef.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class COLBLK: Base class for table column descriptors. */
|
||||
/***********************************************************************/
|
||||
class DllExport COLBLK : public XOBJECT {
|
||||
friend class TDBPIVOT;
|
||||
protected:
|
||||
// Default constructors used by derived classes
|
||||
COLBLK(PCOLDEF cdp = NULL, PTDB tdbp = NULL, int i = 0);
|
||||
COLBLK(PCOL colp, PTDB tdbp = NULL); // Used in copy process
|
||||
COLBLK(int n) {} // Used when changing a column class in TDBXML
|
||||
|
||||
public:
|
||||
// Implementation
|
||||
virtual int GetType(void) {return TYPE_COLBLK;}
|
||||
virtual int GetResultType(void) {return Buf_Type;}
|
||||
virtual int GetPrecision(void) {return Format.Prec;}
|
||||
virtual int GetLength(void) {return Long;}
|
||||
virtual int GetLengthEx(void);
|
||||
virtual int GetAmType() {return TYPE_AM_ERROR;}
|
||||
virtual void SetOk(void) {Status |= BUF_EMPTY;}
|
||||
virtual PTDB GetTo_Tdb(void) {return To_Tdb;}
|
||||
PCOL GetNext(void) {return Next;}
|
||||
PSZ GetName(void) {return Name;}
|
||||
int GetIndex(void) {return Index;}
|
||||
int GetOpt(void) {return Opt;}
|
||||
ushort GetColUse(void) {return ColUse;}
|
||||
ushort GetColUse(ushort u) {return (ColUse & u);}
|
||||
ushort GetStatus(void) {return Status;}
|
||||
ushort GetStatus(ushort u) {return (Status & u);}
|
||||
void SetColUse(ushort u) {ColUse = u;}
|
||||
void SetStatus(ushort u) {Status = u;}
|
||||
void AddColUse(ushort u) {ColUse |= u;}
|
||||
void AddStatus(ushort u) {Status |= u;}
|
||||
void SetNext(PCOL cp) {Next = cp;}
|
||||
void SetKcol(PXCOL kcp) {To_Kcol = kcp;}
|
||||
PCOLDEF GetCdp(void) {return Cdp;}
|
||||
PSZ GetDomain(void) {return (Cdp) ? Cdp->Decode : NULL;}
|
||||
PSZ GetDesc(void) {return (Cdp) ? Cdp->Desc : NULL;}
|
||||
PSZ GetFmt(void) {return (Cdp) ? Cdp->Fmt : NULL;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual bool Compare(PXOB xp);
|
||||
virtual bool SetFormat(PGLOBAL, FORMAT&);
|
||||
virtual int CheckColumn(PGLOBAL g, PSQL sqlp, PXOB &xp, int &ag);
|
||||
virtual bool IsSpecial(void) {return false;}
|
||||
virtual int CheckSpcCol(PTDB tdbp, int n) {return 2;}
|
||||
virtual bool CheckSort(PTDB tdbp);
|
||||
virtual void MarkCol(ushort bits);
|
||||
virtual bool Eval(PGLOBAL g);
|
||||
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
|
||||
virtual void SetTo_Val(PVAL valp) {}
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
virtual void Print(PGLOBAL g, FILE *, uint);
|
||||
virtual void Print(PGLOBAL g, char *, uint);
|
||||
virtual bool VarSize(void) {return false;}
|
||||
virtual bool IsColInside(PCOL colp) {return this == colp;}
|
||||
bool InitValue(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PCOL Next; // Next column in table
|
||||
PSZ Name; // Column name
|
||||
PCOLDEF Cdp; // To column definition block
|
||||
PTDB To_Tdb; // Points to Table Descriptor Block
|
||||
PXCOL To_Kcol; // Points to Xindex matching column
|
||||
int Index; // Column number in table
|
||||
int Opt; // Cluster/sort information
|
||||
int Buf_Type; // Data type
|
||||
int Long; // Internal length in table
|
||||
FORMAT Format; // Output format
|
||||
ushort ColUse; // Column usage
|
||||
ushort Status; // Column read status
|
||||
}; // end of class COLBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class SPCBLK: Base class for special column descriptors. */
|
||||
/***********************************************************************/
|
||||
class SPCBLK : public COLBLK {
|
||||
public:
|
||||
// Constructor
|
||||
SPCBLK(PCOLUMN cp);
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) = 0;
|
||||
virtual bool GetRnm(void) {return false;}
|
||||
|
||||
// Methods
|
||||
virtual bool IsSpecial(void) {return true;}
|
||||
virtual void ReadColumn(PGLOBAL g) = 0;
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
SPCBLK(void) : COLBLK(1) {}
|
||||
}; // end of class SPCBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class RIDBLK: ROWID special column descriptor. */
|
||||
/***********************************************************************/
|
||||
class RIDBLK : public SPCBLK {
|
||||
public:
|
||||
// Constructor
|
||||
RIDBLK(PCOLUMN cp, bool rnm);
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_ROWID;}
|
||||
virtual bool GetRnm(void) {return Rnm;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
bool Rnm; // False for RowID, True for RowNum
|
||||
}; // end of class RIDBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class FIDBLK: FILEID special column descriptor. */
|
||||
/***********************************************************************/
|
||||
class FIDBLK : public SPCBLK {
|
||||
public:
|
||||
// Constructor
|
||||
FIDBLK(PCOLUMN cp);
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_FILID;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void) {} // This is a pseudo constant column
|
||||
virtual int CheckSpcCol(PTDB tdbp, int n)
|
||||
{return (n == 2 && tdbp == To_Tdb) ? 1 : 2;}
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
PSZ Fn; // The current To_File of the table
|
||||
}; // end of class FIDBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class TIDBLK: TABID special column descriptor. */
|
||||
/***********************************************************************/
|
||||
class TIDBLK : public SPCBLK {
|
||||
public:
|
||||
// Constructor
|
||||
TIDBLK(PCOLUMN cp);
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_TABID;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void) {} // This is a pseudo constant column
|
||||
virtual int CheckSpcCol(PTDB tdbp, int n)
|
||||
{return (n == 3 && tdbp == To_Tdb) ? 1 : 2;}
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
TIDBLK(void) {}
|
||||
|
||||
// Members
|
||||
PSZ Tname; // The current table name
|
||||
}; // end of class TIDBLK
|
||||
|
||||
#endif // __COLBLK__H
|
||||
866
storage/connect/connect.cc
Normal file
866
storage/connect/connect.cc
Normal file
@@ -0,0 +1,866 @@
|
||||
/* Copyright (C) Olivier Bertrand 2004 - 2012
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Author Olivier BERTRAND bertrandop@gmail.com 2004-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the CONNECT general purpose semantic routines. */
|
||||
/***********************************************************************/
|
||||
#ifdef __GNUC__
|
||||
#pragma implementation // gcc: Class implementation
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files */
|
||||
/* */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing the DB applic. declarations. */
|
||||
/***********************************************************************/
|
||||
#define MYSQL_SERVER 1
|
||||
#define DONT_DEFINE_VOID
|
||||
#include "handler.h"
|
||||
#undef OFFSET
|
||||
|
||||
typedef class ha_connect *PHC;
|
||||
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "xobject.h"
|
||||
#include "connect.h"
|
||||
#include "tabcol.h"
|
||||
#include "catalog.h"
|
||||
#include "ha_connect.h"
|
||||
#include "mycat.h"
|
||||
|
||||
#define my_strupr(p) my_caseup_str(default_charset_info, (p));
|
||||
#define my_strlwr(p) my_casedn_str(default_charset_info, (p));
|
||||
#define my_stricmp(a, b) my_strcasecmp(default_charset_info, (a), (b))
|
||||
|
||||
/***********************************************************************/
|
||||
/* DB static variables. */
|
||||
/***********************************************************************/
|
||||
extern int xtrace;
|
||||
|
||||
#if defined(WIN32)
|
||||
typedef unsigned __int64 ulonglong;
|
||||
#else
|
||||
typedef unsigned long long ulonglong;
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Routines called internally by semantic routines. */
|
||||
/***********************************************************************/
|
||||
void CntEndDB(PGLOBAL);
|
||||
RCODE EvalColumns(PGLOBAL g, PTDB tdbp);
|
||||
|
||||
/***********************************************************************/
|
||||
/* MySQL routines called externally by semantic routines. */
|
||||
/***********************************************************************/
|
||||
int rename_file_ext(const char *from, const char *to,const char *ext);
|
||||
|
||||
/***********************************************************************/
|
||||
/* CntExit: CONNECT termination routine. */
|
||||
/***********************************************************************/
|
||||
PGLOBAL CntExit(PGLOBAL g)
|
||||
{
|
||||
if (g) {
|
||||
PDBUSER dup= PlgGetUser(g);
|
||||
|
||||
CntEndDB(g);
|
||||
PlugExit(g);
|
||||
|
||||
if (dup->Catalog) {
|
||||
delete dup->Catalog;
|
||||
dup->Catalog= NULL;
|
||||
} // endif
|
||||
|
||||
free(dup);
|
||||
g= NULL;
|
||||
} // endif g
|
||||
|
||||
return g;
|
||||
} // end of CntExit
|
||||
|
||||
/***********************************************************************/
|
||||
/* CntEndDB: DB termination semantic routine. */
|
||||
/***********************************************************************/
|
||||
void CntEndDB(PGLOBAL g)
|
||||
{
|
||||
PDBUSER dbuserp= PlgGetUser(g);
|
||||
|
||||
if (dbuserp) {
|
||||
if (dbuserp->Catalog) {
|
||||
delete dbuserp->Catalog;
|
||||
dbuserp->Catalog= NULL;
|
||||
} // endif Catalog
|
||||
|
||||
*dbuserp->Name= '\0';
|
||||
// *dbuserp->Work= '\0';
|
||||
} // endif dbuserp
|
||||
|
||||
} // end of CntEndDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* CntCheckDB: Initialize a DB application session. */
|
||||
/* Note: because MySQL does not call a storage handler when a user */
|
||||
/* executes a use db command, a check must be done before an SQL */
|
||||
/* command is executed to check whether we are still working on the */
|
||||
/* current database, and if not to load the newly used database. */
|
||||
/***********************************************************************/
|
||||
bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname)
|
||||
{
|
||||
bool rc= false;
|
||||
PDBUSER dbuserp= PlgGetUser(g);
|
||||
|
||||
if (xtrace) {
|
||||
printf("CntCheckDB: dbuserp=%p\n", dbuserp);
|
||||
} // endif xtrace
|
||||
|
||||
if (!dbuserp || !handler)
|
||||
return true;
|
||||
|
||||
if (xtrace)
|
||||
printf("cat=%p oldhandler=%p newhandler=%p\n", dbuserp->Catalog,
|
||||
(dbuserp->Catalog) ? ((MYCAT*)dbuserp->Catalog)->GetHandler() : NULL,
|
||||
handler);
|
||||
|
||||
if (dbuserp->Catalog) {
|
||||
// ((MYCAT *)dbuserp->Catalog)->SetHandler(handler); done later
|
||||
((MYCAT *)dbuserp->Catalog)->SetDataPath(g, pathname);
|
||||
return false; // Nothing else to do
|
||||
} // endif Catalog
|
||||
|
||||
// Copy new database name in dbuser block
|
||||
strncpy(dbuserp->Name, "???", sizeof(dbuserp->Name) - 1);
|
||||
|
||||
dbuserp->Vtdbno= 0; // Init of TDB numbers
|
||||
|
||||
/*********************************************************************/
|
||||
/* Now allocate and initialize the Database Catalog. */
|
||||
/*********************************************************************/
|
||||
dbuserp->Step= MSG(READY);
|
||||
|
||||
if (!(dbuserp->Catalog= new MYCAT(handler)))
|
||||
return true;
|
||||
|
||||
((MYCAT *)dbuserp->Catalog)->SetDataPath(g, pathname);
|
||||
dbuserp->UseTemp= TMP_YES; // Must use temporary file
|
||||
|
||||
/*********************************************************************/
|
||||
/* All is correct. */
|
||||
/*********************************************************************/
|
||||
sprintf(g->Message, MSG(DATABASE_LOADED), "???");
|
||||
|
||||
if (xtrace)
|
||||
printf("msg=%s\n", g->Message);
|
||||
|
||||
return rc;
|
||||
} // end of CntCheckDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* CntInfo: Get table info. */
|
||||
/* Returns valid: true if this is a table info. */
|
||||
/***********************************************************************/
|
||||
bool CntInfo(PGLOBAL g, PTDB tp, PXF info)
|
||||
{
|
||||
bool b;
|
||||
PTDBDOS tdbp= (PTDBDOS)tp;
|
||||
|
||||
if (tdbp) {
|
||||
b= tdbp->GetFtype() != RECFM_NAF;
|
||||
info->data_file_length= (b) ? (ulonglong)tdbp->GetFileLength(g) : 0;
|
||||
info->records= (unsigned)tdbp->GetMaxSize(g);
|
||||
// info->mean_rec_length= tdbp->GetLrecl();
|
||||
info->mean_rec_length= 0;
|
||||
info->data_file_name= (b) ? tdbp->GetFile(g) : NULL;
|
||||
return true;
|
||||
} else {
|
||||
info->data_file_length= 0;
|
||||
info->records= 0;
|
||||
info->mean_rec_length= 0;
|
||||
info->data_file_name= NULL;
|
||||
return false;
|
||||
} // endif tdbp
|
||||
|
||||
} // end of CntInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTDB: Get the table description block of a CONNECT table. */
|
||||
/***********************************************************************/
|
||||
PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h)
|
||||
{
|
||||
int rc;
|
||||
PTDB tdbp;
|
||||
PTABLE tabp;
|
||||
PDBUSER dup= PlgGetUser(g);
|
||||
PCATLG cat= (dup) ? dup->Catalog : NULL; // Safe over longjmp
|
||||
|
||||
if (xtrace)
|
||||
printf("CntGetTDB: name=%s mode=%d cat=%p\n", name, mode, cat);
|
||||
|
||||
if (!cat)
|
||||
return NULL;
|
||||
|
||||
// Save stack and allocation environment and prepare error return
|
||||
if (g->jump_level == MAX_JUMP) {
|
||||
strcpy(g->Message, MSG(TOO_MANY_JUMPS));
|
||||
return NULL;
|
||||
} // endif jump_level
|
||||
|
||||
if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) {
|
||||
tdbp= NULL;
|
||||
goto err;
|
||||
} // endif rc
|
||||
|
||||
// Get table object from the catalog
|
||||
tabp= new(g) XTAB(name);
|
||||
|
||||
if (xtrace)
|
||||
printf("CntGetTDB: tabp=%p\n", tabp);
|
||||
|
||||
// Perhaps this should be made thread safe
|
||||
((MYCAT*)cat)->SetHandler(h);
|
||||
|
||||
if (!(tdbp= cat->GetTable(g, tabp, mode)))
|
||||
printf("CntGetTDB: %s\n", g->Message);
|
||||
|
||||
err:
|
||||
if (xtrace)
|
||||
printf("Returning tdbp=%p mode=%d\n", tdbp, mode);
|
||||
|
||||
g->jump_level--;
|
||||
return tdbp;
|
||||
} // end of CntGetTDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* OPENTAB: Open a Table. */
|
||||
/***********************************************************************/
|
||||
bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2,
|
||||
bool del, PHC h)
|
||||
{
|
||||
char *p;
|
||||
int i, n;
|
||||
PCOL colp;
|
||||
PCOLUMN cp;
|
||||
PDBUSER dup= PlgGetUser(g);
|
||||
|
||||
if (xtrace)
|
||||
printf("CntOpenTable: tdbp=%p mode=%d\n", tdbp, mode);
|
||||
|
||||
if (!tdbp) {
|
||||
strcpy(g->Message, "Null tdbp");
|
||||
printf("CntOpenTable: %s\n", g->Message);
|
||||
return true;
|
||||
} // endif tdbp
|
||||
|
||||
if (!c1)
|
||||
// Allocate all column blocks for that table
|
||||
tdbp->ColDB(g, NULL, 0);
|
||||
else for (p= c1; *p; p+= n) {
|
||||
// Allocate only used column blocks
|
||||
if (xtrace)
|
||||
printf("Allocating column %s\n", p);
|
||||
|
||||
if (*p == '*') {
|
||||
// This is a special column
|
||||
cp= new(g) COLUMN(p + 1);
|
||||
cp->SetTo_Table(tdbp->GetTable());
|
||||
colp= ((PTDBASE)tdbp)->InsertSpcBlk(g, cp);
|
||||
} else
|
||||
colp= tdbp->ColDB(g, p, 0);
|
||||
|
||||
if (!colp) {
|
||||
sprintf(g->Message, "Column %s not found in %s", p, tdbp->GetName());
|
||||
return true;
|
||||
} // endif colp
|
||||
|
||||
n= strlen(p) + 1;
|
||||
} // endfor p
|
||||
|
||||
for (i= 0, colp= tdbp->GetColumns(); colp; i++, colp= colp->GetNext()) {
|
||||
if (colp->InitValue(g))
|
||||
return true;
|
||||
|
||||
if (mode == MODE_INSERT)
|
||||
if (colp->SetBuffer(g, colp->GetValue(), true, true))
|
||||
return true;
|
||||
|
||||
colp->AddColUse(U_P); // For PLG tables
|
||||
} // endfor colp
|
||||
|
||||
// Now do open the physical table
|
||||
tdbp->SetMode(mode);
|
||||
|
||||
if (del && ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF) {
|
||||
// To avoid erasing the table when doing a partial delete
|
||||
// make a fake Next
|
||||
PDOSDEF ddp= new(g) DOSDEF;
|
||||
PTDB tp= new(g) TDBDOS(ddp, NULL);
|
||||
tdbp->SetNext(tp);
|
||||
dup->Check &= ~CHK_DELETE;
|
||||
} // endif del
|
||||
|
||||
|
||||
if (xtrace)
|
||||
printf("About to open the table: tdbp=%p\n", tdbp);
|
||||
|
||||
if (mode != MODE_ANY) {
|
||||
if (tdbp->OpenDB(g)) {
|
||||
printf("%s\n", g->Message);
|
||||
return true;
|
||||
} else
|
||||
tdbp->SetNext(NULL);
|
||||
|
||||
} // endif mode
|
||||
|
||||
/*********************************************************************/
|
||||
/* In Update mode, the updated column blocks must be distinct from */
|
||||
/* the read column blocks. So make a copy of the TDB and allocate */
|
||||
/* its column blocks in mode write (required by XML tables). */
|
||||
/*********************************************************************/
|
||||
if (mode == MODE_UPDATE) {
|
||||
PTDBASE utp;
|
||||
|
||||
if (!(utp= (PTDBASE)tdbp->Duplicate(g))) {
|
||||
sprintf(g->Message, MSG(INV_UPDT_TABLE), tdbp->GetName());
|
||||
return true;
|
||||
} // endif tp
|
||||
|
||||
if (!c2)
|
||||
// Allocate all column blocks for that table
|
||||
utp->ColDB(g, NULL, 0);
|
||||
else for (p= c2; *p; p+= n) {
|
||||
// Allocate only used column blocks
|
||||
utp->ColDB(g, p, 0);
|
||||
n= strlen(p) + 1;
|
||||
} // endfor p
|
||||
|
||||
for (i= 0, colp= utp->GetColumns(); colp; i++, colp= colp->GetNext()) {
|
||||
if (colp->InitValue(g))
|
||||
return true;
|
||||
|
||||
if (colp->SetBuffer(g, colp->GetValue(), true, true))
|
||||
return true;
|
||||
|
||||
} // endfor colp
|
||||
|
||||
// Attach the updated columns list to the main table
|
||||
((PTDBASE)tdbp)->SetSetCols(utp->GetColumns());
|
||||
} else if (tdbp && mode == MODE_INSERT)
|
||||
((PTDBASE)tdbp)->SetSetCols(tdbp->GetColumns());
|
||||
|
||||
if (xtrace)
|
||||
printf("Opening table %s in mode %d tdbp=%p\n",
|
||||
tdbp->GetName(), mode, tdbp);
|
||||
|
||||
return false;
|
||||
} // end of CntOpenTable
|
||||
|
||||
/***********************************************************************/
|
||||
/* Rewind a table by reopening it. */
|
||||
/***********************************************************************/
|
||||
bool CntRewindTable(PGLOBAL g, PTDB tdbp)
|
||||
{
|
||||
if (!tdbp)
|
||||
return true;
|
||||
|
||||
tdbp->OpenDB(g);
|
||||
return false;
|
||||
} // end of CntRewindTable
|
||||
|
||||
/***********************************************************************/
|
||||
/* Evaluate all columns after a record is read. */
|
||||
/***********************************************************************/
|
||||
RCODE EvalColumns(PGLOBAL g, PTDB tdbp)
|
||||
{
|
||||
RCODE rc= RC_OK;
|
||||
PCOL colp;
|
||||
|
||||
// Save stack and allocation environment and prepare error return
|
||||
if (g->jump_level == MAX_JUMP) {
|
||||
if (xtrace) {
|
||||
strcpy(g->Message, MSG(TOO_MANY_JUMPS));
|
||||
printf("EvalColumns: %s\n", g->Message);
|
||||
} // endif
|
||||
|
||||
return RC_FX;
|
||||
} // endif jump_level
|
||||
|
||||
if (setjmp(g->jumper[++g->jump_level]) != 0) {
|
||||
if (xtrace)
|
||||
printf("Error reading columns: %s\n", g->Message);
|
||||
|
||||
rc= RC_FX;
|
||||
goto err;
|
||||
} // endif rc
|
||||
|
||||
for (colp= tdbp->GetColumns(); rc == RC_OK && colp;
|
||||
colp= colp->GetNext()) {
|
||||
colp->Reset();
|
||||
|
||||
// Virtual columns are computed by MariaDB
|
||||
if (!colp->GetColUse(U_VIRTUAL))
|
||||
if (colp->Eval(g))
|
||||
rc= RC_FX;
|
||||
|
||||
} // endfor colp
|
||||
|
||||
err:
|
||||
g->jump_level--;
|
||||
return rc;
|
||||
} // end of EvalColumns
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadNext: Read next record sequentially. */
|
||||
/***********************************************************************/
|
||||
RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
|
||||
{
|
||||
RCODE rc;
|
||||
|
||||
if (!tdbp)
|
||||
return RC_FX;
|
||||
else if (((PTDBASE)tdbp)->GetKindex()) {
|
||||
// Reading sequencially an indexed table. This happens after the
|
||||
// handler function records_in_range was called and MySQL decides
|
||||
// to quit using the index (!!!) Drop the index.
|
||||
for (PCOL colp= tdbp->GetColumns(); colp; colp= colp->GetNext())
|
||||
colp->SetKcol(NULL);
|
||||
|
||||
((PTDBASE)tdbp)->SetKindex(NULL);
|
||||
} // endif index
|
||||
|
||||
while ((rc= (RCODE)tdbp->ReadDB(g)) == RC_NF) ;
|
||||
|
||||
return (rc != RC_OK) ? rc : EvalColumns(g, tdbp);
|
||||
} // end of CntReadNext
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteRow: Insert a new row into a table. */
|
||||
/***********************************************************************/
|
||||
RCODE CntWriteRow(PGLOBAL g, PTDB tdbp)
|
||||
{
|
||||
RCODE rc;
|
||||
PCOL colp;
|
||||
PTDBASE tp= (PTDBASE)tdbp;
|
||||
|
||||
if (!tdbp)
|
||||
return RC_FX;
|
||||
|
||||
// Save stack and allocation environment and prepare error return
|
||||
if (g->jump_level == MAX_JUMP) {
|
||||
strcpy(g->Message, MSG(TOO_MANY_JUMPS));
|
||||
return RC_FX;
|
||||
} // endif jump_level
|
||||
|
||||
if (setjmp(g->jumper[++g->jump_level]) != 0) {
|
||||
printf("%s\n", g->Message);
|
||||
rc= RC_FX;
|
||||
goto err;
|
||||
} // endif rc
|
||||
|
||||
// Store column values in table write buffer(s)
|
||||
for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
|
||||
if (!colp->GetColUse(U_VIRTUAL))
|
||||
colp->WriteColumn(g);
|
||||
|
||||
// if (tdbp->GetMode() == MODE_INSERT)
|
||||
// tbxp->SetModified(true);
|
||||
|
||||
// Return result code from write operation
|
||||
rc= (RCODE)tdbp->WriteDB(g);
|
||||
|
||||
err:
|
||||
g->jump_level--;
|
||||
return rc;
|
||||
} // end of CntWriteRow
|
||||
|
||||
/***********************************************************************/
|
||||
/* UpdateRow: Update a row into a table. */
|
||||
/***********************************************************************/
|
||||
RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp)
|
||||
{
|
||||
if (!tdbp || tdbp->GetMode() != MODE_UPDATE)
|
||||
return RC_FX;
|
||||
|
||||
// Return result code from write operation
|
||||
return CntWriteRow(g, tdbp);
|
||||
} // end of CntUpdateRow
|
||||
|
||||
/***********************************************************************/
|
||||
/* DeleteRow: Delete a row from a table. */
|
||||
/***********************************************************************/
|
||||
RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all)
|
||||
{
|
||||
RCODE rc;
|
||||
|
||||
if (!tdbp || tdbp->GetMode() != MODE_DELETE)
|
||||
return RC_FX;
|
||||
// else
|
||||
// ((PTDBDOX)tdbp)->SetModified(true);
|
||||
|
||||
if (((PTDBASE)tdbp)->GetDef()->Indexable() && all)
|
||||
((PTDBDOS)tdbp)->Cardinal= 0;
|
||||
|
||||
// Return result code from delete operation
|
||||
// Note: if all, this call will be done when closing the table
|
||||
rc= (RCODE)tdbp->DeleteDB(g, (all) ? RC_FX : RC_OK);
|
||||
return rc;
|
||||
} // end of CntDeleteRow
|
||||
|
||||
/***********************************************************************/
|
||||
/* CLOSETAB: Close a table. */
|
||||
/***********************************************************************/
|
||||
int CntCloseTable(PGLOBAL g, PTDB tdbp)
|
||||
{
|
||||
int rc= RC_OK;
|
||||
TDBDOX *tbxp= NULL;
|
||||
|
||||
if (!tdbp)
|
||||
return rc; // Already done
|
||||
|
||||
if (xtrace)
|
||||
printf("CntCloseTable: tdbp=%p mode=%d\n", tdbp, tdbp->GetMode());
|
||||
|
||||
/*********************************************************************/
|
||||
/* This will close the table file(s) and also finalize write */
|
||||
/* operations such as Insert, Update, or Delete. */
|
||||
/*********************************************************************/
|
||||
if (tdbp->GetMode() == MODE_DELETE)
|
||||
rc= tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine
|
||||
|
||||
// Prepare error return
|
||||
if (g->jump_level == MAX_JUMP) {
|
||||
strcpy(g->Message, MSG(TOO_MANY_JUMPS));
|
||||
rc= RC_FX;
|
||||
goto err;
|
||||
} // endif
|
||||
|
||||
if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) {
|
||||
g->jump_level--;
|
||||
goto err;
|
||||
} // endif
|
||||
|
||||
tdbp->CloseDB(g);
|
||||
|
||||
g->jump_level--;
|
||||
|
||||
if (xtrace > 1)
|
||||
printf("Table %s closed\n", tdbp->GetName());
|
||||
|
||||
//if (!((PTDBDOX)tdbp)->GetModified())
|
||||
// return 0;
|
||||
|
||||
if (tdbp->GetMode() == MODE_READ || tdbp->GetMode() == MODE_ANY)
|
||||
return 0;
|
||||
|
||||
if (xtrace > 1)
|
||||
printf("About to reset opt\n");
|
||||
|
||||
// Make all the eventual indexes
|
||||
tbxp= (TDBDOX*)tdbp;
|
||||
tbxp->SetKindex(NULL);
|
||||
tbxp->To_Key_Col= NULL;
|
||||
rc= tbxp->ResetTableOpt(g, ((PTDBASE)tdbp)->GetDef()->Indexable());
|
||||
|
||||
err:
|
||||
if (xtrace > 1)
|
||||
printf("Done rc=%d\n", rc);
|
||||
|
||||
return (rc == RC_OK || rc == RC_INFO) ? 0 : rc;
|
||||
} // end of CntCloseTable
|
||||
|
||||
/***********************************************************************/
|
||||
/* Load and initialize the use of an index. */
|
||||
/* This is the condition(s) for doing indexing. */
|
||||
/* Note: FIX table are not reset here to Nrec= 1. */
|
||||
/***********************************************************************/
|
||||
int CntIndexInit(PGLOBAL g, PTDB ptdb, int id)
|
||||
{
|
||||
int k;
|
||||
PCOL colp;
|
||||
PVAL valp;
|
||||
PKXBASE xp;
|
||||
PXLOAD pxp;
|
||||
PIXDEF xdp;
|
||||
XKPDEF *kdp;
|
||||
PTDBDOX tdbp;
|
||||
PCOLDEF cdp;
|
||||
DOXDEF *dfp;
|
||||
|
||||
if (!ptdb)
|
||||
return -1;
|
||||
else if (!((PTDBASE)ptdb)->GetDef()->Indexable()) {
|
||||
sprintf(g->Message, "Table %s is not indexable", ptdb->GetName());
|
||||
return 0;
|
||||
} else
|
||||
tdbp= (PTDBDOX)ptdb;
|
||||
|
||||
dfp= (DOXDEF*)tdbp->To_Def;
|
||||
|
||||
//if (!(k= colp->GetKey()))
|
||||
// if (colp->GetOpt() >= 2) {
|
||||
// strcpy(g->Message, "Not a valid indexed column");
|
||||
// return -1;
|
||||
// } else
|
||||
// This is a pseudo indexed sorted block optimized column
|
||||
// return 0;
|
||||
|
||||
if (tdbp->To_Kindex)
|
||||
if (((XXBASE*)tdbp->To_Kindex)->GetID() == id) {
|
||||
tdbp->To_Kindex->Reset(); // Same index
|
||||
return (tdbp->To_Kindex->IsMul()) ? 2 : 1;
|
||||
} else {
|
||||
tdbp->To_Kindex->Close();
|
||||
tdbp->To_Kindex= NULL;
|
||||
} // endif colp
|
||||
|
||||
for (xdp= dfp->To_Indx; xdp; xdp= xdp->GetNext())
|
||||
if (xdp->GetID() == id)
|
||||
break;
|
||||
|
||||
if (!xdp) {
|
||||
sprintf(g->Message, "Wrong index ID %d", id);
|
||||
return 0;
|
||||
} // endif xdp
|
||||
|
||||
// Allocate the key columns definition block
|
||||
tdbp->Knum= xdp->GetNparts();
|
||||
tdbp->To_Key_Col= (PCOL*)PlugSubAlloc(g, NULL, tdbp->Knum * sizeof(PCOL));
|
||||
|
||||
// Get the key column description list
|
||||
for (k= 0, kdp= (XKPDEF*)xdp->GetToKeyParts(); kdp; kdp= (XKPDEF*)kdp->Next)
|
||||
if (!(colp= tdbp->ColDB(g, kdp->Name, 0)) || colp->InitValue(g)) {
|
||||
sprintf(g->Message, "Wrong column %s", kdp->Name);
|
||||
return 0;
|
||||
} else
|
||||
tdbp->To_Key_Col[k++]= colp;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (k != tdbp->Knum) {
|
||||
sprintf(g->Message, "Key part number mismatch for %s",
|
||||
xdp->GetName());
|
||||
return 0;
|
||||
} // endif k
|
||||
#endif // _DEBUG
|
||||
|
||||
// Allocate the pseudo constants that will contain the key values
|
||||
tdbp->To_Link= (PXOB*)PlugSubAlloc(g, NULL, tdbp->Knum * sizeof(PXOB));
|
||||
|
||||
for (k= 0, kdp= (XKPDEF*)xdp->GetToKeyParts();
|
||||
kdp; k++, kdp= (XKPDEF*)kdp->Next) {
|
||||
cdp= tdbp->Key(k)->GetCdp();
|
||||
valp= AllocateValue(g, cdp->GetType(), cdp->GetLength());
|
||||
tdbp->To_Link[k]= new(g) CONSTANT(valp);
|
||||
|
||||
//if (kdp->Klen && tdbp->To_Link[k]->GetResultType() == TYPE_STRING)
|
||||
// ((XCOLBLK*)tdbp->To_Link[k])->SetLength(kdp->Klen);
|
||||
|
||||
//((PCOL)tdbp->To_Link[k])->InitValue(g);
|
||||
} // endfor k
|
||||
|
||||
// Make the index on xdp
|
||||
if (!xdp->IsAuto()) {
|
||||
if (dfp->Huge)
|
||||
pxp= new(g) XHUGE;
|
||||
else
|
||||
pxp= new(g) XFILE;
|
||||
|
||||
if (tdbp->Knum == 1) // Single index
|
||||
xp= new(g) XINDXS(tdbp, xdp, pxp, tdbp->To_Key_Col, tdbp->To_Link);
|
||||
else // Multi-Column index
|
||||
xp= new(g) XINDEX(tdbp, xdp, pxp, tdbp->To_Key_Col, tdbp->To_Link);
|
||||
|
||||
} else // Column contains same values as ROWID
|
||||
xp= new(g) XXROW(tdbp);
|
||||
|
||||
if (xp->Init(g))
|
||||
return 0;
|
||||
|
||||
tdbp->To_Kindex= xp;
|
||||
return (xp->IsMul()) ? 2 : 1;
|
||||
} // end of CntIndexInit
|
||||
|
||||
/***********************************************************************/
|
||||
/* IndexRead: fetch a record having the index value. */
|
||||
/***********************************************************************/
|
||||
RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op,
|
||||
const void *key, int len)
|
||||
{
|
||||
char *kp= (char*)key;
|
||||
int n;
|
||||
short lg;
|
||||
RCODE rc;
|
||||
PVAL valp;
|
||||
PCOL colp;
|
||||
XXBASE *xbp;
|
||||
PTDBDOX tdbp;
|
||||
|
||||
if (!ptdb)
|
||||
return RC_FX;
|
||||
if (!((PTDBASE)ptdb)->GetDef()->Indexable()) {
|
||||
sprintf(g->Message, "Table %s is not indexable", ptdb->GetName());
|
||||
return RC_FX;
|
||||
} else
|
||||
tdbp= (PTDBDOX)ptdb;
|
||||
|
||||
// Set reference values and index operator
|
||||
if (!tdbp->To_Link || !tdbp->To_Kindex) {
|
||||
sprintf(g->Message, "Index not initialized for table %s", tdbp->Name);
|
||||
return RC_FX;
|
||||
} else
|
||||
xbp= (XXBASE*)tdbp->To_Kindex;
|
||||
|
||||
if (key) {
|
||||
for (n= 0; n < tdbp->Knum; n++) {
|
||||
colp= (PCOL)tdbp->To_Key_Col[n];
|
||||
|
||||
if (colp->GetColUse(U_NULLS))
|
||||
kp++; // Skip null byte
|
||||
|
||||
valp= tdbp->To_Link[n]->GetValue();
|
||||
|
||||
if (!valp->IsTypeNum()) {
|
||||
if (colp->GetColUse(U_VAR)) {
|
||||
lg= *(short*)kp;
|
||||
kp+= sizeof(short);
|
||||
valp->SetValue_char(kp, (int)lg);
|
||||
} else
|
||||
valp->SetValue_char(kp, valp->GetClen());
|
||||
|
||||
} else
|
||||
valp->SetBinValue((void*)kp);
|
||||
|
||||
kp+= valp->GetClen();
|
||||
|
||||
if (len == kp - (char*)key) {
|
||||
n++;
|
||||
break;
|
||||
} else if (len < kp - (char*)key) {
|
||||
strcpy(g->Message, "Key buffer is too small");
|
||||
return RC_FX;
|
||||
} // endif len
|
||||
|
||||
} // endfor n
|
||||
|
||||
xbp->SetNval(n);
|
||||
} // endif key
|
||||
|
||||
xbp->SetOp(op);
|
||||
xbp->SetNth(0);
|
||||
|
||||
if ((rc= (RCODE)tdbp->ReadDB(g)) == RC_OK)
|
||||
rc= EvalColumns(g, tdbp);
|
||||
|
||||
return rc;
|
||||
} // end of CntIndexRead
|
||||
|
||||
/***********************************************************************/
|
||||
/* Return the number of rows matching given values. */
|
||||
/***********************************************************************/
|
||||
int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len,
|
||||
bool *incl, key_part_map *kmap)
|
||||
{
|
||||
const uchar *p, *kp;
|
||||
int i, n, k[2];
|
||||
short lg;
|
||||
bool b;
|
||||
PVAL valp;
|
||||
PCOL colp;
|
||||
PTDBDOX tdbp;
|
||||
XXBASE *xbp;
|
||||
|
||||
if (!ptdb)
|
||||
return -1;
|
||||
else if (!((PTDBASE)ptdb)->GetDef()->Indexable()) {
|
||||
sprintf(g->Message, "Table %s is not indexable", ptdb->GetName());
|
||||
DBUG_PRINT("Range", (g->Message));
|
||||
return -1;
|
||||
} else
|
||||
tdbp= (PTDBDOX)ptdb;
|
||||
|
||||
if (!tdbp->To_Link || !tdbp->To_Kindex) {
|
||||
sprintf(g->Message, "Index not initialized for table %s", tdbp->Name);
|
||||
DBUG_PRINT("Range", (g->Message));
|
||||
return -1;
|
||||
} else
|
||||
xbp= (XXBASE*)tdbp->To_Kindex;
|
||||
|
||||
for (b= false, i= 0; i < 2; i++) {
|
||||
p= kp= key[i];
|
||||
|
||||
if (kp) {
|
||||
for (n= 0; n < tdbp->Knum; n++) {
|
||||
if (kmap[i] & (key_part_map)(1 << n)) {
|
||||
if (b == true)
|
||||
// Cannot do indexing with missing intermediate key
|
||||
return -1;
|
||||
|
||||
colp= (PCOL)tdbp->To_Key_Col[n];
|
||||
|
||||
if (colp->GetColUse(U_NULLS))
|
||||
p++; // Skip null byte ???
|
||||
|
||||
valp= tdbp->To_Link[n]->GetValue();
|
||||
|
||||
if (!valp->IsTypeNum()) {
|
||||
if (colp->GetColUse(U_VAR)) {
|
||||
lg= *(short*)p;
|
||||
p+= sizeof(short);
|
||||
valp->SetValue_char((char*)p, (int)lg);
|
||||
} else
|
||||
valp->SetValue_char((char*)p, valp->GetClen());
|
||||
|
||||
} else
|
||||
valp->SetBinValue((void*)p);
|
||||
|
||||
if (xtrace) {
|
||||
char bf[32];
|
||||
printf("i=%d n=%d key=%s\n", i, n, valp->GetCharString(bf));
|
||||
} // endif xtrace
|
||||
|
||||
p+= valp->GetClen();
|
||||
|
||||
if (len[i] == p - kp) {
|
||||
n++;
|
||||
break;
|
||||
} else if (len[i] < (unsigned)(p - kp)) {
|
||||
strcpy(g->Message, "Key buffer is too small");
|
||||
return -1;
|
||||
} // endif len
|
||||
|
||||
} else
|
||||
b= true;
|
||||
|
||||
} // endfor n
|
||||
|
||||
xbp->SetNval(n);
|
||||
|
||||
if (xtrace)
|
||||
printf("xbp=%p Nval=%d i=%d incl=%d\n", xbp, n, i, incl[i]);
|
||||
|
||||
k[i]= xbp->Range(g, i + 1, incl[i]);
|
||||
} else
|
||||
k[i]= (i) ? xbp->GetNum_K() : 0;
|
||||
|
||||
} // endfor i
|
||||
|
||||
if (xtrace)
|
||||
printf("k1=%d k0=%d\n", k[1], k[0]);
|
||||
|
||||
return k[1] - k[0];
|
||||
} // end of CntIndexRange
|
||||
77
storage/connect/connect.h
Normal file
77
storage/connect/connect.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Copyright (C) Olivier Bertrand 2004 - 2011
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/**************** Cnt H Declares Source Code File (.H) *****************/
|
||||
/* Name: CONNECT.H Version 2.4 */
|
||||
/* This file contains the some based classes declares. */
|
||||
/***********************************************************************/
|
||||
//#include "xtable.h" // Base class declares
|
||||
#include "filamtxt.h"
|
||||
#include "tabdos.h"
|
||||
|
||||
//typedef struct _tabdesc *PTABD; // For friend setting
|
||||
typedef struct _xinfo *PXF;
|
||||
typedef struct _create_xinfo *PCXF;
|
||||
typedef class TDBDOX *PTDBDOX;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definition of classes XCOLCRT, XIXDEF, XKPDEF, DOXDEF, TDBDOX */
|
||||
/* These classes purpose is chiefly to access protected items! */
|
||||
/***********************************************************************/
|
||||
class XCOLCRT: public COLCRT {
|
||||
friend class ha_connect;
|
||||
friend bool CntCreateTable(PGLOBAL, char *, PCXF);
|
||||
public:
|
||||
XCOLCRT(PSZ name) : COLCRT(name) {Nulls= -1;} // Constructor
|
||||
bool HasNulls(void) {return (Nulls != 0);}
|
||||
|
||||
private:
|
||||
int Nulls;
|
||||
}; // end of class XCOLCRT
|
||||
|
||||
class DOXDEF: public DOSDEF {
|
||||
//friend class TDBDOX;
|
||||
//friend int MakeIndex(PGLOBAL, PTDB, PIXDEF);
|
||||
friend int CntIndexInit(PGLOBAL, PTDB, int);
|
||||
}; // end of class DOXDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method base class declaration. */
|
||||
/***********************************************************************/
|
||||
class TDBDOX: public TDBDOS {
|
||||
friend int MakeIndex(PGLOBAL, PTDB, PIXDEF);
|
||||
friend int CntCloseTable(PGLOBAL, PTDB);
|
||||
friend int CntIndexInit(PGLOBAL, PTDB, int);
|
||||
friend RCODE CntIndexRead(PGLOBAL, PTDB, OPVAL, const void*, int);
|
||||
friend RCODE CntDeleteRow(PGLOBAL, PTDB, bool);
|
||||
friend int CntIndexRange(PGLOBAL, PTDB, const uchar**, uint*,
|
||||
bool*, key_part_map*);
|
||||
friend class ha_connect;
|
||||
}; // end of class TDBDOX
|
||||
|
||||
class XKPDEF: public KPARTDEF {
|
||||
friend class TDBDOX;
|
||||
friend class ha_connect;
|
||||
//friend int CntMakeIndex(PGLOBAL, const char *, PIXDEF);
|
||||
friend int CntIndexInit(PGLOBAL, PTDB, int);
|
||||
public:
|
||||
XKPDEF(const char *name, int n) : KPARTDEF((PSZ)name, n) {HasNulls= false;}
|
||||
void SetNulls(bool b) {HasNulls= b;}
|
||||
|
||||
protected:
|
||||
bool HasNulls; /* Can have null values */
|
||||
}; // end of class XKPDEF
|
||||
|
||||
RCODE CheckRecord(PGLOBAL g, PTDB tdbp, char *oldbuf, char *newbuf);
|
||||
962
storage/connect/csort.cpp
Normal file
962
storage/connect/csort.cpp
Normal file
@@ -0,0 +1,962 @@
|
||||
/*************** CSort C Program Source Code File (.CPP) ***************/
|
||||
/* PROGRAM NAME: CSORT */
|
||||
/* ------------- */
|
||||
/* Version 2.2 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier Bertrand 1995-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program is the C++ sorting routines that use qsort/insert */
|
||||
/* algorithm and produces an offset/break table while sorting. */
|
||||
/* */
|
||||
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
||||
/* -------------------------------------- */
|
||||
/* */
|
||||
/* REQUIRED FILES: */
|
||||
/* --------------- */
|
||||
/* csort.cpp - Source code */
|
||||
/* */
|
||||
/* REQUIRED LIBRARIES: */
|
||||
/* ------------------- */
|
||||
/* OS2DEF.LIB - OS2 libray definition subset. */
|
||||
/* */
|
||||
/* REQUIRED PROGRAMS: */
|
||||
/* ------------------ */
|
||||
/* Microsoft C++ Compiler */
|
||||
/* or GNU Compiler/Linker */
|
||||
/* or BORLAND 4.5 C++ compiler */
|
||||
/* */
|
||||
/* NOTE */
|
||||
/* ---- */
|
||||
/* These functions are not 64-bits ready. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files */
|
||||
/***********************************************************************/
|
||||
#include <stdlib.h> /* C standard library */
|
||||
#include <string.h> /* String manipulation declares */
|
||||
#include <stdio.h> /* Required for sprintf declare */
|
||||
#if defined(_DEBUG)
|
||||
#include <assert.h> /* Assertion routine declares */
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include CSort class header file */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h" /* For MBLOCK type definition */
|
||||
#include "csort.h" /* CSort class definition */
|
||||
|
||||
#if !defined(BIGSORT)
|
||||
#define BIGSORT 200000
|
||||
#endif // !BIGSORT
|
||||
|
||||
/***********************************************************************/
|
||||
/* DB static external variables. */
|
||||
/***********************************************************************/
|
||||
extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Initialize the CSORT static members. */
|
||||
/***********************************************************************/
|
||||
int CSORT::Limit = 0;
|
||||
double CSORT::Lg2 = log(2.0);
|
||||
size_t CSORT::Cpn[1000] = {0}; /* Precalculated cmpnum values */
|
||||
|
||||
/***********************************************************************/
|
||||
/* CSORT constructor. */
|
||||
/***********************************************************************/
|
||||
CSORT::CSORT(bool cns, int th, int mth)
|
||||
: Pex((int*&)Index.Memp), Pof((int*&)Offset.Memp)
|
||||
{
|
||||
G = NULL;
|
||||
Dup =NULL;
|
||||
Cons = cns;
|
||||
Thresh = th;
|
||||
Mthresh = mth;
|
||||
Nitem = 0;
|
||||
Index = Nmblk;
|
||||
Offset = Nmblk;
|
||||
Swix = NULL;
|
||||
Savmax = 0;
|
||||
Savcur = 0;
|
||||
Savstep = NULL;
|
||||
} // end of CSORT constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* CSORT intialization. */
|
||||
/***********************************************************************/
|
||||
int CSORT::Qsort(PGLOBAL g, int nb)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
assert(Index.Size >= nb * sizeof(int));
|
||||
#endif
|
||||
|
||||
if (nb > BIGSORT) {
|
||||
G = g;
|
||||
Dup = (PDBUSER)g->Activityp->Aptr;
|
||||
|
||||
if (Dup->Proginfo) {
|
||||
Savstep = Dup->Step;
|
||||
Savmax = Dup->ProgMax;
|
||||
Savcur = Dup->ProgCur;
|
||||
|
||||
// Evaluate the number of comparisons that we will do
|
||||
Dup->ProgMax = Cmpnum(nb);
|
||||
Dup->ProgCur = 0;
|
||||
Dup->Step = (char*)PlugSubAlloc(g, NULL, 32);
|
||||
sprintf((char*)Dup->Step, MSG(SORTING_VAL), nb);
|
||||
} else
|
||||
Dup = NULL;
|
||||
|
||||
} else
|
||||
Dup = NULL;
|
||||
|
||||
Nitem = nb;
|
||||
|
||||
for (int n = 0; n < Nitem; n++)
|
||||
Pex[n] = n;
|
||||
|
||||
rc = (Cons) ? Qsortc() : Qsortx();
|
||||
|
||||
if (Dup) {
|
||||
// Restore any change in progress info settings
|
||||
// printf("Progcur=%u\n", Dup->ProgCur);
|
||||
|
||||
Dup->Step = Savstep;
|
||||
Dup->ProgMax = Savmax;
|
||||
Dup->ProgCur = Savcur;
|
||||
} // endif Subcor
|
||||
|
||||
return rc;
|
||||
} // end of QSort
|
||||
|
||||
#if defined(DEBTRACE)
|
||||
/***********************************************************************/
|
||||
/* Debug routine to be used by sort for specific data (dummy as now) */
|
||||
/***********************************************************************/
|
||||
void CSORT::DebugSort(int ph, int n, int *base, int *mid, int *tmp)
|
||||
{
|
||||
htrc("phase=%d n=%d base=%p mid=%p tmp=%p\n",
|
||||
ph, n, base, mid, tmp);
|
||||
} // end of DebugSort
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Qsortx: Version adapted from qsortx.c by O.Bertrand */
|
||||
/* This version is specialy adapted for Index sorting, meaning that */
|
||||
/* the data is not moved, but the Index only is sorted. */
|
||||
/* Index array elements are any 4-byte word (a pointer or a int int */
|
||||
/* array index), they are not interpreted except by the user provided */
|
||||
/* comparison routine which must works accordingly. */
|
||||
/* In addition, this program takes care of data in which there is a */
|
||||
/* high rate of repetitions. */
|
||||
/* CAUTION: the sort algorithm used here is not conservative. Equal */
|
||||
/* values will be internally stored in unpredictable order. */
|
||||
/* The THRESHold below is the insertion sort threshold, and also the */
|
||||
/* threshold for continuing que quicksort partitioning. */
|
||||
/* The MTHREShold is where we stop finding a better median. */
|
||||
/* These two quantities should be adjusted dynamically depending upon */
|
||||
/* the repetition rate of the data. */
|
||||
/* Algorithm used: */
|
||||
/* First, set up some global parameters for Qstx to share. Then, */
|
||||
/* quicksort with Qstx(), and then a cleanup insertion sort ourselves. */
|
||||
/* Sound simple? It's not... */
|
||||
/***********************************************************************/
|
||||
int CSORT::Qsortx(void)
|
||||
{
|
||||
register int c;
|
||||
register int lo, hi, min;
|
||||
register int i, j, rc = 0;
|
||||
// To do: rc should be checked for being used uninitialized
|
||||
int *top;
|
||||
#ifdef DEBTRACE
|
||||
int ncp;
|
||||
|
||||
num_comp = 0;
|
||||
#endif
|
||||
|
||||
/*********************************************************************/
|
||||
/* Prepare the Offset array that will be updated during sorts. */
|
||||
/*********************************************************************/
|
||||
if (Pof)
|
||||
for (Pof[Nitem] = Nitem, j = 0; j < Nitem; j++)
|
||||
Pof[j] = 0;
|
||||
else
|
||||
j = Nitem + 1;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Sort on one or zero element is obvious. */
|
||||
/*********************************************************************/
|
||||
if (Nitem <= 1)
|
||||
return Nitem;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Thresh seems to be good as (10 * n / rep). But for testing we */
|
||||
/* set it directly as one parameter of the Xset function call. */
|
||||
/* Note: this should be final as the rep parameter is no more used. */
|
||||
/*********************************************************************/
|
||||
top = Pex + Nitem;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Qsortx: nitem=%d thresh=%d mthresh=%d\n",
|
||||
Nitem, Thresh, Mthresh);
|
||||
#endif
|
||||
|
||||
/*********************************************************************/
|
||||
/* If applicable, do a rough preliminary quick sort. */
|
||||
/*********************************************************************/
|
||||
if (Nitem >= Thresh)
|
||||
Qstx(Pex, top);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" after quick sort num_comp=%d\n", num_comp);
|
||||
ncp = num_comp;
|
||||
num_comp = 0;
|
||||
#ifdef DEBUG2
|
||||
DebugSort((Pof) ? 1 : 4, Nitem, Pex, NULL, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (Thresh > 2) {
|
||||
if (Pof)
|
||||
/*****************************************************************/
|
||||
/* The preliminary search for the smallest element has been */
|
||||
/* removed so with no sentinel in place, we must check for x */
|
||||
/* going below the Pof pointer. For each remaining element */
|
||||
/* group from [1] to [n-1], set hi to the index of the element */
|
||||
/* AFTER which this one goes. Then, do the standard insertion */
|
||||
/* sort shift on an integer at a time basis for each equal */
|
||||
/* element group in the frob. */
|
||||
/*****************************************************************/
|
||||
for (min = hi = 0; min < Nitem; min = hi) {
|
||||
if (Pof[hi]) {
|
||||
hi += Pof[hi];
|
||||
continue;
|
||||
} // endif Pof
|
||||
|
||||
Pof[min] = 1;
|
||||
|
||||
#ifdef DEBUG2
|
||||
htrc("insert from min=%d\n", min);
|
||||
#endif
|
||||
|
||||
for (lo = hi; !Pof[++hi]; lo = hi) {
|
||||
while (lo >= min && (rc = Qcompare(Pex + lo, Pex + hi)) > 0)
|
||||
if (Pof[lo] > 0)
|
||||
lo -= Pof[lo];
|
||||
else
|
||||
return -2;
|
||||
|
||||
if (++lo != hi) {
|
||||
c = Pex[hi];
|
||||
|
||||
for (i = j = hi; i > 0; i = j)
|
||||
if (Pof[i - 1] <= 0)
|
||||
return -3;
|
||||
else if ((j -= Pof[i - 1]) >= lo) {
|
||||
Pex[i] = Pex[j];
|
||||
Pof[j + 1] = Pof[i] = Pof[j];
|
||||
} else
|
||||
break;
|
||||
|
||||
Pex[i] = c;
|
||||
} // endif lo
|
||||
|
||||
if (rc)
|
||||
Pof[lo] = 1;
|
||||
else {
|
||||
i = lo - Pof[lo - 1];
|
||||
Pof[lo] = ++Pof[i];
|
||||
} // endelse
|
||||
|
||||
#ifdef DEBUG2
|
||||
htrc("rc=%d lo=%d hi=%d trx=%d\n", rc, lo, hi, Pof[lo]);
|
||||
#endif
|
||||
|
||||
} // endfor hi
|
||||
|
||||
} // endfor min
|
||||
|
||||
else
|
||||
/*****************************************************************/
|
||||
/* Call conservative insertion sort not using/setting offset. */
|
||||
/*****************************************************************/
|
||||
Istc(Pex, Pex + min(Nitem, Thresh), top);
|
||||
|
||||
} // endif Thresh
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" after insert sort num_comp=%d\n", num_comp);
|
||||
num_comp += ncp;
|
||||
#endif
|
||||
|
||||
if (Pof)
|
||||
/*******************************************************************/
|
||||
/* Reduce the Offset array. */
|
||||
/*******************************************************************/
|
||||
for (i = j = 0; i <= Nitem; j++, i += c) {
|
||||
#ifdef DEBUG2
|
||||
htrc(" trxp(%d)=%d trxp(%d)=%d c=%d\n",
|
||||
i, Pof[i], j, Pof[j], c);
|
||||
#endif
|
||||
if ((c = Pof[i]))
|
||||
Pof[j] = i;
|
||||
else
|
||||
return -4;
|
||||
|
||||
} // endfor i
|
||||
|
||||
return (j - 1);
|
||||
} // end of Qsortx
|
||||
|
||||
/***********************************************************************/
|
||||
/* Qstx: Do a quicksort on index elements (just one int int). */
|
||||
/* First, find the median element, and put that one in the first place */
|
||||
/* as the discriminator. (This "median" is just the median of the */
|
||||
/* first, last and middle elements). (Using this median instead of */
|
||||
/* the first element is a big win). Then, the usual partitioning/ */
|
||||
/* swapping, followed by moving the discriminator into the right place.*/
|
||||
/* Element equal to the discriminator are placed against it, so the */
|
||||
/* mid (discriminator) block grows when equal elements exist. This is */
|
||||
/* a huge win in case of repartitions with few different elements. */
|
||||
/* The mid block being at its final position, its first and last */
|
||||
/* elements are marked in the offset list (used to make break list). */
|
||||
/* Then, figure out the sizes of the two partitions, do the smaller */
|
||||
/* one recursively and the larger one via a repeat of this code. */
|
||||
/* Stopping when there are less than THRESH elements in a partition */
|
||||
/* and cleaning up with an insertion sort (in our caller) is a huge */
|
||||
/* win(?). All data swaps are done in-line, which is space-losing but */
|
||||
/* time-saving. (And there are only three places where this is done). */
|
||||
/***********************************************************************/
|
||||
void CSORT::Qstx(int *base, int *max)
|
||||
{
|
||||
register int *i, *j, *jj, *mid, *him, c;
|
||||
int *tmp;
|
||||
int lo, hi, rc;
|
||||
size_t zlo, zhi, cnm;
|
||||
|
||||
zlo = zhi = cnm = 0; // Avoid warning message
|
||||
|
||||
lo = max - base; // Number of elements as longs
|
||||
|
||||
if (Dup)
|
||||
cnm = Cmpnum(lo);
|
||||
|
||||
do {
|
||||
/*******************************************************************/
|
||||
/* At the top here, lo is the number of integers of elements in */
|
||||
/* the current partition. (Which should be max - base). */
|
||||
/* Find the median of the first, last, and middle element and make */
|
||||
/* that the middle element. Set j to largest of first and middle. */
|
||||
/* If max is larger than that guy, then it's that guy, else */
|
||||
/* compare max with loser of first and take larger. Things are */
|
||||
/* set up to prefer the middle, then the first in case of ties. */
|
||||
/* In addition, hi and rc are set to comparison results. So if hi */
|
||||
/* is null, the two high values are equal and if rc is null, the */
|
||||
/* two low values are equal. This was used to set which test will */
|
||||
/* be made by LE and which one by LT (does not apply anymore). */
|
||||
/*******************************************************************/
|
||||
him = mid = i = base + (lo >> 1);
|
||||
hi = rc = 0;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
tmp = max - 1;
|
||||
htrc("--> block base=%d size=%d\n", base - Pex, lo);
|
||||
DebugSort(2, 0, base, mid, tmp);
|
||||
#endif
|
||||
|
||||
if (lo >= Mthresh) {
|
||||
rc = Qcompare((jj = base), i);
|
||||
j = (rc > 0) ? jj : i;
|
||||
hi = Qcompare(j, (tmp = max - 1));
|
||||
|
||||
if (hi > 0 && rc) {
|
||||
j = (j == jj) ? i : jj; // switch to first loser
|
||||
|
||||
if ((rc = Qcompare(j, tmp)) < 0)
|
||||
j = tmp;
|
||||
|
||||
} // endif
|
||||
|
||||
if (j != i) {
|
||||
c = *i;
|
||||
*i = *j;
|
||||
*j = c;
|
||||
} // endif j
|
||||
|
||||
} else if (lo == 2) {
|
||||
/*****************************************************************/
|
||||
/* Small group. Do special quicker processing. */
|
||||
/*****************************************************************/
|
||||
if ((rc = Qcompare(base, (him = base + 1))) > 0)
|
||||
c = *base, *base = *him, *him = c;
|
||||
|
||||
if (Pof)
|
||||
Pof[base - Pex] = Pof[him - Pex] = (rc) ? 1 : 2;
|
||||
|
||||
break;
|
||||
} // endif lo
|
||||
|
||||
#ifdef DEBTRACE
|
||||
DebugSort(3, hi, NULL, mid, &rc);
|
||||
#endif
|
||||
|
||||
/*******************************************************************/
|
||||
/* Semi-standard quicksort partitioning/swapping. Added here is */
|
||||
/* a test on equality. All values equal to the mid element are */
|
||||
/* placed under or over it. Mid block can be also moved when it */
|
||||
/* is necessary because the other partition is full. At the end */
|
||||
/* of the for loop the mid block is definitely positionned. */
|
||||
/*******************************************************************/
|
||||
for (i = base, j = max - 1; ;) {
|
||||
CONT:
|
||||
while (i < mid)
|
||||
if ((rc = Qcompare(i, mid)) < 0)
|
||||
i++;
|
||||
else if (!rc) {
|
||||
c = *i;
|
||||
*i = *(--mid);
|
||||
*mid = c;
|
||||
} else
|
||||
break;
|
||||
|
||||
while (j > him)
|
||||
if ((rc = Qcompare(him, j)) < 0)
|
||||
j--;
|
||||
else if (!rc) {
|
||||
c = *j;
|
||||
*j = *(++him);
|
||||
*him = c;
|
||||
} else if (i == mid) { // Triple move:
|
||||
c = *j; // j goes under mid block
|
||||
*j = *(++him); // val over mid block -> j
|
||||
*him = *mid++; // and mid block goes one
|
||||
*i++ = c; // position higher.
|
||||
} else { // i <-> j
|
||||
c = *i;
|
||||
*i++ = *j;
|
||||
*j-- = c;
|
||||
goto CONT;
|
||||
} // endif's
|
||||
|
||||
if (i == mid)
|
||||
break;
|
||||
else { // Triple move:
|
||||
c = *i; // i goes over mid block
|
||||
*i = *(--mid); // val under mid block -> i
|
||||
*mid = *him--; // and mid block goes one
|
||||
*j-- = c; // position lower.
|
||||
} // endelse
|
||||
|
||||
} // endfor i
|
||||
|
||||
/*******************************************************************/
|
||||
/* The mid block being placed at its final position we can now set */
|
||||
/* the offset array values indicating break point and block size. */
|
||||
/*******************************************************************/
|
||||
j = mid;
|
||||
i = him + 1;
|
||||
|
||||
if (Pof)
|
||||
Pof[him - Pex] = Pof[mid - Pex] = i - j;
|
||||
|
||||
/*******************************************************************/
|
||||
/* Look at sizes of the two partitions, do the smaller one first */
|
||||
/* by recursion, then do the larger one by making sure lo is its */
|
||||
/* size, base and max are update correctly, and branching back. */
|
||||
/* But only repeat (recursively or by branching) if the partition */
|
||||
/* is of at least size THRESH. */
|
||||
/*******************************************************************/
|
||||
lo = j - base;
|
||||
hi = max - i;
|
||||
|
||||
if (Dup) { // Update progress information
|
||||
zlo = Cmpnum(lo);
|
||||
zhi = Cmpnum(hi);
|
||||
Dup->ProgCur += cnm - (zlo + zhi);
|
||||
} // endif Dup
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" done lo=%d sep=%d hi=%d\n", lo, i - j, hi);
|
||||
#endif
|
||||
|
||||
if (lo <= hi) {
|
||||
if (lo >= Thresh)
|
||||
Qstx(base, j);
|
||||
else if (lo == 1 && Pof)
|
||||
Pof[base - Pex] = 1;
|
||||
|
||||
base = i;
|
||||
lo = hi;
|
||||
cnm = zhi;
|
||||
} else {
|
||||
if (hi >= Thresh)
|
||||
Qstx(i, max);
|
||||
else if (hi == 1 && Pof)
|
||||
Pof[i - Pex] = 1;
|
||||
|
||||
max = j;
|
||||
cnm = zlo;
|
||||
} // endif
|
||||
|
||||
if (lo == 1 && Pof)
|
||||
Pof[base - Pex] = 1;
|
||||
|
||||
} while (lo >= Thresh); // enddo
|
||||
|
||||
} // end of Qstx
|
||||
|
||||
/***********************************************************************/
|
||||
/* Qsortc.c: Version adapted from qsort.c by O.Bertrand */
|
||||
/* This version is specialy adapted for Index sorting, meaning that */
|
||||
/* the data is not moved, but the Index only is sorted. */
|
||||
/* Index array elements are any 4-byte word (a pointer or a int int */
|
||||
/* array index), they are not interpreted except by the user provided */
|
||||
/* comparison routine which must works accordingly. */
|
||||
/* In addition, this program takes care of data in which there is a */
|
||||
/* high rate of repetitions. */
|
||||
/* NOTE: the sort algorithm used here is conservative. Equal and */
|
||||
/* greater than values are internally stored in additional work area. */
|
||||
/* The THRESHold below is the insertion sort threshold, and also the */
|
||||
/* threshold for continuing que quicksort partitioning. */
|
||||
/* The MTHREShold is where we stop finding a better median. */
|
||||
/* These two quantities should be adjusted dynamically depending upon */
|
||||
/* the repetition rate of the data. */
|
||||
/* Algorithm used: */
|
||||
/* First, set up some global parameters for Qstc to share. Then, */
|
||||
/* quicksort with Qstc(), and then a cleanup insertion sort ourselves.*/
|
||||
/* Sound simple? It's not... */
|
||||
/***********************************************************************/
|
||||
int CSORT::Qsortc(void)
|
||||
{
|
||||
register int c;
|
||||
register int lo, hi, min;
|
||||
register int i, j, k, m, rc = 0;
|
||||
// To do: rc should be checked for being used uninitialized
|
||||
int *max;
|
||||
#ifdef DEBTRACE
|
||||
int ncp;
|
||||
|
||||
num_comp = 0;
|
||||
#endif
|
||||
|
||||
/*********************************************************************/
|
||||
/* Prepare the Offset array that will be updated during sorts. */
|
||||
/*********************************************************************/
|
||||
if (Pof)
|
||||
for (Pof[Nitem] = Nitem, j = 0; j < Nitem; j++)
|
||||
Pof[j] = 0;
|
||||
else
|
||||
j = Nitem + 1;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Sort on one or zero element is obvious. */
|
||||
/*********************************************************************/
|
||||
if (Nitem <= 1)
|
||||
return Nitem;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Thresh seems to be good as (10 * n / rep). But for testing we */
|
||||
/* set it directly as one parameter of the Xset function call. */
|
||||
/* Note: this should be final as the rep parameter is no more used. */
|
||||
/*********************************************************************/
|
||||
max = Pex + Nitem;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Qsortc: nitem=%d thresh=%d mthresh=%d\n",
|
||||
Nitem, Thresh, Mthresh);
|
||||
#endif
|
||||
|
||||
/*********************************************************************/
|
||||
/* If applicable, do a rough preliminary conservative quick sort. */
|
||||
/*********************************************************************/
|
||||
if (Nitem >= Thresh) {
|
||||
if (!(Swix = (int *)malloc(Nitem * sizeof(int))))
|
||||
return -1;
|
||||
|
||||
Qstc(Pex, max);
|
||||
|
||||
free(Swix);
|
||||
Swix = NULL;
|
||||
} // endif n
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" after quick sort num_comp=%d\n", num_comp);
|
||||
ncp = num_comp;
|
||||
num_comp = 0;
|
||||
#ifdef DEBUG2
|
||||
DebugSort((Pof) ? 1 : 4, Nitem, Pex, NULL, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (Thresh > 2) {
|
||||
if (Pof)
|
||||
/*****************************************************************/
|
||||
/* The preliminary search for the smallest element has been */
|
||||
/* removed so with no sentinel in place, we must check for x */
|
||||
/* going below the Pof pointer. For each remaining element */
|
||||
/* group from [1] to [n-1], set hi to the index of the element */
|
||||
/* AFTER which this one goes. Then, do the standard insertion */
|
||||
/* sort shift on an integer at a time basis for each equal */
|
||||
/* element group in the frob. */
|
||||
/*****************************************************************/
|
||||
for (min = hi = 0; min < Nitem; min = hi) {
|
||||
if (Pof[hi]) {
|
||||
hi += Pof[hi];
|
||||
continue;
|
||||
} // endif
|
||||
|
||||
Pof[min] = 1;
|
||||
|
||||
#ifdef DEBUG2
|
||||
htrc("insert from min=%d\n", min);
|
||||
#endif
|
||||
|
||||
for (lo = hi; !Pof[++hi]; lo = hi) {
|
||||
while (lo >= min && (rc = Qcompare(Pex + lo, Pex + hi)) > 0)
|
||||
if (Pof[lo] > 0)
|
||||
lo -= Pof[lo];
|
||||
else
|
||||
return -2;
|
||||
|
||||
if (++lo != hi) {
|
||||
c = Pex[hi];
|
||||
|
||||
for (i = j = hi; i > 0; i = j)
|
||||
if (Pof[i - 1] <= 0)
|
||||
return -3;
|
||||
else if ((j -= Pof[i - 1]) >= lo) {
|
||||
for (k = m = i; --m >= j; k--) // Move intermediate
|
||||
Pex[k] = Pex[m]; // for conservation.
|
||||
|
||||
Pof[j + 1] = Pof[i] = Pof[j];
|
||||
} else
|
||||
break;
|
||||
|
||||
Pex[i] = c;
|
||||
} // endif
|
||||
|
||||
if (rc)
|
||||
Pof[lo] = 1;
|
||||
else {
|
||||
i = lo - Pof[lo - 1];
|
||||
Pof[lo] = ++Pof[i];
|
||||
} // endelse
|
||||
|
||||
#ifdef DEBUG2
|
||||
htrc("rc=%d lo=%d hi=%d ofx=%d\n", rc, lo, hi, Pof[lo]);
|
||||
#endif
|
||||
|
||||
} // endfor hi
|
||||
|
||||
} // endfor min
|
||||
|
||||
else
|
||||
/*****************************************************************/
|
||||
/* Call conservative insertion sort not using/setting offset. */
|
||||
/*****************************************************************/
|
||||
Istc(Pex, Pex + min(Nitem, Thresh), max);
|
||||
|
||||
} // endif Thresh
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" after insert sort num_comp=%d\n", num_comp);
|
||||
num_comp += ncp;
|
||||
#endif
|
||||
|
||||
if (Pof)
|
||||
/*******************************************************************/
|
||||
/* Reduce the Offset array. */
|
||||
/*******************************************************************/
|
||||
for (i = j = 0; i <= Nitem; j++, i += c) {
|
||||
#ifdef DEBUG2
|
||||
htrc(" Pof(%d)=%d Pof(%d)=%d c=%d\n",
|
||||
i, Pof[i], j, Pof[j], c);
|
||||
#endif
|
||||
if ((c = Pof[i]))
|
||||
Pof[j] = i;
|
||||
else
|
||||
return -4;
|
||||
|
||||
} // endfor i
|
||||
|
||||
return (j - 1);
|
||||
} // end of Qsortc
|
||||
|
||||
/***********************************************************************/
|
||||
/* Qstc: Do a quicksort on index elements (just one int int). */
|
||||
/* First, find the median element, and set it as the discriminator. */
|
||||
/* (This "median" is just the median of the first, last and middle */
|
||||
/* elements). (Using this median instead of the first element is a */
|
||||
/* big win). Then, the special partitioning/swapping, where elements */
|
||||
/* smaller than the discriminator are placed in the sorted block, */
|
||||
/* elements equal to the discriminator are placed backward from the */
|
||||
/* top of the work area and elements greater than *j (discriminator) */
|
||||
/* are placed in the work area from its bottom. Then the elements in */
|
||||
/* the work area are placed back in the sort area in natural order, */
|
||||
/* making the sort conservative. Non equal blocks shrink faster when */
|
||||
/* equal elements exist. This is a huge win in case of repartitions */
|
||||
/* with few different elements. The mid block being at its final */
|
||||
/* position, its first and last elements are marked in the offset */
|
||||
/* list (used to make break list). Then, figure out the sizes of the */
|
||||
/* two partitions, do the smaller one recursively and the larger one */
|
||||
/* via a repeat of this code. Stopping when there are less than */
|
||||
/* THRESH elements in a partition and cleaning up with an insertion */
|
||||
/* sort (in our caller) is a huge win (yet to be proved?). */
|
||||
/***********************************************************************/
|
||||
void CSORT::Qstc(int *base, int *max)
|
||||
{
|
||||
register int *i, *j, *jj, *lt, *eq, *gt, *mid;
|
||||
int c, lo, hi, rc;
|
||||
size_t zlo, zhi, cnm;
|
||||
|
||||
zlo = zhi = cnm = 0; // Avoid warning message
|
||||
|
||||
lo = max - base; // Number of elements as longs
|
||||
|
||||
if (Dup)
|
||||
cnm = Cmpnum(lo);
|
||||
|
||||
do {
|
||||
/*******************************************************************/
|
||||
/* At the top here, lo is the number of integers of elements in */
|
||||
/* the current partition. (Which should be max - base). Find the */
|
||||
/* median of the first, last, and middle element and make that */
|
||||
/* the compare element. Set jj to smallest of middle and last. */
|
||||
/* If base is smaller or equal than that guy, then it's that guy, */
|
||||
/* else compare base with loser of first and take smaller. Things */
|
||||
/* are set up to prefer the top, then the middle in case of ties. */
|
||||
/*******************************************************************/
|
||||
i = base + (lo >> 1);
|
||||
jj = mid = max - 1;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("--> block base=%d size=%d\n", base - Pex, lo);
|
||||
DebugSort(2, 0, base, i, mid);
|
||||
#endif
|
||||
|
||||
if (lo >= Mthresh) {
|
||||
jj = ((rc = Qcompare(i, mid)) < 0) ? i : mid;
|
||||
|
||||
if (rc && Qcompare(base, jj) > 0) {
|
||||
jj = (jj == mid) ? i : mid; // switch to first loser
|
||||
|
||||
if (Qcompare(base, jj) < 0)
|
||||
jj = base;
|
||||
|
||||
} // endif
|
||||
|
||||
if (jj != mid) {
|
||||
/***************************************************************/
|
||||
/* The compare element must be at the top of the block so it */
|
||||
/* cannot be overwritten while making the partitioning. So */
|
||||
/* save the last block value which will be compared later. */
|
||||
/***************************************************************/
|
||||
c = *mid;
|
||||
*mid = *jj;
|
||||
} // endif
|
||||
|
||||
} else if (lo == 2) {
|
||||
/*****************************************************************/
|
||||
/* Small group. Do special quicker processing. */
|
||||
/*****************************************************************/
|
||||
if ((rc = Qcompare(base, (i = base + 1))) > 0)
|
||||
c = *base, *base = *i, *i = c;
|
||||
|
||||
if (Pof)
|
||||
Pof[base - Pex] = Pof[i - Pex] = (rc) ? 1 : 2;
|
||||
|
||||
break;
|
||||
} // endif lo
|
||||
|
||||
#ifdef DEBTRACE
|
||||
DebugSort(3, lo, NULL, jj, &rc);
|
||||
#endif
|
||||
|
||||
/*******************************************************************/
|
||||
/* Non-standard quicksort partitioning using additional storage */
|
||||
/* to store values less than, equal or greater than the middle */
|
||||
/* element. This uses more memory but provides conservation of */
|
||||
/* the equal elements order. */
|
||||
/*******************************************************************/
|
||||
lt = base;
|
||||
eq = Swix + lo;
|
||||
gt = Swix;
|
||||
|
||||
if (jj == mid) {
|
||||
/*****************************************************************/
|
||||
/* Compare element was last. No problem. */
|
||||
/*****************************************************************/
|
||||
for (i = base; i < max; i++)
|
||||
if ((rc = Qcompare(i, mid)) < 0)
|
||||
*lt++ = *i;
|
||||
else if (rc > 0)
|
||||
*gt++ = *i;
|
||||
else
|
||||
*--eq = *i;
|
||||
|
||||
} else {
|
||||
/*****************************************************************/
|
||||
/* Compare element was not last and was copied to top of block. */
|
||||
/*****************************************************************/
|
||||
for (i = base; i < mid; i++)
|
||||
if ((rc = Qcompare(i, mid)) < 0)
|
||||
*lt++ = *i;
|
||||
else if (rc > 0)
|
||||
*gt++ = *i;
|
||||
else
|
||||
*--eq = *i;
|
||||
|
||||
/*****************************************************************/
|
||||
/* Restore saved last value and do the comparison from there. */
|
||||
/*****************************************************************/
|
||||
*--i = c;
|
||||
|
||||
if ((rc = Qcompare(i, mid)) < 0)
|
||||
*lt++ = *i;
|
||||
else if (rc > 0)
|
||||
*gt++ = *i;
|
||||
else
|
||||
*--eq = *i;
|
||||
|
||||
} // endif
|
||||
|
||||
/*******************************************************************/
|
||||
/* Now copy the equal and greater values back in the main array in */
|
||||
/* the same order they have been placed in the work area. */
|
||||
/*******************************************************************/
|
||||
for (j = Swix + lo, i = lt; j > eq; )
|
||||
*i++ = *--j;
|
||||
|
||||
for (j = Swix, jj = i; j < gt; )
|
||||
*i++ = *j++;
|
||||
|
||||
/*******************************************************************/
|
||||
/* The mid block being placed at its final position we can now set */
|
||||
/* the offset array values indicating break point and block size. */
|
||||
/*******************************************************************/
|
||||
if (Pof)
|
||||
Pof[lt - Pex] = Pof[(jj - 1) - Pex] = jj - lt;
|
||||
|
||||
/*******************************************************************/
|
||||
/* Look at sizes of the two partitions, do the smaller one first */
|
||||
/* by recursion, then do the larger one by making sure lo is its */
|
||||
/* size, base and max are update correctly, and branching back. */
|
||||
/* But only repeat (recursively or by branching) if the partition */
|
||||
/* is of at least size THRESH. */
|
||||
/*******************************************************************/
|
||||
lo = lt - base;
|
||||
hi = gt - Swix;
|
||||
|
||||
if (Dup) { // Update progress information
|
||||
zlo = Cmpnum(lo);
|
||||
zhi = Cmpnum(hi);
|
||||
Dup->ProgCur += cnm - (zlo + zhi);
|
||||
} // endif Dup
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" done lo=%d hi=%d\n",
|
||||
lo, /*Swix + lt - base - eq,*/ hi);
|
||||
#endif
|
||||
|
||||
if (lo <= hi) {
|
||||
if (lo >= Thresh)
|
||||
Qstc(base, lt);
|
||||
else if (lo == 1 && Pof)
|
||||
Pof[base - Pex] = 1;
|
||||
|
||||
base = jj;
|
||||
lo = hi;
|
||||
cnm = zhi;
|
||||
} else {
|
||||
if (hi >= Thresh)
|
||||
Qstc(jj, max);
|
||||
else if (hi == 1 && Pof)
|
||||
Pof[jj - Pex] = 1;
|
||||
|
||||
max = lt;
|
||||
cnm = zlo;
|
||||
} // endif
|
||||
|
||||
if (lo == 1 && Pof)
|
||||
Pof[base - Pex] = 1;
|
||||
|
||||
} while (lo >= Thresh); // enddo
|
||||
|
||||
} // end of Qstc
|
||||
|
||||
/***********************************************************************/
|
||||
/* Conservative insertion sort not using/setting offset array. */
|
||||
/***********************************************************************/
|
||||
void CSORT::Istc(int *base, int *hi, int *max)
|
||||
{
|
||||
register int c;
|
||||
register int *lo;
|
||||
register int *i, *j;
|
||||
|
||||
/*********************************************************************/
|
||||
/* First put smallest element, which must be in the first THRESH, */
|
||||
/* in the first position as a sentinel. This is done just by */
|
||||
/* searching the 1st THRESH elements (or the 1st n if n < THRESH) */
|
||||
/* finding the min, and shifting it into the first position. */
|
||||
/*********************************************************************/
|
||||
for (j = lo = base; ++lo < hi; )
|
||||
if (Qcompare(j, lo) > 0)
|
||||
j = lo;
|
||||
|
||||
if (j != base) { // shift j into place
|
||||
c = *j;
|
||||
|
||||
for (i = j; --j >= base; i = j)
|
||||
*i = *j;
|
||||
|
||||
*base = c;
|
||||
} // endif j
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("sentinel %d in place, base=%p hi=%p max=%p\n",
|
||||
c, base, hi, max);
|
||||
#endif
|
||||
|
||||
/*********************************************************************/
|
||||
/* With our sentinel in place, we now run the following hyper- */
|
||||
/* fast insertion sort. For each remaining element, lo, from [1] */
|
||||
/* to [n-1], set hi to the index of the element AFTER which this */
|
||||
/* one goes. Then, do the standard insertion sort shift for each */
|
||||
/* element in the frob. */
|
||||
/*********************************************************************/
|
||||
for (lo = base; (hi = ++lo) < max;) {
|
||||
while (Qcompare(--hi, lo) > 0) ;
|
||||
|
||||
#ifdef DEBUG2
|
||||
htrc("after while: hi(%p)=%d lo(%p)=%d\n",
|
||||
hi, *hi, lo, *lo);
|
||||
#endif
|
||||
|
||||
if (++hi != lo) {
|
||||
c = *lo;
|
||||
|
||||
for (i = j = lo; --j >= hi; i = j)
|
||||
*i = *j;
|
||||
|
||||
*i = c;
|
||||
} // endif hi
|
||||
|
||||
} // endfor lo
|
||||
|
||||
} // end of Istc
|
||||
|
||||
/* -------------------------- End of CSort --------------------------- */
|
||||
106
storage/connect/csort.h
Normal file
106
storage/connect/csort.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*************** Csort H Declares Source Code File (.H) ****************/
|
||||
/* Name: CSORT.H Version 1.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2000-2012 */
|
||||
/* */
|
||||
/* This file contains the CSORT class declares (not 64-bits ready) */
|
||||
/* */
|
||||
/* Note on use of this class: This class is meant to be used as a */
|
||||
/* base class by the calling class. This is because the comparison */
|
||||
/* routine must belong to both CSORT and the calling class. */
|
||||
/* This avoids to pass explicitly to it the calling "this" pointer. */
|
||||
/***********************************************************************/
|
||||
#if !defined(CSORT_DEFINED)
|
||||
#define CSORT_DEFINED
|
||||
|
||||
#include <math.h> /* Required for log function */
|
||||
#undef DOMAIN // Was defined in math.h
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constant and external definitions. */
|
||||
/***********************************************************************/
|
||||
#define THRESH 4 /* Threshold for insertion (was 4) */
|
||||
#define MTHRESH 6 /* Threshold for median */
|
||||
|
||||
#ifdef DEBTRACE
|
||||
extern FILE *debug; /* Debug file */
|
||||
#endif
|
||||
|
||||
typedef int* const CPINT;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the CSORT base class declaration. */
|
||||
/***********************************************************************/
|
||||
class DllExport CSORT {
|
||||
public:
|
||||
// Constructor
|
||||
CSORT(bool cns, int th = THRESH, int mth = MTHRESH);
|
||||
|
||||
protected:
|
||||
// Implementation
|
||||
/*********************************************************************/
|
||||
/* qsortx/qstx are NOT conservative but use less storage space. */
|
||||
/* qsortc/qstc ARE conservative but use more storage space. */
|
||||
/*********************************************************************/
|
||||
int Qsortx(void); /* Index quick/insert sort */
|
||||
void Qstx(int *base, int *max); /* Preliminary quick sort */
|
||||
int Qsortc(void); /* Conservative q/ins sort */
|
||||
void Qstc(int *base, int *max); /* Preliminary quick sort */
|
||||
void Istc(int *base, int *hi, int *max); /* Insertion sort routine */
|
||||
|
||||
public:
|
||||
// Methods
|
||||
int Qsort(PGLOBAL g, int n); /* Sort calling routine */
|
||||
//virtual void Print(PGLOBAL g, FILE *f, uint n);
|
||||
//virtual void Print(PGLOBAL g, char *ps, uint z);
|
||||
#ifdef DEBTRACE
|
||||
int GetNcmp(void) {return num_comp;}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Overridable
|
||||
virtual int Qcompare(int *, int *) = 0; /* Item compare routine */
|
||||
#ifdef DEBTRACE
|
||||
virtual void DebugSort(int ph, int n, int *base, int *mid, int *tmp);
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Utility
|
||||
static void SetCmpNum(void)
|
||||
{for (int i = 1; i < 1000; i++) Cpn[i] = Cmpnum(i); Limit = 1000;}
|
||||
protected:
|
||||
static size_t Cmpnum(int n)
|
||||
#if defined(AIX)
|
||||
{return (n < Limit) ? Cpn[n]
|
||||
: (size_t)round(1.0 + (double)n * (log2((double)n) - 1.0));}
|
||||
#else // !AIX
|
||||
{return (n < Limit) ? Cpn[n]
|
||||
: (size_t)(1.5 + (double)n * (log((double)n)/Lg2 - 1.0));}
|
||||
#endif // !AIX
|
||||
|
||||
|
||||
// Members
|
||||
static int Limit; /* Size of precalculated array */
|
||||
static size_t Cpn[1000]; /* Precalculated cmpnum values */
|
||||
static double Lg2; /* Precalculated log(2) value */
|
||||
PGLOBAL G;
|
||||
PDBUSER Dup; /* Used for progress info */
|
||||
bool Cons; /* true for conservative sort */
|
||||
int Thresh; /* Threshold for using qsort */
|
||||
int Mthresh; /* Threshold for median find */
|
||||
int Nitem; /* Number of items to sort */
|
||||
MBLOCK Index; /* Index allocation block */
|
||||
MBLOCK Offset; /* Offset allocation block */
|
||||
CPINT &Pex; /* Reference to sort index */
|
||||
CPINT &Pof; /* Reference to offset array */
|
||||
int *Swix; /* Pointer on EQ/GT work area */
|
||||
int Savmax; /* Saved ProgMax value */
|
||||
int Savcur; /* Saved ProgCur value */
|
||||
LPCSTR Savstep; /* Saved progress step */
|
||||
#ifdef DEBTRACE
|
||||
int num_comp; /* Number of quick sort calls */
|
||||
#endif
|
||||
}; // end of class CSORT
|
||||
|
||||
#endif // CSORT_DEFINED
|
||||
|
||||
595
storage/connect/domdoc.cpp
Normal file
595
storage/connect/domdoc.cpp
Normal file
@@ -0,0 +1,595 @@
|
||||
/******************************************************************/
|
||||
/* Implementation of XML document processing using MS DOM */
|
||||
/* Author: Olivier Bertrand 2007 - 2013 */
|
||||
/******************************************************************/
|
||||
#include "my_global.h"
|
||||
#include <stdio.h>
|
||||
#if defined(WIN32)
|
||||
//#include <windows.h>
|
||||
#if defined(MSX2)
|
||||
#import "msxml2.dll" //Does not exist on Vista
|
||||
#elif defined(MSX3)
|
||||
#import "msxml3.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
|
||||
#else // MSX4
|
||||
#import "msxml4.dll" //Causes error C2872: DOMNodeType: ambiguous symbol
|
||||
#endif // MSX
|
||||
using namespace MSXML2;
|
||||
#else
|
||||
#error This is a Windows implementation only
|
||||
#endif
|
||||
|
||||
#define NODE_TYPE_LIST
|
||||
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "xobject.h"
|
||||
#include "domdoc.h"
|
||||
|
||||
inline bool TestHr(PGLOBAL g, HRESULT hr)
|
||||
{
|
||||
if FAILED(hr) {
|
||||
sprintf(g->Message, "%s, hr=%d", MSG(COM_ERROR), hr);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
|
||||
} // end of TestHr
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a DOMDOC as a XMLDOC. */
|
||||
/******************************************************************/
|
||||
PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf,
|
||||
char *enc, PFBLOCK fp)
|
||||
{
|
||||
return (PXDOC) new(g) DOMDOC(nsl, nsdf, enc, fp);
|
||||
} // end of GetDomDoc
|
||||
|
||||
/***********************************************************************/
|
||||
/* Close a loaded DOM XML file. */
|
||||
/***********************************************************************/
|
||||
void CloseXMLFile(PGLOBAL g, PFBLOCK fp, bool all)
|
||||
{
|
||||
PXBLOCK xp = (PXBLOCK)fp;
|
||||
|
||||
if (xp && xp->Count > 1 && !all) {
|
||||
xp->Count--;
|
||||
} else if (xp && xp->Count > 0) {
|
||||
try {
|
||||
xp->Docp->Release();
|
||||
} catch(_com_error e) {
|
||||
sprintf(g->Message, "%s %s", MSG(COM_ERROR), e.Description());
|
||||
} catch(...) {}
|
||||
|
||||
CoUninitialize();
|
||||
xp->Count = 0;
|
||||
} // endif
|
||||
|
||||
} // end of CloseXMLFile
|
||||
|
||||
/* ------------------------ class DOMDOC ------------------------ */
|
||||
|
||||
/******************************************************************/
|
||||
/* DOMDOC constructor. */
|
||||
/******************************************************************/
|
||||
DOMDOC::DOMDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp)
|
||||
: XMLDOCUMENT(nsl, nsdf, enc)
|
||||
{
|
||||
assert (!fp || fp->Type == TYPE_FB_XML);
|
||||
Docp = (fp) ? ((PXBLOCK)fp)->Docp : NULL;
|
||||
Nlist = NULL;
|
||||
Hr = 0;
|
||||
} // end of DOMDOC constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Initialize XML parser and check library compatibility. */
|
||||
/******************************************************************/
|
||||
bool DOMDOC::Initialize(PGLOBAL g)
|
||||
{
|
||||
if (TestHr(g, CoInitialize(NULL)))
|
||||
return true;
|
||||
|
||||
if (TestHr(g, Docp.CreateInstance("msxml2.domdocument")))
|
||||
return true;
|
||||
|
||||
return MakeNSlist(g);
|
||||
} // end of Initialize
|
||||
|
||||
/******************************************************************/
|
||||
/* Parse the XML file and construct node tree in memory. */
|
||||
/******************************************************************/
|
||||
bool DOMDOC::ParseFile(char *fn)
|
||||
{
|
||||
// Load the document
|
||||
Docp->async = false;
|
||||
|
||||
if (!(bool)Docp->load((_bstr_t)fn))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} // end of ParseFile
|
||||
|
||||
/******************************************************************/
|
||||
/* Create or reuse an Xblock for this document. */
|
||||
/******************************************************************/
|
||||
PFBLOCK DOMDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
|
||||
{
|
||||
PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
|
||||
PXBLOCK xp = (PXBLOCK)PlugSubAlloc(g, NULL, sizeof(XBLOCK));
|
||||
|
||||
memset(xp, 0, sizeof(XBLOCK));
|
||||
xp->Next = (PXBLOCK)dup->Openlist;
|
||||
dup->Openlist = (PFBLOCK)xp;
|
||||
xp->Type = TYPE_FB_XML;
|
||||
xp->Fname = (LPCSTR)PlugSubAlloc(g, NULL, strlen(fn) + 1);
|
||||
strcpy((char*)xp->Fname, fn);
|
||||
xp->Count = 1;
|
||||
xp->Length = (m == MODE_READ) ? 1 : 0;
|
||||
xp->Docp = Docp;
|
||||
xp->Retcode = rc;
|
||||
|
||||
// Return xp as a fp
|
||||
return (PFBLOCK)xp;
|
||||
} // end of LinkXblock
|
||||
|
||||
/******************************************************************/
|
||||
/* Create the XML node. */
|
||||
/******************************************************************/
|
||||
bool DOMDOC::NewDoc(PGLOBAL g, char *ver)
|
||||
{
|
||||
char buf[64];
|
||||
MSXML2::IXMLDOMProcessingInstructionPtr pip;
|
||||
|
||||
sprintf(buf, "version=\"%s\" encoding=\"%s\"", ver, Encoding);
|
||||
pip = Docp->createProcessingInstruction("xml", buf);
|
||||
return(TestHr(g, Docp->appendChild(pip)));
|
||||
} // end of NewDoc
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a comment to the document node. */
|
||||
/******************************************************************/
|
||||
void DOMDOC::AddComment(PGLOBAL g, char *com)
|
||||
{
|
||||
TestHr(g, Docp->appendChild(Docp->createComment(com)));
|
||||
} // end of AddComment
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node class of the root of the document. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMDOC::GetRoot(PGLOBAL g)
|
||||
{
|
||||
MSXML2::IXMLDOMElementPtr root = Docp->documentElement;
|
||||
|
||||
if (root == NULL)
|
||||
return NULL;
|
||||
|
||||
return new(g) DOMNODE(this, root);
|
||||
} // end of GetRoot
|
||||
|
||||
/******************************************************************/
|
||||
/* Create a new root element and return its class node. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMDOC::NewRoot(PGLOBAL g, char *name)
|
||||
{
|
||||
MSXML2::IXMLDOMElementPtr ep = Docp->createElement(name);
|
||||
|
||||
if (ep == NULL || TestHr(g, Docp->appendChild(ep)))
|
||||
return NULL;
|
||||
|
||||
return new(g) DOMNODE(this, ep);
|
||||
} // end of NewRoot
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a void DOMNODE node class. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMDOC::NewPnode(PGLOBAL g, char *name)
|
||||
{
|
||||
MSXML2::IXMLDOMElementPtr root = NULL;
|
||||
|
||||
if (name)
|
||||
if ((root = Docp->createElement(name)) == NULL)
|
||||
return NULL;
|
||||
|
||||
return new(g) DOMNODE(this, root);
|
||||
} // end of NewPnode
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a void DOMATTR node class. */
|
||||
/******************************************************************/
|
||||
PXATTR DOMDOC::NewPattr(PGLOBAL g)
|
||||
{
|
||||
return new(g) DOMATTR(this, NULL);
|
||||
} // end of NewPattr
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a void DOMATTR node class. */
|
||||
/******************************************************************/
|
||||
PXLIST DOMDOC::NewPlist(PGLOBAL g)
|
||||
{
|
||||
return new(g) DOMNODELIST(this, NULL);
|
||||
} // end of NewPlist
|
||||
|
||||
/******************************************************************/
|
||||
/* Dump the node tree to a new XML file. */
|
||||
/******************************************************************/
|
||||
int DOMDOC::DumpDoc(PGLOBAL g, char *ofn)
|
||||
{
|
||||
if (TestHr(g, Docp->save(ofn)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
} // end of Dump
|
||||
|
||||
/******************************************************************/
|
||||
/* Free the document, cleanup the XML library, and */
|
||||
/* debug memory for regression tests. */
|
||||
/******************************************************************/
|
||||
void DOMDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
|
||||
{
|
||||
CloseXMLFile(g, xp, false);
|
||||
} // end of Close
|
||||
|
||||
/* ----------------------- class DOMNODE ------------------------ */
|
||||
|
||||
/******************************************************************/
|
||||
/* DOMNODE constructor. */
|
||||
/******************************************************************/
|
||||
DOMNODE::DOMNODE(PXDOC dp, MSXML2::IXMLDOMNodePtr np) : XMLNODE(dp)
|
||||
{
|
||||
Docp = ((PDOMDOC)dp)->Docp;
|
||||
Nodep = np;
|
||||
Ws = NULL;
|
||||
Len = 0;
|
||||
} // end of DOMNODE constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node name. */
|
||||
/******************************************************************/
|
||||
char *DOMNODE::GetName(PGLOBAL g)
|
||||
{
|
||||
if (!WideCharToMultiByte(CP_ACP, 0, Nodep->nodeName, -1,
|
||||
Name, sizeof(Name), NULL, NULL)) {
|
||||
strcpy(g->Message, MSG(NAME_CONV_ERR));
|
||||
return NULL;
|
||||
} // endif
|
||||
|
||||
return Name;
|
||||
} // end of GetName
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node class of next sibling of the node. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMNODE::GetNext(PGLOBAL g)
|
||||
{
|
||||
if (Nodep->nextSibling == NULL)
|
||||
Next = NULL;
|
||||
else if (!Next)
|
||||
Next = new(g) DOMNODE(Doc, Nodep->nextSibling);
|
||||
|
||||
return Next;
|
||||
} // end of GetNext
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node class of first children of the node. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMNODE::GetChild(PGLOBAL g)
|
||||
{
|
||||
if (Nodep->firstChild == NULL)
|
||||
Children = NULL;
|
||||
else if (!Children)
|
||||
Children = new(g) DOMNODE(Doc, Nodep->firstChild);
|
||||
|
||||
return Children;
|
||||
} // end of GetChild
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the content of a node and subnodes. */
|
||||
/******************************************************************/
|
||||
char *DOMNODE::GetText(char *buf, int len)
|
||||
{
|
||||
// Nodep can be null for a missing HTML table column
|
||||
if (Nodep)
|
||||
strncpy(buf, Nodep->text, len);
|
||||
else
|
||||
*buf = '\0';
|
||||
|
||||
return buf;
|
||||
} // end of GetText
|
||||
|
||||
/******************************************************************/
|
||||
/* Set the text content of an attribute. */
|
||||
/******************************************************************/
|
||||
bool DOMNODE::SetContent(PGLOBAL g, char *txtp, int len)
|
||||
{
|
||||
bool rc;
|
||||
BSTR val;
|
||||
|
||||
if (len > Len || !Ws) {
|
||||
Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
|
||||
Len = len;
|
||||
} // endif len
|
||||
|
||||
if (!MultiByteToWideChar(CP_ACP, 0, txtp, strlen(txtp) + 1,
|
||||
Ws, Len + 1)) {
|
||||
sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
|
||||
return true;
|
||||
} // endif
|
||||
|
||||
val = SysAllocString(Ws);
|
||||
rc = TestHr(g, Nodep->put_text(val));
|
||||
SysFreeString(val);
|
||||
return rc;
|
||||
} // end of SetContent
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a clone of this node. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMNODE::Clone(PGLOBAL g, PXNODE np)
|
||||
{
|
||||
if (np) {
|
||||
((PDOMNODE)np)->Nodep = Nodep;
|
||||
return np;
|
||||
} else
|
||||
return new(g) DOMNODE(Doc, Nodep);
|
||||
|
||||
} // end of Clone
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the list of all or matching children that are elements.*/
|
||||
/******************************************************************/
|
||||
PXLIST DOMNODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp)
|
||||
{
|
||||
MSXML2::IXMLDOMNodeListPtr dnlp;
|
||||
|
||||
if (xp) {
|
||||
if (Nodep->nodeType == MSXML2::NODE_ELEMENT) {
|
||||
MSXML2::IXMLDOMElementPtr ep = Nodep;
|
||||
dnlp = ep->getElementsByTagName(xp);
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} else
|
||||
dnlp = Nodep->childNodes;
|
||||
|
||||
if (lp) {
|
||||
((PDOMLIST)lp)->Listp = dnlp;
|
||||
return lp;
|
||||
} else
|
||||
return new(g) DOMNODELIST(Doc, dnlp);
|
||||
|
||||
} // end of GetChildElements
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the list of nodes verifying the passed Xapth. */
|
||||
/******************************************************************/
|
||||
PXLIST DOMNODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp)
|
||||
{
|
||||
MSXML2::IXMLDOMNodeListPtr dnlp = Nodep->selectNodes(xp);
|
||||
|
||||
if (lp) {
|
||||
((PDOMLIST)lp)->Listp = dnlp;
|
||||
return lp;
|
||||
} else
|
||||
return new(g) DOMNODELIST(Doc, dnlp);
|
||||
|
||||
} // end of SelectNodes
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the first node verifying the passed Xapth. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMNODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np)
|
||||
{
|
||||
MSXML2::IXMLDOMNodePtr dnp = Nodep->selectSingleNode(xp);
|
||||
|
||||
if (dnp) {
|
||||
if (np) {
|
||||
((PDOMNODE)np)->Nodep = dnp;
|
||||
return np;
|
||||
} else
|
||||
return new(g) DOMNODE(Doc, dnp);
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of SelectSingleNode
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node attribute with the specified name. */
|
||||
/******************************************************************/
|
||||
PXATTR DOMNODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap)
|
||||
{
|
||||
MSXML2::IXMLDOMElementPtr ep = Nodep;
|
||||
MSXML2::IXMLDOMAttributePtr atp = ep->getAttributeNode(name);
|
||||
|
||||
if (atp) {
|
||||
if (ap) {
|
||||
((PDOMATTR)ap)->Atrp = atp;
|
||||
return ap;
|
||||
} else
|
||||
return new(g) DOMATTR(Doc, atp);
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of GetAttribute
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a new element child node to this node and return it. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMNODE::AddChildNode(PGLOBAL g, char *name, PXNODE np)
|
||||
{
|
||||
char *p, *pn;
|
||||
// char *p, *pn, *epf, *pf = NULL;
|
||||
MSXML2::IXMLDOMNodePtr ep;
|
||||
// _bstr_t uri((wchar_t*)NULL);
|
||||
|
||||
#if 0
|
||||
// Is a prefix specified ?
|
||||
if ((p = strchr(name, ':'))) {
|
||||
pf = BufAlloc(g, name, p - name);
|
||||
|
||||
// Is it the pseudo default prefix
|
||||
if (Doc->DefNs && !strcmp(pf, Doc->DefNs)) {
|
||||
name = p + 1; // Suppress it from name
|
||||
pf = NULL; // No real prefix
|
||||
} // endif DefNs
|
||||
|
||||
} // endif p
|
||||
|
||||
// Look for matching namespace URI in context
|
||||
for (ep = Nodep; ep; ep = ep->parentNode) {
|
||||
epf = (_bstr_t)ep->prefix;
|
||||
|
||||
if ((!pf && !epf) || (pf && epf && !strcmp(pf, epf))) {
|
||||
uri = Nodep->namespaceURI;
|
||||
break;
|
||||
} // endif
|
||||
|
||||
} // endfor ep
|
||||
|
||||
if ((wchar_t*)uri == NULL) {
|
||||
if (!pf)
|
||||
pf = Doc->DefNs;
|
||||
|
||||
// Look for the namespace URI corresponding to this node
|
||||
if (pf)
|
||||
for (PNS nsp = Doc->Namespaces; nsp; nsp = nsp->Next)
|
||||
if (!strcmp(pf, nsp->Prefix)) {
|
||||
uri = nsp->Uri;
|
||||
break;
|
||||
} // endfor nsp
|
||||
|
||||
} // endif pns
|
||||
#endif // 0
|
||||
|
||||
// If name has the format m[n] only m is taken as node name
|
||||
if ((p = strchr(name, '[')))
|
||||
pn = BufAlloc(g, name, p - name);
|
||||
else
|
||||
pn = name;
|
||||
|
||||
// Construct the element node with eventual namespace
|
||||
// ep = Docp->createNode(_variant_t("Element"), pn, uri);
|
||||
ep = Docp->createElement(pn);
|
||||
|
||||
_bstr_t pfx = ep->prefix;
|
||||
_bstr_t uri = ep->namespaceURI;
|
||||
|
||||
if (ep == NULL || TestHr(g, Nodep->appendChild(ep)))
|
||||
return NULL;
|
||||
|
||||
if (np)
|
||||
((PDOMNODE)np)->Nodep = ep;
|
||||
else
|
||||
np = new(g) DOMNODE(Doc, ep);
|
||||
|
||||
return NewChild(np);
|
||||
} // end of AddChildNode
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a new property to this node and return it. */
|
||||
/******************************************************************/
|
||||
PXATTR DOMNODE::AddProperty(PGLOBAL g, char *name, PXATTR ap)
|
||||
{
|
||||
MSXML2::IXMLDOMAttributePtr atp = Docp->createAttribute(name);
|
||||
|
||||
if (atp) {
|
||||
MSXML2::IXMLDOMElementPtr ep = Nodep;
|
||||
ep->setAttributeNode(atp);
|
||||
|
||||
if (ap) {
|
||||
((PDOMATTR)ap)->Atrp = atp;
|
||||
return ap;
|
||||
} else
|
||||
return new(g) DOMATTR(Doc, atp);
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of AddProperty
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a new text node to this node. */
|
||||
/******************************************************************/
|
||||
void DOMNODE::AddText(PGLOBAL g, char *txtp)
|
||||
{
|
||||
MSXML2::IXMLDOMTextPtr tp= Docp->createTextNode((_bstr_t)txtp);
|
||||
|
||||
if (tp != NULL)
|
||||
TestHr(g, Nodep->appendChild(tp));
|
||||
|
||||
} // end of AddText
|
||||
|
||||
/******************************************************************/
|
||||
/* Remove a child node from this node. */
|
||||
/******************************************************************/
|
||||
void DOMNODE::DeleteChild(PGLOBAL g, PXNODE dnp)
|
||||
{
|
||||
TestHr(g, Nodep->removeChild(((PDOMNODE)dnp)->Nodep));
|
||||
// ((PDOMNODE)dnp)->Nodep->Release(); bad idea, causes a crash
|
||||
Delete(dnp);
|
||||
} // end of DeleteChild
|
||||
|
||||
/* --------------------- class DOMNODELIST ---------------------- */
|
||||
|
||||
/******************************************************************/
|
||||
/* DOMNODELIST constructor. */
|
||||
/******************************************************************/
|
||||
DOMNODELIST::DOMNODELIST(PXDOC dp, MSXML2::IXMLDOMNodeListPtr lp)
|
||||
: XMLNODELIST(dp)
|
||||
{
|
||||
Listp = lp;
|
||||
} // end of DOMNODELIST constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the nth element of the list. */
|
||||
/******************************************************************/
|
||||
PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
|
||||
{
|
||||
if (Listp == NULL || Listp->length <= n)
|
||||
return NULL;
|
||||
|
||||
if (np) {
|
||||
((PDOMNODE)np)->Nodep = Listp->item[n];
|
||||
return np;
|
||||
} else
|
||||
return new(g) DOMNODE(Doc, Listp->item[n]);
|
||||
|
||||
} // end of GetItem
|
||||
|
||||
/* ----------------------- class DOMATTR ------------------------ */
|
||||
|
||||
/******************************************************************/
|
||||
/* DOMATTR constructor. */
|
||||
/******************************************************************/
|
||||
DOMATTR::DOMATTR(PXDOC dp, MSXML2::IXMLDOMAttributePtr ap)
|
||||
: XMLATTRIBUTE(dp)
|
||||
{
|
||||
Atrp = ap;
|
||||
Ws = NULL;
|
||||
Len = 0;
|
||||
} // end of DOMATTR constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Set the text content of an attribute. */
|
||||
/******************************************************************/
|
||||
bool DOMATTR::SetText(PGLOBAL g, char *txtp, int len)
|
||||
{
|
||||
bool rc;
|
||||
BSTR val;
|
||||
|
||||
if (len > Len || !Ws) {
|
||||
Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
|
||||
Len = len;
|
||||
} // endif len
|
||||
|
||||
if (!MultiByteToWideChar(CP_ACP, 0, txtp, strlen(txtp) + 1,
|
||||
Ws, Len + 1)) {
|
||||
sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
|
||||
return true;
|
||||
} // endif
|
||||
|
||||
val = SysAllocString(Ws);
|
||||
rc = TestHr(g, Atrp->put_text(val));
|
||||
SysFreeString(val);
|
||||
return rc;
|
||||
} // end of SetText
|
||||
138
storage/connect/domdoc.h
Normal file
138
storage/connect/domdoc.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/******************************************************************/
|
||||
/* Declaration of XML document processing using MS DOM */
|
||||
/* Author: Olivier Bertrand 2007 - 2012 */
|
||||
/******************************************************************/
|
||||
#include "plgxml.h"
|
||||
|
||||
typedef class DOMDOC *PDOMDOC;
|
||||
typedef class DOMNODE *PDOMNODE;
|
||||
typedef class DOMATTR *PDOMATTR;
|
||||
typedef class DOMNODELIST *PDOMLIST;
|
||||
|
||||
/******************************************************************/
|
||||
/* XML block. Must have the same layout than FBLOCK up to Type. */
|
||||
/******************************************************************/
|
||||
typedef struct _xblock { /* Loaded XML file block */
|
||||
struct _xblock *Next;
|
||||
LPCSTR Fname; /* Point on file name */
|
||||
size_t Length; /* Used to tell if read mode */
|
||||
short Count; /* Nb of times file is used */
|
||||
short Type; /* TYPE_FB_XML */
|
||||
int Retcode; /* Return code from Load */
|
||||
MSXML2::IXMLDOMDocumentPtr Docp;/* Document interface pointer */
|
||||
//IXMLDOMNodeListPtr Nlist;
|
||||
} XBLOCK, *PXBLOCK;
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of DOM document. */
|
||||
/******************************************************************/
|
||||
class DOMDOC : public XMLDOCUMENT {
|
||||
friend class DOMNODE;
|
||||
public:
|
||||
// Constructor
|
||||
DOMDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp);
|
||||
|
||||
// Properties
|
||||
virtual short GetDocType(void) {return TYPE_FB_XML;}
|
||||
virtual void *GetDocPtr(void) {return Docp;}
|
||||
|
||||
// Methods
|
||||
virtual bool Initialize(PGLOBAL g);
|
||||
virtual bool ParseFile(char *fn);
|
||||
virtual bool NewDoc(PGLOBAL g, char *ver);
|
||||
virtual void AddComment(PGLOBAL g, char *com);
|
||||
virtual PXNODE GetRoot(PGLOBAL g);
|
||||
virtual PXNODE NewRoot(PGLOBAL g, char *name);
|
||||
virtual PXNODE NewPnode(PGLOBAL g, char *name);
|
||||
virtual PXATTR NewPattr(PGLOBAL g);
|
||||
virtual PXLIST NewPlist(PGLOBAL g);
|
||||
virtual int DumpDoc(PGLOBAL g, char *ofn);
|
||||
virtual void CloseDoc(PGLOBAL g, PFBLOCK xp);
|
||||
virtual PFBLOCK LinkXblock(PGLOBAL g, MODE m, int rc, char *fn);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
MSXML2::IXMLDOMDocumentPtr Docp;
|
||||
MSXML2::IXMLDOMNodeListPtr Nlist;
|
||||
HRESULT Hr;
|
||||
}; // end of class DOMDOC
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of DOM XML node. */
|
||||
/******************************************************************/
|
||||
class DOMNODE : public XMLNODE {
|
||||
friend class DOMDOC;
|
||||
friend class DOMNODELIST;
|
||||
public:
|
||||
// Properties
|
||||
virtual char *GetName(PGLOBAL g);
|
||||
virtual int GetType(void) {return Nodep->nodeType;}
|
||||
virtual PXNODE GetNext(PGLOBAL g);
|
||||
virtual PXNODE GetChild(PGLOBAL g);
|
||||
|
||||
// Methods
|
||||
virtual char *GetText(char *buf, int len);
|
||||
virtual bool SetContent(PGLOBAL g, char *txtp, int len);
|
||||
virtual PXNODE Clone(PGLOBAL g, PXNODE np);
|
||||
virtual PXLIST GetChildElements(PGLOBAL g, char *xp, PXLIST lp);
|
||||
virtual PXLIST SelectNodes(PGLOBAL g, char *xp, PXLIST lp);
|
||||
virtual PXNODE SelectSingleNode(PGLOBAL g, char *xp, PXNODE np);
|
||||
virtual PXATTR GetAttribute(PGLOBAL g, char *name, PXATTR ap);
|
||||
virtual PXNODE AddChildNode(PGLOBAL g, char *name, PXNODE np);
|
||||
virtual PXATTR AddProperty(PGLOBAL g, char *name, PXATTR ap);
|
||||
virtual void AddText(PGLOBAL g, char *txtp);
|
||||
virtual void DeleteChild(PGLOBAL g, PXNODE dnp);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
DOMNODE(PXDOC dp, MSXML2::IXMLDOMNodePtr np);
|
||||
|
||||
// Members
|
||||
MSXML2::IXMLDOMDocumentPtr Docp;
|
||||
MSXML2::IXMLDOMNodePtr Nodep;
|
||||
char Name[64];
|
||||
WCHAR *Ws;
|
||||
int Len;
|
||||
}; // end of class DOMNODE
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of DOM XML node list. */
|
||||
/******************************************************************/
|
||||
class DOMNODELIST : public XMLNODELIST {
|
||||
friend class DOMDOC;
|
||||
friend class DOMNODE;
|
||||
public:
|
||||
// Methods
|
||||
virtual int GetLength(void) {return Listp->length;}
|
||||
virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
DOMNODELIST(PXDOC dp, MSXML2::IXMLDOMNodeListPtr lp);
|
||||
|
||||
// Members
|
||||
MSXML2::IXMLDOMNodeListPtr Listp;
|
||||
}; // end of class DOMNODELIST
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of DOM XML attribute. */
|
||||
/******************************************************************/
|
||||
class DOMATTR : public XMLATTRIBUTE {
|
||||
friend class DOMDOC;
|
||||
friend class DOMNODE;
|
||||
public:
|
||||
// Properties
|
||||
//virtual char *GetText(void);
|
||||
|
||||
// Methods
|
||||
virtual bool SetText(PGLOBAL g, char *txtp, int len);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
DOMATTR(PXDOC dp, MSXML2::IXMLDOMAttributePtr ap);
|
||||
|
||||
// Members
|
||||
MSXML2::IXMLDOMAttributePtr Atrp;
|
||||
WCHAR *Ws;
|
||||
int Len;
|
||||
}; // end of class DOMATTR
|
||||
1013
storage/connect/engmsg.h
Normal file
1013
storage/connect/engmsg.h
Normal file
File diff suppressed because it is too large
Load Diff
688
storage/connect/filamap.cpp
Normal file
688
storage/connect/filamap.cpp
Normal file
@@ -0,0 +1,688 @@
|
||||
/*********** File AM Map C++ Program Source Code File (.CPP) ***********/
|
||||
/* PROGRAM NAME: FILAMAP */
|
||||
/* ------------- */
|
||||
/* Version 1.4 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the MAP file access method classes. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant sections of the System header files. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif // __BORLANDC__
|
||||
//#include <windows.h>
|
||||
#else // !WIN32
|
||||
#if defined(UNIX)
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#else // !UNIX
|
||||
#include <io.h>
|
||||
#endif // !UNIX
|
||||
#include <fcntl.h>
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing the DB application declarations. */
|
||||
/* filamtxt.h is header containing the file AM classes declarations. */
|
||||
/* Note: these files are included inside the include files below. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "osutil.h"
|
||||
#include "maputil.h"
|
||||
#include "filamap.h"
|
||||
#include "tabdos.h"
|
||||
|
||||
bool PushWarning(PGLOBAL, PTDBASE);
|
||||
|
||||
/* --------------------------- Class MAPFAM -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constructors. */
|
||||
/***********************************************************************/
|
||||
MAPFAM::MAPFAM(PDOSDEF tdp) : TXTFAM(tdp)
|
||||
{
|
||||
Memory = NULL;
|
||||
Mempos = NULL;
|
||||
Tpos = NULL;
|
||||
Fpos = NULL;
|
||||
Spos = NULL;
|
||||
Top = NULL;
|
||||
} // end of MAPFAM standard constructor
|
||||
|
||||
MAPFAM::MAPFAM(PMAPFAM tmfp) : TXTFAM(tmfp)
|
||||
{
|
||||
Memory = tmfp->Memory;
|
||||
Mempos = tmfp->Mempos;
|
||||
Fpos = tmfp->Fpos;
|
||||
Spos = tmfp->Spos;
|
||||
Tpos = tmfp->Tpos;
|
||||
Top = tmfp->Top;
|
||||
} // end of MAPFAM copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset: reset position values at the beginning of file. */
|
||||
/***********************************************************************/
|
||||
void MAPFAM::Reset(void)
|
||||
{
|
||||
TXTFAM::Reset();
|
||||
Fpos = Tpos = Spos = NULL;
|
||||
} // end of Reset
|
||||
|
||||
/***********************************************************************/
|
||||
/* MAP GetFileLength: returns file size in number of bytes. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::GetFileLength(PGLOBAL g)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = (To_Fb) ? To_Fb->Length : TXTFAM::GetFileLength(g);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Mapped file length=%d\n", len);
|
||||
#endif
|
||||
|
||||
return len;
|
||||
} // end of GetFileLength
|
||||
|
||||
/***********************************************************************/
|
||||
/* OpenTableFile: Open a DOS/UNIX table file as a mapped file. */
|
||||
/***********************************************************************/
|
||||
bool MAPFAM::OpenTableFile(PGLOBAL g)
|
||||
{
|
||||
char filename[_MAX_PATH];
|
||||
int len;
|
||||
MODE mode = Tdbp->GetMode();
|
||||
PFBLOCK fp;
|
||||
PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
// Insert mode is no more handled using file mapping
|
||||
assert(mode != MODE_INSERT);
|
||||
#endif // _DEBUG
|
||||
|
||||
/*********************************************************************/
|
||||
/* We used the file name relative to recorded datapath. */
|
||||
/*********************************************************************/
|
||||
PlugSetPath(filename, To_File, Tdbp->GetPath());
|
||||
|
||||
/*********************************************************************/
|
||||
/* Under Win32 the whole file will be mapped so we can use it as */
|
||||
/* if it were entirely read into virtual memory. */
|
||||
/* Firstly we check whether this file have been already mapped. */
|
||||
/*********************************************************************/
|
||||
if (mode == MODE_READ) {
|
||||
for (fp = dbuserp->Openlist; fp; fp = fp->Next)
|
||||
if (fp->Type == TYPE_FB_MAP && !stricmp(fp->Fname, filename)
|
||||
&& fp->Count && fp->Mode == mode)
|
||||
break;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Mapping file, fp=%p\n", fp);
|
||||
#endif
|
||||
} else
|
||||
fp = NULL;
|
||||
|
||||
if (fp) {
|
||||
/*******************************************************************/
|
||||
/* File already mapped. Just increment use count and get pointer. */
|
||||
/*******************************************************************/
|
||||
fp->Count++;
|
||||
Memory = fp->Memory;
|
||||
len = fp->Length;
|
||||
} else {
|
||||
/*******************************************************************/
|
||||
/* If required, delete the whole file if no filtering is implied. */
|
||||
/*******************************************************************/
|
||||
bool del;
|
||||
HANDLE hFile;
|
||||
MEMMAP mm;
|
||||
|
||||
del = mode == MODE_DELETE && !Tdbp->GetNext();
|
||||
|
||||
if (del)
|
||||
DelRows = Cardinality(g);
|
||||
|
||||
/*******************************************************************/
|
||||
/* Create the mapping file object. */
|
||||
/*******************************************************************/
|
||||
hFile = CreateFileMap(g, filename, &mm, mode, del);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
DWORD rc = GetLastError();
|
||||
|
||||
if (!(*g->Message))
|
||||
sprintf(g->Message, MSG(OPEN_MODE_ERROR),
|
||||
"map", rc, filename);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("%s\n", g->Message);
|
||||
#endif
|
||||
return (mode == MODE_READ && rc == ENOENT)
|
||||
? PushWarning(g, Tdbp) : true;
|
||||
} // endif hFile
|
||||
|
||||
/*******************************************************************/
|
||||
/* Get the file size (assuming file is smaller than 4 GB) */
|
||||
/*******************************************************************/
|
||||
len = mm.lenL;
|
||||
Memory = (char *)mm.memory;
|
||||
|
||||
if (!len) { // Empty or deleted file
|
||||
CloseFileHandle(hFile);
|
||||
Tdbp->ResetSize();
|
||||
return false;
|
||||
} // endif len
|
||||
|
||||
if (!Memory) {
|
||||
CloseFileHandle(hFile);
|
||||
sprintf(g->Message, MSG(MAP_VIEW_ERROR),
|
||||
filename, GetLastError());
|
||||
return true;
|
||||
} // endif Memory
|
||||
|
||||
if (mode != MODE_DELETE) {
|
||||
CloseFileHandle(hFile); // Not used anymore
|
||||
hFile = INVALID_HANDLE_VALUE; // For Fblock
|
||||
} // endif Mode
|
||||
|
||||
/*******************************************************************/
|
||||
/* Link a Fblock. This make possible to reuse already opened maps */
|
||||
/* and also to automatically unmap them in case of error g->jump. */
|
||||
/* Note: block can already exist for previously closed file. */
|
||||
/*******************************************************************/
|
||||
fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
|
||||
fp->Type = TYPE_FB_MAP;
|
||||
fp->Fname = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
|
||||
strcpy((char*)fp->Fname, filename);
|
||||
fp->Next = dbuserp->Openlist;
|
||||
dbuserp->Openlist = fp;
|
||||
fp->Count = 1;
|
||||
fp->Length = len;
|
||||
fp->Memory = Memory;
|
||||
fp->Mode = mode;
|
||||
fp->File = NULL;
|
||||
fp->Handle = hFile; // Used for Delete
|
||||
} // endif fp
|
||||
|
||||
To_Fb = fp; // Useful when closing
|
||||
|
||||
/*********************************************************************/
|
||||
/* The pseudo "buffer" is here the entire file mapping view. */
|
||||
/*********************************************************************/
|
||||
Fpos = Mempos = Memory;
|
||||
Top = Memory + len;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n",
|
||||
fp, fp->Count, Memory, len, Top);
|
||||
#endif
|
||||
|
||||
return AllocateBuffer(g); // Useful for DBF files
|
||||
} // end of OpenTableFile
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetRowID: return the RowID of last read record. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::GetRowID(void)
|
||||
{
|
||||
return Rows;
|
||||
} // end of GetRowID
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetPos: return the position of last read record. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::GetPos(void)
|
||||
{
|
||||
return Fpos - Memory;
|
||||
} // end of GetPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetNextPos: return the position of next record. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::GetNextPos(void)
|
||||
{
|
||||
return Mempos - Memory;
|
||||
} // end of GetNextPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetPos: Replace the table at the specified position. */
|
||||
/***********************************************************************/
|
||||
bool MAPFAM::SetPos(PGLOBAL g, int pos)
|
||||
{
|
||||
Fpos = Mempos = Memory + pos;
|
||||
|
||||
if (Mempos >= Top || Mempos < Memory) {
|
||||
strcpy(g->Message, MSG(INV_MAP_POS));
|
||||
return true;
|
||||
} // endif Mempos
|
||||
|
||||
Placed = true;
|
||||
return false;
|
||||
} // end of SetPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Record file position in case of UPDATE or DELETE. */
|
||||
/***********************************************************************/
|
||||
bool MAPFAM::RecordPos(PGLOBAL g)
|
||||
{
|
||||
Fpos = Mempos;
|
||||
return false;
|
||||
} // end of RecordPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Skip one record in file. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::SkipRecord(PGLOBAL g, bool header)
|
||||
{
|
||||
PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
|
||||
|
||||
// Skip this record
|
||||
while (*Mempos++ != '\n') ; // What about Unix ???
|
||||
|
||||
if (Mempos >= Top)
|
||||
return RC_EF;
|
||||
|
||||
// Update progress information
|
||||
dup->ProgCur = GetPos();
|
||||
|
||||
if (header)
|
||||
Fpos = Tpos = Spos = Mempos; // For Delete
|
||||
|
||||
return RC_OK;
|
||||
} // end of SkipRecord
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBuffer: Read one line for a mapped text file. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
int len;
|
||||
|
||||
// Are we at the end of the memory
|
||||
if (Mempos >= Top)
|
||||
return RC_EF;
|
||||
|
||||
if (!Placed) {
|
||||
/*******************************************************************/
|
||||
/* Record file position in case of UPDATE or DELETE. */
|
||||
/*******************************************************************/
|
||||
Fpos = Mempos;
|
||||
CurBlk = (int)Rows++;
|
||||
} else
|
||||
Placed = false;
|
||||
|
||||
// Immediately calculate next position (Used by DeleteDB)
|
||||
while (*Mempos++ != '\n') ; // What about Unix ???
|
||||
|
||||
// Set caller line buffer
|
||||
len = (Mempos - Fpos) - Ending;
|
||||
memcpy(Tdbp->GetLine(), Fpos, len);
|
||||
Tdbp->GetLine()[len] = '\0';
|
||||
return RC_OK;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteBuffer: File write routine for MAP access method. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::WriteBuffer(PGLOBAL g)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
// Insert mode is no more handled using file mapping
|
||||
if (Tdbp->GetMode() == MODE_INSERT) {
|
||||
strcpy(g->Message, MSG(NO_MAP_INSERT));
|
||||
return RC_FX;
|
||||
} // endif
|
||||
#endif // _DEBUG
|
||||
|
||||
/*********************************************************************/
|
||||
/* Copy the updated record back into the memory mapped file. */
|
||||
/*********************************************************************/
|
||||
memcpy(Fpos, Tdbp->GetLine(), strlen(Tdbp->GetLine()));
|
||||
return RC_OK;
|
||||
} // end of WriteBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for MAP (and FIX?) access methods. */
|
||||
/* Lines between deleted lines are moved in the mapfile view. */
|
||||
/***********************************************************************/
|
||||
int MAPFAM::DeleteRecords(PGLOBAL g, int irc)
|
||||
{
|
||||
int n;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
fprintf(debug,
|
||||
"MAP DeleteDB: irc=%d mempos=%p tobuf=%p Tpos=%p Spos=%p\n",
|
||||
irc, Mempos, To_Buf, Tpos, Spos);
|
||||
#endif
|
||||
|
||||
if (irc != RC_OK) {
|
||||
/*******************************************************************/
|
||||
/* EOF: position Fpos at the top of map position. */
|
||||
/*******************************************************************/
|
||||
Fpos = Top;
|
||||
#ifdef DEBTRACE
|
||||
htrc("Fpos placed at file top=%p\n", Fpos);
|
||||
#endif
|
||||
} // endif irc
|
||||
|
||||
if (Tpos == Spos)
|
||||
/*******************************************************************/
|
||||
/* First line to delete. Move of eventual preceeding lines is */
|
||||
/* not required here, just setting of future Spos and Tpos. */
|
||||
/*******************************************************************/
|
||||
Tpos = Fpos; // Spos is set below
|
||||
else if ((n = Fpos - Spos) > 0) {
|
||||
/*******************************************************************/
|
||||
/* Non consecutive line to delete. Move intermediate lines. */
|
||||
/*******************************************************************/
|
||||
memmove(Tpos, Spos, n);
|
||||
Tpos += n;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("move %d bytes\n", n);
|
||||
#endif
|
||||
} // endif n
|
||||
|
||||
if (irc == RC_OK) {
|
||||
Spos = Mempos; // New start position
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
/*******************************************************************/
|
||||
/* Last call after EOF has been reached. */
|
||||
/* We must firstly Unmap the view and use the saved file handle */
|
||||
/* to put an EOF at the end of the copied part of the file. */
|
||||
/*******************************************************************/
|
||||
PFBLOCK fp = To_Fb;
|
||||
|
||||
CloseMemMap(fp->Memory, (size_t)fp->Length);
|
||||
fp->Count = 0; // Avoid doing it twice
|
||||
|
||||
/*******************************************************************/
|
||||
/* Remove extra records. */
|
||||
/*******************************************************************/
|
||||
n = Tpos - Memory;
|
||||
|
||||
#if defined(WIN32)
|
||||
DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN);
|
||||
|
||||
if (drc == 0xFFFFFFFF) {
|
||||
sprintf(g->Message, MSG(FUNCTION_ERROR),
|
||||
"SetFilePointer", GetLastError());
|
||||
CloseHandle(fp->Handle);
|
||||
return RC_FX;
|
||||
} // endif
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc);
|
||||
#endif
|
||||
|
||||
if (!SetEndOfFile(fp->Handle)) {
|
||||
sprintf(g->Message, MSG(FUNCTION_ERROR),
|
||||
"SetEndOfFile", GetLastError());
|
||||
CloseHandle(fp->Handle);
|
||||
return RC_FX;
|
||||
} // endif
|
||||
|
||||
CloseHandle(fp->Handle);
|
||||
#else // UNIX
|
||||
if (ftruncate(fp->Handle, (off_t)n)) {
|
||||
sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
|
||||
close(fp->Handle);
|
||||
return RC_FX;
|
||||
} // endif
|
||||
|
||||
close(fp->Handle);
|
||||
#endif // UNIX
|
||||
} // endif irc
|
||||
|
||||
return RC_OK; // All is correct
|
||||
} // end of DeleteRecords
|
||||
|
||||
/***********************************************************************/
|
||||
/* Table file close routine for MAP access method. */
|
||||
/***********************************************************************/
|
||||
void MAPFAM::CloseTableFile(PGLOBAL g)
|
||||
{
|
||||
PlugCloseFile(g, To_Fb);
|
||||
To_Fb = NULL; // To get correct file size in Cardinality
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("MAP Close: closing %s count=%d\n",
|
||||
To_File, (To_Fb) ? To_Fb->Count : 0);
|
||||
#endif
|
||||
} // end of CloseTableFile
|
||||
|
||||
/***********************************************************************/
|
||||
/* Rewind routine for MAP access method. */
|
||||
/***********************************************************************/
|
||||
void MAPFAM::Rewind(void)
|
||||
{
|
||||
Mempos = Memory;
|
||||
} // end of Rewind
|
||||
|
||||
/* --------------------------- Class MBKFAM -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constructors. */
|
||||
/***********************************************************************/
|
||||
MBKFAM::MBKFAM(PDOSDEF tdp) : MAPFAM(tdp)
|
||||
{
|
||||
Blocked = true;
|
||||
Block = tdp->GetBlock();
|
||||
Last = tdp->GetLast();
|
||||
Nrec = tdp->GetElemt();
|
||||
BlkPos = tdp->GetTo_Pos();
|
||||
CurNum = Nrec;
|
||||
} // end of MBKFAM standard constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset: reset position values at the beginning of file. */
|
||||
/***********************************************************************/
|
||||
void MBKFAM::Reset(void)
|
||||
{
|
||||
MAPFAM::Reset();
|
||||
CurNum = Nrec; // To start by a new block
|
||||
} // end of Reset
|
||||
|
||||
/***********************************************************************/
|
||||
/* 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). */
|
||||
/***********************************************************************/
|
||||
int MBKFAM::Cardinality(PGLOBAL g)
|
||||
{
|
||||
// Should not be called in this version
|
||||
return (g) ? -1 : 0;
|
||||
//return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
|
||||
} // end of Cardinality
|
||||
|
||||
/***********************************************************************/
|
||||
/* Skip one record in file. */
|
||||
/***********************************************************************/
|
||||
int MBKFAM::SkipRecord(PGLOBAL g, bool header)
|
||||
{
|
||||
return RC_OK;
|
||||
} // end of SkipRecord
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetRowID: return the RowID of last read record. */
|
||||
/***********************************************************************/
|
||||
int MBKFAM::GetRowID(void)
|
||||
{
|
||||
return CurNum + Nrec * CurBlk + 1;
|
||||
} // end of GetRowID
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBuffer: Read one line for a mapped Fix file. */
|
||||
/***********************************************************************/
|
||||
int MBKFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
int len;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Sequential block reading when Placed is not true. */
|
||||
/*********************************************************************/
|
||||
if (Placed) {
|
||||
Placed = false;
|
||||
} else if (Mempos >= Top) { // Are we at the end of the memory
|
||||
return RC_EF;
|
||||
} else if (++CurNum < Nrec) {
|
||||
Fpos = Mempos;
|
||||
} else {
|
||||
/*******************************************************************/
|
||||
/* New block. */
|
||||
/*******************************************************************/
|
||||
CurNum = 0;
|
||||
|
||||
if (++CurBlk >= Block)
|
||||
return RC_EF;
|
||||
|
||||
Fpos = Mempos = Memory + BlkPos[CurBlk];
|
||||
} // endif's
|
||||
|
||||
// Immediately calculate next position (Used by DeleteDB)
|
||||
while (*Mempos++ != '\n') ; // What about Unix ???
|
||||
|
||||
// Set caller line buffer
|
||||
len = (Mempos - Fpos) - Ending;
|
||||
memcpy(Tdbp->GetLine(), Fpos, len);
|
||||
Tdbp->GetLine()[len] = '\0';
|
||||
return RC_OK;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* Rewind routine for FIX MAP access method. */
|
||||
/***********************************************************************/
|
||||
void MBKFAM::Rewind(void)
|
||||
{
|
||||
Mempos = Memory + Headlen;
|
||||
CurBlk = -1;
|
||||
CurNum = Nrec;
|
||||
} // end of Rewind
|
||||
|
||||
/* --------------------------- Class MPXFAM -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constructors. */
|
||||
/***********************************************************************/
|
||||
MPXFAM::MPXFAM(PDOSDEF tdp) : MBKFAM(tdp)
|
||||
{
|
||||
Blksize = tdp->GetBlksize();
|
||||
Padded = tdp->GetPadded();
|
||||
|
||||
if (Padded && Blksize)
|
||||
Nrec = Blksize / Lrecl;
|
||||
else {
|
||||
Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
|
||||
Blksize = Nrec * Lrecl;
|
||||
Padded = false;
|
||||
} // endelse
|
||||
|
||||
CurNum = Nrec;
|
||||
} // end of MPXFAM standard constructor
|
||||
|
||||
#if 0 // MBKFAM routine is correct
|
||||
/***********************************************************************/
|
||||
/* GetRowID: return the RowID of last read record. */
|
||||
/***********************************************************************/
|
||||
int MPXFAM::GetRowID(void)
|
||||
{
|
||||
return (Mempos - Memory - Headlen) / Lrecl;
|
||||
} // end of GetRowID
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetPos: return the position of last read record. */
|
||||
/***********************************************************************/
|
||||
int MPXFAM::GetPos(void)
|
||||
{
|
||||
return (CurNum + Nrec * CurBlk); // Computed file index
|
||||
} // end of GetPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetPos: Replace the table at the specified position. */
|
||||
/***********************************************************************/
|
||||
bool MPXFAM::SetPos(PGLOBAL g, int pos)
|
||||
{
|
||||
if (pos < 0) {
|
||||
strcpy(g->Message, MSG(INV_REC_POS));
|
||||
return true;
|
||||
} // endif recpos
|
||||
|
||||
CurBlk = pos / Nrec;
|
||||
CurNum = pos % Nrec;
|
||||
Fpos = Mempos = Memory + Headlen + pos * Lrecl;
|
||||
|
||||
// Indicate the table position was externally set
|
||||
Placed = true;
|
||||
return false;
|
||||
} // end of SetPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBuffer: Read one line for a mapped Fix file. */
|
||||
/***********************************************************************/
|
||||
int MPXFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* Sequential block reading when Placed is not true. */
|
||||
/*********************************************************************/
|
||||
if (Placed) {
|
||||
Placed = false;
|
||||
} else if (Mempos >= Top) { // Are we at the end of the memory
|
||||
return RC_EF;
|
||||
} else if (++CurNum < Nrec) {
|
||||
Fpos = Mempos;
|
||||
} else {
|
||||
/*******************************************************************/
|
||||
/* New block. */
|
||||
/*******************************************************************/
|
||||
CurNum = 0;
|
||||
|
||||
if (++CurBlk >= Block)
|
||||
return RC_EF;
|
||||
|
||||
Fpos = Mempos = Headlen + Memory + CurBlk * Blksize;
|
||||
} // endif's
|
||||
|
||||
Tdbp->SetLine(Mempos);
|
||||
|
||||
// Immediately calculate next position (Used by DeleteDB)
|
||||
Mempos += Lrecl;
|
||||
return RC_OK;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteBuffer: File write routine for MAP access method. */
|
||||
/***********************************************************************/
|
||||
int MPXFAM::WriteBuffer(PGLOBAL g)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
// Insert mode is no more handled using file mapping
|
||||
if (Tdbp->GetMode() == MODE_INSERT) {
|
||||
strcpy(g->Message, MSG(NO_MAP_INSERT));
|
||||
return RC_FX;
|
||||
} // endif
|
||||
#endif // _DEBUG
|
||||
|
||||
// In Update mode, file was modified in memory
|
||||
return RC_OK;
|
||||
} // end of WriteBuffer
|
||||
|
||||
114
storage/connect/filamap.h
Normal file
114
storage/connect/filamap.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*************** FilAMap H Declares Source Code File (.H) **************/
|
||||
/* Name: FILAMAP.H Version 1.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the MAP file access method classes declares. */
|
||||
/***********************************************************************/
|
||||
#ifndef __FILAMAP_H
|
||||
#define __FILAMAP_H
|
||||
|
||||
#include "block.h"
|
||||
#include "filamtxt.h"
|
||||
|
||||
typedef class MAPFAM *PMAPFAM;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the variable file access method using file mapping. */
|
||||
/***********************************************************************/
|
||||
class DllExport MAPFAM : public TXTFAM {
|
||||
public:
|
||||
// Constructor
|
||||
MAPFAM(PDOSDEF tdp);
|
||||
MAPFAM(PMAPFAM tmfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_MAP;}
|
||||
virtual int GetPos(void);
|
||||
virtual int GetNextPos(void);
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) MAPFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual int GetFileLength(PGLOBAL g);
|
||||
virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;}
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
|
||||
virtual int GetRowID(void);
|
||||
virtual bool RecordPos(PGLOBAL g);
|
||||
virtual bool SetPos(PGLOBAL g, int recpos);
|
||||
virtual int SkipRecord(PGLOBAL g, bool header);
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual bool DeferReading(void) {return false;}
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *Memory; // Pointer on file mapping view.
|
||||
char *Mempos; // Position of next data to read
|
||||
char *Fpos; // Position of last read record
|
||||
char *Tpos; // Target Position for delete move
|
||||
char *Spos; // Start position for delete move
|
||||
char *Top; // Mark end of file mapping view
|
||||
}; // end of class MAPFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the blocked file access method using file mapping. */
|
||||
/***********************************************************************/
|
||||
class DllExport MBKFAM : public MAPFAM {
|
||||
public:
|
||||
// Constructor
|
||||
MBKFAM(PDOSDEF tdp);
|
||||
MBKFAM(PMAPFAM tmfp) : MAPFAM(tmfp) {}
|
||||
|
||||
// Implementation
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) MBKFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s)
|
||||
{return TXTFAM::MaxBlkSize(g, s);}
|
||||
virtual int GetRowID(void);
|
||||
virtual int SkipRecord(PGLOBAL g, bool header);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
// No additional members
|
||||
}; // end of class MBKFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the fixed file access method using file mapping. */
|
||||
/***********************************************************************/
|
||||
class DllExport MPXFAM : public MBKFAM {
|
||||
public:
|
||||
// Constructor
|
||||
MPXFAM(PDOSDEF tdp);
|
||||
MPXFAM(PMAPFAM tmfp) : MBKFAM(tmfp) {}
|
||||
|
||||
// Implementation
|
||||
virtual int GetPos(void);
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) MPXFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);}
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s)
|
||||
{return TXTFAM::MaxBlkSize(g, s);}
|
||||
//virtual int GetRowID(void);
|
||||
virtual bool SetPos(PGLOBAL g, int recpos);
|
||||
virtual bool DeferReading(void) {return false;}
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// No additional members
|
||||
}; // end of class MPXFAM
|
||||
|
||||
#endif // __FILAMAP_H
|
||||
975
storage/connect/filamdbf.cpp
Normal file
975
storage/connect/filamdbf.cpp
Normal file
@@ -0,0 +1,975 @@
|
||||
/*********** File AM Dbf C++ Program Source Code File (.CPP) ****************/
|
||||
/* PROGRAM NAME: FILAMDBF */
|
||||
/* ------------- */
|
||||
/* Version 1.6 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the DBF file access method classes. */
|
||||
/* */
|
||||
/* ACKNOWLEDGEMENT: */
|
||||
/* ---------------- */
|
||||
/* Somerset Data Systems, Inc. (908) 766-5845 */
|
||||
/* Version 1.2 April 6, 1991 */
|
||||
/* Programmer: Jay Parsons */
|
||||
/****************************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant sections of the System header files. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
//#include <errno.h>
|
||||
//#include <windows.h>
|
||||
#else // !WIN32
|
||||
#if defined(UNIX)
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#else // !UNIX
|
||||
//#include <io.h>
|
||||
#endif // !UNIX
|
||||
//#include <fcntl.h>
|
||||
#endif // !WIN32
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing the DB application declarations. */
|
||||
/* tabdos.h is header containing the TABDOS class declarations. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
//#include "catalog.h"
|
||||
//#include "kindex.h"
|
||||
#include "filamdbf.h"
|
||||
#include "tabdos.h"
|
||||
#include "valblk.h"
|
||||
#define NO_FUNC
|
||||
#include "plgcnx.h" // For DB types
|
||||
#include "resource.h"
|
||||
|
||||
/****************************************************************************/
|
||||
/* Definitions. */
|
||||
/****************************************************************************/
|
||||
#define HEADLEN 32 /* sizeof ( mainhead or thisfield ) */
|
||||
//efine MEMOLEN 10 /* length of memo field in .dbf */
|
||||
#define DBFTYPE 3 /* value of bits 0 and 1 if .dbf */
|
||||
#define EOH 0x0D /* end-of-header marker in .dbf file */
|
||||
|
||||
/****************************************************************************/
|
||||
/* Catalog utility function. */
|
||||
/****************************************************************************/
|
||||
PQRYRES PlgAllocResult(PGLOBAL, int, int, int, int *, int *,
|
||||
unsigned int *, bool blank = true, bool nonull = false);
|
||||
bool PushWarning(PGLOBAL, PTDBASE);
|
||||
|
||||
extern "C" int trace; // The general trace value
|
||||
|
||||
/****************************************************************************/
|
||||
/* First 32 bytes of a .dbf file. */
|
||||
/* Note: some reserved fields are used here to store info (Fields) */
|
||||
/****************************************************************************/
|
||||
typedef struct _dbfheader {
|
||||
//uchar Dbf :2; /* both 1 for dBASE III or IV .dbf */
|
||||
//uchar :1;
|
||||
//uchar Db4dbt:1; /* 1 if a dBASE IV-type .dbt exists */
|
||||
//uchar Dbfox :4; /* FoxPro if equal to 3 */
|
||||
uchar Version; /* Version information flags */
|
||||
char Filedate[3]; /* date, YYMMDD, binary. YY=year-1900 */
|
||||
uint Records; /* records in the file */
|
||||
ushort Headlen; /* bytes in the header */
|
||||
ushort Reclen; /* bytes in a record */
|
||||
ushort Fields; /* Reserved but used to store fields */
|
||||
char Incompleteflag; /* 01 if incomplete, else 00 */
|
||||
char Encryptflag; /* 01 if encrypted, else 00 */
|
||||
char Reserved2[12]; /* for LAN use */
|
||||
char Mdxflag; /* 01 if production .mdx, else 00 */
|
||||
char Language; /* Codepage */
|
||||
char Reserved3[2];
|
||||
} DBFHEADER;
|
||||
|
||||
/****************************************************************************/
|
||||
/* Column field descriptor of a .dbf file. */
|
||||
/****************************************************************************/
|
||||
typedef struct _descriptor {
|
||||
char Name[11]; /* field name, in capitals, null filled*/
|
||||
char Type; /* field type, C, D, F, L, M or N */
|
||||
uint Offset; /* used in memvars, not in files. */
|
||||
uchar Length; /* field length */
|
||||
uchar Decimals; /* number of decimal places */
|
||||
short Reserved4;
|
||||
char Workarea; /* ??? */
|
||||
char Reserved5[2];
|
||||
char Setfield; /* ??? */
|
||||
char Reserved6[7];
|
||||
char Mdxfield; /* 01 if tag field in production .mdx */
|
||||
} DESCRIPTOR;
|
||||
|
||||
/****************************************************************************/
|
||||
/* dbfhead: Routine to analyze a .dbf header. */
|
||||
/* Parameters: */
|
||||
/* PGLOBAL g -- pointer to the Plug Global structure */
|
||||
/* FILE *file -- pointer to file to analyze */
|
||||
/* PSZ fn -- pathname of the file to analyze */
|
||||
/* DBFHEADER *buf -- pointer to _dbfheader structure */
|
||||
/* Returns: */
|
||||
/* RC_OK, RC_NF, RC_INFO, or RC_FX if error. */
|
||||
/* Side effects: */
|
||||
/* Moves file pointer to byte 32; fills buffer at buf with */
|
||||
/* first 32 bytes of file. */
|
||||
/****************************************************************************/
|
||||
static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf)
|
||||
{
|
||||
char endmark[2];
|
||||
int dbc = 2, rc = RC_OK;
|
||||
|
||||
*g->Message = '\0';
|
||||
|
||||
// Read the first 32 bytes into buffer
|
||||
if (fread(buf, HEADLEN, 1, file) != 1) {
|
||||
strcpy(g->Message, MSG(NO_READ_32));
|
||||
return RC_NF;
|
||||
} // endif fread
|
||||
|
||||
// Check first byte to be sure of .dbf type
|
||||
if ((buf->Version & 0x03) != DBFTYPE) {
|
||||
strcpy(g->Message, MSG(NOT_A_DBF_FILE));
|
||||
rc = RC_INFO;
|
||||
|
||||
if ((buf->Version & 0x30) == 0x30) {
|
||||
strcpy(g->Message, MSG(FOXPRO_FILE));
|
||||
dbc = 264; // FoxPro database container
|
||||
} // endif Version
|
||||
|
||||
} else
|
||||
strcpy(g->Message, MSG(DBASE_FILE));
|
||||
|
||||
// Check last byte(s) of header
|
||||
if (fseek(file, buf->Headlen - dbc, SEEK_SET) != 0) {
|
||||
sprintf(g->Message, MSG(BAD_HEADER), fn);
|
||||
return RC_FX;
|
||||
} // endif fseek
|
||||
|
||||
if (fread(&endmark, 2, 1, file) != 1) {
|
||||
strcpy(g->Message, MSG(BAD_HEAD_END));
|
||||
return RC_FX;
|
||||
} // endif fread
|
||||
|
||||
// Some files have just 1D others have 1D00 following fields
|
||||
if (endmark[0] != EOH && endmark[1] != EOH) {
|
||||
sprintf(g->Message, MSG(NO_0DH_HEAD), dbc);
|
||||
|
||||
if (rc == RC_OK)
|
||||
return RC_FX;
|
||||
|
||||
} // endif endmark
|
||||
|
||||
// Calculate here the number of fields while we have the dbc info
|
||||
buf->Fields = (buf->Headlen - dbc - 1) / 32;
|
||||
fseek(file, HEADLEN, SEEK_SET);
|
||||
return rc;
|
||||
} // end of dbfhead
|
||||
|
||||
/* -------------------------- Function DBFColumns ------------------------- */
|
||||
|
||||
/****************************************************************************/
|
||||
/* DBFColumns: constructs the result blocks containing the description */
|
||||
/* of all the columns of a DBF file that will be retrieved by #GetData. */
|
||||
/****************************************************************************/
|
||||
PQRYRES DBFColumns(PGLOBAL g, char *fn, BOOL info)
|
||||
{
|
||||
static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR,
|
||||
DB_INT, DB_INT, DB_SHORT};
|
||||
static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
|
||||
TYPE_INT, TYPE_INT, TYPE_SHORT};
|
||||
static unsigned int length[] = {11, 6, 8, 10, 10, 6};
|
||||
char buf[2], filename[_MAX_PATH];
|
||||
int ncol = sizeof(dbtype) / sizeof(int);
|
||||
int rc, type, field, fields;
|
||||
BOOL bad;
|
||||
DBFHEADER mainhead;
|
||||
DESCRIPTOR thisfield;
|
||||
FILE *infile;
|
||||
PQRYRES qrp;
|
||||
PCOLRES crp;
|
||||
|
||||
if (trace)
|
||||
htrc("DBFColumns: File %s\n", SVP(fn));
|
||||
|
||||
if (!fn) {
|
||||
strcpy(g->Message, MSG(MISSING_FNAME));
|
||||
return NULL;
|
||||
} // endif fn
|
||||
|
||||
/**************************************************************************/
|
||||
/* Open the input file. */
|
||||
/**************************************************************************/
|
||||
PlugSetPath(filename, fn, PlgGetDataPath(g));
|
||||
|
||||
if (!(infile = fopen(filename, "rb"))) {
|
||||
sprintf(g->Message, MSG(CANNOT_OPEN), filename);
|
||||
return NULL;
|
||||
} // endif file
|
||||
|
||||
/**************************************************************************/
|
||||
/* Get the first 32 bytes of the header. */
|
||||
/**************************************************************************/
|
||||
if ((rc = dbfhead(g, infile, filename, &mainhead)) == RC_FX) {
|
||||
fclose(infile);
|
||||
return NULL;
|
||||
} // endif dbfhead
|
||||
|
||||
/**************************************************************************/
|
||||
/* Allocate the structures used to refer to the result set. */
|
||||
/**************************************************************************/
|
||||
//fields = (mainhead.Headlen - 33) / 32;
|
||||
fields = mainhead.Fields;
|
||||
qrp = PlgAllocResult(g, ncol, fields, IDS_COLUMNS + 3,
|
||||
dbtype, buftyp, length);
|
||||
qrp->Info = info || (rc == RC_INFO);
|
||||
|
||||
if (trace) {
|
||||
htrc("Structure of %s\n", filename);
|
||||
htrc("headlen=%hd reclen=%hd degree=%d\n",
|
||||
mainhead.Headlen, mainhead.Reclen, fields);
|
||||
htrc("flags(iem)=%d,%d,%d cp=%d\n", mainhead.Incompleteflag,
|
||||
mainhead.Encryptflag, mainhead.Mdxflag, mainhead.Language);
|
||||
htrc("%hd records, last changed %02d/%02d/%d\n",
|
||||
mainhead.Records, mainhead.Filedate[1], mainhead.Filedate[2],
|
||||
mainhead.Filedate[0] + (mainhead.Filedate[0] <= 30) ? 2000 : 1900);
|
||||
htrc("Field Type Offset Len Dec Set Mdx\n");
|
||||
} // endif trace
|
||||
|
||||
buf[1] = '\0';
|
||||
|
||||
/**************************************************************************/
|
||||
/* Do it field by field. We are at byte 32 of file. */
|
||||
/**************************************************************************/
|
||||
for (field = 0; field < fields; field++) {
|
||||
bad = FALSE;
|
||||
|
||||
if (fread(&thisfield, HEADLEN, 1, infile) != 1) {
|
||||
sprintf(g->Message, MSG(ERR_READING_REC), field+1, fn);
|
||||
goto err;
|
||||
} // endif fread
|
||||
|
||||
if (trace)
|
||||
htrc("%-11s %c %6ld %3d %2d %3d %3d\n",
|
||||
thisfield.Name, thisfield.Type, thisfield.Offset, thisfield.Length,
|
||||
thisfield.Decimals, thisfield.Setfield, thisfield.Mdxfield);
|
||||
|
||||
/************************************************************************/
|
||||
/* Now get the results into blocks. */
|
||||
/************************************************************************/
|
||||
switch (thisfield.Type) {
|
||||
case 'C': // Characters
|
||||
case 'L': // Logical 'T' or 'F'
|
||||
type = TYPE_STRING;
|
||||
break;
|
||||
case 'N':
|
||||
type = (thisfield.Decimals) ? TYPE_FLOAT : TYPE_INT;
|
||||
break;
|
||||
case 'F':
|
||||
type = TYPE_FLOAT;
|
||||
break;
|
||||
case 'D':
|
||||
type = TYPE_DATE; // Is this correct ???
|
||||
break;
|
||||
default:
|
||||
if (!info) {
|
||||
sprintf(g->Message, MSG(BAD_DBF_TYPE), thisfield.Type);
|
||||
goto err;
|
||||
} // endif info
|
||||
|
||||
type = TYPE_ERROR;
|
||||
bad = TRUE;
|
||||
} // endswitch Type
|
||||
|
||||
crp = qrp->Colresp; // Column Name
|
||||
crp->Kdata->SetValue(thisfield.Name, field);
|
||||
crp = crp->Next; // Data Type
|
||||
crp->Kdata->SetValue((int)type, field);
|
||||
crp = crp->Next; // Type Name
|
||||
|
||||
if (bad) {
|
||||
buf[0] = thisfield.Type;
|
||||
crp->Kdata->SetValue(buf, field);
|
||||
} else
|
||||
crp->Kdata->SetValue(GetTypeName(type), field);
|
||||
|
||||
crp = crp->Next; // Precision
|
||||
crp->Kdata->SetValue((int)thisfield.Length, field);
|
||||
crp = crp->Next; // Length
|
||||
crp->Kdata->SetValue((int)thisfield.Length, field);
|
||||
crp = crp->Next; // Scale (precision)
|
||||
crp->Kdata->SetValue((int)thisfield.Decimals, field);
|
||||
} // endfor field
|
||||
|
||||
qrp->Nblin = field;
|
||||
fclose(infile);
|
||||
|
||||
if (info) {
|
||||
/************************************************************************/
|
||||
/* Prepare return message for dbfinfo command. */
|
||||
/************************************************************************/
|
||||
char buf[64];
|
||||
|
||||
sprintf(buf,
|
||||
"Ver=%02x ncol=%hu nlin=%u lrecl=%hu headlen=%hu date=%02d/%02d/%02d",
|
||||
mainhead.Version, fields, mainhead.Records, mainhead.Reclen,
|
||||
mainhead.Headlen, mainhead.Filedate[0], mainhead.Filedate[1],
|
||||
mainhead.Filedate[2]);
|
||||
|
||||
strcat(g->Message, buf);
|
||||
} // endif info
|
||||
|
||||
/**************************************************************************/
|
||||
/* Return the result pointer for use by GetData routines. */
|
||||
/**************************************************************************/
|
||||
return qrp;
|
||||
|
||||
err:
|
||||
fclose(infile);
|
||||
return NULL;
|
||||
} // end of DBFColumns
|
||||
|
||||
/* ---------------------------- Class DBFBASE ----------------------------- */
|
||||
|
||||
/****************************************************************************/
|
||||
/* Constructors. */
|
||||
/****************************************************************************/
|
||||
DBFBASE::DBFBASE(PDOSDEF tdp)
|
||||
{
|
||||
Records = 0;
|
||||
Nerr = 0;
|
||||
Maxerr = tdp->Maxerr;
|
||||
Accept = tdp->Accept;
|
||||
ReadMode = tdp->ReadMode;
|
||||
} // end of DBFBASE standard constructor
|
||||
|
||||
DBFBASE::DBFBASE(DBFBASE *txfp)
|
||||
{
|
||||
Records = txfp->Records;
|
||||
Nerr = txfp->Nerr;
|
||||
Maxerr = txfp->Maxerr;
|
||||
Accept = txfp->Accept;
|
||||
ReadMode = txfp->ReadMode;
|
||||
} // end of DBFBASE copy constructor
|
||||
|
||||
/****************************************************************************/
|
||||
/* ScanHeader: scan the DBF file header for number of records, record size,*/
|
||||
/* and header length. Set Records, check that Reclen is equal to lrecl and */
|
||||
/* return the header length or 0 in case of error. */
|
||||
/****************************************************************************/
|
||||
int DBFBASE::ScanHeader(PGLOBAL g, PSZ fname, int lrecl, char *defpath)
|
||||
{
|
||||
int rc;
|
||||
char filename[_MAX_PATH];
|
||||
DBFHEADER header;
|
||||
FILE *infile;
|
||||
|
||||
/************************************************************************/
|
||||
/* Open the input file. */
|
||||
/************************************************************************/
|
||||
PlugSetPath(filename, fname, defpath);
|
||||
|
||||
if (!(infile = fopen(filename, "rb"))) {
|
||||
sprintf(g->Message, MSG(CANNOT_OPEN), filename);
|
||||
return 0; // Assume file does not exist
|
||||
} // endif file
|
||||
|
||||
/************************************************************************/
|
||||
/* Get the first 32 bytes of the header. */
|
||||
/************************************************************************/
|
||||
rc = dbfhead(g, infile, filename, &header);
|
||||
fclose(infile);
|
||||
|
||||
if (rc == RC_NF) {
|
||||
Records = 0;
|
||||
return 0;
|
||||
} else if (rc == RC_FX)
|
||||
return -1;
|
||||
|
||||
if ((int)header.Reclen != lrecl) {
|
||||
sprintf(g->Message, MSG(BAD_LRECL), lrecl, header.Reclen);
|
||||
return -1;
|
||||
} // endif Lrecl
|
||||
|
||||
Records = (int)header.Records;
|
||||
return (int)header.Headlen;
|
||||
} // end of ScanHeader
|
||||
|
||||
/* ---------------------------- Class DBFFAM ------------------------------ */
|
||||
|
||||
/****************************************************************************/
|
||||
/* 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). */
|
||||
/****************************************************************************/
|
||||
int DBFFAM::Cardinality(PGLOBAL g)
|
||||
{
|
||||
if (!g)
|
||||
return 1;
|
||||
|
||||
if (!Headlen)
|
||||
if ((Headlen = ScanHeader(g, To_File, Lrecl, Tdbp->GetPath())) < 0)
|
||||
return -1; // Error in ScanHeader
|
||||
|
||||
// Set number of blocks for later use
|
||||
Block = (Records > 0) ? (Records + Nrec - 1) / Nrec : 0;
|
||||
return Records;
|
||||
} // end of Cardinality
|
||||
|
||||
#if 0 // Not compatible with ROWID block optimization
|
||||
/***********************************************************************/
|
||||
/* GetRowID: return the RowID of last read record. */
|
||||
/***********************************************************************/
|
||||
int DBFFAM::GetRowID(void)
|
||||
{
|
||||
return Rows;
|
||||
} // end of GetRowID
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* OpenTableFile: Open a DBF table file using C standard I/Os. */
|
||||
/* Binary mode cannot be used on Insert because of EOF (CTRL+Z) char. */
|
||||
/***********************************************************************/
|
||||
bool DBFFAM::OpenTableFile(PGLOBAL g)
|
||||
{
|
||||
char opmode[4], filename[_MAX_PATH];
|
||||
//int ftype = Tdbp->GetFtype();
|
||||
MODE mode = Tdbp->GetMode();
|
||||
PDBUSER dbuserp = PlgGetUser(g);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
strcpy(opmode, "rb");
|
||||
break;
|
||||
case MODE_DELETE:
|
||||
if (!Tdbp->GetNext()) {
|
||||
// Store the number of deleted lines
|
||||
DelRows = -1; // Means all lines deleted
|
||||
// DelRows = Cardinality(g); no good because of soft deleted lines
|
||||
|
||||
// This will erase the entire file
|
||||
strcpy(opmode, "w");
|
||||
Tdbp->ResetSize();
|
||||
Records = 0;
|
||||
break;
|
||||
} // endif
|
||||
|
||||
// Selective delete, pass thru
|
||||
case MODE_UPDATE:
|
||||
UseTemp = Tdbp->IsUsingTemp(g);
|
||||
strcpy(opmode, (UseTemp) ? "rb" : "r+b");
|
||||
break;
|
||||
case MODE_INSERT:
|
||||
// Must be in text mode to remove an eventual EOF character
|
||||
strcpy(opmode, "a+");
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
|
||||
return true;
|
||||
} // endswitch Mode
|
||||
|
||||
// Now open the file stream
|
||||
PlugSetPath(filename, To_File, Tdbp->GetPath());
|
||||
|
||||
if (!(Stream = PlugOpenFile(g, filename, opmode))) {
|
||||
sprintf(g->Message, MSG(OPEN_MODE_ERROR),
|
||||
opmode, (int)errno, filename);
|
||||
strcat(strcat(g->Message, ": "), strerror(errno));
|
||||
#ifdef DEBTRACE
|
||||
htrc("%s\n", g->Message);
|
||||
#endif
|
||||
return (errno == ENOENT) ? PushWarning(g, Tdbp) : true;
|
||||
} // endif Stream
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("File %s is open in mode %s\n", filename, opmode);
|
||||
#endif
|
||||
|
||||
To_Fb = dbuserp->Openlist; // Keep track of File block
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate the line buffer. For mode Delete a bigger buffer has to */
|
||||
/* be allocated because is it also used to move lines into the file.*/
|
||||
/*********************************************************************/
|
||||
return AllocateBuffer(g);
|
||||
} // end of OpenTableFile
|
||||
|
||||
/****************************************************************************/
|
||||
/* Allocate the block buffer for the table. */
|
||||
/****************************************************************************/
|
||||
bool DBFFAM::AllocateBuffer(PGLOBAL g)
|
||||
{
|
||||
int rc;
|
||||
MODE mode = Tdbp->GetMode();
|
||||
|
||||
Buflen = Blksize;
|
||||
To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
|
||||
|
||||
if (mode == MODE_INSERT) {
|
||||
#if defined(WIN32)
|
||||
/************************************************************************/
|
||||
/* Now we can revert to binary mode in particular because the eventual */
|
||||
/* writing of a new header must be done in binary mode to avoid */
|
||||
/* translating 0A bytes (LF) into 0D0A (CRLF) by Windows in text mode. */
|
||||
/************************************************************************/
|
||||
if (_setmode(_fileno(Stream), _O_BINARY) == -1) {
|
||||
sprintf(g->Message, MSG(BIN_MODE_FAIL), strerror(errno));
|
||||
return true;
|
||||
} // endif setmode
|
||||
#endif // WIN32
|
||||
|
||||
/************************************************************************/
|
||||
/* If this is a new file, the header must be generated. */
|
||||
/************************************************************************/
|
||||
int len = GetFileLength(g);
|
||||
|
||||
if (!len) {
|
||||
// Make the header for this DBF table file
|
||||
struct tm *datm;
|
||||
int hlen, n = 0, reclen = 1;
|
||||
time_t t;
|
||||
DBFHEADER *header;
|
||||
DESCRIPTOR *descp;
|
||||
PCOLDEF cdp;
|
||||
PDOSDEF tdp = (PDOSDEF)Tdbp->GetDef();
|
||||
|
||||
// Count the number of columns
|
||||
for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) {
|
||||
reclen += cdp->GetLong();
|
||||
n++;
|
||||
} // endfor cdp
|
||||
|
||||
if (Lrecl != reclen) {
|
||||
sprintf(g->Message, MSG(BAD_LRECL), Lrecl, reclen);
|
||||
return true;
|
||||
} // endif Lrecl
|
||||
|
||||
hlen = HEADLEN * (n + 1) + 2;
|
||||
header = (DBFHEADER*)PlugSubAlloc(g, NULL, hlen);
|
||||
memset(header, 0, hlen);
|
||||
header->Version = DBFTYPE;
|
||||
t = time(NULL) - (time_t)DTVAL::GetShift();
|
||||
datm = gmtime(&t);
|
||||
header->Filedate[0] = datm->tm_year - 100;
|
||||
header->Filedate[1] = datm->tm_mon + 1;
|
||||
header->Filedate[2] = datm->tm_mday;
|
||||
header->Headlen = (ushort)hlen;
|
||||
header->Reclen = (ushort)reclen;
|
||||
descp = (DESCRIPTOR*)header;
|
||||
|
||||
for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) {
|
||||
descp++;
|
||||
strncpy(descp->Name, cdp->GetName(), 11);
|
||||
descp->Type = *GetFormatType(cdp->GetType());
|
||||
descp->Length = (uchar)cdp->GetLong();
|
||||
descp->Decimals = (uchar)cdp->F.Prec;
|
||||
} // endfor cdp
|
||||
|
||||
*(char*)(++descp) = EOH;
|
||||
|
||||
// Now write the header
|
||||
if (fwrite(header, 1, hlen, Stream) != (unsigned)hlen) {
|
||||
sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
|
||||
return true;
|
||||
} // endif fwrite
|
||||
|
||||
Records = 0;
|
||||
Headlen = hlen;
|
||||
} else if (len < 0)
|
||||
return true; // Error in GetFileLength
|
||||
|
||||
/************************************************************************/
|
||||
/* For Insert the buffer must be prepared. */
|
||||
/************************************************************************/
|
||||
memset(To_Buf, ' ', Buflen);
|
||||
Rbuf = Nrec; // To be used by WriteDB
|
||||
} else if (UseTemp) {
|
||||
// Allocate a separate buffer so block reading can be kept
|
||||
Dbflen = Nrec;
|
||||
DelBuf = PlugSubAlloc(g, NULL, Blksize);
|
||||
} // endif's
|
||||
|
||||
if (!Headlen) {
|
||||
/************************************************************************/
|
||||
/* Here is a good place to process the DBF file header */
|
||||
/************************************************************************/
|
||||
DBFHEADER header;
|
||||
|
||||
if ((rc = dbfhead(g, Stream, Tdbp->GetFile(g), &header)) == RC_OK) {
|
||||
if (Lrecl != (int)header.Reclen) {
|
||||
sprintf(g->Message, MSG(BAD_LRECL), Lrecl, header.Reclen);
|
||||
return true;
|
||||
} // endif Lrecl
|
||||
|
||||
Records = (int)header.Records;
|
||||
Headlen = (int)header.Headlen;
|
||||
} else if (rc == RC_NF) {
|
||||
Records = 0;
|
||||
Headlen = 0;
|
||||
} else // RC_FX
|
||||
return true; // Error in dbfhead
|
||||
|
||||
} // endif Headlen
|
||||
|
||||
/**************************************************************************/
|
||||
/* Position the file at the begining of the data. */
|
||||
/**************************************************************************/
|
||||
if (Tdbp->GetMode() == MODE_INSERT)
|
||||
rc = fseek(Stream, 0, SEEK_END);
|
||||
else
|
||||
rc = fseek(Stream, Headlen, SEEK_SET);
|
||||
|
||||
if (rc) {
|
||||
sprintf(g->Message, MSG(BAD_DBF_FILE), Tdbp->GetFile(g));
|
||||
return true;
|
||||
} // endif fseek
|
||||
|
||||
return false;
|
||||
} // end of AllocateBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset buffer access according to indexing and to mode. */
|
||||
/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
|
||||
/***********************************************************************/
|
||||
void DBFFAM::ResetBuffer(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* If access is random, performances can be much better when the */
|
||||
/* reads are done on only one row, except for small tables that can */
|
||||
/* be entirely read in one block. If the index is just used as a */
|
||||
/* bitmap filter, as for Update or delete, reading will be */
|
||||
/* sequential and we better keep block reading. */
|
||||
/*********************************************************************/
|
||||
if (Tdbp->GetKindex() && Tdbp->GetMode() == MODE_READ &&
|
||||
ReadBlks != 1) {
|
||||
Nrec = 1; // Better for random access
|
||||
Rbuf = 0;
|
||||
Blksize = Lrecl;
|
||||
OldBlk = -2; // Has no meaning anymore
|
||||
Block = Tdbp->Cardinality(g); // Blocks are one line now
|
||||
} // endif Mode
|
||||
|
||||
} // end of ResetBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBuffer: Read one line for a DBF file. */
|
||||
/***********************************************************************/
|
||||
int DBFFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
if (!Placed && !Closing && GetRowID() == Records)
|
||||
return RC_EF;
|
||||
|
||||
int rc = FIXFAM::ReadBuffer(g);
|
||||
|
||||
if (rc != RC_OK || Closing)
|
||||
return rc;
|
||||
|
||||
switch (*Tdbp->GetLine()) {
|
||||
case '*':
|
||||
if (!ReadMode)
|
||||
rc = RC_NF; // Deleted line
|
||||
else
|
||||
Rows++;
|
||||
|
||||
break;
|
||||
case ' ':
|
||||
if (ReadMode < 2)
|
||||
Rows++; // Non deleted line
|
||||
else
|
||||
rc = RC_NF;
|
||||
|
||||
break;
|
||||
default:
|
||||
if (++Nerr >= Maxerr && !Accept) {
|
||||
sprintf(g->Message, MSG(BAD_DBF_REC), Tdbp->GetFile(g), GetRowID());
|
||||
rc = RC_FX;
|
||||
} else
|
||||
rc = (Accept) ? RC_OK : RC_NF;
|
||||
|
||||
} // endswitch To_Buf
|
||||
|
||||
return rc;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* Copy the header into the temporary file. */
|
||||
/***********************************************************************/
|
||||
bool DBFFAM::CopyHeader(PGLOBAL g)
|
||||
{
|
||||
bool rc = true;
|
||||
|
||||
if (Headlen) {
|
||||
void *hdr = PlugSubAlloc(g, NULL, Headlen);
|
||||
size_t n, hlen = (size_t)Headlen;
|
||||
int pos = ftell(Stream);
|
||||
|
||||
if (fseek(Stream, 0, SEEK_SET))
|
||||
strcpy(g->Message, "Seek error in CopyHeader");
|
||||
else if ((n = fread(hdr, 1, hlen, Stream)) != hlen)
|
||||
sprintf(g->Message, MSG(BAD_READ_NUMBER), n, To_File);
|
||||
else if ((n = fwrite(hdr, 1, hlen, T_Stream)) != hlen)
|
||||
sprintf(g->Message, MSG(WRITE_STRERROR), To_Fbt->Fname
|
||||
, strerror(errno));
|
||||
else if (fseek(Stream, pos, SEEK_SET))
|
||||
strcpy(g->Message, "Seek error in CopyHeader");
|
||||
else
|
||||
rc = false;
|
||||
|
||||
} else
|
||||
rc = false;
|
||||
|
||||
return rc;
|
||||
} // end of CopyHeader
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for DBF access methods. */
|
||||
/* Deleted lines are just flagged in the first buffer character. */
|
||||
/***********************************************************************/
|
||||
int DBFFAM::DeleteRecords(PGLOBAL g, int irc)
|
||||
{
|
||||
if (irc == RC_OK) {
|
||||
// T_Stream is the temporary stream or the table file stream itself
|
||||
if (!T_Stream)
|
||||
if (UseTemp) {
|
||||
if (OpenTempFile(g))
|
||||
return RC_FX;
|
||||
|
||||
if (CopyHeader(g)) // For DBF tables
|
||||
return RC_FX;
|
||||
|
||||
} else
|
||||
T_Stream = Stream;
|
||||
|
||||
*Tdbp->GetLine() = '*';
|
||||
Modif++; // Modified line in Delete mode
|
||||
} // endif irc
|
||||
|
||||
return RC_OK;
|
||||
} // end of DeleteRecords
|
||||
|
||||
/***********************************************************************/
|
||||
/* Rewind routine for DBF access method. */
|
||||
/***********************************************************************/
|
||||
void DBFFAM::Rewind(void)
|
||||
{
|
||||
BLKFAM::Rewind();
|
||||
Nerr = 0;
|
||||
} // end of Rewind
|
||||
|
||||
/***********************************************************************/
|
||||
/* Table file close routine for DBF access method. */
|
||||
/***********************************************************************/
|
||||
void DBFFAM::CloseTableFile(PGLOBAL g)
|
||||
{
|
||||
int rc = RC_OK, wrc = RC_OK;
|
||||
MODE mode = Tdbp->GetMode();
|
||||
|
||||
// Closing is True if last Write was in error
|
||||
if (mode == MODE_INSERT && CurNum && !Closing) {
|
||||
// Some more inserted lines remain to be written
|
||||
Rbuf = CurNum--;
|
||||
// Closing = true;
|
||||
wrc = WriteBuffer(g);
|
||||
} else if (mode == MODE_UPDATE || mode == MODE_DELETE) {
|
||||
if (Modif && !Closing) {
|
||||
// Last updated block remains to be written
|
||||
Closing = true;
|
||||
wrc = ReadBuffer(g);
|
||||
} // endif Modif
|
||||
|
||||
if (UseTemp && T_Stream && wrc == RC_OK) {
|
||||
// Copy any remaining lines
|
||||
bool b;
|
||||
|
||||
Fpos = Tdbp->Cardinality(g);
|
||||
|
||||
if ((rc = MoveIntermediateLines(g, &b)) == RC_OK) {
|
||||
// Delete the old file and rename the new temp file.
|
||||
RenameTempFile(g);
|
||||
goto fin;
|
||||
} // endif rc
|
||||
|
||||
} // endif UseTemp
|
||||
|
||||
} // endif's mode
|
||||
|
||||
if (Tdbp->GetMode() == MODE_INSERT) {
|
||||
int n = ftell(Stream) - Headlen;
|
||||
|
||||
rc = PlugCloseFile(g, To_Fb);
|
||||
|
||||
if (n >= 0 && !(n % Lrecl)) {
|
||||
n /= Lrecl; // New number of lines
|
||||
|
||||
if (n > Records) {
|
||||
// Update the number of rows in the file header
|
||||
char filename[_MAX_PATH];
|
||||
|
||||
PlugSetPath(filename, To_File, Tdbp->GetPath());
|
||||
Stream = fopen(filename, "r+b");
|
||||
fseek(Stream, 4, SEEK_SET); // Get header.Records position
|
||||
fwrite(&n, sizeof(int), 1, Stream);
|
||||
fclose(Stream);
|
||||
Stream = NULL;
|
||||
Records = n; // Update Records value
|
||||
} // endif n
|
||||
|
||||
} // endif n
|
||||
|
||||
} else // Finally close the file
|
||||
rc = PlugCloseFile(g, To_Fb);
|
||||
|
||||
fin:
|
||||
#ifdef DEBTRACE
|
||||
htrc("DBF CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
|
||||
To_File, mode, wrc, rc);
|
||||
#endif
|
||||
Stream = NULL; // So we can know whether table is open
|
||||
} // end of CloseTableFile
|
||||
|
||||
/* ---------------------------- Class DBMFAM ------------------------------ */
|
||||
|
||||
/****************************************************************************/
|
||||
/* 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). */
|
||||
/****************************************************************************/
|
||||
int DBMFAM::Cardinality(PGLOBAL g)
|
||||
{
|
||||
if (!g)
|
||||
return 1;
|
||||
|
||||
if (!Headlen)
|
||||
if ((Headlen = ScanHeader(g, To_File, Lrecl, Tdbp->GetPath())) < 0)
|
||||
return -1; // Error in ScanHeader
|
||||
|
||||
// Set number of blocks for later use
|
||||
Block = (Records > 0) ? (Records + Nrec - 1) / Nrec : 0;
|
||||
return Records;
|
||||
} // end of Cardinality
|
||||
|
||||
#if 0 // Not compatible with ROWID block optimization
|
||||
/***********************************************************************/
|
||||
/* GetRowID: return the RowID of last read record. */
|
||||
/***********************************************************************/
|
||||
int DBMFAM::GetRowID(void)
|
||||
{
|
||||
return Rows;
|
||||
} // end of GetRowID
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Just check that on all deletion the unknown deleted line number is */
|
||||
/* sent back because Cardinality doesn't count soft deleted lines. */
|
||||
/***********************************************************************/
|
||||
int DBMFAM::GetDelRows(void)
|
||||
{
|
||||
if (Tdbp->GetMode() == MODE_DELETE && !Tdbp->GetNext())
|
||||
return -1; // Means all lines deleted
|
||||
else
|
||||
return DelRows;
|
||||
|
||||
} // end of GetDelRows
|
||||
|
||||
/****************************************************************************/
|
||||
/* Allocate the block buffer for the table. */
|
||||
/****************************************************************************/
|
||||
bool DBMFAM::AllocateBuffer(PGLOBAL g)
|
||||
{
|
||||
if (!Headlen) {
|
||||
/************************************************************************/
|
||||
/* Here is a good place to process the DBF file header */
|
||||
/************************************************************************/
|
||||
DBFHEADER *hp = (DBFHEADER*)Memory;
|
||||
|
||||
if (Lrecl != (int)hp->Reclen) {
|
||||
sprintf(g->Message, MSG(BAD_LRECL), Lrecl, hp->Reclen);
|
||||
return true;
|
||||
} // endif Lrecl
|
||||
|
||||
Records = (int)hp->Records;
|
||||
Headlen = (int)hp->Headlen;
|
||||
} // endif Headlen
|
||||
|
||||
/**************************************************************************/
|
||||
/* Position the file at the begining of the data. */
|
||||
/**************************************************************************/
|
||||
Fpos = Mempos = Memory + Headlen;
|
||||
Top--; // Because of EOF marker
|
||||
return false;
|
||||
} // end of AllocateBuffer
|
||||
|
||||
/****************************************************************************/
|
||||
/* ReadBuffer: Read one line for a FIX file. */
|
||||
/****************************************************************************/
|
||||
int DBMFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
// if (!Placed && GetRowID() == Records)
|
||||
// return RC_EF;
|
||||
|
||||
int rc = MPXFAM::ReadBuffer(g);
|
||||
|
||||
if (rc != RC_OK)
|
||||
return rc;
|
||||
|
||||
switch (*Fpos) {
|
||||
case '*':
|
||||
if (!ReadMode)
|
||||
rc = RC_NF; // Deleted line
|
||||
else
|
||||
Rows++;
|
||||
|
||||
break;
|
||||
case ' ':
|
||||
if (ReadMode < 2)
|
||||
Rows++; // Non deleted line
|
||||
else
|
||||
rc = RC_NF;
|
||||
|
||||
break;
|
||||
default:
|
||||
if (++Nerr >= Maxerr && !Accept) {
|
||||
sprintf(g->Message, MSG(BAD_DBF_REC), Tdbp->GetFile(g), GetRowID());
|
||||
rc = RC_FX;
|
||||
} else
|
||||
rc = (Accept) ? RC_OK : RC_NF;
|
||||
} // endswitch To_Buf
|
||||
|
||||
return rc;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/****************************************************************************/
|
||||
/* Data Base delete line routine for DBF access methods. */
|
||||
/* Deleted lines are just flagged in the first buffer character. */
|
||||
/****************************************************************************/
|
||||
int DBMFAM::DeleteRecords(PGLOBAL g, int irc)
|
||||
{
|
||||
if (irc == RC_OK)
|
||||
*Fpos = '*';
|
||||
|
||||
return RC_OK;
|
||||
} // end of DeleteRecords
|
||||
|
||||
/***********************************************************************/
|
||||
/* Rewind routine for DBF access method. */
|
||||
/***********************************************************************/
|
||||
void DBMFAM::Rewind(void)
|
||||
{
|
||||
MBKFAM::Rewind();
|
||||
Nerr = 0;
|
||||
} // end of Rewind
|
||||
|
||||
/* --------------------------------- EOF ---------------------------------- */
|
||||
111
storage/connect/filamdbf.h
Normal file
111
storage/connect/filamdbf.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/***************** FilAmDbf H Declares Source Code File (.H) ****************/
|
||||
/* Name: filamdbf.h Version 1.3 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the DBF file access method classes declares. */
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef __FILAMDBF_H
|
||||
#define __FILAMDBF_H
|
||||
|
||||
#include "filamfix.h"
|
||||
#include "filamap.h"
|
||||
|
||||
typedef class DBFBASE *PDBF;
|
||||
typedef class DBFFAM *PDBFFAM;
|
||||
typedef class DBMFAM *PDBMFAM;
|
||||
|
||||
/****************************************************************************/
|
||||
/* This is the base class for dBASE file access methods. */
|
||||
/****************************************************************************/
|
||||
class DllExport DBFBASE {
|
||||
public:
|
||||
// Constructors
|
||||
DBFBASE(PDOSDEF tdp);
|
||||
DBFBASE(PDBF txfp);
|
||||
|
||||
// Implementation
|
||||
int ScanHeader(PGLOBAL g, PSZ fname, int lrecl, char *defpath);
|
||||
|
||||
protected:
|
||||
// Default constructor, not to be used
|
||||
DBFBASE(void) {}
|
||||
|
||||
// Members
|
||||
int Records; /* records in the file */
|
||||
bool Accept; /* true if bad lines are accepted */
|
||||
int Nerr; /* Number of bad records */
|
||||
int Maxerr; /* Maximum number of bad records */
|
||||
int ReadMode; /* 1: ALL 2: DEL 0: NOT DEL */
|
||||
//PSZ Defpath; /* Default data path */
|
||||
}; // end of class DBFBASE
|
||||
|
||||
/****************************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for DBase files. */
|
||||
/****************************************************************************/
|
||||
class DllExport DBFFAM : public FIXFAM, public DBFBASE {
|
||||
public:
|
||||
// Constructors
|
||||
DBFFAM(PDOSDEF tdp) : FIXFAM(tdp), DBFBASE(tdp) {}
|
||||
DBFFAM(PDBFFAM txfp) : FIXFAM(txfp), DBFBASE((PDBF)txfp) {}
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_DBF;}
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) DBFFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual int GetNerr(void) {return Nerr;}
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
//virtual int GetRowID(void); // Temporarily suppressed
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual void ResetBuffer(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
//virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
virtual bool CopyHeader(PGLOBAL g);
|
||||
|
||||
//int Records; in TXTFAM
|
||||
//int Headlen; in TXTFAM
|
||||
}; // end of class DBFFAM
|
||||
|
||||
/****************************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for DBase files */
|
||||
/* using file mapping to access the file. */
|
||||
/****************************************************************************/
|
||||
class DllExport DBMFAM : public MPXFAM, public DBFBASE {
|
||||
public:
|
||||
// Constructors
|
||||
DBMFAM(PDOSDEF tdp) : MPXFAM(tdp), DBFBASE(tdp) {}
|
||||
DBMFAM(PDBMFAM txfp) : MPXFAM(txfp), DBFBASE((PDBF)txfp) {}
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_DBF;}
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) DBMFAM(this);}
|
||||
virtual int GetDelRows(void);
|
||||
|
||||
// Methods
|
||||
virtual int GetNerr(void) {return Nerr;}
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
//virtual int GetRowID(void); // Temporarily suppressed
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
//virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
//int Records; in TXTFAM
|
||||
//int Headlen; in TXTFAM
|
||||
}; // end of class DBFFAM
|
||||
|
||||
#endif // __FILAMDBF_H
|
||||
1446
storage/connect/filamfix.cpp
Normal file
1446
storage/connect/filamfix.cpp
Normal file
File diff suppressed because it is too large
Load Diff
98
storage/connect/filamfix.h
Normal file
98
storage/connect/filamfix.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/************** FilAMFix H Declares Source Code File (.H) **************/
|
||||
/* Name: FILAMFIX.H Version 1.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005 - 2012 */
|
||||
/* */
|
||||
/* This file contains the FIX file access method classes declares. */
|
||||
/***********************************************************************/
|
||||
|
||||
#ifndef __FILAMFIX_H
|
||||
#define __FILAMFIX_H
|
||||
|
||||
#include "filamtxt.h"
|
||||
|
||||
typedef class FIXFAM *PFIXFAM;
|
||||
typedef class BGXFAM *PBGXFAM;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for standard */
|
||||
/* files with fixed record format (FIX, BIN) */
|
||||
/***********************************************************************/
|
||||
class DllExport FIXFAM : public BLKFAM {
|
||||
public:
|
||||
// Constructor
|
||||
FIXFAM(PDOSDEF tdp);
|
||||
FIXFAM(PFIXFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_FIX;}
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) FIXFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);}
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s)
|
||||
{return TXTFAM::MaxBlkSize(g, s);}
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual void ResetBuffer(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
virtual bool CopyHeader(PGLOBAL g) {return false;}
|
||||
virtual bool MoveIntermediateLines(PGLOBAL g, bool *b);
|
||||
|
||||
// No additional members
|
||||
}; // end of class FIXFAM
|
||||
|
||||
#if defined(WIN32)
|
||||
typedef __int64 BIGINT;
|
||||
#else // !WIN32
|
||||
typedef off64_t BIGINT;
|
||||
#define FILE_BEGIN SEEK_SET
|
||||
#define FILE_CURRENT SEEK_CUR
|
||||
#define FILE_END SEEK_END
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* that are standard files with columns starting at fixed offset */
|
||||
/* This class is for fixed formatted files of more than 2 gigabytes. */
|
||||
/***********************************************************************/
|
||||
class BGXFAM : public FIXFAM {
|
||||
public:
|
||||
// Constructor
|
||||
BGXFAM(PDOSDEF tdp);
|
||||
BGXFAM(PBGXFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) BGXFAM(this);}
|
||||
|
||||
// Methods
|
||||
//virtual void Reset(void);
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos
|
||||
, int org = FILE_BEGIN);
|
||||
int BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req);
|
||||
bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req);
|
||||
virtual bool OpenTempFile(PGLOBAL g);
|
||||
virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
|
||||
|
||||
// Members
|
||||
HANDLE Hfile; // Handle(descriptor) to big file
|
||||
HANDLE Tfile; // Handle(descriptor) to big temp file
|
||||
//BIGINT Xpos; // Current file position
|
||||
}; // end of class BGXFAM
|
||||
|
||||
#endif // __FILAMFIX_H
|
||||
1422
storage/connect/filamtxt.cpp
Normal file
1422
storage/connect/filamtxt.cpp
Normal file
File diff suppressed because it is too large
Load Diff
198
storage/connect/filamtxt.h
Normal file
198
storage/connect/filamtxt.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/************** FilAMTxt H Declares Source Code File (.H) **************/
|
||||
/* Name: FILAMTXT.H Version 1.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the file access method classes declares. */
|
||||
/***********************************************************************/
|
||||
|
||||
#ifndef __FILAMTXT_H
|
||||
#define __FILAMTXT_H
|
||||
|
||||
#include "block.h"
|
||||
|
||||
typedef class TXTFAM *PTXF;
|
||||
typedef class DOSFAM *PDOSFAM;
|
||||
typedef class BLKFAM *PBLKFAM;
|
||||
typedef class DOSDEF *PDOSDEF;
|
||||
typedef class TDBDOS *PTDBDOS;
|
||||
|
||||
#define TYPE_AM_BLK (AMT)160
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the base class for all file access method classes. */
|
||||
/***********************************************************************/
|
||||
class DllExport TXTFAM : public BLOCK {
|
||||
friend class TDBDOS;
|
||||
friend class TDBCSV;
|
||||
friend class TDBFIX;
|
||||
friend class TDBVCT;
|
||||
friend class DOSCOL;
|
||||
friend class BINCOL;
|
||||
friend class VCTCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TXTFAM(PDOSDEF tdp);
|
||||
TXTFAM(PTXF txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) = 0;
|
||||
virtual int GetPos(void) = 0;
|
||||
virtual int GetNextPos(void) = 0;
|
||||
virtual PTXF Duplicate(PGLOBAL g) = 0;
|
||||
virtual bool GetUseTemp(void) {return false;}
|
||||
virtual int GetDelRows(void) {return DelRows;}
|
||||
int GetCurBlk(void) {return CurBlk;}
|
||||
void SetTdbp(PTDBDOS tdbp) {Tdbp = tdbp;}
|
||||
int GetBlock(void) {return Block;}
|
||||
void SetBlkPos(int *bkp) {BlkPos = bkp;}
|
||||
void SetNrec(int n) {Nrec = n;}
|
||||
char *GetBuf(void) {return To_Buf;}
|
||||
int GetRows(void) {return Rows;}
|
||||
bool IsBlocked(void) {return Blocked;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual int GetFileLength(PGLOBAL g);
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s);
|
||||
virtual bool AllocateBuffer(PGLOBAL g) {return false;}
|
||||
virtual void ResetBuffer(PGLOBAL g) {}
|
||||
virtual int GetNerr(void) {return 0;}
|
||||
virtual int GetRowID(void) = 0;
|
||||
virtual bool RecordPos(PGLOBAL g) = 0;
|
||||
virtual bool SetPos(PGLOBAL g, int recpos) = 0;
|
||||
virtual int SkipRecord(PGLOBAL g, bool header) = 0;
|
||||
virtual bool OpenTableFile(PGLOBAL g) = 0;
|
||||
virtual bool DeferReading(void) {IsRead = false; return true;}
|
||||
virtual int ReadBuffer(PGLOBAL g) = 0;
|
||||
virtual int WriteBuffer(PGLOBAL g) = 0;
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc) = 0;
|
||||
virtual void CloseTableFile(PGLOBAL g) = 0;
|
||||
virtual void Rewind(void) = 0;
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PTDBDOS Tdbp; // To table class
|
||||
PSZ To_File; // Points to table file name
|
||||
PFBLOCK To_Fb; // Pointer to file block
|
||||
bool Placed; // true if Recpos was externally set
|
||||
bool IsRead; // false for deferred reading
|
||||
bool Blocked; // true if using blocked I/O
|
||||
char *To_Buf; // Points to I/O buffer
|
||||
void *DelBuf; // Buffer used to move lines in Delete
|
||||
int *BlkPos; // To array of block positions
|
||||
int BlkLen; // Current block length
|
||||
int Buflen; // Buffer length
|
||||
int Dbflen; // Delete buffer length
|
||||
int Rows; // Number of rows read so far
|
||||
int DelRows; // Number of deleted rows
|
||||
int Headlen; // Number of bytes in header
|
||||
int Lrecl; // Logical Record Length
|
||||
int Block; // Number of blocks in table
|
||||
int Last; // Number of elements of last block
|
||||
int Nrec; // Number of records in buffer
|
||||
int OldBlk; // Index of last read block
|
||||
int CurBlk; // Index of current block
|
||||
int CurNum; // Current buffer line number
|
||||
int ReadBlks; // Number of blocks read (selected)
|
||||
int Rbuf; // Number of lines read in buffer
|
||||
int Modif; // Number of modified lines in block
|
||||
int Blksize; // Size of padded blocks
|
||||
int Ending; // Length of line end
|
||||
bool Padded; // true if fixed size blocks are padded
|
||||
bool Eof; // true if an EOF (0xA) character exists
|
||||
char *CrLf; // End of line character(s)
|
||||
}; // end of class TXTFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for standard */
|
||||
/* text files with variable record format (DOS, CSV, FMT) */
|
||||
/***********************************************************************/
|
||||
class DllExport DOSFAM : public TXTFAM {
|
||||
public:
|
||||
// Constructor
|
||||
DOSFAM(PDOSDEF tdp);
|
||||
DOSFAM(PDOSFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_DOS;}
|
||||
virtual bool GetUseTemp(void) {return UseTemp;}
|
||||
virtual int GetPos(void);
|
||||
virtual int GetNextPos(void);
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) DOSFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual int GetFileLength(PGLOBAL g);
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s);
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual int GetRowID(void);
|
||||
virtual bool RecordPos(PGLOBAL g);
|
||||
virtual bool SetPos(PGLOBAL g, int recpos);
|
||||
virtual int SkipRecord(PGLOBAL g, bool header);
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
virtual bool OpenTempFile(PGLOBAL g);
|
||||
virtual bool MoveIntermediateLines(PGLOBAL g, bool *b);
|
||||
virtual int RenameTempFile(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
FILE *Stream; // Points to Dos file structure
|
||||
FILE *T_Stream; // Points to temporary file structure
|
||||
PFBLOCK To_Fbt; // Pointer to temp file block
|
||||
int Fpos; // Position of last read record
|
||||
int Tpos; // Target Position for delete move
|
||||
int Spos; // Start position for delete move
|
||||
bool UseTemp; // True to use a temporary file in Delete
|
||||
bool Bin; // True to force binary mode
|
||||
}; // end of class DOSFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for standard */
|
||||
/* text files with variable record format (DOS, CSV, FMT) */
|
||||
/***********************************************************************/
|
||||
class DllExport BLKFAM : public DOSFAM {
|
||||
public:
|
||||
// Constructor
|
||||
BLKFAM(PDOSDEF tdp);
|
||||
BLKFAM(PBLKFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_BLK;}
|
||||
virtual int GetPos(void);
|
||||
virtual int GetNextPos(void);
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) BLKFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s);
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual int GetRowID(void);
|
||||
virtual bool RecordPos(PGLOBAL g);
|
||||
virtual bool SetPos(PGLOBAL g, int recpos);
|
||||
virtual int SkipRecord(PGLOBAL g, bool header);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *CurLine; // Position of current line in buffer
|
||||
char *NxtLine; // Position of Next line in buffer
|
||||
char *OutBuf; // Buffer to write in temporary file
|
||||
bool Closing; // True when closing on Update
|
||||
}; // end of class BLKFAM
|
||||
|
||||
#endif // __FILAMTXT_H
|
||||
4221
storage/connect/filamvct.cpp
Normal file
4221
storage/connect/filamvct.cpp
Normal file
File diff suppressed because it is too large
Load Diff
249
storage/connect/filamvct.h
Normal file
249
storage/connect/filamvct.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/************** FilAMVct H Declares Source Code File (.H) **************/
|
||||
/* Name: FILAMVCT.H Version 1.5 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the VCT file access method classes declares. */
|
||||
/***********************************************************************/
|
||||
#ifndef __FILAMVCT__
|
||||
#define __FILAMVCT__
|
||||
|
||||
#include "filamfix.h"
|
||||
|
||||
typedef class VCTFAM *PVCTFAM;
|
||||
typedef class VCTCOL *PVCTCOL;
|
||||
typedef class VCMFAM *PVCMFAM;
|
||||
typedef class VECFAM *PVECFAM;
|
||||
typedef class VMPFAM *PVMPFAM;
|
||||
typedef class BGVFAM *PBGVFAM;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* in vector format. If MaxBlk=0, each block containing "Elements" */
|
||||
/* records, values of each columns are consecutively stored (vector). */
|
||||
/* Otherwise, data is arranged by column in the file and MaxBlk is */
|
||||
/* used to set the maximum number of blocks. This leave some white */
|
||||
/* space allowing to insert new values up to this maximum size. */
|
||||
/***********************************************************************/
|
||||
class DllExport VCTFAM : public FIXFAM {
|
||||
friend class TDBVCT;
|
||||
friend class VCTCOL;
|
||||
public:
|
||||
// Constructor
|
||||
VCTFAM(PVCTDEF tdp);
|
||||
VCTFAM(PVCTFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_VCT;}
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) VCTFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s);
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual bool InitInsert(PGLOBAL g);
|
||||
virtual void ResetBuffer(PGLOBAL g) {}
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int GetRowID(void);
|
||||
|
||||
// Database routines
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
// Specific functions
|
||||
virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
|
||||
virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
|
||||
|
||||
protected:
|
||||
virtual bool MakeEmptyFile(PGLOBAL g, char *fn);
|
||||
virtual bool OpenTempFile(PGLOBAL g);
|
||||
virtual bool MoveLines(PGLOBAL g) {return false;}
|
||||
virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
|
||||
virtual bool CleanUnusedSpace(PGLOBAL g);
|
||||
virtual int GetBlockInfo(PGLOBAL g);
|
||||
virtual bool SetBlockInfo(PGLOBAL g);
|
||||
bool ResetTableSize(PGLOBAL g, int block, int last);
|
||||
|
||||
// Members
|
||||
char *NewBlock; // To block written on Insert
|
||||
char *Colfn; // Pattern for column file names (VER)
|
||||
char *Tempat; // Pattern for temp file names (VER)
|
||||
int *Clens; // Pointer to col size array
|
||||
int *Deplac; // Pointer to col start position array
|
||||
bool *Isnum; // Pointer to buffer type isnum result
|
||||
bool AddBlock; // True when adding new blocks on Insert
|
||||
bool Split; // true: split column file vector format
|
||||
int Header; // 0: no, 1: separate, 2: in data file
|
||||
int MaxBlk; // Max number of blocks (True vector format)
|
||||
int Bsize; // Because Nrec can be modified
|
||||
int Ncol; // The number of columns;
|
||||
}; // end of class VCTFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* in vector format accessed using file mapping. */
|
||||
/***********************************************************************/
|
||||
class DllExport VCMFAM : public VCTFAM {
|
||||
friend class TDBVCT;
|
||||
friend class VCTCOL;
|
||||
public:
|
||||
// Constructor
|
||||
VCMFAM(PVCTDEF tdp);
|
||||
VCMFAM(PVCMFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_VMP;}
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) VCMFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual bool InitInsert(PGLOBAL g);
|
||||
|
||||
// Database routines
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
|
||||
// Specific functions
|
||||
virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
|
||||
virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
|
||||
|
||||
// Members
|
||||
char* Memory; // Pointer on file mapping view.
|
||||
char* *Memcol; // Pointer on column start.
|
||||
}; // end of class VCMFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* in full vertical format. Each column is contained in a separate */
|
||||
/* file whose name is the table name followed by the column number. */
|
||||
/***********************************************************************/
|
||||
class DllExport VECFAM : public VCTFAM {
|
||||
friend class TDBVCT;
|
||||
friend class VCTCOL;
|
||||
public:
|
||||
// Constructor
|
||||
VECFAM(PVCTDEF tdp);
|
||||
VECFAM(PVECFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) VECFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual bool InitInsert(PGLOBAL g);
|
||||
virtual void ResetBuffer(PGLOBAL g);
|
||||
|
||||
// Database routines
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
|
||||
// Specific functions
|
||||
virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
|
||||
virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
|
||||
|
||||
protected:
|
||||
virtual bool OpenTempFile(PGLOBAL g);
|
||||
virtual bool MoveLines(PGLOBAL g);
|
||||
virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
|
||||
virtual int RenameTempFile(PGLOBAL g);
|
||||
bool OpenColumnFile(PGLOBAL g, char *opmode, int i);
|
||||
|
||||
// Members
|
||||
FILE* *Streams; // Points to Dos file structure array
|
||||
FILE* *T_Streams; // Points to temp file structure array
|
||||
PFBLOCK *To_Fbs; // Pointer to file block array
|
||||
PFBLOCK *T_Fbs; // Pointer to temp file block array
|
||||
void* *To_Bufs; // Pointer to col val block array
|
||||
bool InitUpdate; // Used to initialize updating
|
||||
}; // end of class VECFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* in full vertical format accessed using file mapping. */
|
||||
/***********************************************************************/
|
||||
class DllExport VMPFAM : public VCMFAM {
|
||||
friend class TDBVCT;
|
||||
friend class VCTCOL;
|
||||
public:
|
||||
// Constructor
|
||||
VMPFAM(PVCTDEF tdp);
|
||||
VMPFAM(PVMPFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) VMPFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
|
||||
// Database routines
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
bool MapColumnFile(PGLOBAL g, MODE mode, int i);
|
||||
|
||||
// Members
|
||||
PFBLOCK *To_Fbs; // Pointer to file block array
|
||||
}; // end of class VMPFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* in (possibly blocked) vector format that can be larger than 2GB. */
|
||||
/***********************************************************************/
|
||||
class BGVFAM : public VCTFAM {
|
||||
friend class VCTCOL;
|
||||
public:
|
||||
// Constructors
|
||||
BGVFAM(PVCTDEF tdp);
|
||||
BGVFAM(PBGVFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) BGVFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
|
||||
// Database routines
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
// Specific functions
|
||||
virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
|
||||
virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
|
||||
|
||||
protected:
|
||||
bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, bool b = false);
|
||||
bool BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req);
|
||||
bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req);
|
||||
virtual bool MakeEmptyFile(PGLOBAL g, char *fn);
|
||||
virtual bool OpenTempFile(PGLOBAL g);
|
||||
virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
|
||||
virtual bool CleanUnusedSpace(PGLOBAL g);
|
||||
virtual bool SetBlockInfo(PGLOBAL g);
|
||||
virtual int GetBlockInfo(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
HANDLE Hfile; // Handle to big file
|
||||
HANDLE Tfile; // Handle to temporary file
|
||||
BIGINT *BigDep; // Pointer to col start position array
|
||||
}; // end of class BGVFAM
|
||||
|
||||
#endif // __FILAMVCT__
|
||||
|
||||
822
storage/connect/filamzip.cpp
Normal file
822
storage/connect/filamzip.cpp
Normal file
@@ -0,0 +1,822 @@
|
||||
/*********** File AM Zip C++ Program Source Code File (.CPP) ***********/
|
||||
/* PROGRAM NAME: FILAMZIP */
|
||||
/* ------------- */
|
||||
/* Version 1.4 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the ZLIB compressed files classes. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif
|
||||
//#include <windows.h>
|
||||
#else // !WIN32
|
||||
#if defined(UNIX)
|
||||
#include <errno.h>
|
||||
#else // !UNIX
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing the DB application declarations. */
|
||||
/* tabdos.h is header containing the TABDOS class declarations. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
//#include "catalog.h"
|
||||
//#include "reldef.h"
|
||||
//#include "xobject.h"
|
||||
//#include "kindex.h"
|
||||
#include "filamtxt.h"
|
||||
#include "tabdos.h"
|
||||
#if defined(UNIX)
|
||||
#include "osutil.h"
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* This define prepares ZLIB function declarations. */
|
||||
/***********************************************************************/
|
||||
//#define ZLIB_DLL
|
||||
|
||||
#include "filamzip.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* DB static variables. */
|
||||
/***********************************************************************/
|
||||
extern int num_read, num_there, num_eq[]; // Statistics
|
||||
bool PushWarning(PGLOBAL g, PTDBASE tdbp);
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the ZIPFAM class. */
|
||||
/***********************************************************************/
|
||||
ZIPFAM::ZIPFAM(PZIPFAM txfp) : TXTFAM(txfp)
|
||||
{
|
||||
Zfile = txfp->Zfile;
|
||||
Zpos = txfp->Zpos;
|
||||
} // end of ZIPFAM copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Zerror: Error function for gz calls. */
|
||||
/* gzerror returns the error message for the last error which occurred*/
|
||||
/* on the given compressed file. errnum is set to zlib error number. */
|
||||
/* If an error occurred in the file system and not in the compression */
|
||||
/* library, errnum is set to Z_ERRNO and the application may consult */
|
||||
/* errno to get the exact error code. */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::Zerror(PGLOBAL g)
|
||||
{
|
||||
int errnum;
|
||||
|
||||
strcpy(g->Message, gzerror(Zfile, &errnum));
|
||||
|
||||
if (errnum == Z_ERRNO)
|
||||
#if defined(WIN32)
|
||||
sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(NULL));
|
||||
#else // !WIN32
|
||||
sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
|
||||
#endif // !WIN32
|
||||
|
||||
return (errnum == Z_STREAM_END) ? RC_EF : RC_FX;
|
||||
} // end of Zerror
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset: reset position values at the beginning of file. */
|
||||
/***********************************************************************/
|
||||
void ZIPFAM::Reset(void)
|
||||
{
|
||||
TXTFAM::Reset();
|
||||
//gzrewind(Zfile); // Useful ?????
|
||||
Zpos = 0;
|
||||
} // end of Reset
|
||||
|
||||
/***********************************************************************/
|
||||
/* ZIP GetFileLength: returns an estimate of what would be the */
|
||||
/* uncompressed file size in number of bytes. */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::GetFileLength(PGLOBAL g)
|
||||
{
|
||||
int len = TXTFAM::GetFileLength(g);
|
||||
|
||||
if (len > 0)
|
||||
// Estimate size reduction to a max of 6
|
||||
len *= 6;
|
||||
|
||||
return len;
|
||||
} // end of GetFileLength
|
||||
|
||||
/***********************************************************************/
|
||||
/* ZIP Access Method opening routine. */
|
||||
/***********************************************************************/
|
||||
bool ZIPFAM::OpenTableFile(PGLOBAL g)
|
||||
{
|
||||
char opmode[4], filename[_MAX_PATH];
|
||||
MODE mode = Tdbp->GetMode();
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
strcpy(opmode, "r");
|
||||
break;
|
||||
case MODE_UPDATE:
|
||||
/*****************************************************************/
|
||||
/* Updating ZIP files not implemented yet. */
|
||||
/*****************************************************************/
|
||||
strcpy(g->Message, MSG(UPD_ZIP_NOT_IMP));
|
||||
return true;
|
||||
case MODE_DELETE:
|
||||
if (!Tdbp->GetNext()) {
|
||||
// Store the number of deleted lines
|
||||
DelRows = Cardinality(g);
|
||||
|
||||
// This will erase the entire file
|
||||
strcpy(opmode, "w");
|
||||
// Block = 0; // For ZBKFAM
|
||||
// Last = Nrec; // For ZBKFAM
|
||||
Tdbp->ResetSize();
|
||||
} else {
|
||||
sprintf(g->Message, MSG(NO_PART_DEL), "ZIP");
|
||||
return true;
|
||||
} // endif filter
|
||||
|
||||
break;
|
||||
case MODE_INSERT:
|
||||
strcpy(opmode, "a+");
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
|
||||
return true;
|
||||
} // endswitch Mode
|
||||
|
||||
/*********************************************************************/
|
||||
/* Open according to logical input/output mode required. */
|
||||
/* Use specific zlib functions. */
|
||||
/* Treat files as binary. */
|
||||
/*********************************************************************/
|
||||
strcat(opmode, "b");
|
||||
Zfile = gzopen(PlugSetPath(filename, To_File, Tdbp->GetPath()), opmode);
|
||||
|
||||
if (Zfile == NULL) {
|
||||
sprintf(g->Message, MSG(GZOPEN_ERROR),
|
||||
opmode, (int)errno, filename);
|
||||
strcat(strcat(g->Message, ": "), strerror(errno));
|
||||
return (mode == MODE_READ && errno == ENOENT)
|
||||
? PushWarning(g, Tdbp) : true;
|
||||
} // endif Zfile
|
||||
|
||||
/*********************************************************************/
|
||||
/* Something to be done here. >>>>>>>> NOT DONE <<<<<<<< */
|
||||
/*********************************************************************/
|
||||
//To_Fb = dbuserp->Openlist; // Keep track of File block
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate the line buffer. */
|
||||
/*********************************************************************/
|
||||
return AllocateBuffer(g);
|
||||
} // end of OpenTableFile
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate the line buffer. For mode Delete a bigger buffer has to */
|
||||
/* be allocated because is it also used to move lines into the file. */
|
||||
/***********************************************************************/
|
||||
bool ZIPFAM::AllocateBuffer(PGLOBAL g)
|
||||
{
|
||||
MODE mode = Tdbp->GetMode();
|
||||
|
||||
Buflen = Lrecl + 2; // Lrecl does not include CRLF
|
||||
//Buflen *= ((Mode == MODE_DELETE) ? DOS_BUFF_LEN : 1); NIY
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("SubAllocating a buffer of %d bytes\n", Buflen);
|
||||
#endif
|
||||
|
||||
To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
|
||||
|
||||
if (mode == MODE_INSERT) {
|
||||
/*******************************************************************/
|
||||
/* For Insert buffer must be prepared. */
|
||||
/*******************************************************************/
|
||||
memset(To_Buf, ' ', Buflen);
|
||||
To_Buf[Buflen - 2] = '\n';
|
||||
To_Buf[Buflen - 1] = '\0';
|
||||
} // endif Insert
|
||||
|
||||
return false;
|
||||
} // end of AllocateBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetRowID: return the RowID of last read record. */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::GetRowID(void)
|
||||
{
|
||||
return Rows;
|
||||
} // end of GetRowID
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetPos: return the position of last read record. */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::GetPos(void)
|
||||
{
|
||||
return (int)Zpos;
|
||||
} // end of GetPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetNextPos: return the position of next record. */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::GetNextPos(void)
|
||||
{
|
||||
return gztell(Zfile);
|
||||
} // end of GetNextPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetPos: Replace the table at the specified position. */
|
||||
/***********************************************************************/
|
||||
bool ZIPFAM::SetPos(PGLOBAL g, int pos)
|
||||
{
|
||||
sprintf(g->Message, MSG(NO_SETPOS_YET), "ZIP");
|
||||
return true;
|
||||
#if 0
|
||||
Fpos = pos;
|
||||
|
||||
if (fseek(Stream, Fpos, SEEK_SET)) {
|
||||
sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
|
||||
return true;
|
||||
} // endif
|
||||
|
||||
Placed = true;
|
||||
return false;
|
||||
#endif // 0
|
||||
} // end of SetPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Record file position in case of UPDATE or DELETE. */
|
||||
/***********************************************************************/
|
||||
bool ZIPFAM::RecordPos(PGLOBAL g)
|
||||
{
|
||||
Zpos = gztell(Zfile);
|
||||
return false;
|
||||
} // end of RecordPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Skip one record in file. */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::SkipRecord(PGLOBAL g, bool header)
|
||||
{
|
||||
// Skip this record
|
||||
if (gzeof(Zfile))
|
||||
return RC_EF;
|
||||
else if (gzgets(Zfile, To_Buf, Buflen) == Z_NULL)
|
||||
return Zerror(g);
|
||||
|
||||
if (header)
|
||||
RecordPos(g);
|
||||
|
||||
return RC_OK;
|
||||
} // end of SkipRecord
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBuffer: Read one line from a compressed text file. */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
char *p;
|
||||
int rc;
|
||||
|
||||
if (!Zfile)
|
||||
return RC_EF;
|
||||
|
||||
if (!Placed) {
|
||||
/*******************************************************************/
|
||||
/* Record file position in case of UPDATE or DELETE. */
|
||||
/*******************************************************************/
|
||||
if (RecordPos(g))
|
||||
return RC_FX;
|
||||
|
||||
CurBlk = Rows++; // Update RowID
|
||||
} else
|
||||
Placed = false;
|
||||
|
||||
if (gzeof(Zfile)) {
|
||||
rc = RC_EF;
|
||||
} else if (gzgets(Zfile, To_Buf, Buflen) != Z_NULL) {
|
||||
p = To_Buf + strlen(To_Buf) - 1;
|
||||
|
||||
if (*p == '\n')
|
||||
*p = '\0'; // Eliminate ending new-line character
|
||||
|
||||
if (*(--p) == '\r')
|
||||
*p = '\0'; // Eliminate eventuel carriage return
|
||||
|
||||
strcpy(Tdbp->GetLine(), To_Buf);
|
||||
IsRead = true;
|
||||
rc = RC_OK;
|
||||
num_read++;
|
||||
} else
|
||||
rc = Zerror(g);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" Read: '%s' rc=%d\n", To_Buf, rc);
|
||||
#endif
|
||||
return rc;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for ZDOS access method. */
|
||||
/* Update is not possible without using a temporary file (NIY). */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::WriteBuffer(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* Prepare the write buffer. */
|
||||
/*********************************************************************/
|
||||
strcat(strcpy(To_Buf, Tdbp->GetLine()), CrLf);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Now start the writing process. */
|
||||
/*********************************************************************/
|
||||
if (gzputs(Zfile, To_Buf) < 0)
|
||||
return Zerror(g);
|
||||
|
||||
return RC_OK;
|
||||
} // end of WriteBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for ZDOS access method. (NIY) */
|
||||
/***********************************************************************/
|
||||
int ZIPFAM::DeleteRecords(PGLOBAL g, int irc)
|
||||
{
|
||||
strcpy(g->Message, MSG(NO_ZIP_DELETE));
|
||||
return RC_FX;
|
||||
} // end of DeleteRecords
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for DOS access method. */
|
||||
/***********************************************************************/
|
||||
void ZIPFAM::CloseTableFile(PGLOBAL g)
|
||||
{
|
||||
int rc = gzclose(Zfile);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("ZIP CloseDB: closing %s rc=%d\n", To_File, rc);
|
||||
#endif
|
||||
|
||||
Zfile = NULL; // So we can know whether table is open
|
||||
//To_Fb->Count = 0; // Avoid double closing by PlugCloseAll
|
||||
} // end of CloseTableFile
|
||||
|
||||
/***********************************************************************/
|
||||
/* Rewind routine for ZIP access method. */
|
||||
/***********************************************************************/
|
||||
void ZIPFAM::Rewind(void)
|
||||
{
|
||||
gzrewind(Zfile);
|
||||
} // end of Rewind
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constructors. */
|
||||
/***********************************************************************/
|
||||
ZBKFAM::ZBKFAM(PDOSDEF tdp) : ZIPFAM(tdp)
|
||||
{
|
||||
Blocked = true;
|
||||
Block = tdp->GetBlock();
|
||||
Last = tdp->GetLast();
|
||||
Nrec = tdp->GetElemt();
|
||||
CurLine = NULL;
|
||||
NxtLine = NULL;
|
||||
Closing = false;
|
||||
BlkPos = tdp->GetTo_Pos();
|
||||
} // end of ZBKFAM standard constructor
|
||||
|
||||
ZBKFAM::ZBKFAM(PZBKFAM txfp) : ZIPFAM(txfp)
|
||||
{
|
||||
CurLine = txfp->CurLine;
|
||||
NxtLine = txfp->NxtLine;
|
||||
Closing = txfp->Closing;
|
||||
} // end of ZBKFAM copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Use BlockTest to reduce the table estimated size. */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::MaxBlkSize(PGLOBAL g, int s)
|
||||
{
|
||||
int savcur = CurBlk;
|
||||
int size;
|
||||
|
||||
// Roughly estimate the table size as the sum of blocks
|
||||
// that can contain good rows
|
||||
for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++)
|
||||
size += (CurBlk == Block - 1) ? Last : Nrec;
|
||||
|
||||
CurBlk = savcur;
|
||||
return size;
|
||||
} // end of MaxBlkSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* ZBK 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). */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::Cardinality(PGLOBAL g)
|
||||
{
|
||||
// Should not be called in this version
|
||||
return (g) ? -1 : 0;
|
||||
//return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
|
||||
} // end of Cardinality
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate the line buffer. For mode Delete a bigger buffer has to */
|
||||
/* be allocated because is it also used to move lines into the file. */
|
||||
/***********************************************************************/
|
||||
bool ZBKFAM::AllocateBuffer(PGLOBAL g)
|
||||
{
|
||||
Buflen = Nrec * (Lrecl + 2);
|
||||
CurLine = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
|
||||
|
||||
if (Tdbp->GetMode() == MODE_INSERT) {
|
||||
// Set values so Block and Last can be recalculated
|
||||
if (Last == Nrec) {
|
||||
CurBlk = Block;
|
||||
Rbuf = Nrec; // To be used by WriteDB
|
||||
} else {
|
||||
// The last block must be completed
|
||||
CurBlk = Block - 1;
|
||||
Rbuf = Nrec - Last; // To be used by WriteDB
|
||||
} // endif Last
|
||||
|
||||
} // endif Insert
|
||||
|
||||
return false;
|
||||
} // end of AllocateBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetRowID: return the RowID of last read record. */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::GetRowID(void)
|
||||
{
|
||||
return CurNum + Nrec * CurBlk + 1;
|
||||
} // end of GetRowID
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetPos: return the position of last read record. */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::GetPos(void)
|
||||
{
|
||||
return CurNum + Nrec * CurBlk; // Computed file index
|
||||
} // end of GetPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Record file position in case of UPDATE or DELETE. */
|
||||
/* Not used yet for fixed tables. */
|
||||
/***********************************************************************/
|
||||
bool ZBKFAM::RecordPos(PGLOBAL g)
|
||||
{
|
||||
//strcpy(g->Message, "RecordPos not implemented for zip blocked tables");
|
||||
//return true;
|
||||
return RC_OK;
|
||||
} // end of RecordPos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Skip one record in file. */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::SkipRecord(PGLOBAL g, bool header)
|
||||
{
|
||||
//strcpy(g->Message, "SkipRecord not implemented for zip blocked tables");
|
||||
//return RC_FX;
|
||||
return RC_OK;
|
||||
} // end of SkipRecord
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBuffer: Read one line from a compressed text file. */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
int n, rc = RC_OK;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Sequential reading when Placed is not true. */
|
||||
/*********************************************************************/
|
||||
if (++CurNum < Rbuf) {
|
||||
CurLine = NxtLine;
|
||||
|
||||
// Get the position of the next line in the buffer
|
||||
while (*NxtLine++ != '\n') ;
|
||||
|
||||
// Set caller line buffer
|
||||
n = NxtLine - CurLine - Ending;
|
||||
memcpy(Tdbp->GetLine(), CurLine, n);
|
||||
Tdbp->GetLine()[n] = '\0';
|
||||
return RC_OK;
|
||||
} else if (Rbuf < Nrec && CurBlk != -1)
|
||||
return RC_EF;
|
||||
|
||||
/*********************************************************************/
|
||||
/* New block. */
|
||||
/*********************************************************************/
|
||||
CurNum = 0;
|
||||
|
||||
if (++CurBlk >= Block)
|
||||
return RC_EF;
|
||||
|
||||
BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk];
|
||||
|
||||
if (!(n = gzread(Zfile, To_Buf, BlkLen))) {
|
||||
rc = RC_EF;
|
||||
} else if (n > 0) {
|
||||
// Get the position of the current line
|
||||
CurLine = To_Buf;
|
||||
|
||||
// Now get the position of the next line
|
||||
for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
|
||||
|
||||
// Set caller line buffer
|
||||
n = NxtLine - CurLine - Ending;
|
||||
memcpy(Tdbp->GetLine(), CurLine, n);
|
||||
Tdbp->GetLine()[n] = '\0';
|
||||
Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
|
||||
IsRead = true;
|
||||
rc = RC_OK;
|
||||
num_read++;
|
||||
} else
|
||||
rc = Zerror(g);
|
||||
|
||||
return rc;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for ZDOS access method. */
|
||||
/* Update is not possible without using a temporary file (NIY). */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::WriteBuffer(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* Prepare the write buffer. */
|
||||
/*********************************************************************/
|
||||
if (!Closing)
|
||||
strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
|
||||
|
||||
/*********************************************************************/
|
||||
/* In Insert mode, blocs are added sequentialy to the file end. */
|
||||
/* Note: Update mode is not handled for zip files. */
|
||||
/*********************************************************************/
|
||||
if (++CurNum == Rbuf) {
|
||||
/*******************************************************************/
|
||||
/* New block, start the writing process. */
|
||||
/*******************************************************************/
|
||||
BlkLen = CurLine + strlen(CurLine) - To_Buf;
|
||||
|
||||
if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
|
||||
gzflush(Zfile, Z_FULL_FLUSH)) {
|
||||
Closing = true;
|
||||
return Zerror(g);
|
||||
} // endif gzwrite
|
||||
|
||||
Rbuf = Nrec;
|
||||
CurBlk++;
|
||||
CurNum = 0;
|
||||
CurLine = To_Buf;
|
||||
} else
|
||||
CurLine += strlen(CurLine);
|
||||
|
||||
return RC_OK;
|
||||
} // end of WriteBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for ZBK access method. */
|
||||
/* Implemented only for total deletion of the table, which is done */
|
||||
/* by opening the file in mode "wb". */
|
||||
/***********************************************************************/
|
||||
int ZBKFAM::DeleteRecords(PGLOBAL g, int irc)
|
||||
{
|
||||
if (irc == RC_EF) {
|
||||
LPCSTR name = Tdbp->GetName();
|
||||
PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
|
||||
PCATLG cat = PlgGetCatalog(g);
|
||||
|
||||
defp->SetBlock(0);
|
||||
defp->SetLast(Nrec);
|
||||
|
||||
if (!cat->SetIntCatInfo(name, "Blocks", 0) ||
|
||||
!cat->SetIntCatInfo(name, "Last", 0)) {
|
||||
sprintf(g->Message, MSG(UPDATE_ERROR), "Header");
|
||||
return RC_FX;
|
||||
} else
|
||||
return RC_OK;
|
||||
|
||||
} else
|
||||
return irc;
|
||||
|
||||
} // end of DeleteRecords
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for ZBK access method. */
|
||||
/***********************************************************************/
|
||||
void ZBKFAM::CloseTableFile(PGLOBAL g)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
|
||||
if (Tdbp->GetMode() == MODE_INSERT) {
|
||||
PCATLG cat = PlgGetCatalog(g);
|
||||
LPCSTR name = Tdbp->GetName();
|
||||
PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
|
||||
|
||||
if (CurNum && !Closing) {
|
||||
// Some more inserted lines remain to be written
|
||||
Last = (Nrec - Rbuf) + CurNum;
|
||||
Block = CurBlk + 1;
|
||||
Rbuf = CurNum--;
|
||||
Closing = true;
|
||||
rc = WriteBuffer(g);
|
||||
} else if (Rbuf == Nrec) {
|
||||
Last = Nrec;
|
||||
Block = CurBlk;
|
||||
} // endif CurNum
|
||||
|
||||
if (rc != RC_FX) {
|
||||
defp->SetBlock(Block);
|
||||
defp->SetLast(Last);
|
||||
cat->SetIntCatInfo(name, "Blocks", Block);
|
||||
cat->SetIntCatInfo(name, "Last", Last);
|
||||
} // endif
|
||||
|
||||
gzclose(Zfile);
|
||||
} else if (Tdbp->GetMode() == MODE_DELETE) {
|
||||
rc = DeleteRecords(g, RC_EF);
|
||||
gzclose(Zfile);
|
||||
} else
|
||||
rc = gzclose(Zfile);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("ZIP CloseDB: closing %s rc=%d\n", To_File, rc);
|
||||
#endif
|
||||
|
||||
Zfile = NULL; // So we can know whether table is open
|
||||
//To_Fb->Count = 0; // Avoid double closing by PlugCloseAll
|
||||
} // end of CloseTableFile
|
||||
|
||||
/***********************************************************************/
|
||||
/* Rewind routine for ZBK access method. */
|
||||
/***********************************************************************/
|
||||
void ZBKFAM::Rewind(void)
|
||||
{
|
||||
gzrewind(Zfile);
|
||||
CurBlk = -1;
|
||||
CurNum = Rbuf;
|
||||
} // end of Rewind
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constructors. */
|
||||
/***********************************************************************/
|
||||
ZIXFAM::ZIXFAM(PDOSDEF tdp) : ZBKFAM(tdp)
|
||||
{
|
||||
//Block = tdp->GetBlock();
|
||||
//Last = tdp->GetLast();
|
||||
Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
|
||||
Blksize = Nrec * Lrecl;
|
||||
} // end of ZIXFAM standard constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ZIX 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). */
|
||||
/***********************************************************************/
|
||||
int ZIXFAM::Cardinality(PGLOBAL g)
|
||||
{
|
||||
if (Last)
|
||||
return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
|
||||
else // Last and Block not defined, cannot do it yet
|
||||
return 0;
|
||||
|
||||
} // end of Cardinality
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate the line buffer. For mode Delete a bigger buffer has to */
|
||||
/* be allocated because is it also used to move lines into the file. */
|
||||
/***********************************************************************/
|
||||
bool ZIXFAM::AllocateBuffer(PGLOBAL g)
|
||||
{
|
||||
Buflen = Blksize;
|
||||
To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
|
||||
|
||||
if (Tdbp->GetMode() == MODE_INSERT) {
|
||||
/*******************************************************************/
|
||||
/* For Insert the buffer must be prepared. */
|
||||
/*******************************************************************/
|
||||
memset(To_Buf, ' ', Buflen);
|
||||
|
||||
if (Tdbp->GetFtype() < 2)
|
||||
// if not binary, the file is physically a text file
|
||||
for (int len = Lrecl; len <= Buflen; len += Lrecl) {
|
||||
#if defined(WIN32)
|
||||
To_Buf[len - 2] = '\r';
|
||||
#endif // WIN32
|
||||
To_Buf[len - 1] = '\n';
|
||||
} // endfor len
|
||||
|
||||
// Set values so Block and Last can be recalculated
|
||||
if (Last == Nrec) {
|
||||
CurBlk = Block;
|
||||
Rbuf = Nrec; // To be used by WriteDB
|
||||
} else {
|
||||
// The last block must be completed
|
||||
CurBlk = Block - 1;
|
||||
Rbuf = Nrec - Last; // To be used by WriteDB
|
||||
} // endif Last
|
||||
|
||||
} // endif Insert
|
||||
|
||||
return false;
|
||||
} // end of AllocateBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBuffer: Read one line from a compressed text file. */
|
||||
/***********************************************************************/
|
||||
int ZIXFAM::ReadBuffer(PGLOBAL g)
|
||||
{
|
||||
int n, rc = RC_OK;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Sequential reading when Placed is not true. */
|
||||
/*********************************************************************/
|
||||
if (++CurNum < Rbuf) {
|
||||
Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
|
||||
return RC_OK;
|
||||
} else if (Rbuf < Nrec && CurBlk != -1)
|
||||
return RC_EF;
|
||||
|
||||
/*********************************************************************/
|
||||
/* New block. */
|
||||
/*********************************************************************/
|
||||
CurNum = 0;
|
||||
Tdbp->SetLine(To_Buf);
|
||||
|
||||
//if (++CurBlk >= Block)
|
||||
// return RC_EF;
|
||||
|
||||
if (!(n = gzread(Zfile, To_Buf, Buflen))) {
|
||||
rc = RC_EF;
|
||||
} else if (n > 0) {
|
||||
Rbuf = n / Lrecl;
|
||||
IsRead = true;
|
||||
rc = RC_OK;
|
||||
num_read++;
|
||||
} else
|
||||
rc = Zerror(g);
|
||||
|
||||
return rc;
|
||||
} // end of ReadBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for ZDOS access method. */
|
||||
/* Update is not possible without using a temporary file (NIY). */
|
||||
/***********************************************************************/
|
||||
int ZIXFAM::WriteBuffer(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* In Insert mode, blocs are added sequentialy to the file end. */
|
||||
/* Note: Update mode is not handled for zip files. */
|
||||
/*********************************************************************/
|
||||
if (++CurNum == Rbuf) {
|
||||
/*******************************************************************/
|
||||
/* New block, start the writing process. */
|
||||
/*******************************************************************/
|
||||
BlkLen = Rbuf * Lrecl;
|
||||
|
||||
if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
|
||||
gzflush(Zfile, Z_FULL_FLUSH)) {
|
||||
Closing = true;
|
||||
return Zerror(g);
|
||||
} // endif gzwrite
|
||||
|
||||
Rbuf = Nrec;
|
||||
CurBlk++;
|
||||
CurNum = 0;
|
||||
Tdbp->SetLine(To_Buf);
|
||||
} else
|
||||
Tdbp->IncLine(Lrecl); // Used by FIXCOL functions
|
||||
|
||||
return RC_OK;
|
||||
} // end of WriteBuffer
|
||||
|
||||
/* ------------------------ End of ZipFam ---------------------------- */
|
||||
174
storage/connect/filamzip.h
Normal file
174
storage/connect/filamzip.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/************** FilAmZip H Declares Source Code File (.H) **************/
|
||||
/* Name: FILAMZIP.H Version 1.1 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the GZIP access method classes declares. */
|
||||
/***********************************************************************/
|
||||
#ifndef __FILAMZIP_H
|
||||
#define __FILAMZIP_H
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
#define TYPE_AM_ZIP (AMT)150
|
||||
#define TYPE_AM_ZLIB (AMT)155
|
||||
|
||||
typedef class ZIPFAM *PZIPFAM;
|
||||
typedef class ZBKFAM *PZBKFAM;
|
||||
typedef class ZIXFAM *PZIXFAM;
|
||||
typedef class ZLBFAM *PZLBFAM;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the access method class declaration for not optimized */
|
||||
/* variable record length files compressed using the gzip library */
|
||||
/* functions. File is accessed record by record (row). */
|
||||
/***********************************************************************/
|
||||
class DllExport ZIPFAM : public TXTFAM {
|
||||
// friend class DOSCOL;
|
||||
public:
|
||||
// Constructor
|
||||
ZIPFAM(PDOSDEF tdp) : TXTFAM(tdp) {Zfile = NULL; Zpos = 0;}
|
||||
ZIPFAM(PZIPFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_ZIP;}
|
||||
virtual int GetPos(void);
|
||||
virtual int GetNextPos(void);
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) ZIPFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual int GetFileLength(PGLOBAL g);
|
||||
virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;}
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual int GetRowID(void);
|
||||
virtual bool RecordPos(PGLOBAL g);
|
||||
virtual bool SetPos(PGLOBAL g, int recpos);
|
||||
virtual int SkipRecord(PGLOBAL g, bool header);
|
||||
virtual bool OpenTableFile(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
int Zerror(PGLOBAL g); // GZ error function
|
||||
|
||||
// Members
|
||||
gzFile Zfile; // Points to GZ file structure
|
||||
z_off_t Zpos; // Uncompressed file position
|
||||
}; // end of class ZIPFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the access method class declaration for optimized variable */
|
||||
/* record length files compressed using the gzip library functions. */
|
||||
/* The File is accessed by block (requires an opt file). */
|
||||
/***********************************************************************/
|
||||
class DllExport ZBKFAM : public ZIPFAM {
|
||||
public:
|
||||
// Constructor
|
||||
ZBKFAM(PDOSDEF tdp);
|
||||
ZBKFAM(PZBKFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual int GetPos(void);
|
||||
virtual int GetNextPos(void) {return 0;}
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) ZBKFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int MaxBlkSize(PGLOBAL g, int s);
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual int GetRowID(void);
|
||||
virtual bool RecordPos(PGLOBAL g);
|
||||
virtual int SkipRecord(PGLOBAL g, bool header);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual int DeleteRecords(PGLOBAL g, int irc);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *CurLine; // Position of current line in buffer
|
||||
char *NxtLine; // Position of Next line in buffer
|
||||
bool Closing; // True when closing on Insert
|
||||
}; // end of class ZBKFAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the access method class declaration for fixed record */
|
||||
/* length files compressed using the gzip library functions. */
|
||||
/* The file is always accessed by block. */
|
||||
/***********************************************************************/
|
||||
class DllExport ZIXFAM : public ZBKFAM {
|
||||
public:
|
||||
// Constructor
|
||||
ZIXFAM(PDOSDEF tdp);
|
||||
ZIXFAM(PZIXFAM txfp) : ZBKFAM(txfp) {}
|
||||
|
||||
// Implementation
|
||||
virtual int GetNextPos(void) {return 0;}
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) ZIXFAM(this);}
|
||||
|
||||
// Methods
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// No additional Members
|
||||
}; // end of class ZIXFAM
|
||||
|
||||
#ifdef NOT_USED
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for PlugDB */
|
||||
/* fixed/variable files compressed using the zlib library functions. */
|
||||
/* Physically these are written and read using the same technique */
|
||||
/* than blocked variable files, only the contain of each block is */
|
||||
/* compressed using the deflate zlib function. The purpose of this */
|
||||
/* specific format is to have a fast mechanism for direct access of */
|
||||
/* records so blocked optimization is fast and direct access (joins) */
|
||||
/* is allowed. Note that the block length is written ahead of each */
|
||||
/* block to enable reading when optimization file is not available. */
|
||||
/***********************************************************************/
|
||||
class DllExport ZLBFAM : public BLKFAM {
|
||||
public:
|
||||
// Constructor
|
||||
ZLBFAM(PDOSDEF tdp);
|
||||
ZLBFAM(PZLBFAM txfp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_ZLIB;}
|
||||
virtual int GetPos(void);
|
||||
virtual int GetNextPos(void);
|
||||
virtual PTXF Duplicate(PGLOBAL g)
|
||||
{return (PTXF)new(g) ZLBFAM(this);}
|
||||
inline void SetOptimized(bool b) {Optimized = b;}
|
||||
|
||||
// Methods
|
||||
virtual int GetFileLength(PGLOBAL g);
|
||||
virtual bool AllocateBuffer(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g);
|
||||
virtual int WriteBuffer(PGLOBAL g);
|
||||
virtual void CloseTableFile(PGLOBAL g);
|
||||
virtual void Rewind(void);
|
||||
|
||||
protected:
|
||||
bool WriteCompressedBuffer(PGLOBAL g);
|
||||
int ReadCompressedBuffer(PGLOBAL g, void *rdbuf);
|
||||
|
||||
// Members
|
||||
z_streamp Zstream; // Compression/decompression stream
|
||||
Byte *Zbuffer; // Compressed block buffer
|
||||
int *Zlenp; // Pointer to block length
|
||||
bool Optimized; // true when opt file is available
|
||||
}; // end of class ZLBFAM
|
||||
#endif // NOT_USED
|
||||
|
||||
#endif // __FILAMZIP_H
|
||||
1522
storage/connect/fmdlex.c
Normal file
1522
storage/connect/fmdlex.c
Normal file
File diff suppressed because it is too large
Load Diff
1013
storage/connect/frmsg1.h
Normal file
1013
storage/connect/frmsg1.h
Normal file
File diff suppressed because it is too large
Load Diff
1013
storage/connect/frmsg2.h
Normal file
1013
storage/connect/frmsg2.h
Normal file
File diff suppressed because it is too large
Load Diff
273
storage/connect/global.h
Normal file
273
storage/connect/global.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/***********************************************************************/
|
||||
/* GLOBAL.H: Declaration file used by all CONNECT implementations. */
|
||||
/* (C) Copyright Olivier Bertrand 1993-2012 */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Included C-definition files common to all Plug routines */
|
||||
/***********************************************************************/
|
||||
#include <string.h> /* String manipulation declares */
|
||||
#include <stdlib.h> /* C standard library */
|
||||
#include <ctype.h> /* C language specific types */
|
||||
#include <stdio.h> /* FOPEN_MAX declaration */
|
||||
#include <time.h> /* time_t type declaration */
|
||||
#include <setjmp.h> /* Long jump declarations */
|
||||
|
||||
#if defined(WIN32) && !defined(NOEX)
|
||||
#define DllExport __declspec( dllexport )
|
||||
#else // !WIN32
|
||||
#define DllExport
|
||||
#endif // !WIN32
|
||||
|
||||
#if defined(XMSG)
|
||||
// Definition used to read messages from message file.
|
||||
#include "msgid.h"
|
||||
#define MSG(I) PlugReadMessage(NULL, MSG_##I, #I)
|
||||
#define STEP(I) PlugReadMessage(g, MSG_##I, #I)
|
||||
#elif defined(NEWMSG)
|
||||
// Definition used to get messages from resource.
|
||||
#include "msgid.h"
|
||||
#define MSG(I) PlugGetMessage(NULL, MSG_##I)
|
||||
#define STEP(I) PlugGetMessage(g, MSG_##I)
|
||||
#else // !XMSG and !NEWMSG
|
||||
// Definition used to replace messages ID's by their definition.
|
||||
#include "messages.h"
|
||||
#define MSG(I) MSG_##I
|
||||
#define STEP(I) MSG_##I
|
||||
#endif // !XMSG and !NEWMSG
|
||||
|
||||
#if defined(WIN32)
|
||||
#define CRLF 2
|
||||
#else // !WIN32
|
||||
#define CRLF 1
|
||||
#define BOOL my_bool
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Miscellaneous Constants */
|
||||
/***********************************************************************/
|
||||
#define NO_IVAL -95684275 /* Used by GetIntegerOption */
|
||||
#define VMLANG 370 /* Size of olf VM lang blocks */
|
||||
#define MAX_JUMP 24 /* Maximum jump level number */
|
||||
#define MAX_STR 1024 /* Maximum string length */
|
||||
#define STR_SIZE 501 /* Length of char strings. */
|
||||
#define STD_INPUT 0 /* Standard language input */
|
||||
#define STD_OUTPUT 1 /* Standard language output */
|
||||
#define ERROR_OUTPUT 2 /* Error message output */
|
||||
#define DEBUG_OUTPUT 3 /* Debug info output */
|
||||
#define PROMPT_OUTPUT 4 /* Prompt message output */
|
||||
#define COPY_OUTPUT 5 /* Copy of language input */
|
||||
#define STD_MSG 6 /* System message file */
|
||||
#define DEBUG_MSG 7 /* Debug message file */
|
||||
#define DUMMY 0 /* Dummy file index in Ldm block */
|
||||
#define STDIN 1 /* stdin file index in Ldm block */
|
||||
#define STDOUT 2 /* stdout file index in Ldm block */
|
||||
#define STDERR 3 /* stderr file index in Ldm block */
|
||||
#define STDEBUG 4 /* debug file index in Ldm block */
|
||||
#define STDPRN 5 /* stdprn file index in Ldm block */
|
||||
#define STDFREE 6 /* Free file index in Ldm block */
|
||||
|
||||
#define TYPE_SEM -2 /* Returned semantic function */
|
||||
#define TYPE_DFONC -2 /* Indirect sem ref in FPARM */
|
||||
#define TYPE_VOID -1
|
||||
#define TYPE_SBPAR -1 /* Phrase reference in FPARM */
|
||||
#define TYPE_SEMX 0 /* Initial semantic function type? */
|
||||
#define TYPE_ERROR 0
|
||||
#define TYPE_STRING 1
|
||||
#define TYPE_FLOAT 2
|
||||
#define TYPE_SHORT 3
|
||||
#define TYPE_LIST 6
|
||||
#define TYPE_INT 7
|
||||
|
||||
#if defined(OS32)
|
||||
#define SYS_STAMP "OS32"
|
||||
#elif defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
|
||||
#define SYS_STAMP "UNIX"
|
||||
#elif defined(OS16)
|
||||
#define SYS_STAMP "OS16"
|
||||
#elif defined(DOSR)
|
||||
#define SYS_STAMP "DOSR"
|
||||
#elif defined(WIN)
|
||||
#define SYS_STAMP "WIN1"
|
||||
#elif defined(WIN32)
|
||||
#define SYS_STAMP "WIN2"
|
||||
#else
|
||||
#define SYS_STAMP "XXXX"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Static variables */
|
||||
/***********************************************************************/
|
||||
#if defined(STORAGE)
|
||||
char sys_stamp[4] = SYS_STAMP;
|
||||
#else
|
||||
extern char sys_stamp[];
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* File-Selection Indicators */
|
||||
/***********************************************************************/
|
||||
#define PAT_LOG "log"
|
||||
|
||||
#if defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
|
||||
/*********************************************************************/
|
||||
/* printf does not accept null pointer for %s target. */
|
||||
/*********************************************************************/
|
||||
#define SVP(S) ((S) ? S : "<null>")
|
||||
#else
|
||||
/*********************************************************************/
|
||||
/* printf accepts null pointer for %s target. */
|
||||
/*********************************************************************/
|
||||
#define SVP(S) S
|
||||
#endif
|
||||
|
||||
#if defined(STORAGE)
|
||||
FILE *debug;
|
||||
#else
|
||||
extern FILE *debug;
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* General purpose type definitions. */
|
||||
/***********************************************************************/
|
||||
#if !defined(WIN32)
|
||||
typedef const char *LPCTSTR;
|
||||
typedef const char *LPCSTR;
|
||||
typedef unsigned char BYTE;
|
||||
typedef char *LPSTR;
|
||||
typedef char *PSZ;
|
||||
#if !defined(NODW)
|
||||
typedef int DWORD;
|
||||
#endif // !NODW
|
||||
#undef HANDLE
|
||||
typedef int HANDLE;
|
||||
#ifdef __cplusplus
|
||||
typedef int bool;
|
||||
#else
|
||||
#define bool my_bool
|
||||
#endif
|
||||
#define _MAX_PATH PATH_MAX
|
||||
#define stricmp strcasecmp
|
||||
#define _stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#define _strnicmp strncasecmp
|
||||
#define _MAX_PATH 260
|
||||
#define _MAX_DRIVE 3
|
||||
#define _MAX_DIR 256
|
||||
#define _MAX_FNAME 256
|
||||
#define _MAX_EXT 256
|
||||
#define INVALID_HANDLE_VALUE (-1)
|
||||
#define __stdcall
|
||||
#endif // !WIN32
|
||||
typedef uint OFFSET;
|
||||
typedef char NAME[9];
|
||||
|
||||
typedef struct {
|
||||
ushort Length;
|
||||
char String[2];
|
||||
} VARSTR;
|
||||
|
||||
#if !defined(PGLOBAL_DEFINED)
|
||||
typedef struct _global *PGLOBAL;
|
||||
#define PGLOBAL_DEFINED
|
||||
#endif
|
||||
typedef struct _globplg *PGS;
|
||||
typedef struct _activity *PACTIVITY;
|
||||
typedef struct _parm *PPARM;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Segment Sub-Allocation block structure declares. */
|
||||
/* Next block is an implementation dependent segment suballoc save */
|
||||
/* structure used to keep the suballocation system offsets and to */
|
||||
/* restore them if needed. This scheme implies that no SubFree be used */
|
||||
/***********************************************************************/
|
||||
typedef struct { /* Plug Area SubAlloc header */
|
||||
OFFSET To_Free; /* Offset of next free block */
|
||||
uint FreeBlk; /* Size of remaining free memory */
|
||||
} POOLHEADER, *PPOOLHEADER;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Language block. Containing all global information for the language */
|
||||
/* this block is saved and retrieved with the language. Information */
|
||||
/* in this block can be set and modified under Grammar editing. */
|
||||
/***********************************************************************/
|
||||
#if defined(BIT64)
|
||||
typedef int TIME_T; /* Lang block size must not change */
|
||||
#else // BIT32
|
||||
typedef time_t TIME_T; /* time_t */
|
||||
#endif // BIT32
|
||||
|
||||
typedef struct {
|
||||
uint Memsize;
|
||||
uint Size;
|
||||
} AREADEF;
|
||||
|
||||
typedef struct Lang_block {
|
||||
NAME LangName; /* Language name */
|
||||
NAME Application; /* Application name */
|
||||
} LANG, *PLANG;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Application block. It contains all global information for the */
|
||||
/* current parse and execution using the corresponding language. */
|
||||
/* This block is dynamically allocated and set at language init. */
|
||||
/***********************************************************************/
|
||||
typedef struct _activity { /* Describes activity and language */
|
||||
void *Aptr; /* Points to user work area(s) */
|
||||
NAME Ap_Name; /* Current application name */
|
||||
} ACTIVITY;
|
||||
|
||||
/*---------------- UNIT ?????????? VERSION ? ----------------------*/
|
||||
typedef struct _parm {
|
||||
void *Value;
|
||||
short Type, Domain;
|
||||
PPARM Next;
|
||||
} PARM;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Global Structure Block. This block contains, or points to, all */
|
||||
/* information used by CONNECT tables. Passed as an argument */
|
||||
/* to any routine allows it to have access to the entire information */
|
||||
/* currently available for the whole set of loaded languages. */
|
||||
/***********************************************************************/
|
||||
typedef struct _global { /* Global structure */
|
||||
void *Sarea; /* Points to work area */
|
||||
uint Sarea_Size; /* Work area size */
|
||||
PACTIVITY Activityp, ActivityStart;
|
||||
char Message[MAX_STR];
|
||||
short Trace;
|
||||
int jump_level;
|
||||
jmp_buf jumper[MAX_JUMP + 2];
|
||||
} GLOBAL;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Exported routine declarations. */
|
||||
/***********************************************************************/
|
||||
#if defined(XMSG)
|
||||
DllExport char *PlugReadMessage(PGLOBAL, int, char *);
|
||||
#elif defined(NEWMSG)
|
||||
DllExport char *PlugGetMessage(PGLOBAL, int);
|
||||
#endif // XMSG || NEWMSG
|
||||
#if defined(WIN32)
|
||||
DllExport short GetLineLength(PGLOBAL); // Console line length
|
||||
#endif // WIN32
|
||||
DllExport PGLOBAL PlugInit(LPCSTR, uint); // Plug global initialization
|
||||
DllExport int PlugExit(PGLOBAL); // Plug global termination
|
||||
DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR);
|
||||
DllExport LPCSTR PlugSetPath(LPSTR, LPCSTR, LPCSTR);
|
||||
DllExport void *PlugAllocMem(PGLOBAL, uint);
|
||||
DllExport BOOL PlugSubSet(PGLOBAL, void *, uint);
|
||||
DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t);
|
||||
DllExport void *MakePtr(void *, OFFSET);
|
||||
DllExport void htrc(char const *fmt, ...);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
/*-------------------------- End of Global.H --------------------------*/
|
||||
3636
storage/connect/ha_connect.cc
Normal file
3636
storage/connect/ha_connect.cc
Normal file
File diff suppressed because it is too large
Load Diff
392
storage/connect/ha_connect.h
Normal file
392
storage/connect/ha_connect.h
Normal file
@@ -0,0 +1,392 @@
|
||||
/* Copyright (C) Olivier Bertrand 2004 - 2011
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/** @file ha_connect.h
|
||||
|
||||
@brief
|
||||
The ha_connect engine is a prototype storage engine to access external data.
|
||||
|
||||
@see
|
||||
/sql/handler.h and /storage/connect/ha_connect.cc
|
||||
*/
|
||||
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
/* Structures used to pass info between CONNECT and ha_connect. */
|
||||
/****************************************************************************/
|
||||
typedef struct _create_xinfo {
|
||||
char *Type; /* Retrieved from table comment */
|
||||
char *Filename; /* Set if not standard */
|
||||
char *IndexFN; /* Set if not standard */
|
||||
ulonglong Maxrows; /* Estimated max nb of rows */
|
||||
ulong Lrecl; /* Set if not default */
|
||||
ulong Elements; /* Number of lines in blocks */
|
||||
bool Fixed; /* False for DOS type */
|
||||
void *Pcf; /* To list of columns */
|
||||
void *Pxdf; /* To list of indexes */
|
||||
} CRXINFO, *PCXF;
|
||||
|
||||
typedef struct _xinfo {
|
||||
ulonglong data_file_length; /* Length of data file */
|
||||
ha_rows records; /* Records in table */
|
||||
ulong mean_rec_length; /* Physical record length */
|
||||
char *data_file_name; /* Physical file name */
|
||||
} XINFO, *PXF;
|
||||
|
||||
typedef class user_connect *PCONNECT;
|
||||
typedef struct ha_table_option_struct TOS, *PTOS;
|
||||
typedef struct ha_field_option_struct FOS, *PFOS;
|
||||
|
||||
/** @brief
|
||||
CONNECT_SHARE is a structure that will be shared among all open handlers.
|
||||
This example implements the minimum of what you will probably need.
|
||||
*/
|
||||
typedef struct st_connect_share {
|
||||
char *table_name;
|
||||
uint table_name_length, use_count;
|
||||
mysql_mutex_t mutex;
|
||||
THR_LOCK lock;
|
||||
#if !defined(MARIADB)
|
||||
PTOS table_options;
|
||||
PFOS field_options;
|
||||
#endif // !MARIADB
|
||||
} CONNECT_SHARE;
|
||||
|
||||
typedef class ha_connect *PHC;
|
||||
|
||||
/** @brief
|
||||
Class definition for the storage engine
|
||||
*/
|
||||
class ha_connect: public handler
|
||||
{
|
||||
THR_LOCK_DATA lock; ///< MySQL lock
|
||||
CONNECT_SHARE *share; ///< Shared lock info
|
||||
|
||||
public:
|
||||
ha_connect(handlerton *hton, TABLE_SHARE *table_arg);
|
||||
~ha_connect();
|
||||
|
||||
// CONNECT Implementation
|
||||
static bool connect_init(void);
|
||||
static bool connect_end(void);
|
||||
char *GetStringOption(char *opname, char *sdef= NULL);
|
||||
PTOS GetTableOptionStruct(TABLE *table_arg);
|
||||
bool GetBooleanOption(char *opname, bool bdef);
|
||||
int GetIntegerOption(char *opname);
|
||||
bool SetIntegerOption(char *opname, int n);
|
||||
PFOS GetFieldOptionStruct(Field *fp);
|
||||
void *GetColumnOption(void *field, PCOLINFO pcf);
|
||||
PIXDEF GetIndexInfo(int n);
|
||||
const char *GetDBName(const char *name);
|
||||
const char *GetTableName(void);
|
||||
int GetColNameLen(Field *fp);
|
||||
char *GetColName(Field *fp);
|
||||
void AddColName(char *cp, Field *fp);
|
||||
TABLE *GetTable(void) {return table;}
|
||||
|
||||
PCONNECT GetUser(THD *thd);
|
||||
PGLOBAL GetPlug(THD *thd);
|
||||
PTDB GetTDB(PGLOBAL g);
|
||||
bool OpenTable(PGLOBAL g, bool del= false);
|
||||
bool IsOpened(void);
|
||||
int CloseTable(PGLOBAL g);
|
||||
int MakeRecord(char *buf);
|
||||
int ScanRecord(PGLOBAL g, uchar *buf);
|
||||
int CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf);
|
||||
int ReadIndexed(uchar *buf, OPVAL op, const uchar* key= NULL,
|
||||
uint key_len= 0);
|
||||
|
||||
/** @brief
|
||||
The name that will be used for display purposes.
|
||||
*/
|
||||
const char *table_type() const {return "CONNECT";}
|
||||
|
||||
/** @brief
|
||||
The name of the index type that will be used for display.
|
||||
Don't implement this method unless you really have indexes.
|
||||
*/
|
||||
const char *index_type(uint inx) { return "XPLUG"; }
|
||||
|
||||
/** @brief
|
||||
The file extensions.
|
||||
*/
|
||||
const char **bas_ext() const;
|
||||
|
||||
/** @brief
|
||||
This is a list of flags that indicate what functionality the storage engine
|
||||
implements. The current table flags are documented in handler.h
|
||||
*/
|
||||
ulonglong table_flags() const
|
||||
{
|
||||
return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_HAS_RECORDS |
|
||||
/*HA_NO_AUTO_INCREMENT |*/ HA_NO_PREFIX_CHAR_KEYS |
|
||||
#if defined(MARIADB)
|
||||
HA_CAN_VIRTUAL_COLUMNS |
|
||||
#endif // MARIADB
|
||||
HA_NULL_IN_KEY | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE);
|
||||
}
|
||||
|
||||
/** @brief
|
||||
This is a bitmap of flags that indicates how the storage engine
|
||||
implements indexes. The current index flags are documented in
|
||||
handler.h. If you do not implement indexes, just return zero here.
|
||||
|
||||
@details
|
||||
part is the key part to check. First key part is 0.
|
||||
If all_parts is set, MySQL wants to know the flags for the combined
|
||||
index, up to and including 'part'.
|
||||
*/
|
||||
ulong index_flags(uint inx, uint part, bool all_parts) const
|
||||
{
|
||||
return HA_READ_NEXT | HA_READ_RANGE;
|
||||
}
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call max_supported_record_length(), max_supported_keys(),
|
||||
max_supported_key_parts(), uint max_supported_key_length()
|
||||
to make sure that the storage engine can handle the data it is about to
|
||||
send. Return *real* limits of your storage engine here; MySQL will do
|
||||
min(your_limits, MySQL_limits) automatically.
|
||||
*/
|
||||
uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call this to make sure that the storage engine can handle
|
||||
the data it is about to send. Return *real* limits of your storage engine
|
||||
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
||||
|
||||
@details
|
||||
There is no need to implement ..._key_... methods if your engine doesn't
|
||||
support indexes.
|
||||
*/
|
||||
uint max_supported_keys() const { return 10; }
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call this to make sure that the storage engine can handle
|
||||
the data it is about to send. Return *real* limits of your storage engine
|
||||
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
||||
|
||||
@details
|
||||
There is no need to implement ..._key_... methods if your engine doesn't
|
||||
support indexes.
|
||||
*/
|
||||
uint max_supported_key_parts() const { return 10; }
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call this to make sure that the storage engine can handle
|
||||
the data it is about to send. Return *real* limits of your storage engine
|
||||
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
||||
|
||||
@details
|
||||
There is no need to implement ..._key_... methods if your engine doesn't
|
||||
support indexes.
|
||||
*/
|
||||
uint max_supported_key_length() const { return 255; }
|
||||
|
||||
/** @brief
|
||||
Called in test_quick_select to determine if indexes should be used.
|
||||
*/
|
||||
virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
|
||||
|
||||
/** @brief
|
||||
This method will never be called if you do not implement indexes.
|
||||
*/
|
||||
virtual double read_time(uint, uint, ha_rows rows)
|
||||
{ return (double) rows / 20.0+1; }
|
||||
|
||||
/*
|
||||
Everything below are methods that we implement in ha_connect.cc.
|
||||
|
||||
Most of these methods are not obligatory, skip them and
|
||||
MySQL will treat them as not implemented
|
||||
*/
|
||||
virtual bool get_error_message(int error, String *buf);
|
||||
|
||||
/**
|
||||
Push condition down to the table handler.
|
||||
|
||||
@param cond Condition to be pushed. The condition tree must not be
|
||||
modified by the by the caller.
|
||||
|
||||
@return
|
||||
The 'remainder' condition that caller must use to filter out records.
|
||||
NULL means the handler will not return rows that do not match the
|
||||
passed condition.
|
||||
|
||||
@note
|
||||
The pushed conditions form a stack (from which one can remove the
|
||||
last pushed condition using cond_pop).
|
||||
The table handler filters out rows using (pushed_cond1 AND pushed_cond2
|
||||
AND ... AND pushed_condN)
|
||||
or less restrictive condition, depending on handler's capabilities.
|
||||
|
||||
handler->ha_reset() call empties the condition stack.
|
||||
Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
|
||||
condition stack.
|
||||
*/
|
||||
virtual const COND *cond_push(const COND *cond);
|
||||
PFIL CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond);
|
||||
char *GetValStr(OPVAL vop, bool neg);
|
||||
|
||||
/**
|
||||
Number of rows in table. It will only be called if
|
||||
(table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
|
||||
*/
|
||||
virtual ha_rows records();
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc; it's a required method.
|
||||
*/
|
||||
int open(const char *name, int mode, uint test_if_locked); // required
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc; it's a required method.
|
||||
*/
|
||||
int close(void); // required
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
int write_row(uchar *buf);
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
int update_row(const uchar *old_data, uchar *new_data);
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
int delete_row(const uchar *buf);
|
||||
|
||||
// Added to the connect handler
|
||||
int index_init(uint idx, bool sorted);
|
||||
int index_end();
|
||||
int index_read(uchar * buf, const uchar * key, uint key_len,
|
||||
enum ha_rkey_function find_flag);
|
||||
int index_next_same(uchar *buf, const uchar *key, uint keylen);
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
//int index_read_map(uchar *buf, const uchar *key,
|
||||
// key_part_map keypart_map, enum ha_rkey_function find_flag);
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
int index_next(uchar *buf);
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
//int index_prev(uchar *buf);
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
int index_first(uchar *buf);
|
||||
|
||||
/** @brief
|
||||
We implement this in ha_connect.cc. It's not an obligatory method;
|
||||
skip it and and MySQL will treat it as not implemented.
|
||||
*/
|
||||
//int index_last(uchar *buf);
|
||||
|
||||
/** @brief
|
||||
Unlike index_init(), rnd_init() can be called two consecutive times
|
||||
without rnd_end() in between (it only makes sense if scan=1). In this
|
||||
case, the second call should prepare for the new table scan (e.g if
|
||||
rnd_init() allocates the cursor, the second call should position the
|
||||
cursor to the start of the table; no need to deallocate and allocate
|
||||
it again. This is a required method.
|
||||
*/
|
||||
int rnd_init(bool scan); //required
|
||||
int rnd_end();
|
||||
int rnd_next(uchar *buf); ///< required
|
||||
int rnd_pos(uchar *buf, uchar *pos); ///< required
|
||||
void position(const uchar *record); ///< required
|
||||
int info(uint); ///< required
|
||||
int extra(enum ha_extra_function operation);
|
||||
int external_lock(THD *thd, int lock_type); ///< required
|
||||
int delete_all_rows(void);
|
||||
ha_rows records_in_range(uint inx, key_range *min_key,
|
||||
key_range *max_key);
|
||||
int delete_table(const char *from);
|
||||
bool pre_create(THD *thd, void *alter_info);
|
||||
int create(const char *name, TABLE *form,
|
||||
HA_CREATE_INFO *create_info); ///< required
|
||||
bool check_if_incompatible_data(HA_CREATE_INFO *info,
|
||||
uint table_changes);
|
||||
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type); ///< required
|
||||
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
|
||||
|
||||
protected:
|
||||
char *GetListOption(char *opname, const char *oplist);
|
||||
bool add_fields(THD *thd, void *alter_info,
|
||||
LEX_STRING *field_name,
|
||||
enum_field_types type,
|
||||
char *length, char *decimals,
|
||||
uint type_modifier,
|
||||
// Item *default_value, Item *on_update_value,
|
||||
LEX_STRING *comment,
|
||||
// char *change,
|
||||
// List<String> *interval_list,
|
||||
CHARSET_INFO *cs,
|
||||
// uint uint_geom_type,
|
||||
void *vcol_info,
|
||||
engine_option_value *create_options);
|
||||
|
||||
// Members
|
||||
static ulong num; // Tracable handler number
|
||||
PCONNECT xp; // To user_connect associated class
|
||||
ulong hnum; // The number of this handler
|
||||
query_id_t valid_query_id; // The one when tdbp was allocated
|
||||
query_id_t creat_query_id; // The one when handler was allocated
|
||||
PTDB tdbp; // To table class object
|
||||
PVAL sdval; // Used to convert date values
|
||||
bool istable; // True for table handler
|
||||
//char tname[64]; // The table name
|
||||
MODE xmod; // Table mode
|
||||
XINFO xinfo; // The table info structure
|
||||
bool valid_info; // True if xinfo is valid
|
||||
bool stop; // Used when creating index
|
||||
//bool hascond; // Too late for Delete
|
||||
int indexing; // Type of indexing for CONNECT
|
||||
#if !defined(MARIADB)
|
||||
PTOS table_options;
|
||||
PFOS field_options;
|
||||
#endif // !MARIADB
|
||||
THR_LOCK_DATA lock_data;
|
||||
|
||||
public:
|
||||
TABLE_SHARE *tshp; // Used by called tables
|
||||
char *data_file_name;
|
||||
char *index_file_name;
|
||||
uint int_table_flags; // Inherited from MyISAM
|
||||
bool enable_activate_all_index; // Inherited from MyISAM
|
||||
}; // end of ha_connect class definition
|
||||
1327
storage/connect/inihandl.c
Normal file
1327
storage/connect/inihandl.c
Normal file
File diff suppressed because it is too large
Load Diff
766
storage/connect/libdoc.cpp
Normal file
766
storage/connect/libdoc.cpp
Normal file
@@ -0,0 +1,766 @@
|
||||
/******************************************************************/
|
||||
/* Implementation of XML document processing using libxml2 */
|
||||
/* Author: Olivier Bertrand 2007-2013 */
|
||||
/******************************************************************/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
//#if defined(WIN32)
|
||||
//#include <windows.h>
|
||||
//#else // !WIN32
|
||||
#include "my_global.h"
|
||||
//#endif // !WIN32
|
||||
|
||||
#if !defined(LIBXML_XPATH_ENABLED) || !defined(LIBXML_SAX1_ENABLED)
|
||||
#error "XPath not supported"
|
||||
#endif
|
||||
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "xobject.h"
|
||||
#include "libdoc.h"
|
||||
|
||||
extern "C" {
|
||||
extern char version[];
|
||||
extern int trace;
|
||||
} // "C"
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a LIBXMLDOC as a XMLDOC. */
|
||||
/******************************************************************/
|
||||
PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
|
||||
char *enc, PFBLOCK fp)
|
||||
{
|
||||
return (PXDOC) new(g) LIBXMLDOC(nsl, nsdf, enc, fp);
|
||||
} // end of GetLibxmlDoc
|
||||
|
||||
/******************************************************************/
|
||||
/* XML library initialization function. */
|
||||
/******************************************************************/
|
||||
void XmlInitParserLib(void)
|
||||
{
|
||||
xmlInitParser();
|
||||
} // end of XmlInitParserLib
|
||||
|
||||
/******************************************************************/
|
||||
/* XML library cleanup function. */
|
||||
/******************************************************************/
|
||||
void XmlCleanupParserLib(void)
|
||||
{
|
||||
xmlCleanupParser();
|
||||
xmlMemoryDump();
|
||||
} // end of XmlCleanupParserLib
|
||||
|
||||
/******************************************************************/
|
||||
/* Close a loaded libxml2 XML file. */
|
||||
/******************************************************************/
|
||||
void CloseXML2File(PGLOBAL g, PFBLOCK fp, bool all)
|
||||
{
|
||||
PX2BLOCK xp = (PX2BLOCK)fp;
|
||||
|
||||
if (xp && xp->Count > 1 && !all) {
|
||||
xp->Count--;
|
||||
} else if (xp && xp->Count > 0) {
|
||||
iconv_close(xp->Cd);
|
||||
iconv_close(xp->Cd2);
|
||||
xmlFreeDoc(xp->Docp);
|
||||
xp->Count = 0;
|
||||
} // endif
|
||||
|
||||
} // end of CloseXML2File
|
||||
|
||||
/* ---------------------- class LIBXMLDOC ----------------------- */
|
||||
|
||||
/******************************************************************/
|
||||
/* LIBXMLDOC constructor. */
|
||||
/******************************************************************/
|
||||
LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp)
|
||||
: XMLDOCUMENT(nsl, nsdf, enc)
|
||||
{
|
||||
assert (!fp || fp->Type == TYPE_FB_XML2);
|
||||
Docp = (fp) ? ((PX2BLOCK)fp)->Docp : NULL;
|
||||
Nlist = NULL;
|
||||
Ctxp = NULL;
|
||||
Xop = NULL;
|
||||
Cd = (fp) ? ((PX2BLOCK)fp)->Cd : NULL;
|
||||
Cd2 = (fp) ? ((PX2BLOCK)fp)->Cd2 : NULL;
|
||||
} // end of LIBXMLDOC constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Initialize XML parser and check library compatibility. */
|
||||
/******************************************************************/
|
||||
bool LIBXMLDOC::Initialize(PGLOBAL g)
|
||||
{
|
||||
//int n = xmlKeepBlanksDefault(0);
|
||||
Cd = iconv_open("ISO-8859-1", "UTF-8");
|
||||
Cd2 = iconv_open("UTF-8", "ISO-8859-1");
|
||||
return MakeNSlist(g);
|
||||
} // end of Initialize
|
||||
|
||||
/******************************************************************/
|
||||
/* Parse the XML file and construct node tree in memory. */
|
||||
/******************************************************************/
|
||||
bool LIBXMLDOC::ParseFile(char *fn)
|
||||
{
|
||||
if ((Docp = xmlParseFile(fn))) {
|
||||
if (Docp->encoding)
|
||||
Encoding = (char*)Docp->encoding;
|
||||
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
|
||||
} // end of ParseFile
|
||||
|
||||
/******************************************************************/
|
||||
/* Create or reuse an Xblock for this document. */
|
||||
/******************************************************************/
|
||||
PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
|
||||
{
|
||||
PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
|
||||
PX2BLOCK xp = (PX2BLOCK)PlugSubAlloc(g, NULL, sizeof(X2BLOCK));
|
||||
|
||||
memset(xp, 0, sizeof(X2BLOCK));
|
||||
xp->Next = (PX2BLOCK)dup->Openlist;
|
||||
dup->Openlist = (PFBLOCK)xp;
|
||||
xp->Type = TYPE_FB_XML2;
|
||||
xp->Fname = (LPCSTR)PlugSubAlloc(g, NULL, strlen(fn) + 1);
|
||||
strcpy((char*)xp->Fname, fn);
|
||||
xp->Count = 1;
|
||||
xp->Length = (m == MODE_READ) ? 1 : 0;
|
||||
xp->Retcode = rc;
|
||||
xp->Docp = Docp;
|
||||
// xp->Ctxp = Ctxp;
|
||||
// xp->Xop = Xop;
|
||||
xp->Cd = Cd;
|
||||
xp->Cd2 = Cd2; // Temporary
|
||||
|
||||
// Return xp as a fp
|
||||
return (PFBLOCK)xp;
|
||||
} // end of LinkXblock
|
||||
|
||||
/******************************************************************/
|
||||
/* Construct and add the XML processing instruction node. */
|
||||
/******************************************************************/
|
||||
bool LIBXMLDOC::NewDoc(PGLOBAL g, char *ver)
|
||||
{
|
||||
return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL);
|
||||
} // end of NewDoc
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a new comment node to the document. */
|
||||
/******************************************************************/
|
||||
void LIBXMLDOC::AddComment(PGLOBAL g, char *txtp)
|
||||
{
|
||||
xmlNodePtr cp = xmlNewDocComment(Docp, BAD_CAST txtp);
|
||||
xmlAddChild((xmlNodePtr)Docp, cp);
|
||||
} // end of AddText
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node class of the root of the document. */
|
||||
/******************************************************************/
|
||||
PXNODE LIBXMLDOC::GetRoot(PGLOBAL g)
|
||||
{
|
||||
xmlNodePtr root = xmlDocGetRootElement(Docp);
|
||||
|
||||
if (!root)
|
||||
return NULL;
|
||||
|
||||
return new(g) XML2NODE(this, root);
|
||||
} // end of GetRoot
|
||||
|
||||
/******************************************************************/
|
||||
/* Create a new root element and return its class node. */
|
||||
/******************************************************************/
|
||||
PXNODE LIBXMLDOC::NewRoot(PGLOBAL g, char *name)
|
||||
{
|
||||
xmlNodePtr root = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL);
|
||||
|
||||
if (root) {
|
||||
xmlDocSetRootElement(Docp, root);
|
||||
return new(g) XML2NODE(this, root);
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of NewRoot
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a void XML2NODE node class. */
|
||||
/******************************************************************/
|
||||
PXNODE LIBXMLDOC::NewPnode(PGLOBAL g, char *name)
|
||||
{
|
||||
xmlNodePtr nop;
|
||||
|
||||
if (name) {
|
||||
nop = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL);
|
||||
|
||||
if (nop == NULL)
|
||||
return NULL;
|
||||
|
||||
} else
|
||||
nop = NULL;
|
||||
|
||||
return new(g) XML2NODE(this, nop);
|
||||
} // end of NewPnode
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a void XML2ATTR node class. */
|
||||
/******************************************************************/
|
||||
PXATTR LIBXMLDOC::NewPattr(PGLOBAL g)
|
||||
{
|
||||
return new(g) XML2ATTR(this, NULL, NULL);
|
||||
} // end of NewPattr
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a void XML2ATTR node class. */
|
||||
/******************************************************************/
|
||||
PXLIST LIBXMLDOC::NewPlist(PGLOBAL g)
|
||||
{
|
||||
return new(g) XML2NODELIST(this, NULL);
|
||||
} // end of NewPlist
|
||||
|
||||
/******************************************************************/
|
||||
/* Dump the node tree to a new XML file. */
|
||||
/******************************************************************/
|
||||
int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn)
|
||||
{
|
||||
int rc;
|
||||
FILE *of;
|
||||
|
||||
if (!(of = fopen(ofn, "w")))
|
||||
return -1;
|
||||
|
||||
#if 1
|
||||
// This function does not crash (
|
||||
rc = xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0);
|
||||
// rc = xmlDocDump(of, Docp);
|
||||
#else // 0
|
||||
// Until this function is fixed, do the job ourself
|
||||
xmlNodePtr Rootp;
|
||||
|
||||
// Save the modified document
|
||||
fprintf(of, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", Encoding);
|
||||
fprintf(of, "<!-- Created by CONNECT %s -->\n", version);
|
||||
|
||||
if (!(Rootp = xmlDocGetRootElement(Docp)))
|
||||
return 1;
|
||||
|
||||
Buf = (char*)PlugSubAlloc(g, NULL, 1024);
|
||||
rc = iconv_close(Cd2);
|
||||
Cd2 = iconv_open(Encoding, "UTF-8");
|
||||
rc = CheckDocument(of, Rootp);
|
||||
#endif // 0
|
||||
|
||||
fclose(of);
|
||||
return rc;
|
||||
} // end of Dump
|
||||
|
||||
/******************************************************************/
|
||||
/* Free the document, cleanup the XML library, and */
|
||||
/* debug memory for regression tests. */
|
||||
/******************************************************************/
|
||||
void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
|
||||
{
|
||||
if (xp && xp->Count == 1) {
|
||||
if (Xop)
|
||||
xmlXPathFreeObject(Xop);
|
||||
|
||||
if (Ctxp)
|
||||
xmlXPathFreeContext(Ctxp);
|
||||
|
||||
} // endif Count
|
||||
|
||||
CloseXML2File(g, xp, false);
|
||||
} // end of Close
|
||||
|
||||
/******************************************************************/
|
||||
/* Evaluate the passed Xpath from the passed context node. */
|
||||
/******************************************************************/
|
||||
xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp)
|
||||
{
|
||||
xmlNodeSetPtr nl;
|
||||
|
||||
if (trace)
|
||||
htrc("GetNodeList %s np=%p\n", xp, np);
|
||||
|
||||
if (!Ctxp) {
|
||||
// Init Xpath
|
||||
xmlXPathInit();
|
||||
|
||||
// Create xpath evaluation context
|
||||
if (!(Ctxp = xmlXPathNewContext(Docp))) {
|
||||
strcpy(g->Message, MSG(XPATH_CNTX_ERR));
|
||||
|
||||
if (trace)
|
||||
htrc("Context error: %s\n", g->Message);
|
||||
|
||||
return NULL;
|
||||
} // endif xpathCtx
|
||||
|
||||
// Register namespaces from list (if any)
|
||||
for (PNS nsp = Namespaces; nsp; nsp = nsp->Next)
|
||||
if (xmlXPathRegisterNs(Ctxp, BAD_CAST nsp->Prefix,
|
||||
BAD_CAST nsp->Uri)) {
|
||||
sprintf(g->Message, MSG(REGISTER_ERR), nsp->Prefix, nsp->Uri);
|
||||
|
||||
if (trace)
|
||||
htrc("Ns error: %s\n", g->Message);
|
||||
|
||||
return NULL;
|
||||
} // endif Registering
|
||||
|
||||
} else
|
||||
xmlXPathFreeNodeSetList(Xop); // To be checked
|
||||
|
||||
// Set the context to the calling node
|
||||
Ctxp->node = np;
|
||||
|
||||
// Evaluate table xpath
|
||||
if (!(Xop = xmlXPathEval(BAD_CAST xp, Ctxp))) {
|
||||
sprintf(g->Message, MSG(XPATH_EVAL_ERR), xp);
|
||||
|
||||
if (trace)
|
||||
htrc("Path error: %s\n", g->Message);
|
||||
|
||||
return NULL;
|
||||
} else
|
||||
nl = Xop->nodesetval;
|
||||
|
||||
if (trace)
|
||||
htrc("GetNodeList nl=%p n=%p\n", nl, (nl) ? nl->nodeNr : 0);
|
||||
|
||||
return nl;
|
||||
} // end of GetNodeList
|
||||
|
||||
/******************************************************************/
|
||||
/* CheckDocument: check if the document is ok to dump. */
|
||||
/* Currently this does the dumping of the document. */
|
||||
/******************************************************************/
|
||||
bool LIBXMLDOC::CheckDocument(FILE *of, xmlNodePtr np)
|
||||
{
|
||||
int n;
|
||||
bool b;
|
||||
|
||||
if (!np)
|
||||
return true;
|
||||
|
||||
if (np->type == XML_ELEMENT_NODE) {
|
||||
n = fprintf(of, "<%s", np->name);
|
||||
b = CheckDocument(of, (xmlNodePtr)np->properties);
|
||||
|
||||
if (np->children)
|
||||
n = fprintf(of, ">");
|
||||
else
|
||||
n = fprintf(of, "/>");
|
||||
|
||||
} else if (np->type == XML_ATTRIBUTE_NODE)
|
||||
n = fprintf(of, " %s=\"", np->name);
|
||||
else if (np->type == XML_TEXT_NODE)
|
||||
n = fprintf(of, "%s", Encode(NULL, (char*)np->content));
|
||||
else if (np->type == XML_COMMENT_NODE)
|
||||
n = fprintf(of, "%s", Encode(NULL, (char*)np->content));
|
||||
|
||||
b = CheckDocument(of, np->children);
|
||||
|
||||
if (np->type == XML_ATTRIBUTE_NODE)
|
||||
n = fprintf(of, "\"");
|
||||
else if (!b && np->type == XML_ELEMENT_NODE)
|
||||
n = fprintf(of, "</%s>", np->name);
|
||||
|
||||
b = CheckDocument(of, np->next);
|
||||
return false;
|
||||
} // end of CheckDocument
|
||||
|
||||
/******************************************************************/
|
||||
/* Convert node or attribute content to latin characters. */
|
||||
/******************************************************************/
|
||||
int LIBXMLDOC::Decode(xmlChar *cnt, char *buf, int n)
|
||||
{
|
||||
#if defined(WIN32) || defined(AIX)
|
||||
const char *inp = (const char *)cnt;
|
||||
#else
|
||||
char *inp = (char *)cnt;
|
||||
#endif
|
||||
char *outp = buf;
|
||||
size_t i = strlen(inp), o = n;
|
||||
|
||||
int rc = iconv(Cd, &inp, &i, &outp, &o);
|
||||
buf[n - o] = '\0';
|
||||
return rc;
|
||||
} // end of Decode
|
||||
|
||||
/******************************************************************/
|
||||
/* Convert node or attribute content to latin characters. */
|
||||
/******************************************************************/
|
||||
xmlChar *LIBXMLDOC::Encode(PGLOBAL g, char *txt)
|
||||
{
|
||||
#if defined(WIN32) || defined(AIX)
|
||||
const char *inp = (const char *)txt;
|
||||
#else
|
||||
char *inp = (char *)txt;
|
||||
#endif
|
||||
int rc;
|
||||
size_t i = strlen(inp);
|
||||
size_t n, o = 2*i + 1;
|
||||
char *outp, *buf;
|
||||
|
||||
if (g) {
|
||||
n = o;
|
||||
buf = (char*)PlugSubAlloc(g, NULL, n);
|
||||
} else {
|
||||
n = o = 1024;
|
||||
buf = Buf;
|
||||
} // endif g
|
||||
|
||||
outp = buf;
|
||||
rc = iconv(Cd2, &inp, &i, &outp, &o);
|
||||
buf[n - o] = '\0';
|
||||
return BAD_CAST buf;
|
||||
} // end of Encode
|
||||
|
||||
/* ---------------------- class XML2NODE ------------------------ */
|
||||
|
||||
/******************************************************************/
|
||||
/* XML2NODE constructor. */
|
||||
/******************************************************************/
|
||||
XML2NODE::XML2NODE(PXDOC dp, xmlNodePtr np) : XMLNODE(dp)
|
||||
{
|
||||
Docp = ((PXDOC2)dp)->Docp;
|
||||
Content = NULL;
|
||||
Nodep = np;
|
||||
} // end of XML2NODE constructor
|
||||
|
||||
int XML2NODE::GetType(void)
|
||||
{
|
||||
if (trace)
|
||||
htrc("GetType type=%d\n", Nodep->type);
|
||||
|
||||
return Nodep->type;
|
||||
} // end of GetType
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node class of next sibling of the node. */
|
||||
/******************************************************************/
|
||||
PXNODE XML2NODE::GetNext(PGLOBAL g)
|
||||
{
|
||||
if (!Nodep->next)
|
||||
Next = NULL;
|
||||
else if (!Next)
|
||||
Next = new(g) XML2NODE(Doc, Nodep->next);
|
||||
|
||||
return Next;
|
||||
} // end of GetNext
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node class of first children of the node. */
|
||||
/******************************************************************/
|
||||
PXNODE XML2NODE::GetChild(PGLOBAL g)
|
||||
{
|
||||
if (!Nodep->children)
|
||||
Children = NULL;
|
||||
else if (!Children)
|
||||
Children = new(g) XML2NODE(Doc, Nodep->children);
|
||||
|
||||
return Children;
|
||||
} // end of GetChild
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the content of a node and subnodes. */
|
||||
/******************************************************************/
|
||||
char *XML2NODE::GetText(char *buf, int len)
|
||||
{
|
||||
if (Content)
|
||||
xmlFree(Content);
|
||||
|
||||
if ((Content = xmlNodeGetContent(Nodep))) {
|
||||
int rc = ((PXDOC2)Doc)->Decode(Content, buf, len);
|
||||
|
||||
if (trace)
|
||||
htrc("GetText buf='%s' len=%d rc=%d\n", buf, len, rc);
|
||||
|
||||
xmlFree(Content);
|
||||
Content = NULL;
|
||||
} else
|
||||
*buf = '\0';
|
||||
|
||||
return buf;
|
||||
} // end of GetText
|
||||
|
||||
/******************************************************************/
|
||||
/* Set the content of a node. */
|
||||
/******************************************************************/
|
||||
bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len)
|
||||
{
|
||||
if (trace)
|
||||
htrc("SetContent %s\n", txtp);
|
||||
|
||||
xmlNodeSetContent(Nodep, ((PXDOC2)Doc)->Encode(g, txtp));
|
||||
return false;
|
||||
} // end of SetContent
|
||||
|
||||
/******************************************************************/
|
||||
/* Return a clone of this node. */
|
||||
/******************************************************************/
|
||||
PXNODE XML2NODE::Clone(PGLOBAL g, PXNODE np)
|
||||
{
|
||||
if (np) {
|
||||
((PNODE2)np)->Nodep = Nodep;
|
||||
return np;
|
||||
} else
|
||||
return new(g) XML2NODE(Doc, Nodep);
|
||||
|
||||
} // end of Clone
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the list of all or matching children that are elements.*/
|
||||
/******************************************************************/
|
||||
PXLIST XML2NODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp)
|
||||
{
|
||||
if (trace)
|
||||
htrc("GetChildElements %s\n", xp);
|
||||
|
||||
return SelectNodes(g, (xp) ? xp : (char*)"*", lp);
|
||||
} // end of GetChildElements
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the list of nodes verifying the passed Xpath. */
|
||||
/******************************************************************/
|
||||
PXLIST XML2NODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp)
|
||||
{
|
||||
if (trace)
|
||||
htrc("SelectNodes %s\n", xp);
|
||||
|
||||
xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp);
|
||||
|
||||
if (lp) {
|
||||
((PLIST2)lp)->Listp = nl;
|
||||
return lp;
|
||||
} else
|
||||
return new(g) XML2NODELIST(Doc, nl);
|
||||
|
||||
} // end of SelectNodes
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the first node verifying the passed Xapth. */
|
||||
/******************************************************************/
|
||||
PXNODE XML2NODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np)
|
||||
{
|
||||
if (trace)
|
||||
htrc("SelectSingleNode %s\n", xp);
|
||||
|
||||
xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp);
|
||||
|
||||
if (nl && nl->nodeNr) {
|
||||
if (np) {
|
||||
((PNODE2)np)->Nodep = nl->nodeTab[0];
|
||||
return np;
|
||||
} else
|
||||
return new(g) XML2NODE(Doc, nl->nodeTab[0]);
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of SelectSingleNode
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the node attribute with the specified name. */
|
||||
/******************************************************************/
|
||||
PXATTR XML2NODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap)
|
||||
{
|
||||
if (trace)
|
||||
htrc("GetAttribute %s\n", name);
|
||||
|
||||
xmlAttrPtr atp = xmlHasProp(Nodep, BAD_CAST name);
|
||||
|
||||
if (atp) {
|
||||
if (ap) {
|
||||
((PATTR2)ap)->Atrp = atp;
|
||||
((PATTR2)ap)->Parent = Nodep;
|
||||
return ap;
|
||||
} else
|
||||
return new(g) XML2ATTR(Doc, atp, Nodep);
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of GetAttribute
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a new child node to this node and return it. */
|
||||
/******************************************************************/
|
||||
PXNODE XML2NODE::AddChildNode(PGLOBAL g, char *name, PXNODE np)
|
||||
{
|
||||
char *p, *pn, *pf = NULL;
|
||||
|
||||
if (trace)
|
||||
htrc("AddChildNode %s\n", name);
|
||||
|
||||
// Is a prefix specified
|
||||
if ((pn = strchr(name, ':'))) {
|
||||
pf = name;
|
||||
*pn++ = '\0'; // Separate name from prefix
|
||||
} else
|
||||
pn = name;
|
||||
|
||||
// If name has the format m[n] only m is taken as node name
|
||||
if ((p = strchr(pn, '[')))
|
||||
p = BufAlloc(g, pn, p - pn);
|
||||
else
|
||||
p = pn;
|
||||
|
||||
xmlNodePtr nop = xmlNewChild(Nodep, NULL, BAD_CAST p, NULL);
|
||||
|
||||
if (!nop)
|
||||
return NULL;
|
||||
|
||||
if (pf) {
|
||||
// Prefixed name, is it the default NS prefix?
|
||||
if (Doc->DefNs && !strcmp(pf, Doc->DefNs))
|
||||
pf = NULL; // Default namespace
|
||||
|
||||
xmlNsPtr nsp = xmlSearchNs(Docp, nop, BAD_CAST pf);
|
||||
|
||||
if (!nsp)
|
||||
nsp = xmlNewNs(nop, NULL, BAD_CAST pf);
|
||||
|
||||
// Set node namespace
|
||||
nop->ns = nsp;
|
||||
*(--p) = ':'; // Restore Xname
|
||||
} else if (Doc->DefNs && xmlSearchNs(Docp, nop, NULL))
|
||||
// Not in default namespace
|
||||
nop->ns = xmlNewNs(nop, BAD_CAST "", NULL);
|
||||
|
||||
if (np)
|
||||
((PNODE2)np)->Nodep = nop;
|
||||
else
|
||||
np = new(g) XML2NODE(Doc, nop);
|
||||
|
||||
return NewChild(np);
|
||||
} // end of AddChildNode
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a new property to this node and return it. */
|
||||
/******************************************************************/
|
||||
PXATTR XML2NODE::AddProperty(PGLOBAL g, char *name, PXATTR ap)
|
||||
{
|
||||
if (trace)
|
||||
htrc("AddProperty %s\n", name);
|
||||
|
||||
xmlAttrPtr atp = xmlNewProp(Nodep, BAD_CAST name, NULL);
|
||||
|
||||
if (atp) {
|
||||
if (ap) {
|
||||
((PATTR2)ap)->Atrp = atp;
|
||||
((PATTR2)ap)->Parent = Nodep;
|
||||
return ap;
|
||||
} else
|
||||
return new(g) XML2ATTR(Doc, atp, Nodep);
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of AddProperty
|
||||
|
||||
/******************************************************************/
|
||||
/* Add a new text node to this node. */
|
||||
/******************************************************************/
|
||||
void XML2NODE::AddText(PGLOBAL g, char *txtp)
|
||||
{
|
||||
if (trace)
|
||||
htrc("AddText %s\n", txtp);
|
||||
|
||||
// This is to avoid a blank line when inserting a new line
|
||||
xmlNodePtr np = xmlGetLastChild(Nodep);
|
||||
|
||||
if (np && np->type == XML_TEXT_NODE) {
|
||||
xmlUnlinkNode(np);
|
||||
xmlFreeNode(np);
|
||||
} // endif type
|
||||
|
||||
// Add the new text
|
||||
xmlAddChild(Nodep, xmlNewText(BAD_CAST txtp));
|
||||
} // end of AddText
|
||||
|
||||
/******************************************************************/
|
||||
/* Remove a child node from this node. */
|
||||
/******************************************************************/
|
||||
void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp)
|
||||
{
|
||||
xmlNodePtr np = ((PNODE2)dnp)->Nodep;
|
||||
xmlNodePtr text = np->next;
|
||||
|
||||
// This is specific to row nodes
|
||||
if (text && text->type == XML_TEXT_NODE) {
|
||||
xmlUnlinkNode(text);
|
||||
xmlFreeNode(text);
|
||||
} // endif type
|
||||
|
||||
xmlUnlinkNode(np);
|
||||
xmlFreeNode(np);
|
||||
Delete(dnp);
|
||||
} // end of DeleteChild
|
||||
|
||||
/* -------------------- class XML2NODELIST ---------------------- */
|
||||
|
||||
/******************************************************************/
|
||||
/* XML2NODELIST constructor. */
|
||||
/******************************************************************/
|
||||
XML2NODELIST::XML2NODELIST(PXDOC dp, xmlNodeSetPtr lp)
|
||||
: XMLNODELIST(dp)
|
||||
{
|
||||
Listp = lp;
|
||||
} // end of XML2NODELIST constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the length of the list. */
|
||||
/******************************************************************/
|
||||
int XML2NODELIST::GetLength(void)
|
||||
{
|
||||
return (Listp) ? Listp->nodeNr : 0;
|
||||
} // end of GetLength
|
||||
|
||||
/******************************************************************/
|
||||
/* Return the nth element of the list. */
|
||||
/******************************************************************/
|
||||
PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
|
||||
{
|
||||
if (trace)
|
||||
htrc("GetItem %d\n", n);
|
||||
|
||||
if (!Listp || Listp->nodeNr <= n)
|
||||
return NULL;
|
||||
|
||||
if (np) {
|
||||
((PNODE2)np)->Nodep = Listp->nodeTab[n];
|
||||
return np;
|
||||
} else
|
||||
return new(g) XML2NODE(Doc, Listp->nodeTab[n]);
|
||||
|
||||
} // end of GetItem
|
||||
|
||||
/* ---------------------- class XML2ATTR ------------------------ */
|
||||
|
||||
/******************************************************************/
|
||||
/* XML2ATTR constructor. */
|
||||
/******************************************************************/
|
||||
XML2ATTR::XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np)
|
||||
: XMLATTRIBUTE(dp)
|
||||
{
|
||||
Atrp = ap;
|
||||
Parent = np;
|
||||
} // end of XML2ATTR constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Set the content of an attribute. */
|
||||
/******************************************************************/
|
||||
bool XML2ATTR::SetText(PGLOBAL g, char *txtp, int len)
|
||||
{
|
||||
if (trace)
|
||||
htrc("SetText %s\n", txtp);
|
||||
|
||||
xmlSetProp(Parent, Atrp->name, ((PXDOC2)Doc)->Encode(g, txtp));
|
||||
return false;
|
||||
} // end of SetText
|
||||
148
storage/connect/libdoc.h
Normal file
148
storage/connect/libdoc.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/******************************************************************/
|
||||
/* Declaration of XML document processing using libxml2 */
|
||||
/* Author: Olivier Bertrand 2007-2012 */
|
||||
/******************************************************************/
|
||||
#include "plgxml.h"
|
||||
|
||||
typedef class LIBXMLDOC *PXDOC2;
|
||||
typedef class XML2NODE *PNODE2;
|
||||
typedef class XML2ATTR *PATTR2;
|
||||
typedef class XML2NODELIST *PLIST2;
|
||||
|
||||
/******************************************************************/
|
||||
/* XML2 block. Must have the same layout than FBLOCK up to Type. */
|
||||
/******************************************************************/
|
||||
typedef struct _x2block { /* Loaded XML file block */
|
||||
struct _x2block *Next;
|
||||
LPCSTR Fname; /* Point on file name */
|
||||
size_t Length; /* Used to tell if read mode */
|
||||
short Count; /* Nb of times file is used */
|
||||
short Type; /* TYPE_FB_XML */
|
||||
int Retcode; /* Return code from Load */
|
||||
xmlDocPtr Docp; /* Document interface pointer */
|
||||
// xmlXPathContextPtr Ctxp;
|
||||
// xmlXPathObjectPtr Xop;
|
||||
iconv_t Cd;
|
||||
iconv_t Cd2;
|
||||
} X2BLOCK, *PX2BLOCK;
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of libxml2 document. */
|
||||
/******************************************************************/
|
||||
class LIBXMLDOC : public XMLDOCUMENT {
|
||||
friend class XML2NODE;
|
||||
friend class XML2ATTR;
|
||||
public:
|
||||
// Constructor
|
||||
LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp);
|
||||
|
||||
// Properties
|
||||
virtual short GetDocType(void) {return TYPE_FB_XML2;}
|
||||
virtual void *GetDocPtr(void) {return Docp;}
|
||||
|
||||
// Methods
|
||||
virtual bool Initialize(PGLOBAL g);
|
||||
virtual bool ParseFile(char *fn);
|
||||
virtual bool NewDoc(PGLOBAL g, char *ver);
|
||||
virtual void AddComment(PGLOBAL g, char *com);
|
||||
virtual PXNODE GetRoot(PGLOBAL g);
|
||||
virtual PXNODE NewRoot(PGLOBAL g, char *name);
|
||||
virtual PXNODE NewPnode(PGLOBAL g, char *name);
|
||||
virtual PXATTR NewPattr(PGLOBAL g);
|
||||
virtual PXLIST NewPlist(PGLOBAL g);
|
||||
virtual int DumpDoc(PGLOBAL g, char *ofn);
|
||||
virtual void CloseDoc(PGLOBAL g, PFBLOCK xp);
|
||||
virtual PFBLOCK LinkXblock(PGLOBAL g, MODE m, int rc, char *fn);
|
||||
|
||||
protected:
|
||||
bool CheckDocument(FILE *of, xmlNodePtr np);
|
||||
xmlNodeSetPtr GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp);
|
||||
int Decode(xmlChar *cnt, char *buf, int n);
|
||||
xmlChar *Encode(PGLOBAL g, char *txt);
|
||||
|
||||
// Members
|
||||
xmlDocPtr Docp;
|
||||
xmlNodeSetPtr Nlist;
|
||||
xmlXPathContextPtr Ctxp;
|
||||
xmlXPathObjectPtr Xop;
|
||||
iconv_t Cd;
|
||||
iconv_t Cd2; // Temporary
|
||||
char *Buf; // Temporary
|
||||
}; // end of class LIBXMLDOC
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of libxml2 node. */
|
||||
/******************************************************************/
|
||||
class XML2NODE : public XMLNODE {
|
||||
friend class LIBXMLDOC;
|
||||
friend class XML2NODELIST;
|
||||
public:
|
||||
// Properties
|
||||
virtual char *GetName(PGLOBAL g) {return (char*)Nodep->name;}
|
||||
virtual int GetType(void);
|
||||
virtual PXNODE GetNext(PGLOBAL g);
|
||||
virtual PXNODE GetChild(PGLOBAL g);
|
||||
|
||||
// Methods
|
||||
virtual char *GetText(char *buf, int len);
|
||||
virtual bool SetContent(PGLOBAL g, char *txtp, int len);
|
||||
virtual PXNODE Clone(PGLOBAL g, PXNODE np);
|
||||
virtual PXLIST GetChildElements(PGLOBAL g, char *xp, PXLIST lp);
|
||||
virtual PXLIST SelectNodes(PGLOBAL g, char *xp, PXLIST lp);
|
||||
virtual PXNODE SelectSingleNode(PGLOBAL g, char *xp, PXNODE np);
|
||||
virtual PXATTR GetAttribute(PGLOBAL g, char *name, PXATTR ap);
|
||||
virtual PXNODE AddChildNode(PGLOBAL g, char *name, PXNODE np);
|
||||
virtual PXATTR AddProperty(PGLOBAL g, char *name, PXATTR ap);
|
||||
virtual void AddText(PGLOBAL g, char *txtp);
|
||||
virtual void DeleteChild(PGLOBAL g, PXNODE dnp);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
XML2NODE(PXDOC dp, xmlNodePtr np);
|
||||
|
||||
// Members
|
||||
xmlDocPtr Docp;
|
||||
xmlChar *Content;
|
||||
xmlNodePtr Nodep;
|
||||
}; // end of class XML2NODE
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of libxml2 node list. */
|
||||
/******************************************************************/
|
||||
class XML2NODELIST : public XMLNODELIST {
|
||||
friend class LIBXMLDOC;
|
||||
friend class XML2NODE;
|
||||
public:
|
||||
// Methods
|
||||
virtual int GetLength(void);
|
||||
virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
XML2NODELIST(PXDOC dp, xmlNodeSetPtr lp);
|
||||
|
||||
// Members
|
||||
xmlNodeSetPtr Listp;
|
||||
}; // end of class XML2NODELIST
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of libxml2 attribute. */
|
||||
/******************************************************************/
|
||||
class XML2ATTR : public XMLATTRIBUTE {
|
||||
friend class LIBXMLDOC;
|
||||
friend class XML2NODE;
|
||||
public:
|
||||
// Properties
|
||||
//virtual char *GetText(void);
|
||||
|
||||
// Methods
|
||||
virtual bool SetText(PGLOBAL g, char *txtp, int len);
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np);
|
||||
|
||||
// Members
|
||||
xmlAttrPtr Atrp;
|
||||
xmlNodePtr Parent;
|
||||
}; // end of class XML2ATTR
|
||||
318
storage/connect/macutil.cpp
Normal file
318
storage/connect/macutil.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/***********************************************************************/
|
||||
/* MACUTIL: Author Olivier Bertrand -- 2008-2012 */
|
||||
/* From the article and sample code by Khalid Shaikh. */
|
||||
/***********************************************************************/
|
||||
#if defined(WIN32)
|
||||
#include "my_global.h"
|
||||
#else // !WIN32
|
||||
#error This is WIN32 only DLL
|
||||
#endif // !WIN32
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "macutil.h"
|
||||
|
||||
#if 0 // This is placed here just to know what are the actual values
|
||||
#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
|
||||
#define MAX_ADAPTER_NAME_LENGTH 256
|
||||
#define MAX_ADAPTER_ADDRESS_LENGTH 8
|
||||
#define DEFAULT_MINIMUM_ENTITIES 32
|
||||
#define MAX_HOSTNAME_LEN 128
|
||||
#define MAX_DOMAIN_NAME_LEN 128
|
||||
#define MAX_SCOPE_ID_LEN 256
|
||||
|
||||
#define BROADCAST_NODETYPE 1
|
||||
#define PEER_TO_PEER_NODETYPE 2
|
||||
#define MIXED_NODETYPE 4
|
||||
#define HYBRID_NODETYPE 8
|
||||
|
||||
#define IP_ADAPTER_DDNS_ENABLED 0x01
|
||||
#define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02
|
||||
#define IP_ADAPTER_DHCP_ENABLED 0x04
|
||||
#define IP_ADAPTER_RECEIVE_ONLY 0x08
|
||||
#define IP_ADAPTER_NO_MULTICAST 0x10
|
||||
#define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
|
||||
#endif // 0
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the MACINFO class. */
|
||||
/***********************************************************************/
|
||||
MACINFO::MACINFO(bool adap, bool fix)
|
||||
{
|
||||
Fip = NULL;
|
||||
Piaf = NULL;
|
||||
Curp = NULL;
|
||||
Buflen = 0;
|
||||
Fix = fix;
|
||||
Adap = adap;
|
||||
N = -1;
|
||||
} // end of MACINFO constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* MACINFO: Return an error message. */
|
||||
/***********************************************************************/
|
||||
void MACINFO::MakeErrorMsg(PGLOBAL g, DWORD drc)
|
||||
{
|
||||
if (drc == ERROR_BUFFER_OVERFLOW)
|
||||
sprintf(g->Message,
|
||||
"GetAdaptersInfo: Buffer Overflow buflen=%d nbofadap=%d",
|
||||
Buflen, N);
|
||||
else if (drc == ERROR_INVALID_PARAMETER)
|
||||
strcpy(g->Message, "GetAdaptersInfo: Invalid parameters");
|
||||
else if (drc == ERROR_NO_DATA)
|
||||
strcpy(g->Message,
|
||||
"No adapter information exists for the local computer");
|
||||
else if (drc == ERROR_NOT_SUPPORTED)
|
||||
strcpy(g->Message, "GetAdaptersInfo is not supported");
|
||||
else
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
|
||||
0, g->Message, sizeof(g->Message), NULL);
|
||||
|
||||
} // end of MakeErrorMsg
|
||||
|
||||
/***********************************************************************/
|
||||
/* MAC: Get the number of found adapters. */
|
||||
/***********************************************************************/
|
||||
int MACINFO::GetNadap(PGLOBAL g)
|
||||
{
|
||||
if (N < 0) {
|
||||
// Best method
|
||||
if (Adap) {
|
||||
DWORD drc = GetAdaptersInfo(NULL, &Buflen);
|
||||
|
||||
if (drc == ERROR_SUCCESS)
|
||||
N = (Fix) ? 1 : 0;
|
||||
else if (drc == ERROR_BUFFER_OVERFLOW)
|
||||
N = Buflen / sizeof(IP_ADAPTER_INFO);
|
||||
else
|
||||
MakeErrorMsg(g, drc);
|
||||
|
||||
} else
|
||||
N = (Fix) ? 1 : 0;
|
||||
|
||||
#if 0
|
||||
// This method returns too many adapters
|
||||
DWORD dw, drc = GetNumberOfInterfaces((PDWORD)&dw);
|
||||
|
||||
if (drc == NO_ERROR) {
|
||||
N = (int)dw;
|
||||
Buflen = N * sizeof(IP_ADAPTER_INFO);
|
||||
} else
|
||||
MakeErrorMsg(g, 0);
|
||||
#endif
|
||||
} // endif MaxSize
|
||||
|
||||
return N;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetMacInfo: Get info for all found adapters. */
|
||||
/***********************************************************************/
|
||||
bool MACINFO::GetMacInfo(PGLOBAL g)
|
||||
{
|
||||
DWORD drc;
|
||||
|
||||
if (GetNadap(g) < 0)
|
||||
return true;
|
||||
else if (N == 0)
|
||||
return false;
|
||||
|
||||
Piaf = (PIP_ADAPTER_INFO)PlugSubAlloc(g, NULL, Buflen);
|
||||
drc = GetAdaptersInfo(Piaf, &Buflen);
|
||||
|
||||
if (drc == ERROR_SUCCESS) {
|
||||
Curp = Piaf; // Curp is the first one
|
||||
return false; // Success
|
||||
} // endif drc
|
||||
|
||||
MakeErrorMsg(g, drc);
|
||||
return true;
|
||||
} // end of GetMacInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetMacInfo: Get info for all found adapters. */
|
||||
/***********************************************************************/
|
||||
bool MACINFO::GetFixedInfo(PGLOBAL g)
|
||||
{
|
||||
ULONG len = (uint)sizeof(FIXED_INFO);
|
||||
DWORD drc;
|
||||
|
||||
Fip = (FIXED_INFO*)PlugSubAlloc(g, NULL, len);
|
||||
drc = GetNetworkParams(Fip, &len);
|
||||
|
||||
if (drc == ERROR_BUFFER_OVERFLOW) {
|
||||
Fip = (FIXED_INFO*)PlugSubAlloc(g, NULL, len);
|
||||
drc = GetNetworkParams(Fip, &len);
|
||||
} // endif drc
|
||||
|
||||
if (drc != ERROR_SUCCESS) {
|
||||
sprintf(g->Message, "GetNetworkParams failed. Rc=%08x\n", drc);
|
||||
return true;
|
||||
} // endif drc
|
||||
|
||||
return false;
|
||||
} // end of GetFip
|
||||
|
||||
#if 0
|
||||
#define IF_OTHER_ADAPTERTYPE 0
|
||||
#define IF_ETHERNET_ADAPTERTYPE 1
|
||||
#define IF_TOKEN_RING_ADAPTERTYPE 2
|
||||
#define IF_FDDI_ADAPTERTYPE 3
|
||||
#define IF_PPP_ADAPTERTYPE 4
|
||||
#define IF_LOOPBACK_ADAPTERTYPE 5
|
||||
#endif // 0
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get next MAC info. */
|
||||
/***********************************************************************/
|
||||
bool MACINFO::NextMac(void)
|
||||
{
|
||||
if (Curp)
|
||||
Curp = Curp->Next;
|
||||
|
||||
return Curp != NULL;
|
||||
} // end of NextMac
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get the next MAC address elements. */
|
||||
/***********************************************************************/
|
||||
bool MACINFO::GetOneInfo(PGLOBAL g, int flag, void *v, int lv)
|
||||
{
|
||||
char *p = NULL, buf[260] = "";
|
||||
unsigned int i;
|
||||
int n = 0;
|
||||
|
||||
if (!Curp && flag >= 10) {
|
||||
// Fix info row, no adapter info available
|
||||
switch (flag) {
|
||||
case 13:
|
||||
case 14:
|
||||
case 19:
|
||||
case 22:
|
||||
case 23:
|
||||
break;
|
||||
default:
|
||||
p = "";
|
||||
} // endswitch flag
|
||||
|
||||
} else switch (flag) {
|
||||
// FIXED INFO
|
||||
case 1: // Host Name
|
||||
p = Fip->HostName;
|
||||
break;
|
||||
case 2: // Domain Name
|
||||
p = Fip->DomainName;
|
||||
break;
|
||||
case 3: // DNS IPaddress
|
||||
p = (Fip->CurrentDnsServer)
|
||||
? (char*)&Fip->CurrentDnsServer->IpAddress
|
||||
: (char*)&Fip->DnsServerList.IpAddress;
|
||||
break;
|
||||
case 4: // Node Type
|
||||
n = (int)Fip->NodeType;
|
||||
break;
|
||||
case 5: // Scope ID ???
|
||||
p = Fip->ScopeId;
|
||||
break;
|
||||
case 6: // Routing enabled
|
||||
n = (int)Fip->EnableRouting;
|
||||
break;
|
||||
case 7: // Proxy enabled
|
||||
n = (int)Fip->EnableProxy;
|
||||
break;
|
||||
case 8: // DNS enabled
|
||||
n = (int)Fip->EnableDns;
|
||||
break;
|
||||
// ADAPTERS INFO
|
||||
case 10: // Name
|
||||
p = Curp->AdapterName;
|
||||
break;
|
||||
case 11: // Description
|
||||
if ((p = strstr(Curp->Description, " - Packet Scheduler Miniport"))) {
|
||||
strncpy(buf, Curp->Description, p - Curp->Description);
|
||||
i = p - Curp->Description;
|
||||
strncpy(buf, Curp->Description, i);
|
||||
buf[i] = 0;
|
||||
p = buf;
|
||||
} else if ((p = strstr(Curp->Description,
|
||||
" - Miniport d'ordonnancement de paquets"))) {
|
||||
i = p - Curp->Description;
|
||||
strncpy(buf, Curp->Description, i);
|
||||
buf[i] = 0;
|
||||
p = buf;
|
||||
} else
|
||||
p = Curp->Description;
|
||||
|
||||
break;
|
||||
case 12: // MAC Address
|
||||
for (p = buf, i = 0; i < Curp->AddressLength; i++) {
|
||||
if (i)
|
||||
strcat(p++, "-");
|
||||
|
||||
p += sprintf(p, "%.2X", Curp->Address[i]);
|
||||
} // endfor i
|
||||
|
||||
p = buf;
|
||||
break;
|
||||
case 13: // Type
|
||||
#if 0 // This is not found in the SDK
|
||||
switch (Curp->Type) {
|
||||
case IF_ETHERNET_ADAPTERTYPE: p = "Ethernet Adapter"; break;
|
||||
case IF_TOKEN_RING_ADAPTERTYPE: p = "Token Ring Adapter"; break;
|
||||
case IF_FDDI_ADAPTERTYPE: p = "FDDI Adapter"; break;
|
||||
case IF_PPP_ADAPTERTYPE: p = "PPP Adapter"; break;
|
||||
case IF_LOOPBACK_ADAPTERTYPE: p = "Loop Back Adapter"; break;
|
||||
// case IF_SLIP_ADAPTERTYPE: p = "Generic Slip Adapter"; break;
|
||||
default:
|
||||
sprintf(buf, "Other Adapter, type=%d", Curp->Type);
|
||||
p = buf;
|
||||
} // endswitch Type
|
||||
#endif // 0
|
||||
n = (int)Curp->Type;
|
||||
break;
|
||||
case 14: // DHCP enabled
|
||||
n = (int)Curp->DhcpEnabled;
|
||||
break;
|
||||
case 15: // IP Address
|
||||
p = (Curp->CurrentIpAddress)
|
||||
? (char*)&Curp->CurrentIpAddress->IpAddress
|
||||
: (char*)&Curp->IpAddressList.IpAddress;
|
||||
break;
|
||||
case 16: // Subnet Mask
|
||||
p = (Curp->CurrentIpAddress)
|
||||
? (char*)&Curp->CurrentIpAddress->IpMask
|
||||
: (char*)&Curp->IpAddressList.IpMask;
|
||||
break;
|
||||
case 17: // Gateway
|
||||
p = (char*)&Curp->GatewayList.IpAddress;
|
||||
break;
|
||||
case 18: // DHCP Server
|
||||
p = (char*)&Curp->DhcpServer.IpAddress;
|
||||
break;
|
||||
case 19: // Have WINS
|
||||
n = (Curp->HaveWins) ? 1 : 0;
|
||||
break;
|
||||
case 20: // Primary WINS
|
||||
p = (char*)&Curp->PrimaryWinsServer.IpAddress;
|
||||
break;
|
||||
case 21: // Secondary WINS
|
||||
p = (char*)&Curp->SecondaryWinsServer.IpAddress;
|
||||
break;
|
||||
case 22: // Lease obtained
|
||||
n = (int)Curp->LeaseObtained;
|
||||
break;
|
||||
case 23: // Lease expires
|
||||
n = (int)Curp->LeaseExpires;
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, "Invalid flag value %d", flag);
|
||||
return true;
|
||||
} // endswitch flag
|
||||
|
||||
if (p)
|
||||
strncpy((char*)v, p, lv);
|
||||
else
|
||||
*((int*)v) = n;
|
||||
|
||||
return false;
|
||||
} // end of ReadColumn
|
||||
36
storage/connect/macutil.h
Normal file
36
storage/connect/macutil.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// MACUTIL.H Olivier Bertrand 2008-2012
|
||||
// Get Mac Addresses via GetAdaptersInfo
|
||||
#if defined(WIN32)
|
||||
#include <iphlpapi.h>
|
||||
#else // !WIN32
|
||||
#error This is WIN32 only
|
||||
#endif // !WIN32
|
||||
#include "block.h"
|
||||
|
||||
typedef class MACINFO *MACIP;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for MACINFO. */
|
||||
/***********************************************************************/
|
||||
class DllExport MACINFO : public BLOCK {
|
||||
public:
|
||||
// Constructor
|
||||
MACINFO(bool adap, bool fix);
|
||||
|
||||
// Implementation
|
||||
int GetNadap(PGLOBAL g);
|
||||
bool GetMacInfo(PGLOBAL g);
|
||||
bool GetFixedInfo(PGLOBAL g);
|
||||
void MakeErrorMsg(PGLOBAL g, DWORD drc);
|
||||
bool NextMac(void);
|
||||
bool GetOneInfo(PGLOBAL g, int flag, void *v, int lv);
|
||||
|
||||
// Members
|
||||
FIXED_INFO *Fip; // Points to fixed info structure
|
||||
PIP_ADAPTER_INFO Piaf; // Points on Adapter info array
|
||||
PIP_ADAPTER_INFO Curp; // Points on current Adapt info
|
||||
ULONG Buflen; // Buffer length
|
||||
bool Fix; // true if FixedInfo is needed
|
||||
bool Adap; // true if Piaf is needed
|
||||
int N; // Number of adapters
|
||||
}; // end of class MACINFO
|
||||
173
storage/connect/maputil.cpp
Normal file
173
storage/connect/maputil.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "my_global.h"
|
||||
#ifdef UNIX
|
||||
#include "osutil.h"
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
//typedef int HANDLE; done in os2def.h
|
||||
#else /* WINDOWS */
|
||||
//#include <windows.h>
|
||||
#include "osutil.h"
|
||||
#endif /* WINDOWS */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "maputil.h"
|
||||
|
||||
#ifdef WIN32
|
||||
/***********************************************************************/
|
||||
/* In Insert mode, just open the file for append. Otherwise */
|
||||
/* create the mapping file object. The map handle can be released */
|
||||
/* immediately because they will not be used anymore. */
|
||||
/* If del is true in DELETE mode, then delete the whole file. */
|
||||
/* Returns the file handle that can be used by caller. */
|
||||
/***********************************************************************/
|
||||
HANDLE CreateFileMap(PGLOBAL g, LPCSTR filename,
|
||||
MEMMAP *mm, MODE mode, bool del)
|
||||
{
|
||||
HANDLE hFile;
|
||||
HANDLE hFileMap;
|
||||
DWORD access, share, disposition;
|
||||
|
||||
memset(mm, 0, sizeof(MEMMAP));
|
||||
*g->Message = '\0';
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
access = GENERIC_READ;
|
||||
share = FILE_SHARE_READ;
|
||||
disposition = OPEN_EXISTING;
|
||||
break;
|
||||
case MODE_UPDATE:
|
||||
case MODE_DELETE:
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
share = 0;
|
||||
disposition = (del) ? TRUNCATE_EXISTING : OPEN_EXISTING;
|
||||
break;
|
||||
case MODE_INSERT:
|
||||
access = GENERIC_WRITE;
|
||||
share = 0;
|
||||
disposition = OPEN_ALWAYS;
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, MSG(BAD_FUNC_MODE), "CreateFileMap", mode);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
} // endswitch
|
||||
|
||||
hFile = CreateFile(filename, access, share, NULL, disposition,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
if (mode != MODE_INSERT) {
|
||||
/*****************************************************************/
|
||||
/* Create the file-mapping object. */
|
||||
/*****************************************************************/
|
||||
access = (mode == MODE_READ) ? PAGE_READONLY : PAGE_READWRITE;
|
||||
hFileMap = CreateFileMapping(hFile, NULL, access, 0, 0, NULL);
|
||||
|
||||
if (!hFileMap) {
|
||||
DWORD ler = GetLastError();
|
||||
|
||||
if (ler && ler != 1006) {
|
||||
sprintf(g->Message, MSG(FILE_MAP_ERROR), filename, ler);
|
||||
CloseHandle(hFile);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
sprintf(g->Message, MSG(FILE_IS_EMPTY), filename);
|
||||
return hFile;
|
||||
} // endif ler
|
||||
|
||||
} // endif hFileMap
|
||||
|
||||
access = (mode == MODE_READ) ? FILE_MAP_READ : FILE_MAP_WRITE;
|
||||
mm->memory = MapViewOfFile(hFileMap, access, 0, 0, 0);
|
||||
// lenH is the high-order word of the file size
|
||||
mm->lenL = GetFileSize(hFile, &mm->lenH);
|
||||
CloseHandle(hFileMap); // Not used anymore
|
||||
} else // MODE_INSERT
|
||||
/*****************************************************************/
|
||||
/* The starting point must be the end of file as for append. */
|
||||
/*****************************************************************/
|
||||
SetFilePointer(hFile, 0, NULL, FILE_END);
|
||||
|
||||
return hFile;
|
||||
} // end of CreateFileMap
|
||||
|
||||
bool CloseMemMap(LPVOID memory, size_t dwSize)
|
||||
{
|
||||
return (memory) ? !UnmapViewOfFile(memory) : false;
|
||||
} // end of CloseMemMap
|
||||
|
||||
#else /* UNIX */
|
||||
// Code to handle Linux and Solaris
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/***********************************************************************/
|
||||
/* In Insert mode, just open the file for append. Otherwise */
|
||||
/* create the mapping file object. The map handle can be released */
|
||||
/* immediately because they will not be used anymore. */
|
||||
/* If del is true in DELETE mode, then delete the whole file. */
|
||||
/* Returns the file handle that can be used by caller. */
|
||||
/***********************************************************************/
|
||||
HANDLE CreateFileMap(PGLOBAL g, LPCSTR fileName,
|
||||
MEMMAP *mm, MODE mode, bool del)
|
||||
{
|
||||
unsigned int openMode;
|
||||
HANDLE fd;
|
||||
size_t filesize;
|
||||
struct stat st;
|
||||
|
||||
memset(mm, 0, sizeof(MEMMAP));
|
||||
*g->Message = '\0';
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
openMode = O_RDONLY;
|
||||
break;
|
||||
case MODE_UPDATE:
|
||||
case MODE_DELETE:
|
||||
openMode = (del) ? (O_RDWR | O_TRUNC) : O_RDWR;
|
||||
break;
|
||||
case MODE_INSERT:
|
||||
openMode = (O_WRONLY | O_CREAT | O_APPEND);
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, MSG(BAD_FUNC_MODE), "CreateFileMap", mode);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
} // endswitch
|
||||
|
||||
// Try to open the addressed file.
|
||||
fd = open(fileName, openMode);
|
||||
|
||||
if (fd != INVALID_HANDLE_VALUE && mode != MODE_INSERT) {
|
||||
/* We must know about the size of the file. */
|
||||
if (fstat(fd, &st)) {
|
||||
sprintf(g->Message, MSG(FILE_MAP_ERROR), fileName, errno);
|
||||
close(fd);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
} // endif fstat
|
||||
|
||||
filesize = st.st_size;
|
||||
|
||||
// Now we are ready to load the file. If mmap() is available we try
|
||||
// this first. If not available or it failed we try to load it.
|
||||
mm->memory = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
mm->lenL = (mm->memory != 0) ? filesize : 0;
|
||||
mm->lenH = 0;
|
||||
} /* endif fd */
|
||||
|
||||
// mmap() call was successful. ??????????
|
||||
return fd;
|
||||
} // end of CreateFileMap
|
||||
|
||||
bool CloseMemMap(void *memory, size_t dwSize)
|
||||
{
|
||||
return (memory) ? ((munmap(memory, dwSize)) ? true : false) : false;
|
||||
} // end of CloseMemMap
|
||||
|
||||
#endif // UNIX
|
||||
22
storage/connect/maputil.h
Normal file
22
storage/connect/maputil.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef __MAPUTIL_H__
|
||||
#define __MAPUTIL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void *memory;
|
||||
DWORD lenL;
|
||||
DWORD lenH;
|
||||
} MEMMAP;
|
||||
|
||||
HANDLE CreateFileMap(PGLOBAL, LPCSTR, MEMMAP *, MODE, bool);
|
||||
bool CloseMemMap(void *memory, size_t dwSize);
|
||||
my_bool CloseFileHandle(HANDLE h);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAPUTIL_H__ */
|
||||
13
storage/connect/messages.h
Normal file
13
storage/connect/messages.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/**************************************************************************/
|
||||
/* NLS messsages definition. */
|
||||
/**************************************************************************/
|
||||
#if defined(FRENCH)
|
||||
#if defined(CPX)
|
||||
#include "frmsg1.h"
|
||||
#else /* not CPX */
|
||||
#include "frmsg2.h"
|
||||
#endif /* CPX */
|
||||
#else /* not FRENCH */
|
||||
#include "engmsg.h"
|
||||
#endif /* FRENCH */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
1013
storage/connect/msgid.h
Normal file
1013
storage/connect/msgid.h
Normal file
File diff suppressed because it is too large
Load Diff
567
storage/connect/mycat.cc
Normal file
567
storage/connect/mycat.cc
Normal file
@@ -0,0 +1,567 @@
|
||||
/* Copyright (C) Olivier Bertrand 2004 - 2012
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*************** Mycat CC Program Source Code File (.CC) ***************/
|
||||
/* PROGRAM NAME: MYCAT */
|
||||
/* ------------- */
|
||||
/* Version 1.2 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the DB description related routines. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#if defined(WIN32)
|
||||
//#include <windows.h>
|
||||
//#include <sqlext.h>
|
||||
#elif defined(UNIX)
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#define DONT_DEFINE_VOID
|
||||
//#include <mysql/plugin.h>
|
||||
#include "handler.h"
|
||||
#undef OFFSET
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files */
|
||||
/* */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing DB application declarations. */
|
||||
/* tabdos.h is header containing TDBDOS classes declarations. */
|
||||
/* MYCAT.h is header containing DB description declarations. */
|
||||
/***********************************************************************/
|
||||
#if defined(UNIX)
|
||||
#include "osutil.h"
|
||||
#endif // UNIX
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "reldef.h"
|
||||
#include "tabcol.h"
|
||||
#include "xtable.h"
|
||||
#include "filamtxt.h"
|
||||
#include "tabdos.h"
|
||||
#include "tabfmt.h"
|
||||
#include "tabvct.h"
|
||||
#include "tabsys.h"
|
||||
#if defined(WIN32)
|
||||
#include "tabmac.h"
|
||||
#include "tabwmi.h"
|
||||
#endif // WIN32
|
||||
#include "tabtbl.h"
|
||||
#if defined(XML_SUPPORT)
|
||||
#include "tabxml.h"
|
||||
#endif // XML_SUPPORT
|
||||
#include "tabmul.h"
|
||||
#if defined(MYSQL_SUPPORT)
|
||||
#include "tabmysql.h"
|
||||
#endif // MYSQL_SUPPORT
|
||||
#if defined(ODBC_SUPPORT)
|
||||
#define NODBC
|
||||
#include "tabodbc.h"
|
||||
#endif // ODBC_SUPPORT
|
||||
#if defined(PIVOT_SUPPORT)
|
||||
#include "tabpivot.h"
|
||||
#endif // PIVOT_SUPPORT
|
||||
#include "ha_connect.h"
|
||||
#include "mycat.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* General DB routines. */
|
||||
/***********************************************************************/
|
||||
//bool PlugCheckPattern(PGLOBAL, LPCSTR, LPCSTR);
|
||||
#if !defined(WIN32)
|
||||
extern "C" int GetRcString(int id, char *buf, int bufsize);
|
||||
#endif // !WIN32
|
||||
//void ptrc(char const *fmt, ...);
|
||||
|
||||
extern int xtrace;
|
||||
|
||||
/* ------------------------- Class CATALOG --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* CATALOG Constructor. */
|
||||
/***********************************************************************/
|
||||
CATALOG::CATALOG(void)
|
||||
{
|
||||
To_Desc= NULL;
|
||||
//*DescFile= '\0';
|
||||
#if defined(WIN32)
|
||||
DataPath= ".\\";
|
||||
#else // !WIN32
|
||||
DataPath= "./";
|
||||
#endif // !WIN32
|
||||
Descp= NULL;
|
||||
//memset(&DescArea, 0, sizeof(AREADEF));
|
||||
memset(&Ctb, 0, sizeof(CURTAB));
|
||||
Cbuf= NULL;
|
||||
Cblen= 0;
|
||||
DefHuge= false;
|
||||
} // end of CATALOG constructor
|
||||
|
||||
/* -------------------------- Class MYCAT ---------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* MYCAT Constructor. */
|
||||
/***********************************************************************/
|
||||
MYCAT::MYCAT(PHC hc) : CATALOG()
|
||||
{
|
||||
Hc= hc;
|
||||
To_Desc= NULL;
|
||||
DefHuge= false;
|
||||
SepIndex= true; // Temporay until we can store offet and size
|
||||
} // end of MYCAT constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* When using volatile storage, reset values pointing to Sarea. */
|
||||
/***********************************************************************/
|
||||
void MYCAT::Reset(void)
|
||||
{
|
||||
To_Desc= NULL;
|
||||
} // end of Reset
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function sets the current database path. */
|
||||
/***********************************************************************/
|
||||
void MYCAT::SetPath(PGLOBAL g, LPCSTR *datapath, const char *path)
|
||||
{
|
||||
if (path) {
|
||||
size_t len= strlen(path) + (*path != '.' ? 4 : 1);
|
||||
char *buf= (char*)PlugSubAlloc(g, NULL, len);
|
||||
|
||||
if (*path != '.') {
|
||||
#if defined(WIN32)
|
||||
char *s= "\\";
|
||||
#else // !WIN32
|
||||
char *s= "/";
|
||||
#endif // !WIN32
|
||||
strcat(strcat(strcat(strcpy(buf, "."), s), path), s);
|
||||
} else
|
||||
strcpy(buf, path);
|
||||
|
||||
*datapath= buf;
|
||||
} // endif path
|
||||
|
||||
} // end of SetDataPath
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function sets an integer MYCAT information. */
|
||||
/***********************************************************************/
|
||||
bool MYCAT::SetIntCatInfo(LPCSTR name, PSZ what, int n)
|
||||
{
|
||||
return Hc->SetIntegerOption(what, n);
|
||||
} // end of SetIntCatInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function returns integer MYCAT information. */
|
||||
/***********************************************************************/
|
||||
int MYCAT::GetIntCatInfo(LPCSTR name, PSZ what, int idef)
|
||||
{
|
||||
int n= Hc->GetIntegerOption(what);
|
||||
|
||||
return (n == NO_IVAL) ? idef : n;
|
||||
} // end of GetIntCatInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function returns Boolean MYCAT information. */
|
||||
/***********************************************************************/
|
||||
bool MYCAT::GetBoolCatInfo(LPCSTR name, PSZ what, bool bdef)
|
||||
{
|
||||
bool b= Hc->GetBooleanOption(what, bdef);
|
||||
|
||||
return b;
|
||||
} // end of GetBoolCatInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function returns size catalog information. */
|
||||
/***********************************************************************/
|
||||
int MYCAT::GetSizeCatInfo(LPCSTR name, PSZ what, PSZ sdef)
|
||||
{
|
||||
char * s, c;
|
||||
int i, n= 0;
|
||||
|
||||
if (!(s= Hc->GetStringOption(what)))
|
||||
s= sdef;
|
||||
|
||||
if ((i= sscanf(s, " %d %c ", &n, &c)) == 2)
|
||||
switch (toupper(c)) {
|
||||
case 'M':
|
||||
n *= 1024;
|
||||
case 'K':
|
||||
n *= 1024;
|
||||
} // endswitch c
|
||||
|
||||
return n;
|
||||
} // end of GetSizeCatInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function sets char MYCAT information in buf. */
|
||||
/***********************************************************************/
|
||||
int MYCAT::GetCharCatInfo(LPCSTR name, PSZ what,
|
||||
PSZ sdef, char *buf, int size)
|
||||
{
|
||||
char *s= Hc->GetStringOption(what);
|
||||
|
||||
strncpy(buf, ((s) ? s : sdef), size);
|
||||
return size;
|
||||
} // end of GetCharCatInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function returns string MYCAT information. */
|
||||
/* Default parameter is "*" to get the handler default. */
|
||||
/***********************************************************************/
|
||||
char *MYCAT::GetStringCatInfo(PGLOBAL g, PSZ name, PSZ what, PSZ sdef)
|
||||
{
|
||||
char *sval, *s= Hc->GetStringOption(what, sdef);
|
||||
|
||||
if (s) {
|
||||
sval= (char*)PlugSubAlloc(g, NULL, strlen(s) + 1);
|
||||
strcpy(sval, s);
|
||||
} else
|
||||
sval = NULL;
|
||||
|
||||
return sval;
|
||||
} // end of GetStringCatInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* This function returns column MYCAT information. */
|
||||
/***********************************************************************/
|
||||
int MYCAT::GetColCatInfo(PGLOBAL g, PTABDEF defp)
|
||||
{
|
||||
char *type= GetStringCatInfo(g, NULL, "Type", "DOS");
|
||||
int i, loff, poff, nof, nlg;
|
||||
void *field= NULL;
|
||||
PCOLDEF cdp, lcdp= NULL, tocols= NULL;
|
||||
PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO));
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get a unique char identifier for types. The letter used are: */
|
||||
/* ABCDEF..IJKLM.OPQRSTUV.XYZ */
|
||||
/*********************************************************************/
|
||||
char tc= (!stricmp(type, "FMT")) ? 'T' // fmT
|
||||
: (!stricmp(type, "DBF")) ? 'A' // dbAse
|
||||
: (!stricmp(type, "TBL")) ? 'L' // tbL
|
||||
: (!stricmp(type, "OEM")) ? 'E' // oEm
|
||||
: (!stricmp(type, "DIR")) ? 'R' : toupper(*type);
|
||||
|
||||
// Take care of the column definitions
|
||||
i= poff= nof= nlg= 0;
|
||||
|
||||
// Offsets of HTML and DIR tables start from 0, DBF at 1
|
||||
loff= (tc == 'A') ? 1 : (tc == 'X' || tc == 'R') ? -1 : 0;
|
||||
|
||||
while (true) {
|
||||
// Default Offset depends on table type
|
||||
switch (tc) {
|
||||
case 'D': // DOS
|
||||
case 'F': // FIX
|
||||
case 'B': // BIN
|
||||
case 'V': // VEC
|
||||
case 'A': // DBF
|
||||
poff= loff + nof; // Default next offset
|
||||
nlg= max(nlg, poff); // Default lrecl
|
||||
break;
|
||||
case 'C': // CSV
|
||||
case 'T': // FMT
|
||||
nlg+= nof;
|
||||
case 'R': // DIR
|
||||
case 'X': // XML
|
||||
poff= loff + 1;
|
||||
break;
|
||||
case 'I': // INI
|
||||
case 'M': // MAC
|
||||
case 'L': // TBL
|
||||
case 'E': // OEM
|
||||
poff = 0; // Offset represents an independant flag
|
||||
break;
|
||||
default: // VCT PLG ODBC MYSQL WMI...
|
||||
poff = 0; // NA
|
||||
break;
|
||||
} // endswitch tc
|
||||
|
||||
do {
|
||||
field= Hc->GetColumnOption(field, pcf);
|
||||
} while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/));
|
||||
|
||||
if (tc == 'A' && pcf->Type == TYPE_DATE && !pcf->Datefmt) {
|
||||
// DBF date format defaults to 'YYYMMDD'
|
||||
pcf->Datefmt= "YYYYMMDD";
|
||||
pcf->Length= 8;
|
||||
} // endif tc
|
||||
|
||||
if (!field)
|
||||
break;
|
||||
|
||||
// Allocate the column description block
|
||||
cdp= new(g) COLDEF;
|
||||
|
||||
if ((nof= cdp->Define(g, NULL, pcf, poff)) < 0)
|
||||
return -1; // Error, probably unhandled type
|
||||
else if (nof)
|
||||
loff= cdp->GetOffset();
|
||||
|
||||
switch (tc) {
|
||||
case 'V':
|
||||
cdp->SetOffset(0); // Not to have shift
|
||||
case 'B':
|
||||
// BIN/VEC are packed by default
|
||||
if (nof)
|
||||
// Field width is the internal representation width
|
||||
// that can also depend on the column format
|
||||
switch (cdp->Fmt ? *cdp->Fmt : 'X') {
|
||||
case 'C': break;
|
||||
case 'R':
|
||||
case 'F':
|
||||
case 'L':
|
||||
case 'I': nof= 4; break;
|
||||
case 'D': nof= 8; break;
|
||||
case 'S': nof= 2; break;
|
||||
case 'T': nof= 1; break;
|
||||
default: nof= cdp->Clen;
|
||||
} // endswitch Fmt
|
||||
|
||||
break;
|
||||
} // endswitch tc
|
||||
|
||||
if (lcdp)
|
||||
lcdp->SetNext(cdp);
|
||||
else
|
||||
tocols= cdp;
|
||||
|
||||
lcdp= cdp;
|
||||
i++;
|
||||
} // endwhile
|
||||
|
||||
// Degree is the the number of defined columns (informational)
|
||||
if (i != defp->GetDegree())
|
||||
defp->SetDegree(i);
|
||||
|
||||
if (defp->GetDefType() == TYPE_AM_DOS) {
|
||||
int ending, recln= 0;
|
||||
PDOSDEF ddp= (PDOSDEF)defp;
|
||||
|
||||
// Was commented because sometimes ending is 0 even when
|
||||
// not specified (for instance if quoted is specified)
|
||||
// if ((ending= Hc->GetIntegerOption("Ending")) < 0) {
|
||||
if ((ending= Hc->GetIntegerOption("Ending")) <= 0) {
|
||||
#if defined(WIN32)
|
||||
ending= 2;
|
||||
#else
|
||||
ending= 1;
|
||||
#endif
|
||||
Hc->SetIntegerOption("Ending", ending);
|
||||
} // endif ending
|
||||
|
||||
// Calculate the default record size
|
||||
switch (tc) {
|
||||
case 'F':
|
||||
recln= nlg + ending; // + length of line ending
|
||||
break;
|
||||
case 'B':
|
||||
case 'V':
|
||||
recln= nlg;
|
||||
|
||||
// if ((k= (pak < 0) ? 8 : pak) > 1)
|
||||
// See above for detailed comment
|
||||
// Round up lrecl to multiple of 8 or pak
|
||||
// recln= ((recln + k - 1) / k) * k;
|
||||
|
||||
break;
|
||||
case 'D':
|
||||
case 'A':
|
||||
recln= nlg;
|
||||
break;
|
||||
case 'C':
|
||||
case 'T':
|
||||
// The number of separators (assuming an extra one can exist)
|
||||
// recln= poff * ((qotd) ? 3 : 1); to be investigated
|
||||
recln= nlg + poff * 3; // To be safe
|
||||
break;
|
||||
} // endswitch tc
|
||||
|
||||
// lrecl must be at least recln to avoid buffer overflow
|
||||
recln= max(recln, Hc->GetIntegerOption("Lrecl"));
|
||||
Hc->SetIntegerOption("Lrecl", recln);
|
||||
ddp->SetLrecl(recln);
|
||||
} // endif Lrecl
|
||||
|
||||
// Attach the column definition to the tabdef
|
||||
defp->SetCols(tocols);
|
||||
return poff;
|
||||
} // end of GetColCatInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetIndexInfo: retrieve index description from the table structure. */
|
||||
/***********************************************************************/
|
||||
bool MYCAT::GetIndexInfo(PGLOBAL g, PTABDEF defp)
|
||||
{
|
||||
PIXDEF xdp, pxd= NULL, toidx= NULL;
|
||||
|
||||
// Now take care of the index definitions
|
||||
for (int n= 0; ; n++) {
|
||||
if (xtrace)
|
||||
printf("Getting index %d info\n", n + 1);
|
||||
|
||||
if (!(xdp= Hc->GetIndexInfo(n)))
|
||||
break;
|
||||
|
||||
if (pxd)
|
||||
pxd->SetNext(xdp);
|
||||
else
|
||||
toidx= xdp;
|
||||
|
||||
pxd= xdp;
|
||||
} // endfor n
|
||||
|
||||
// All is correct, attach new index(es)
|
||||
defp->SetIndx(toidx);
|
||||
return false;
|
||||
} // end of GetIndexInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTableDesc: retrieve a table descriptor. */
|
||||
/* Look for a table descriptor matching the name and type. If found */
|
||||
/* in storage, return a pointer to it, else look in the XDB file. If */
|
||||
/* found, make and add the descriptor and return a pointer to it. */
|
||||
/***********************************************************************/
|
||||
PRELDEF MYCAT::GetTableDesc(PGLOBAL g, LPCSTR name,
|
||||
LPCSTR am, PRELDEF *prp)
|
||||
{
|
||||
LPCSTR type;
|
||||
|
||||
if (xtrace)
|
||||
printf("GetTableDesc: name=%s am=%s\n", name, SVP(am));
|
||||
|
||||
// Firstly check whether this table descriptor is in memory
|
||||
if (To_Desc)
|
||||
return To_Desc;
|
||||
|
||||
// Here get the type of this table
|
||||
if (!(type= Hc->GetStringOption("Type")))
|
||||
type= "DOS";
|
||||
|
||||
return MakeTableDesc(g, name, type);
|
||||
} // end of GetTableDesc
|
||||
|
||||
/***********************************************************************/
|
||||
/* MakeTableDesc: make a table/view description. */
|
||||
/* Note: caller must check if name already exists before calling it. */
|
||||
/***********************************************************************/
|
||||
PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am)
|
||||
{
|
||||
PRELDEF tdp= NULL;
|
||||
|
||||
if (xtrace)
|
||||
printf("MakeTableDesc: name=%s am=%s\n", name, SVP(am));
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get a unique char identifier for types. The letter used are: */
|
||||
/* ABCDEF..IJKLM.OPQRSTUVWXYZ and Allocate table definition class */
|
||||
/*********************************************************************/
|
||||
switch ((!am) ? 'D' : (!stricmp(am, "FMT")) ? 'C' // CSV
|
||||
: (!stricmp(am, "DIR")) ? 'R'
|
||||
: (!stricmp(am, "SYS")) ? 'I' // INI
|
||||
// : (!stricmp(am, "DUMMY")) ? 'U'
|
||||
: (!stricmp(am, "TBL")) ? 'L'
|
||||
// : (!stricmp(am, "PLG")) ? 'S' // Compatibility
|
||||
: (!stricmp(am, "MYSQL")) ? 'Y' // mYsql
|
||||
: (!stricmp(am, "OEM")) ? 'E' : toupper(*am)) {
|
||||
case 'F':
|
||||
case 'B':
|
||||
case 'D': tdp= new(g) DOSDEF; break;
|
||||
case 'C': tdp= new(g) CSVDEF; break;
|
||||
case 'I': tdp= new(g) INIDEF; break;
|
||||
case 'R': tdp= new(g) DIRDEF; break;
|
||||
#if defined(XML_SUPPORT)
|
||||
case 'X': tdp= new(g) XMLDEF; break;
|
||||
#endif // XML_SUPPORT
|
||||
case 'V': tdp= new(g) VCTDEF; break;
|
||||
#if defined(ODBC_SUPPORT)
|
||||
case 'O': tdp= new(g) ODBCDEF; break;
|
||||
#endif // ODBC_SUPPORT
|
||||
#if defined(WIN32)
|
||||
case 'M': tdp= new(g) MACDEF; break;
|
||||
case 'W': tdp= new(g) WMIDEF; break;
|
||||
#endif // WIN32
|
||||
case 'E': tdp= new(g) OEMDEF; break;
|
||||
case 'L': tdp= new(g) TBLDEF; break;
|
||||
#if defined(MYSQL_SUPPORT)
|
||||
case 'Y': tdp= new(g) MYSQLDEF; break;
|
||||
#endif // MYSQL_SUPPORT
|
||||
#if defined(PIVOT_SUPPORT)
|
||||
case 'P': tdp= new(g) PIVOTDEF; break;
|
||||
#endif // PIVOT_SUPPORT
|
||||
default:
|
||||
sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name);
|
||||
} // endswitch
|
||||
|
||||
// Do make the table/view definition from XDB file information
|
||||
if (tdp && tdp->Define(g, this, name, am))
|
||||
tdp= NULL;
|
||||
|
||||
return tdp;
|
||||
} // end of MakeTableDesc
|
||||
|
||||
/***********************************************************************/
|
||||
/* Initialize a Table Description Block construction. */
|
||||
/***********************************************************************/
|
||||
PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode)
|
||||
{
|
||||
PRELDEF tdp;
|
||||
PTDB tdbp= NULL;
|
||||
LPCSTR name= tablep->GetName();
|
||||
|
||||
if (xtrace)
|
||||
printf("GetTableDB: name=%s\n", name);
|
||||
|
||||
// Look for the description of the requested table
|
||||
tdp= GetTableDesc(g, name, NULL);
|
||||
|
||||
if (tdp) {
|
||||
if (xtrace)
|
||||
printf("tdb=%p type=%s\n", tdp, tdp->GetType());
|
||||
|
||||
if (tablep->GetQualifier())
|
||||
SetPath(g, &tdp->Database, tablep->GetQualifier());
|
||||
|
||||
tdbp= tdp->GetTable(g, mode);
|
||||
} // endif tdp
|
||||
|
||||
if (tdbp) {
|
||||
if (xtrace)
|
||||
printf("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(),
|
||||
tdbp->GetAmType());
|
||||
tablep->SetTo_Tdb(tdbp);
|
||||
tdbp->SetTable(tablep);
|
||||
} // endif tdbp
|
||||
|
||||
return (tdbp);
|
||||
} // end of GetTable
|
||||
|
||||
/***********************************************************************/
|
||||
/* ClearDB: Terminates Database usage. */
|
||||
/***********************************************************************/
|
||||
void MYCAT::ClearDB(PGLOBAL g)
|
||||
{
|
||||
To_Desc= NULL;
|
||||
} // end of ClearDB
|
||||
|
||||
/* ------------------------ End of MYCAT --------------------------- */
|
||||
64
storage/connect/mycat.h
Normal file
64
storage/connect/mycat.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* Copyright (C) Olivier Bertrand 2004 - 2011
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/**************** MYCAT H Declares Source Code File (.H) ***************/
|
||||
/* Name: MYCAT.H Version 2.3 */
|
||||
/* */
|
||||
/* This file contains the CONNECT plugin MYCAT class definitions. */
|
||||
/***********************************************************************/
|
||||
#ifndef __MYCAT__H
|
||||
#define __MYCAT__H
|
||||
|
||||
#include "block.h"
|
||||
#include "catalog.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* MYCAT: class for managing the CONNECT plugin DB items. */
|
||||
/***********************************************************************/
|
||||
class MYCAT : public CATALOG {
|
||||
public:
|
||||
MYCAT(PHC hc); // Constructor
|
||||
|
||||
// Implementation
|
||||
PHC GetHandler(void) {return Hc;}
|
||||
void SetHandler(PHC hc) {Hc= hc;}
|
||||
|
||||
// Methods
|
||||
void Reset(void);
|
||||
void SetDataPath(PGLOBAL g, const char *path)
|
||||
{SetPath(g, &DataPath, path);}
|
||||
bool GetBoolCatInfo(LPCSTR name, PSZ what, bool bdef);
|
||||
bool SetIntCatInfo(LPCSTR name, PSZ what, int ival);
|
||||
int GetIntCatInfo(LPCSTR name, PSZ what, int idef);
|
||||
int GetSizeCatInfo(LPCSTR name, PSZ what, PSZ sdef);
|
||||
int GetCharCatInfo(LPCSTR name, PSZ what, PSZ sdef, char *buf, int size);
|
||||
char *GetStringCatInfo(PGLOBAL g, PSZ name, PSZ what, PSZ sdef);
|
||||
int GetColCatInfo(PGLOBAL g, PTABDEF defp);
|
||||
bool GetIndexInfo(PGLOBAL g, PTABDEF defp);
|
||||
bool StoreIndex(PGLOBAL g, PTABDEF defp) {return false;} // Temporary
|
||||
PRELDEF GetTableDesc(PGLOBAL g, LPCSTR name,
|
||||
LPCSTR am, PRELDEF *prp = NULL);
|
||||
PTDB GetTable(PGLOBAL g, PTABLE tablep, MODE mode = MODE_READ);
|
||||
void ClearDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
PRELDEF MakeTableDesc(PGLOBAL g, LPCSTR name, LPCSTR am);
|
||||
void SetPath(PGLOBAL g, LPCSTR *datapath, const char *path);
|
||||
|
||||
// Members
|
||||
ha_connect *Hc; // The Connect handler
|
||||
}; // end of class MYCAT
|
||||
|
||||
#endif __MYCAT__H
|
||||
547
storage/connect/myconn.cpp
Normal file
547
storage/connect/myconn.cpp
Normal file
@@ -0,0 +1,547 @@
|
||||
/************** MyConn C++ Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: MYCONN */
|
||||
/* ------------- */
|
||||
/* Version 1.5 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2007-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* Implements a connection to MySQL. */
|
||||
/* It can optionally use the embedded MySQL library. */
|
||||
/* */
|
||||
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
||||
/* -------------------------------------- */
|
||||
/* */
|
||||
/* REQUIRED FILES: */
|
||||
/* --------------- */
|
||||
/* MYCONN.CPP - Source code */
|
||||
/* MYCONN.H - MYCONN class 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 "my_global.h"
|
||||
#if defined(WIN32)
|
||||
//#include <windows.h>
|
||||
#else // !WIN32
|
||||
#include "osutil.h"
|
||||
#endif // !WIN32
|
||||
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "value.h"
|
||||
#include "valblk.h"
|
||||
#define DLL_EXPORT // Items are exported from this DLL
|
||||
#include "myconn.h"
|
||||
|
||||
#if defined(EMBEDDED)
|
||||
static char *server_args[] = {
|
||||
"this_program", /* this string is not used */
|
||||
"--skip-bdb",
|
||||
"--skip-innodb"
|
||||
};
|
||||
|
||||
static char *server_groups[] = {
|
||||
"PlugDB_SERVER",
|
||||
"embedded",
|
||||
"server",
|
||||
(char *)NULL
|
||||
};
|
||||
#endif // EMBEDDED
|
||||
|
||||
/* -------------------------- Class MYSQLC --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the MYSQLC class. */
|
||||
/***********************************************************************/
|
||||
MYSQLC::MYSQLC(void)
|
||||
{
|
||||
m_DB = NULL;
|
||||
m_Stmt = NULL;
|
||||
m_Res = NULL;
|
||||
m_Rows = -1;
|
||||
m_Row = NULL;
|
||||
m_Fields = -1;
|
||||
N = 0;
|
||||
} // end of MYSQLC constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get the number of lines of the result set. */
|
||||
/* Currently we send the Select command and return m_Rows */
|
||||
/* Perhaps should we use Select count(*) ... (?????) */
|
||||
/* No because here we execute only one query instead of two */
|
||||
/* (the select count(*) plus the normal query) */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::GetResultSize(PGLOBAL g, PSZ sql)
|
||||
{
|
||||
if (m_Rows < 0)
|
||||
if (ExecSQL(g, sql) != RC_OK)
|
||||
return -1;
|
||||
|
||||
return m_Rows;
|
||||
} // end of GetResultSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* Open a MySQL (remote) connection. */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::Open(PGLOBAL g, PSZ host, PSZ db, PSZ user, PSZ pwd, int pt)
|
||||
{
|
||||
m_DB = mysql_init(NULL);
|
||||
|
||||
if (!m_DB) {
|
||||
strcpy(g->Message, "mysql_init failed: no memory");
|
||||
return RC_FX;
|
||||
} // endif m_DB
|
||||
|
||||
// Notice that the client and server use separate group names.
|
||||
// This is critical, because the server will not accept the
|
||||
// client's options, and vice versa.
|
||||
mysql_options(m_DB, MYSQL_READ_DEFAULT_GROUP, "PlugDB_CLIENT");
|
||||
|
||||
#if 0
|
||||
if (pwd && !strcmp(pwd, "*")) {
|
||||
if (GetPromptAnswer(g, "*Enter password:")) {
|
||||
m_DB = NULL;
|
||||
return RC_FX;
|
||||
} else
|
||||
pwd = g->Message;
|
||||
|
||||
} // endif pwd
|
||||
#endif // 0
|
||||
|
||||
if (!mysql_real_connect(m_DB, host, user, pwd, db, pt, NULL, CLIENT_MULTI_RESULTS)) {
|
||||
#if defined(_DEBUG)
|
||||
sprintf(g->Message, "mysql_real_connect failed: (%d) %s",
|
||||
mysql_errno(m_DB), mysql_error(m_DB));
|
||||
#else // !_DEBUG
|
||||
sprintf(g->Message, "(%d) %s", mysql_errno(m_DB), mysql_error(m_DB));
|
||||
#endif // !_DEBUG
|
||||
m_DB = NULL;
|
||||
return RC_FX;
|
||||
} // endif mysql_real_connect
|
||||
|
||||
return RC_OK;
|
||||
} // end of Open
|
||||
|
||||
/***********************************************************************/
|
||||
/* Returns true if the connection is still alive. */
|
||||
/***********************************************************************/
|
||||
bool MYSQLC::Connected(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!m_DB)
|
||||
return FALSE;
|
||||
else if ((rc = mysql_ping(m_DB)) == CR_SERVER_GONE_ERROR)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
} // end of Connected
|
||||
|
||||
/***********************************************************************/
|
||||
/* Returns the thread ID of the current MySQL connection. */
|
||||
/***********************************************************************/
|
||||
ulong MYSQLC::GetThreadID(void)
|
||||
{
|
||||
return (m_DB) ? mysql_thread_id(m_DB) : 0;
|
||||
} // end of GetThreadID
|
||||
|
||||
/***********************************************************************/
|
||||
/* Returns a string that represents the server version number. */
|
||||
/***********************************************************************/
|
||||
const char *MYSQLC::ServerInfo(void)
|
||||
{
|
||||
return (m_DB) ? mysql_get_server_info(m_DB) : NULL;
|
||||
} // end of ServerInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* Returns the version number of the server as a number that */
|
||||
/* represents the MySQL server version in this format: */
|
||||
/* major_version*10000 + minor_version *100 + sub_version */
|
||||
/***********************************************************************/
|
||||
ulong MYSQLC::ServerVersion(void)
|
||||
{
|
||||
return (m_DB) ? mysql_get_server_version(m_DB) : 0;
|
||||
} // end of ServerVersion
|
||||
|
||||
/**************************************************************************/
|
||||
/* KillQuery: Send MySQL a Kill Query command. */
|
||||
/**************************************************************************/
|
||||
int MYSQLC::KillQuery(ulong id)
|
||||
{
|
||||
char kill[20];
|
||||
|
||||
sprintf(kill, "KILL QUERY %u", id);
|
||||
return (m_DB) ? mysql_query(m_DB, kill) : 1;
|
||||
} // end of KillQuery
|
||||
|
||||
/***********************************************************************/
|
||||
/* Prepare the SQL statement used to insert into a MySQL table. */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::PrepareSQL(PGLOBAL g, const char *stmt)
|
||||
{
|
||||
if (!m_DB) {
|
||||
strcpy(g->Message, "MySQL not connected");
|
||||
return -4;
|
||||
} else if (m_Stmt)
|
||||
return -1; // should not append
|
||||
|
||||
#if defined(ALPHA)
|
||||
if (!(m_Stmt = mysql_prepare(m_DB, stmt, strlen(stmt)))) {
|
||||
|
||||
sprintf(g->Message, "mysql_prepare failed: %s [%s]",
|
||||
mysql_error(m_DB), stmt);
|
||||
return -1;
|
||||
} // endif m_Stmt
|
||||
|
||||
// Return the parameter count from the statement
|
||||
return mysql_param_count(m_Stmt);
|
||||
#else // !ALPHA
|
||||
if (!(m_Stmt = mysql_stmt_init(m_DB))) {
|
||||
strcpy(g->Message, "mysql_stmt_init(), out of memory");
|
||||
return -2;
|
||||
} // endif m_Stmt
|
||||
|
||||
if (mysql_stmt_prepare(m_Stmt, stmt, strlen(stmt))) {
|
||||
sprintf(g->Message, "mysql_stmt_prepare() failed: (%d) %s",
|
||||
mysql_stmt_errno(m_Stmt), mysql_stmt_error(m_Stmt));
|
||||
return -3;
|
||||
} // endif prepare
|
||||
|
||||
// Return the parameter count from the statement
|
||||
return mysql_stmt_param_count(m_Stmt);
|
||||
#endif // !ALPHA
|
||||
} // end of PrepareSQL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Exec the Select SQL command and get back the result size in rows. */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::ExecSQL(PGLOBAL g, const char *query, int *w)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
|
||||
if (!m_DB) {
|
||||
strcpy(g->Message, "MySQL not connected");
|
||||
return RC_FX;
|
||||
} // endif m_DB
|
||||
|
||||
if (w)
|
||||
*w = 0;
|
||||
|
||||
if (m_Rows >= 0)
|
||||
return RC_OK; // Already done
|
||||
|
||||
if (mysql_query(m_DB, query) != 0) {
|
||||
char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
|
||||
|
||||
sprintf(msg, "(%d) %s [%s]", mysql_errno(m_DB),
|
||||
mysql_error(m_DB), query);
|
||||
strncpy(g->Message, msg, sizeof(g->Message) - 1);
|
||||
g->Message[sizeof(g->Message) - 1] = 0;
|
||||
rc = RC_FX;
|
||||
} else if (mysql_field_count(m_DB) > 0) {
|
||||
if (!(m_Res = mysql_store_result(m_DB))) {
|
||||
char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
|
||||
|
||||
sprintf(msg, "mysql_store_result failed: %s", mysql_error(m_DB));
|
||||
strncpy(g->Message, msg, sizeof(g->Message) - 1);
|
||||
g->Message[sizeof(g->Message) - 1] = 0;
|
||||
rc = RC_FX;
|
||||
} else {
|
||||
m_Fields = mysql_num_fields(m_Res);
|
||||
m_Rows = (int)mysql_num_rows(m_Res);
|
||||
} // endif m_Res
|
||||
|
||||
} else {
|
||||
m_Rows = (int)mysql_affected_rows(m_DB);
|
||||
sprintf(g->Message, "Affected rows: %d\n", m_Rows);
|
||||
rc = RC_NF;
|
||||
} // endif field count
|
||||
|
||||
if (w)
|
||||
*w = mysql_warning_count(m_DB);
|
||||
|
||||
return rc;
|
||||
} // end of ExecSQL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Bind the parameter buffers. */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::BindParams(PGLOBAL g, MYSQL_BIND *bind)
|
||||
{
|
||||
if (!m_DB) {
|
||||
strcpy(g->Message, "MySQL not connected");
|
||||
return RC_FX;
|
||||
} else
|
||||
assert(m_Stmt);
|
||||
|
||||
#if defined(ALPHA)
|
||||
if (mysql_bind_param(m_Stmt, bind)) {
|
||||
sprintf(g->Message, "mysql_bind_param() failed: %s",
|
||||
mysql_stmt_error(m_Stmt));
|
||||
#else // !ALPHA
|
||||
if (mysql_stmt_bind_param(m_Stmt, bind)) {
|
||||
sprintf(g->Message, "mysql_stmt_bind_param() failed: %s",
|
||||
mysql_stmt_error(m_Stmt));
|
||||
#endif // !ALPHA
|
||||
return RC_FX;
|
||||
} // endif bind
|
||||
|
||||
return RC_OK;
|
||||
} // end of BindParams
|
||||
|
||||
/***********************************************************************/
|
||||
/* Execute a prepared statement. */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::ExecStmt(PGLOBAL g)
|
||||
{
|
||||
if (!m_DB) {
|
||||
strcpy(g->Message, "MySQL not connected");
|
||||
return RC_FX;
|
||||
} // endif m_DB
|
||||
|
||||
#if defined(ALPHA)
|
||||
if (mysql_execute(m_Stmt)) {
|
||||
sprintf(g->Message, "mysql_execute() failed: %s",
|
||||
mysql_stmt_error(m_Stmt));
|
||||
return RC_FX;
|
||||
} // endif execute
|
||||
#else // !ALPHA
|
||||
if (mysql_stmt_execute(m_Stmt)) {
|
||||
sprintf(g->Message, "mysql_stmt_execute() failed: %s",
|
||||
mysql_stmt_error(m_Stmt));
|
||||
return RC_FX;
|
||||
} // endif execute
|
||||
#endif // !ALPHA
|
||||
|
||||
// Check the total number of affected rows
|
||||
if (mysql_stmt_affected_rows(m_Stmt) != 1) {
|
||||
sprintf(g->Message, "Invalid affected rows by MySQL");
|
||||
return RC_FX;
|
||||
} // endif affected_rows
|
||||
|
||||
return RC_OK;
|
||||
} // end of ExecStmt
|
||||
|
||||
/***********************************************************************/
|
||||
/* Fetch one result line from the query result set. */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::Fetch(PGLOBAL g, int pos)
|
||||
{
|
||||
if (!m_DB) {
|
||||
strcpy(g->Message, "MySQL not connected");
|
||||
return RC_FX;
|
||||
} // endif m_DB
|
||||
|
||||
if (!m_Res) {
|
||||
// Result set was not initialized
|
||||
strcpy(g->Message, MSG(FETCH_NO_RES));
|
||||
return RC_FX;
|
||||
} else
|
||||
N++;
|
||||
|
||||
if (pos >= 0)
|
||||
mysql_data_seek(m_Res, (my_ulonglong)pos);
|
||||
|
||||
m_Row = mysql_fetch_row(m_Res);
|
||||
return (m_Row) ? RC_OK : RC_EF;
|
||||
} // end of Fetch
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get one field of the current row. */
|
||||
/***********************************************************************/
|
||||
char *MYSQLC::GetCharField(int i)
|
||||
{
|
||||
if (m_Res && m_Row) {
|
||||
#if defined(_DEBUG)
|
||||
MYSQL_FIELD *fld = mysql_fetch_field_direct(m_Res, i);
|
||||
#endif // _DEBUG
|
||||
MYSQL_ROW row = m_Row + i;
|
||||
|
||||
return (row) ? (char*)*row : (char*)"<null>";
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
} // end of GetCharField
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get the max length of the field. */
|
||||
/***********************************************************************/
|
||||
int MYSQLC::GetFieldLength(int i)
|
||||
{
|
||||
if (m_Res) {
|
||||
MYSQL_FIELD *fld = mysql_fetch_field_direct(m_Res, i);
|
||||
|
||||
return fld->max_length;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
} // end of GetFieldLength
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make a PlugDB result structure from the MySQL result. */
|
||||
/***********************************************************************/
|
||||
PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb)
|
||||
{
|
||||
char *fmt;
|
||||
int n;
|
||||
PCOLRES *pcrp, crp;
|
||||
PQRYRES qrp;
|
||||
MYSQL_FIELD *fld;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (!m_Res || !m_Fields) {
|
||||
sprintf(g->Message, "%s result", (m_Res) ? "Void" : "No");
|
||||
return NULL;
|
||||
} // endif m_Res
|
||||
|
||||
/*********************************************************************/
|
||||
/* Put the result in storage for future retrieval. */
|
||||
/*********************************************************************/
|
||||
qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
|
||||
pcrp = &qrp->Colresp;
|
||||
qrp->Continued = FALSE;
|
||||
qrp->Truncated = FALSE;
|
||||
qrp->Info = FALSE;
|
||||
qrp->Suball = TRUE;
|
||||
qrp->BadLines = 0;
|
||||
qrp->Maxsize = m_Rows;
|
||||
qrp->Maxres = m_Rows;
|
||||
qrp->Nbcol = 0;
|
||||
qrp->Nblin = 0;
|
||||
qrp->Cursor = 0;
|
||||
|
||||
for (fld = mysql_fetch_field(m_Res); fld;
|
||||
fld = mysql_fetch_field(m_Res)) {
|
||||
*pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
|
||||
crp = *pcrp;
|
||||
pcrp = &crp->Next;
|
||||
crp->Ncol = ++qrp->Nbcol;
|
||||
|
||||
crp->Name = (char*)PlugSubAlloc(g, NULL, fld->name_length + 1);
|
||||
strcpy(crp->Name, fld->name);
|
||||
|
||||
if ((crp->Type = MYSQLtoPLG(fld->type)) == TYPE_ERROR) {
|
||||
sprintf(g->Message, "Type %d not supported for column %s",
|
||||
fld->type, crp->Name);
|
||||
return NULL;
|
||||
} else if (crp->Type == TYPE_DATE && !pdb)
|
||||
// For direct MySQL connection, display the MySQL date string
|
||||
crp->Type = TYPE_STRING;
|
||||
|
||||
crp->Prec = fld->decimals;
|
||||
crp->Length = fld->max_length;
|
||||
crp->Clen = GetTypeSize(crp->Type, crp->Length);
|
||||
crp->DBtype = GetDBType((int)crp->Type);
|
||||
|
||||
if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
|
||||
crp->Clen, 0, FALSE, TRUE))) {
|
||||
sprintf(g->Message, MSG(INV_RESULT_TYPE),
|
||||
GetFormatType(crp->Type));
|
||||
return NULL;
|
||||
} else if (crp->Type == TYPE_DATE) {
|
||||
fmt = MyDateFmt(fld->type);
|
||||
crp->Kdata->SetFormat(g, fmt, strlen(fmt));
|
||||
} // endif's
|
||||
|
||||
if (fld->flags & NOT_NULL_FLAG)
|
||||
crp->Nulls = NULL;
|
||||
else {
|
||||
crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
|
||||
memset(crp->Nulls, ' ', m_Rows);
|
||||
} // endelse fld->flags
|
||||
|
||||
} // endfor fld
|
||||
|
||||
*pcrp = NULL;
|
||||
assert(qrp->Nbcol == m_Fields);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Now fill the allocated result structure. */
|
||||
/*********************************************************************/
|
||||
for (n = 0; n < m_Rows; n++) {
|
||||
if (!(m_Row = mysql_fetch_row(m_Res))) {
|
||||
sprintf(g->Message, "Missing row %d from result", n + 1);
|
||||
return NULL;
|
||||
} // endif m_Row
|
||||
|
||||
for (crp = qrp->Colresp; crp; crp = crp->Next) {
|
||||
if (row = m_Row + (crp->Ncol - 1))
|
||||
if (*row)
|
||||
crp->Kdata->SetValue((PSZ)*row, n);
|
||||
else {
|
||||
if (!*row && crp->Nulls)
|
||||
crp->Nulls[n] = '*'; // Null value
|
||||
|
||||
crp->Kdata->Reset(n);
|
||||
} // endelse *row
|
||||
|
||||
} // endfor crp
|
||||
|
||||
} // endfor n
|
||||
|
||||
qrp->Nblin = n;
|
||||
return qrp;
|
||||
} // end of GetResult
|
||||
|
||||
/***********************************************************************/
|
||||
/* Free the current result. */
|
||||
/***********************************************************************/
|
||||
void MYSQLC::FreeResult(void)
|
||||
{
|
||||
if (m_Res) {
|
||||
mysql_free_result(m_Res);
|
||||
m_Res = NULL;
|
||||
} // endif m_Res
|
||||
|
||||
// Reset the connection
|
||||
m_Row = NULL;
|
||||
m_Rows = -1;
|
||||
m_Fields = -1;
|
||||
N = 0;
|
||||
} // end of FreeResult
|
||||
|
||||
/***********************************************************************/
|
||||
/* Place the cursor at the beginning of the result set. */
|
||||
/***********************************************************************/
|
||||
void MYSQLC::Rewind(void)
|
||||
{
|
||||
if (m_Res)
|
||||
mysql_data_seek(m_Res, 0);
|
||||
|
||||
} // end of Rewind
|
||||
|
||||
/***********************************************************************/
|
||||
/* Close the connection. */
|
||||
/***********************************************************************/
|
||||
void MYSQLC::Close(void)
|
||||
{
|
||||
FreeResult();
|
||||
mysql_close(m_DB);
|
||||
m_DB = NULL;
|
||||
} // end of Close
|
||||
|
||||
/***********************************************************************/
|
||||
/* Discard additional results from a stored procedure. */
|
||||
/***********************************************************************/
|
||||
void MYSQLC::DiscardResults(void)
|
||||
{
|
||||
MYSQL_RES *res;
|
||||
|
||||
while(!mysql_next_result(m_DB)) {
|
||||
res = mysql_store_result(m_DB);
|
||||
mysql_free_result(res);
|
||||
} // endwhile next result
|
||||
|
||||
} // end of DiscardResults
|
||||
91
storage/connect/myconn.h
Normal file
91
storage/connect/myconn.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/***********************************************************************/
|
||||
/* MYCONN.H Olivier Bertrand 2007-2012 */
|
||||
/* */
|
||||
/* This is the declaration file for the MySQL connection class and */
|
||||
/* a few utility functions used to communicate with MySQL. */
|
||||
/* */
|
||||
/* DO NOT define DLL_EXPORT in your application so these items are */
|
||||
/* declared are imported from the Myconn DLL. */
|
||||
/***********************************************************************/
|
||||
#if defined(WIN32)
|
||||
#include <winsock.h>
|
||||
#else // !WIN32
|
||||
#include <sys/socket.h>
|
||||
#endif // !WIN32
|
||||
#include <mysql.h>
|
||||
#include <errmsg.h>
|
||||
|
||||
#if defined(WIN32) && defined(MYCONN_EXPORTS)
|
||||
#if defined(DLL_EXPORT)
|
||||
#define DllItem _declspec(dllexport)
|
||||
#else // !DLL_EXPORT
|
||||
#define DllItem _declspec(dllimport)
|
||||
#endif // !DLL_EXPORT
|
||||
#else // !WIN32 || !MYCONN_EXPORTS
|
||||
#define DllItem
|
||||
#endif // !WIN32
|
||||
|
||||
//#define TYPE_AM_MYSQL (AMT)192
|
||||
#define MYSQL_ENABLED 0x00000001
|
||||
#define MYSQL_LOGON 0x00000002
|
||||
|
||||
typedef class MYSQLC *PMYC;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Exported/Imported functions. */
|
||||
/***********************************************************************/
|
||||
DllItem int MYSQLtoPLG(char *);
|
||||
DllItem int MYSQLtoPLG(int);
|
||||
DllItem enum enum_field_types PLGtoMYSQL(int, bool gdf = FALSE);
|
||||
DllItem char *MyDateFmt(int);
|
||||
DllItem char *MyDateFmt(char *);
|
||||
|
||||
/* -------------------------- MYCONN class --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* MYSQLC exported/imported class. A MySQL connection. */
|
||||
/***********************************************************************/
|
||||
class DllItem MYSQLC {
|
||||
friend class TDBMYSQL;
|
||||
// Construction
|
||||
public:
|
||||
MYSQLC(void);
|
||||
|
||||
// Implementation
|
||||
int GetRows(void) {return m_Rows;}
|
||||
bool Connected(void);
|
||||
|
||||
// Methods
|
||||
// int GetCurPos(void) {return (m_Res) ? N : 0;}
|
||||
// int GetProgCur(void) {return N;}
|
||||
int GetResultSize(PGLOBAL g, PSZ sql);
|
||||
int Open(PGLOBAL g, PSZ host, PSZ db, PSZ user = "root",
|
||||
PSZ pwd = "*", int pt = 0);
|
||||
ulong GetThreadID(void);
|
||||
ulong ServerVersion(void);
|
||||
const char *ServerInfo(void);
|
||||
int KillQuery(ulong id);
|
||||
int ExecSQL(PGLOBAL g, const char *query, int *w = NULL);
|
||||
int PrepareSQL(PGLOBAL g, const char *query);
|
||||
int ExecStmt(PGLOBAL g);
|
||||
int BindParams(PGLOBAL g, MYSQL_BIND *bind);
|
||||
PQRYRES GetResult(PGLOBAL g, bool pdb = FALSE);
|
||||
int Fetch(PGLOBAL g, int pos);
|
||||
char *GetCharField(int i);
|
||||
int GetFieldLength(int i);
|
||||
void Rewind(void);
|
||||
void FreeResult(void);
|
||||
void Close(void);
|
||||
void DiscardResults(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
MYSQL *m_DB; // The return from MySQL connection
|
||||
MYSQL_STMT *m_Stmt; // Prepared statement handle
|
||||
MYSQL_RES *m_Res; // Points to MySQL Result
|
||||
MYSQL_ROW m_Row; // Point to current row
|
||||
int m_Rows; // The number of rows of the result
|
||||
int N;
|
||||
int m_Fields; // The number of result fields
|
||||
}; // end of class MYSQLC
|
||||
|
||||
185
storage/connect/myutil.cpp
Normal file
185
storage/connect/myutil.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
/************** MyUtil C++ Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: MYUTIL */
|
||||
/* ------------- */
|
||||
/* Version 1.0 */
|
||||
/* */
|
||||
/* Author Olivier BERTRAND 2013 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* It contains utility functions to convert data types. */
|
||||
/* It can optionally use the embedded MySQL library. */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
#include "my_global.h"
|
||||
#include <mysql.h>
|
||||
#if defined(WIN32)
|
||||
//#include <windows.h>
|
||||
#else // !WIN32
|
||||
#include "osutil.h"
|
||||
#endif // !WIN32
|
||||
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
//#include "value.h"
|
||||
//#include "valblk.h"
|
||||
#define DLL_EXPORT // Items are exported from this DLL
|
||||
|
||||
/************************************************************************/
|
||||
/* Convert from MySQL type name to PlugDB type number */
|
||||
/************************************************************************/
|
||||
int MYSQLtoPLG(char *typname)
|
||||
{
|
||||
int type;
|
||||
|
||||
if (!stricmp(typname, "int") || !stricmp(typname, "mediumint") ||
|
||||
!stricmp(typname, "integer"))
|
||||
type = TYPE_INT;
|
||||
else if (!stricmp(typname, "tinyint") || !stricmp(typname, "smallint"))
|
||||
type = TYPE_SHORT;
|
||||
else if (!stricmp(typname, "char") || !stricmp(typname, "varchar") ||
|
||||
!stricmp(typname, "text") || !stricmp(typname, "blob"))
|
||||
type = TYPE_STRING;
|
||||
else if (!stricmp(typname, "double") || !stricmp(typname, "float") ||
|
||||
!stricmp(typname, "real") || !stricmp(typname, "bigint") ||
|
||||
!stricmp(typname, "decimal") || !stricmp(typname, "numeric"))
|
||||
type = TYPE_FLOAT;
|
||||
else if (!stricmp(typname, "date") || !stricmp(typname, "datetime") ||
|
||||
!stricmp(typname, "time") || !stricmp(typname, "timestamp") ||
|
||||
!stricmp(typname, "year"))
|
||||
type = TYPE_DATE;
|
||||
else
|
||||
type = TYPE_ERROR;
|
||||
|
||||
return type;
|
||||
} // end of MYSQLtoPLG
|
||||
|
||||
/************************************************************************/
|
||||
/* Convert from PlugDB type to MySQL type number */
|
||||
/************************************************************************/
|
||||
enum enum_field_types PLGtoMYSQL(int type, bool gdf)
|
||||
{
|
||||
enum enum_field_types mytype;
|
||||
|
||||
switch (type) {
|
||||
case TYPE_INT:
|
||||
mytype = MYSQL_TYPE_LONG;
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
mytype = MYSQL_TYPE_SHORT;
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
mytype = MYSQL_TYPE_DOUBLE;
|
||||
break;
|
||||
case TYPE_DATE:
|
||||
mytype = (gdf) ? MYSQL_TYPE_DATE : MYSQL_TYPE_DATETIME;
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
mytype = MYSQL_TYPE_VARCHAR;
|
||||
break;
|
||||
default:
|
||||
mytype = MYSQL_TYPE_NULL;
|
||||
} // endswitch mytype
|
||||
|
||||
return mytype;
|
||||
} // end of PLGtoMYSQL
|
||||
|
||||
/************************************************************************/
|
||||
/* Convert from MySQL type to PlugDB type number */
|
||||
/************************************************************************/
|
||||
int MYSQLtoPLG(int mytype)
|
||||
{
|
||||
int type;
|
||||
|
||||
switch (mytype) {
|
||||
case MYSQL_TYPE_TINY:
|
||||
case MYSQL_TYPE_SHORT:
|
||||
type = TYPE_SHORT;
|
||||
break;
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_INT24:
|
||||
type = TYPE_INT;
|
||||
break;
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
#if !defined(ALPHA)
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
#endif // !ALPHA)
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
type = TYPE_FLOAT;
|
||||
break;
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_YEAR:
|
||||
case MYSQL_TYPE_TIME:
|
||||
type = TYPE_DATE;
|
||||
break;
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
#if !defined(ALPHA)
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
#endif // !ALPHA)
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
type = TYPE_STRING;
|
||||
break;
|
||||
default:
|
||||
type = TYPE_ERROR;
|
||||
} // endswitch mytype
|
||||
|
||||
return type;
|
||||
} // end of MYSQLtoPLG
|
||||
|
||||
/************************************************************************/
|
||||
/* Returns the format corresponding to a MySQL date type. */
|
||||
/************************************************************************/
|
||||
char *MyDateFmt(int mytype)
|
||||
{
|
||||
char *fmt;
|
||||
|
||||
switch (mytype) {
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
fmt = "YYYY-MM-DD hh:mm:ss";
|
||||
break;
|
||||
case MYSQL_TYPE_DATE:
|
||||
fmt = "YYYY-MM-DD";
|
||||
break;
|
||||
case MYSQL_TYPE_YEAR:
|
||||
fmt = "YYYY";
|
||||
break;
|
||||
case MYSQL_TYPE_TIME:
|
||||
fmt = "hh:mm:ss";
|
||||
break;
|
||||
default:
|
||||
fmt = NULL;
|
||||
} // endswitch mytype
|
||||
|
||||
return fmt;
|
||||
} // end of MyDateFmt
|
||||
|
||||
/************************************************************************/
|
||||
/* Returns the format corresponding to a MySQL date type. */
|
||||
/************************************************************************/
|
||||
char *MyDateFmt(char *typname)
|
||||
{
|
||||
char *fmt;
|
||||
|
||||
if (!stricmp(typname, "datetime") || !stricmp(typname, "timestamp"))
|
||||
fmt = "YYYY-MM-DD hh:mm:ss";
|
||||
else if (!stricmp(typname, "date"))
|
||||
fmt = "YYYY-MM-DD";
|
||||
else if (!stricmp(typname, "year"))
|
||||
fmt = "YYYY";
|
||||
else if (!stricmp(typname, "time"))
|
||||
fmt = "hh:mm:ss";
|
||||
else
|
||||
fmt = NULL;
|
||||
|
||||
return fmt;
|
||||
} // end of MyDateFmt
|
||||
|
||||
1856
storage/connect/odbconn.cpp
Normal file
1856
storage/connect/odbconn.cpp
Normal file
File diff suppressed because it is too large
Load Diff
184
storage/connect/odbconn.h
Normal file
184
storage/connect/odbconn.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/***********************************************************************/
|
||||
/* ODBConn.h : header file for the ODBC connection classes. */
|
||||
/***********************************************************************/
|
||||
//nclude <windows.h> /* Windows include file */
|
||||
//nclude <windowsx.h> /* Message crackers */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Included C-definition files required by the interface. */
|
||||
/***********************************************************************/
|
||||
#include "block.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC interface. */
|
||||
/***********************************************************************/
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constants and defines. */
|
||||
/***********************************************************************/
|
||||
// Miscellaneous sizing info
|
||||
#define MAX_NUM_OF_MSG 10 // Max number of error messages
|
||||
//efine MAX_CURRENCY 30 // Max size of Currency($) string
|
||||
#define MAX_TNAME_LEN 32 // Max size of table names
|
||||
//efine MAX_FNAME_LEN 256 // Max size of field names
|
||||
#define MAX_STRING_INFO 256 // Max size of string from SQLGetInfo
|
||||
//efine MAX_DNAME_LEN 256 // Max size of Recordset names
|
||||
#define MAX_CONNECT_LEN 512 // Max size of Connect string
|
||||
//efine MAX_CURSOR_NAME 18 // Max size of a cursor name
|
||||
#define DEFAULT_FIELD_TYPE SQL_TYPE_NULL // pick "C" data type to match SQL data type
|
||||
|
||||
#if !defined(WIN32)
|
||||
typedef unsigned char *PUCHAR;
|
||||
#endif // !WIN32
|
||||
|
||||
// Timeout and net wait defaults
|
||||
#define DEFAULT_LOGIN_TIMEOUT 15 // seconds to before fail on connect
|
||||
#define DEFAULT_QUERY_TIMEOUT 15 // seconds to before fail waiting for results
|
||||
|
||||
// Field Flags, used to indicate status of fields
|
||||
//efine SQL_FIELD_FLAG_DIRTY 0x1
|
||||
//efine SQL_FIELD_FLAG_NULL 0x2
|
||||
|
||||
// Update options flags
|
||||
#define SQL_SETPOSUPDATES 0x0001
|
||||
#define SQL_POSITIONEDSQL 0x0002
|
||||
//efine SQL_GDBOUND 0x0004
|
||||
|
||||
enum CATINFO {CAT_TAB = 1, /* SQLTables */
|
||||
CAT_COL = 2, /* SQLColumns */
|
||||
CAT_KEY = 3, /* SQLPrimaryKeys */
|
||||
CAT_STAT = 4, /* SQLStatistics */
|
||||
CAT_SPC = 5}; /* SQLSpecialColumns */
|
||||
|
||||
/***********************************************************************/
|
||||
/* This structure is used to control the catalog functions. */
|
||||
/***********************************************************************/
|
||||
typedef struct tagCATPARM {
|
||||
CATINFO Id; // Id to indicate function
|
||||
PQRYRES Qrp; // Result set pointer
|
||||
PUCHAR Tab; // Table name or pattern
|
||||
PUCHAR Pat; // Table type or column pattern
|
||||
SQLLEN* *Vlen; // To array of indicator values
|
||||
UWORD *Status; // To status block
|
||||
// For SQLStatistics
|
||||
UWORD Unique; // Index type
|
||||
UWORD Accuracy; // For Cardinality and Pages
|
||||
// For SQLSpecialColumns
|
||||
UWORD ColType;
|
||||
UWORD Scope;
|
||||
UWORD Nullable;
|
||||
} CATPARM;
|
||||
|
||||
// ODBC connection to a data source
|
||||
class TDBODBC;
|
||||
class ODBCCOL;
|
||||
class ODBConn;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class DBX (ODBC exception). */
|
||||
/***********************************************************************/
|
||||
class DBX : public BLOCK {
|
||||
friend class ODBConn;
|
||||
// Construction (by ThrowDBX only) -- destruction
|
||||
protected:
|
||||
DBX(RETCODE rc);
|
||||
public:
|
||||
//virtual ~DBX() {}
|
||||
//void operator delete(void*, PGLOBAL, void*) {};
|
||||
|
||||
// Implementation (use ThrowDBX to create)
|
||||
RETCODE GetRC(void) {return m_RC;}
|
||||
PSZ GetErrorMessage(int i)
|
||||
{return (i >=0 && i < MAX_NUM_OF_MSG) ? m_ErrMsg[i]
|
||||
: "No ODBC error";}
|
||||
protected:
|
||||
void BuildErrorMessage(ODBConn* pdb, HSTMT hstmt = SQL_NULL_HSTMT);
|
||||
|
||||
// Attributes
|
||||
RETCODE m_RC;
|
||||
PSZ m_ErrMsg[MAX_NUM_OF_MSG];
|
||||
}; // end of DBX class definition
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBConn class. */
|
||||
/***********************************************************************/
|
||||
class ODBConn : public BLOCK {
|
||||
friend class DBX;
|
||||
friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
|
||||
private:
|
||||
ODBConn(); // Standard (unused) constructor
|
||||
|
||||
public:
|
||||
ODBConn(PGLOBAL g, TDBODBC *tdbp);
|
||||
|
||||
enum DOP { // Db Open oPtions
|
||||
traceSQL = 0x0001, // Trace SQL calls
|
||||
openReadOnly = 0x0002, // Open database read only
|
||||
useCursorLib = 0x0004, // Use ODBC cursor lib
|
||||
noOdbcDialog = 0x0008, // Don't display ODBC Connect dialog
|
||||
forceOdbcDialog = 0x0010}; // Always display ODBC connect dialog
|
||||
|
||||
int Open(PSZ ConnectString, DWORD Options = 0);
|
||||
void Close(void);
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
char GetQuoteChar(void) {return m_IDQuoteChar;}
|
||||
// Database successfully opened?
|
||||
bool IsOpen(void) {return m_hdbc != SQL_NULL_HDBC;}
|
||||
PSZ GetStringInfo(ushort infotype);
|
||||
int GetMaxValue(ushort infotype);
|
||||
PSZ GetConnect(void) {return m_Connect;}
|
||||
|
||||
public:
|
||||
// Operations
|
||||
void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
|
||||
void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
|
||||
int GetResultSize(char *sql, ODBCCOL *colp);
|
||||
int ExecDirectSQL(char *sql, ODBCCOL *tocols);
|
||||
int Fetch(void);
|
||||
int PrepareSQL(char *sql);
|
||||
bool ExecuteSQL(void);
|
||||
bool BindParam(ODBCCOL *colp);
|
||||
int GetCatInfo(CATPARM *cap);
|
||||
|
||||
public:
|
||||
// Set special options
|
||||
void OnSetOptions(HSTMT hstmt);
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
// virtual ~ODBConn();
|
||||
|
||||
// ODBC operations
|
||||
protected:
|
||||
bool Check(RETCODE rc);
|
||||
void ThrowDBX(RETCODE rc, HSTMT hstmt = SQL_NULL_HSTMT);
|
||||
void ThrowDBX(PSZ msg);
|
||||
void AllocConnect(DWORD dwOptions);
|
||||
bool Connect(DWORD Options);
|
||||
void VerifyConnect(void);
|
||||
void GetConnectInfo(void);
|
||||
void Free(void);
|
||||
|
||||
protected:
|
||||
// Static members
|
||||
static HENV m_henv;
|
||||
static int m_nAlloc; // per-Appl reference to HENV above
|
||||
|
||||
// Members
|
||||
PGLOBAL m_G;
|
||||
TDBODBC *m_Tdb;
|
||||
HDBC m_hdbc;
|
||||
HSTMT m_hstmt;
|
||||
DWORD m_LoginTimeout;
|
||||
DWORD m_QueryTimeout;
|
||||
DWORD m_UpdateOptions;
|
||||
DWORD m_RowsetSize;
|
||||
int m_Catver;
|
||||
PSZ m_Connect;
|
||||
bool m_Updatable;
|
||||
char m_IDQuoteChar;
|
||||
}; // end of ODBConn class definition
|
||||
200
storage/connect/os2def.h
Normal file
200
storage/connect/os2def.h
Normal file
@@ -0,0 +1,200 @@
|
||||
|
||||
/****************************** Module Header ******************************/
|
||||
/* Module Name: OS2DEF.H */
|
||||
/* OS/2 Common Definitions file adapted for UNIX system. */
|
||||
/***************************************************************************/
|
||||
#ifndef __OS2DEFS__H__
|
||||
#define __OS2DEFS__H__
|
||||
#include "my_global.h"
|
||||
|
||||
#if 0
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#define CHAR char /* ch */
|
||||
#define SHORT short /* s */
|
||||
#if defined(BIT64)
|
||||
typedef int LONG; /* i */
|
||||
#else // BIT32
|
||||
typedef long LONG; /* l */
|
||||
#endif // BIT32
|
||||
#define INT int /* i */
|
||||
#define VOID void
|
||||
#undef HANDLE
|
||||
typedef void* LPVOID;
|
||||
typedef unsigned short *LPWSTR;
|
||||
typedef const unsigned short *LPCWSTR;
|
||||
|
||||
#if defined(UNIX) || defined(UNIV_LINUX) || defined(WIN32)
|
||||
typedef int bool; /* f */
|
||||
#elif !defined(WIN)
|
||||
typedef unsigned short bool; /* f */
|
||||
#else
|
||||
typedef unsigned short WBOOL; /* f */
|
||||
#define bool WBOOL
|
||||
#endif
|
||||
|
||||
typedef unsigned char UCHAR; /* uch */
|
||||
typedef unsigned short USHORT; /* us */
|
||||
#if defined(BIT64)
|
||||
typedef unsigned int ULONG; /* ul */
|
||||
#else // BIT32
|
||||
typedef unsigned long ULONG; /* ul */
|
||||
#endif // BIT32
|
||||
typedef unsigned int uint; /* ui */
|
||||
typedef unsigned char BYTE; /* b */
|
||||
typedef char *PSZ;
|
||||
typedef char *PCH;
|
||||
typedef const char *LPCSTR;
|
||||
typedef const char *LPCTSTR;
|
||||
typedef char *LPSTR;
|
||||
typedef char *LPTSTR;
|
||||
typedef CHAR *PCHAR;
|
||||
typedef SHORT *PSHORT;
|
||||
typedef ULONG DWORD;
|
||||
typedef USHORT WORD;
|
||||
#if defined(WIN)
|
||||
typedef int *WPLONG;
|
||||
typedef BYTE *WPBYTE;
|
||||
typedef INT *WPINT;
|
||||
#define PINT WPLONG
|
||||
#define PBYTE WPBYTE
|
||||
#define PINT WPINT
|
||||
#else
|
||||
//typedef int *PINT;
|
||||
typedef BYTE *PBYTE;
|
||||
typedef INT *PINT;
|
||||
#endif
|
||||
typedef UCHAR *PUCHAR;
|
||||
typedef USHORT *PUSHORT;
|
||||
typedef ULONG *PULONG;
|
||||
typedef uint *PUINT;
|
||||
typedef VOID *PVOID;
|
||||
typedef PVOID *PPVOID;
|
||||
typedef bool *PBOOL;
|
||||
|
||||
#if defined(UNIX) || defined(UNIV_LINUX)
|
||||
//#if !defined(MYSQL_DYNAMIC_PLUGIN)
|
||||
#ifndef min
|
||||
#define max(x,y) (((x)>(y))?(x):(y))
|
||||
#define min(x,y) (((x)<(y))?(x):(y))
|
||||
#endif // !MYSQL_DYNAMIC_PLUGIN
|
||||
#define FAR
|
||||
#define cdecl
|
||||
#define _MAX_PATH 260
|
||||
#define _MAX_DRIVE 3
|
||||
#define _MAX_DIR 256
|
||||
#define _MAX_FNAME 256
|
||||
#define _MAX_EXT 256
|
||||
#define INVALID_HANDLE_VALUE (-1)
|
||||
//#define FILE file
|
||||
//#if defined(LINUX)
|
||||
//typedef void *HANDLE;
|
||||
typedef int HANDLE;
|
||||
//#else
|
||||
#if !defined(MYSQL_DYNAMIC_PLUGIN)
|
||||
//typedef int HANDLE;
|
||||
#endif
|
||||
//#endif // !LINUX
|
||||
typedef long long __int64;
|
||||
//int getcwd(char *, int);
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#define _stricmp stricmp
|
||||
#define _strnicmp strnicmp
|
||||
#define _open open
|
||||
#define MAX_PATH 256
|
||||
|
||||
#ifdef LINUX
|
||||
//#define _fileno(p) __sfileno(p) to be clarified
|
||||
#endif // LINUX
|
||||
|
||||
#define __stdcall
|
||||
#else // !UNIX
|
||||
typedef LPVOID HANDLE;
|
||||
#if defined(__cplusplus)
|
||||
#if !defined(__MINMAX_DEFINED)
|
||||
#define __MINMAX_DEFINED
|
||||
#ifndef max
|
||||
#define max(x,y) (((x)>(y))?(x):(y))
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(x,y) (((x)<(y))?(x):(y))
|
||||
#endif
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
#if defined(WIN)
|
||||
#define FAR _far
|
||||
#define NEAR _near
|
||||
#define PASCAL _pascal
|
||||
#elif defined(WIN32)
|
||||
#define FAR
|
||||
#define NEAR
|
||||
#else
|
||||
#define PASCAL pascal
|
||||
#define FAR far
|
||||
#define NEAR near
|
||||
#endif
|
||||
#endif // !UNIX
|
||||
|
||||
typedef unsigned short SEL; /* sel */
|
||||
//typedef HANDLE HWND;
|
||||
#define HINSTANCE HANDLE;
|
||||
|
||||
#if defined(OS32)
|
||||
typedef SEL *PSEL;
|
||||
|
||||
/*** Useful Helper Macros */
|
||||
|
||||
/* Create untyped far pointer from selector and offset */
|
||||
#define MAKEP( sel,off ) (( void * )( void * _Seg16 )( (sel) << 16 | (off) ))
|
||||
#define MAKE16P( sel,off ) (( void * _Seg16 )( (sel) << 16 | (off) ))
|
||||
|
||||
/* Extract selector or offset from far pointer */
|
||||
#define SELECTOROF(ptr) ((((ULONG)(ptr))>>13)|7)
|
||||
#define OFFSETOF(p) (((PUSHORT)&(p))[0])
|
||||
#else
|
||||
typedef SEL FAR *PSEL;
|
||||
|
||||
/*** Useful Helper Macros */
|
||||
|
||||
/* Create untyped far pointer from selector and offset */
|
||||
#define MAKEP(sel, off) ((PVOID)MAKEULONG(off, sel))
|
||||
|
||||
/* Extract selector or offset from far pointer */
|
||||
#if !defined(ODBC)
|
||||
#define SELECTOROF(p) (((PUSHORT)&(p))[1])
|
||||
#define OFFSETOF(p) (((PUSHORT)&(p))[0])
|
||||
#endif
|
||||
|
||||
/* Combine l & h to form a 32 bit quantity. */
|
||||
#define MAKEULONG(l, h) ((ULONG)(((USHORT)(l)) | ((ULONG)((USHORT)(h))) << 16))
|
||||
#endif
|
||||
|
||||
#if defined(UNIX) || defined(UNIV_LINUX)
|
||||
#define FORMAT_MESSAGE_ALLOCATE_BUFFER 1
|
||||
#define FORMAT_MESSAGE_FROM_SYSTEM 2
|
||||
#define FORMAT_MESSAGE_IGNORE_INSERTS 4
|
||||
typedef const LPVOID LPCVOID;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DWORD FormatMessage(
|
||||
DWORD dwFlags,
|
||||
LPCVOID lpSource,
|
||||
DWORD dwMessageId,
|
||||
DWORD dwLanguageId,
|
||||
LPSTR lpBuffer,
|
||||
DWORD nSize, ...
|
||||
);
|
||||
unsigned long _filelength(int);
|
||||
void Sleep(DWORD);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // UNIX
|
||||
#endif // 0
|
||||
#endif // ! __OS2DEFS__H__
|
||||
/**************************** end of file **********************************/
|
||||
232
storage/connect/osutil.c
Normal file
232
storage/connect/osutil.c
Normal file
@@ -0,0 +1,232 @@
|
||||
#include "my_global.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "osutil.h"
|
||||
|
||||
#ifdef WIN32
|
||||
my_bool CloseFileHandle(HANDLE h)
|
||||
{
|
||||
return !CloseHandle(h);
|
||||
} /* end of CloseFileHandle */
|
||||
|
||||
#else /* UNIX */
|
||||
/* code to handle Linux and Solaris */
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
//#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define DWORD int
|
||||
extern FILE *debug;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Define some functions not existing in the UNIX library. */
|
||||
/***********************************************************************/
|
||||
PSZ strupr(PSZ p)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; p[i]; i++)
|
||||
p[i] = toupper(p[i]);
|
||||
|
||||
return (p);
|
||||
} /* end of strupr */
|
||||
|
||||
PSZ strlwr(PSZ p)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; p[i]; i++)
|
||||
p[i] = tolower(p[i]);
|
||||
|
||||
return (p);
|
||||
} /* end of strlwr */
|
||||
|
||||
#if defined(NOT_USED) /*&& !defined(sun) && !defined(LINUX) && !defined(AIX)*/
|
||||
/***********************************************************************/
|
||||
/* Define stricmp function not existing in some UNIX libraries. */
|
||||
/***********************************************************************/
|
||||
int stricmp(char *str1, char *str2)
|
||||
{
|
||||
register int i;
|
||||
int n;
|
||||
char c;
|
||||
char *sup1 = malloc(strlen(str1) + 1);
|
||||
char *sup2 = malloc(strlen(str2) + 1);
|
||||
|
||||
for (i = 0; c = str1[i]; i++)
|
||||
sup1[i] = toupper(c);
|
||||
|
||||
sup1[i] = 0;
|
||||
|
||||
for (i = 0; c = str2[i]; i++)
|
||||
sup2[i] = toupper(c);
|
||||
|
||||
sup2[i] = 0;
|
||||
n = strcmp(sup1, sup2);
|
||||
free(sup1);
|
||||
free(sup2);
|
||||
return (n);
|
||||
} /* end of stricmp */
|
||||
#endif /* sun */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Define the splitpath function not existing in the UNIX library. */
|
||||
/***********************************************************************/
|
||||
void _splitpath(LPCSTR name, LPSTR drive, LPSTR dir, LPSTR fn, LPSTR ft)
|
||||
{
|
||||
LPCSTR p2, p = name;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
fprintf(debug,"SplitPath: name=%s [%s (%d)]\n",
|
||||
XSTR(name), XSTR(__FILE__), __LINE__);
|
||||
#endif
|
||||
|
||||
if (drive) *drive = '\0';
|
||||
if (dir) *dir = '\0';
|
||||
if (fn) *fn = '\0';
|
||||
if (ft) *ft = '\0';
|
||||
|
||||
if ((p2 = strrchr(p, '/'))) {
|
||||
p2++;
|
||||
if (dir) strncat(dir, p, p2 - p);
|
||||
p = p2;
|
||||
} /* endif p2 */
|
||||
|
||||
if ((p2 = strrchr(p, '.'))) {
|
||||
if (fn) strncat(fn, p, p2 - p);
|
||||
if (ft) strcpy(ft, p2);
|
||||
} else
|
||||
if (fn) strcpy(fn, p);
|
||||
|
||||
#ifdef DEBTRACE
|
||||
fprintf(debug,"SplitPath: name=%s drive=%s dir=%s filename=%s type=%s [%s(%d)]\n",
|
||||
XSTR(name), XSTR(drive), XSTR(dir), XSTR(fn), XSTR(ft), __FILE__, __LINE__);
|
||||
#endif
|
||||
} /* end of _splitpath */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Define the makepath function not existing in the UNIX library. */
|
||||
/***********************************************************************/
|
||||
void _makepath(LPSTR name, LPCSTR drive, LPCSTR dir, LPCSTR fn, LPCSTR ft)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!name)
|
||||
return;
|
||||
else
|
||||
*name = '\0';
|
||||
|
||||
if (dir && (n = strlen(dir)) > 0) {
|
||||
strcpy(name, dir);
|
||||
|
||||
if (name[n-1] != '/')
|
||||
strcat(name, "/");
|
||||
|
||||
} /* endif dir */
|
||||
|
||||
if (fn)
|
||||
strcat(name, fn);
|
||||
|
||||
if (ft && strlen(ft)) {
|
||||
if (*ft != '.')
|
||||
strcat(name, ".");
|
||||
|
||||
strcat(name, ft);
|
||||
} /* endif ft */
|
||||
|
||||
} /* end of _makepath */
|
||||
|
||||
my_bool CloseFileHandle(HANDLE h)
|
||||
{
|
||||
return (close(h)) ? TRUE : FALSE;
|
||||
} /* end of CloseFileHandle */
|
||||
|
||||
void Sleep(DWORD time)
|
||||
{
|
||||
//FIXME: TODO
|
||||
} /* end of Sleep */
|
||||
|
||||
int GetLastError()
|
||||
{
|
||||
return errno;
|
||||
} /* end of GetLastError */
|
||||
|
||||
unsigned long _filelength(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
|
||||
if (fstat(fd, &st) != 0)
|
||||
return 0;
|
||||
|
||||
return st.st_size;
|
||||
} /* end of _filelength */
|
||||
|
||||
char *_fullpath(char *absPath, const char *relPath, size_t maxLength)
|
||||
{
|
||||
// Fixme
|
||||
char *p;
|
||||
|
||||
if( *relPath == '\\' || *relPath == '/' ) {
|
||||
strncpy(absPath, relPath, maxLength);
|
||||
} else if(*relPath == '~') {
|
||||
// get the path to the home directory
|
||||
// Fixme
|
||||
strncpy(absPath, relPath, maxLength);
|
||||
} else {
|
||||
char buff[2*_MAX_PATH];
|
||||
|
||||
getcwd(buff, _MAX_PATH);
|
||||
strcat(buff,"/");
|
||||
strcat(buff, relPath);
|
||||
strncpy(absPath, buff, maxLength);
|
||||
} /* endif's relPath */
|
||||
|
||||
p = absPath;
|
||||
|
||||
for(; *p; p++)
|
||||
if (*p == '\\')
|
||||
*p = '/';
|
||||
|
||||
return absPath;
|
||||
} /* end of _fullpath */
|
||||
|
||||
bool MessageBeep(uint i)
|
||||
{
|
||||
// Fixme
|
||||
return TRUE;
|
||||
} /* end of MessageBeep */
|
||||
|
||||
LPSTR _strerror(int errn)
|
||||
{
|
||||
static char buff[256];
|
||||
|
||||
sprintf(buff,"error: %d", errn);
|
||||
return buff;
|
||||
} /* end of _strerror */
|
||||
|
||||
int _isatty(int fileNo)
|
||||
{
|
||||
return isatty(fileNo);
|
||||
} /* end of _isatty */
|
||||
|
||||
/* This function is ridiculous and should be revisited */
|
||||
DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
|
||||
DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, ...)
|
||||
{
|
||||
char buff[32];
|
||||
int n;
|
||||
|
||||
//if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
||||
// return 0; /* means error */
|
||||
|
||||
n = sprintf(buff, "Error code: %d", dwMessageId);
|
||||
strncpy(lpBuffer, buff, nSize);
|
||||
return min(n, nSize);
|
||||
} /* end of FormatMessage */
|
||||
|
||||
#endif // UNIX
|
||||
121
storage/connect/osutil.h
Normal file
121
storage/connect/osutil.h
Normal file
@@ -0,0 +1,121 @@
|
||||
#ifndef __OSUTIL_H__
|
||||
#define __OSUTIL_H__
|
||||
|
||||
#if defined(UNIX) || defined(UNIV_LINUX)
|
||||
#include "my_global.h"
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef const void *LPCVOID;
|
||||
typedef const char *LPCTSTR;
|
||||
typedef const char *LPCSTR;
|
||||
typedef unsigned char BYTE;
|
||||
typedef char *LPSTR;
|
||||
typedef char *LPTSTR;
|
||||
typedef char *PSZ;
|
||||
typedef int INT;
|
||||
//typedef int DWORD;
|
||||
#undef HANDLE
|
||||
typedef int HANDLE;
|
||||
#ifdef __cplusplus
|
||||
//typedef int bool;
|
||||
#else
|
||||
#define bool my_bool
|
||||
#endif
|
||||
#define _MAX_PATH PATH_MAX
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#define MB_OK 0x00000000
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#if !defined(__MINMAX_DEFINED)
|
||||
#define __MINMAX_DEFINED
|
||||
#ifndef max
|
||||
#define max(x,y) (((x)>(y))?(x):(y))
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(x,y) (((x)<(y))?(x):(y))
|
||||
#endif
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int GetLastError();
|
||||
void _splitpath(const char*, char*, char*, char*, char*);
|
||||
void _makepath(char*, const char*, const char*, const char*, const char*);
|
||||
char *_fullpath(char *absPath, const char *relPath, size_t maxLength);
|
||||
bool MessageBeep(uint);
|
||||
unsigned long _filelength(int fd);
|
||||
|
||||
int GetPrivateProfileString(
|
||||
LPCTSTR lpAppName, // section name
|
||||
LPCTSTR lpKeyName, // key name
|
||||
LPCTSTR lpDefault, // default string
|
||||
LPTSTR lpReturnedString, // destination buffer
|
||||
int nSize, // size of destination buffer
|
||||
LPCTSTR lpFileName // initialization file name
|
||||
);
|
||||
|
||||
uint GetPrivateProfileInt(
|
||||
LPCTSTR lpAppName, // section name
|
||||
LPCTSTR lpKeyName, // key name
|
||||
INT nDefault, // return value if key name not found
|
||||
LPCTSTR lpFileName // initialization file name
|
||||
);
|
||||
|
||||
bool WritePrivateProfileString(
|
||||
LPCTSTR lpAppName, // section name
|
||||
LPCTSTR lpKeyName, // key name
|
||||
LPCTSTR lpString, // string to add
|
||||
LPCTSTR lpFileName // initialization file
|
||||
);
|
||||
|
||||
int GetPrivateProfileSection(
|
||||
LPCTSTR lpAppName, // section name
|
||||
LPTSTR lpReturnedString, // return buffer
|
||||
int nSize, // size of return buffer
|
||||
LPCTSTR lpFileName // initialization file name
|
||||
);
|
||||
|
||||
bool WritePrivateProfileSection(
|
||||
LPCTSTR lpAppName, // section name
|
||||
LPCTSTR lpString, // data
|
||||
LPCTSTR lpFileName // file name
|
||||
);
|
||||
|
||||
PSZ strupr(PSZ s);
|
||||
PSZ strlwr(PSZ s);
|
||||
|
||||
typedef size_t FILEPOS;
|
||||
//pedef int FILEHANDLE; // UNIX
|
||||
|
||||
#ifndef _MAX_PATH
|
||||
#define MAX_PATH 256
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* WINDOWS */
|
||||
#include <windows.h>
|
||||
|
||||
typedef __int64 FILEPOS;
|
||||
//pedef HANDLE FILEHANDLE; // Win32
|
||||
|
||||
#endif /* WINDOWS */
|
||||
|
||||
#define XSTR(x) ((x)?(x):"<null>")
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OSUTIL_H__ */
|
||||
218
storage/connect/plgcnx.h
Normal file
218
storage/connect/plgcnx.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/**************************************************************************/
|
||||
/* PLGCNX.H */
|
||||
/* Copyright to the author: Olivier Bertrand 2000-2012 */
|
||||
/* */
|
||||
/* This is the connection DLL's declares. */
|
||||
/**************************************************************************/
|
||||
#if !defined(_PLGCNX_H)
|
||||
#define _PLGCNX_H
|
||||
|
||||
#define MAXMSGLEN 65512 /* Default max length of cnx message */
|
||||
#define MAXERRMSG 512 /* Max length of error messages */
|
||||
#define MAXMESSAGE 256 /* Max length of returned messages */
|
||||
#define MAXDBNAME 128 /* Max length of DB related names */
|
||||
|
||||
/**************************************************************************/
|
||||
/* API Function return codes. */
|
||||
/**************************************************************************/
|
||||
enum FNRC {RC_LICENSE = 7, /* PLGConnect prompt for license key */
|
||||
RC_PASSWD = 6, /* PLGConnect prompt for User/Pwd */
|
||||
RC_SUCWINFO = 5, /* Succes With Info return code */
|
||||
RC_SOCKET = 4, /* RC from PLGConnect to socket DLL */
|
||||
RC_PROMPT = 3, /* Intermediate prompt return */
|
||||
RC_CANCEL = 2, /* Command was cancelled by user */
|
||||
RC_PROGRESS = 1, /* Intermediate progress info */
|
||||
RC_SUCCESS = 0, /* Successful function (must be 0) */
|
||||
RC_MEMORY = -1, /* Storage allocation error */
|
||||
RC_TRUNCATED = -2, /* Result has been truncated */
|
||||
RC_TIMEOUT = -3, /* Connection timeout occured */
|
||||
RC_TOOBIG = -4, /* Data is too big for connection */
|
||||
RC_KEY = -5, /* Null ptr to key in Connect */
|
||||
/* or bad key in other functions */
|
||||
RC_MAXCONN = -6, /* Too many conn's for one process */
|
||||
RC_MAXCLIENT = -7, /* Too many clients for one system */
|
||||
RC_SYNCHRO = -8, /* Synchronization error */
|
||||
RC_SERVER = -9, /* Error related to the server */
|
||||
RC_MAXCOL = -10, /* Result has too many columns */
|
||||
RC_LAST = -10}; /* Other error codes are < this and */
|
||||
/* are system errors. */
|
||||
|
||||
/**************************************************************************/
|
||||
/* Standard function return codes. */
|
||||
/**************************************************************************/
|
||||
#if !defined(RC_OK_DEFINED)
|
||||
#define RC_OK_DEFINED
|
||||
enum RCODE {RC_OK = 0, /* No error return code */
|
||||
RC_NF = 1, /* Not found return code */
|
||||
RC_EF = 2, /* End of file return code */
|
||||
RC_FX = 3, /* Error return code */
|
||||
RC_INFO = 4}; /* Success with info */
|
||||
#endif // !RC_OK_DEFINED
|
||||
|
||||
/**************************************************************************/
|
||||
/* Data types. */
|
||||
/**************************************************************************/
|
||||
enum XDBTYPE {DB_ERROR = 0, /* Unknown or wrong type */
|
||||
DB_STRING = 1, /* Null terminated string */
|
||||
DB_CHAR = 2, /* Character array */
|
||||
DB_SHORT = 3, /* Used by some catalog functions */
|
||||
DB_INT = 4, /* Long integer array */
|
||||
DB_DOUBLE = 5, /* Double float array */
|
||||
DB_DATE = 6}; /* Datetime value array */
|
||||
|
||||
/**************************************************************************/
|
||||
/* Index of info values within the info int integer array. */
|
||||
/**************************************************************************/
|
||||
enum INFO {INDX_RC, /* Index of PlugDB return code field */
|
||||
INDX_TIME, /* Index of elapsed time in millisec */
|
||||
INDX_CHG, /* Index of Language or DB changed */
|
||||
INDX_RSAV, /* Index of Result Set availability */
|
||||
INDX_TYPE, /* Index of returned data type field */
|
||||
INDX_LINE, /* Index of number of lines field */
|
||||
INDX_LEN, /* Index of line length field */
|
||||
INDX_SIZE, /* Index of returned data size field */
|
||||
INDX_MAX}; /* Size of info array */
|
||||
|
||||
/**************************************************************************/
|
||||
/* Internal message types. */
|
||||
/**************************************************************************/
|
||||
enum MSGTYP {MST_OPEN = 10, /* Code for old connecting message */
|
||||
MST_COMMAND = 11, /* Code for send command message */
|
||||
MST_RESULT = 12, /* Code for get result message */
|
||||
MST_CLOSE = 13, /* Code for disconnecting message */
|
||||
MST_PROGRESS = 14, /* Code for progress message */
|
||||
MST_CANCEL = 15, /* Code for cancel message */
|
||||
MST_PROCESSED = 16, /* Code for already processed msg */
|
||||
MST_ERROR = 17, /* Code for get error message */
|
||||
MST_CHAR = 18, /* Code for get char value message */
|
||||
MST_LONG = 19, /* Code for get int value message */
|
||||
MST_COLUMN = 20, /* Code for get col value message */
|
||||
MST_MESSAGE = 21, /* Code for get message message */
|
||||
MST_HEADER = 22, /* Code for get header message */
|
||||
MST_SOCKET = 23, /* Code for socket error message */
|
||||
MST_SHUTDOWN = 24, /* Code for shutdown message */
|
||||
MST_SOCKPROG = 25, /* Code for socket progress message */
|
||||
MST_POST = 26, /* Code for post command message */
|
||||
MST_NEW_OPEN = 27, /* Code for new connecting message */
|
||||
MST_PROG_NUM = 5}; /* Num of integers in progress msg */
|
||||
|
||||
/**************************************************************************/
|
||||
/* Vendors. */
|
||||
/**************************************************************************/
|
||||
enum VENDOR {VDR_UNKNOWN = -2, /* Not known or not connected */
|
||||
VDR_PlugDB = -1, /* PlugDB */
|
||||
VDR_OTHER = 0}; /* OEM */
|
||||
|
||||
/**************************************************************************/
|
||||
/* Attribute keys of Result Description structure (arranged by type). */
|
||||
/**************************************************************************/
|
||||
enum CKEYS {K_ProgMsg, K_Lang, K_ActiveDB, K_Cmax};
|
||||
enum LKEYS {K_NBcol, K_NBlin, K_CurPos, K_RC, K_Result, K_Elapsed,
|
||||
K_Continued, K_Maxsize, K_Lmax, K_Maxcol,
|
||||
K_Maxres, K_Maxlin, K_NBparm};
|
||||
enum NKEYS {K_Type, K_Length, K_Prec, K_DataLen, K_Nmax};
|
||||
|
||||
/**************************************************************************/
|
||||
/* Result description structures. */
|
||||
/**************************************************************************/
|
||||
typedef struct _MsgTagAttr {
|
||||
bool fSupplied;
|
||||
char Attr[MAXMESSAGE];
|
||||
} MTAG, *PMTAG;
|
||||
|
||||
typedef struct _CharTagAttr {
|
||||
bool fSupplied;
|
||||
char Attr[MAXDBNAME];
|
||||
} CTAG, *PCTAG;
|
||||
|
||||
typedef struct _LongTagAttr {
|
||||
bool fSupplied;
|
||||
int Attr;
|
||||
} LTAG, *PLTAG;
|
||||
|
||||
typedef struct _ColVar {
|
||||
LTAG Lat[K_Nmax];
|
||||
CTAG Cat;
|
||||
} COLVAR, *LPCOLVAR;
|
||||
|
||||
typedef struct _ResDesc {
|
||||
int Maxcol; /* Max number of columns */
|
||||
int Colnum; /* Number of columns */
|
||||
MTAG Mat; /* Message */
|
||||
CTAG Cat[K_Cmax]; /* Character attributes */
|
||||
LTAG Lat[K_Lmax]; /* Long int attributes */
|
||||
COLVAR Col[1]; /* Column attributes */
|
||||
} RDESC, *PRDESC;
|
||||
|
||||
/**************************************************************************/
|
||||
/* Exported PlugDB client functions in Plgcnx DLL. */
|
||||
/**************************************************************************/
|
||||
#if !defined(CNXFUNC)
|
||||
#if defined(UNIX) || defined(UNIV_LINUX)
|
||||
#undef __stdcall
|
||||
#define __stdcall
|
||||
#endif
|
||||
|
||||
#if defined(NOLIB) /* Dynamic link of plgcnx.dll */
|
||||
#define CNXFUNC(f) (__stdcall *f)
|
||||
#else /* LIB */ /* Static link with plgcnx.lib */
|
||||
#define CNXFUNC(f) __stdcall f
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(CNXKEY)
|
||||
#define CNXKEY uint
|
||||
#endif
|
||||
|
||||
#if !defined(XTRN)
|
||||
#define XTRN
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
//#if !defined(NO_FUNC)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
XTRN int CNXFUNC(PLGConnect) (CNXKEY *, const char *, bool);
|
||||
XTRN int CNXFUNC(PLGSendCommand) (CNXKEY, const char *, void *, int, int *);
|
||||
XTRN int CNXFUNC(PLGGetResult) (CNXKEY, void *, int, int *, bool);
|
||||
XTRN int CNXFUNC(PLGDisconnect) (CNXKEY);
|
||||
XTRN int CNXFUNC(PLGGetErrorMsg) (CNXKEY, char *, int, int *);
|
||||
XTRN bool CNXFUNC(PLGGetCharValue)(CNXKEY, char *, int, int);
|
||||
XTRN bool CNXFUNC(PLGGetIntValue)(CNXKEY, int *, int);
|
||||
XTRN bool CNXFUNC(PLGGetColValue) (CNXKEY, int *, int, int);
|
||||
XTRN bool CNXFUNC(PLGGetMessage) (CNXKEY, char *, int);
|
||||
XTRN bool CNXFUNC(PLGGetHeader) (CNXKEY, char *, int, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
//#endif /* !NO_FUNC */
|
||||
|
||||
/**************************************************************************/
|
||||
/* Convenience function Definitions */
|
||||
/**************************************************************************/
|
||||
#define PLGPostCommand(T,C) PLGSendCommand(T,C,NULL,0,NULL)
|
||||
#if defined(FNCMAC)
|
||||
#define PLGGetProgMsg(T,C,S) PLGGetCharValue(T,C,S,K_ProgMsg)
|
||||
#define PLGGetLangID(T,C,S) PLGGetCharValue(T,C,S,K_Lang)
|
||||
#define PLGGetActiveDB(T,C,S) PLGGetCharValue(T,C,S,K_ActiveDB)
|
||||
#define PLGGetCursorPos(T,L) PLGGetIntValue(T,L,K_CurPos)
|
||||
#define PLGGetResultType(T,L) PLGGetIntValue(T,L,K_Result)
|
||||
#define PLGGetNBcol(T,L) PLGGetIntValue(T,L,K_NBcol)
|
||||
#define PLGGetNBlin(T,L) PLGGetIntValue(T,L,K_NBlin)
|
||||
#define PLGGetRetCode(T,L) PLGGetIntValue(T,L,K_RC)
|
||||
#define PLGGetElapsed(T,L) PLGGetIntValue(T,L,K_Elapsed)
|
||||
#define PLGGetContinued(T,L) PLGGetIntValue(T,L,K_Continued)
|
||||
#define PLGGetMaxSize(T,L) PLGGetIntValue(T,L,K_Maxsize)
|
||||
#define PLGGetLength(T,L,C) PLGGetColValue(T,L,K_Length,C)
|
||||
#define PLGGetDataSize(T,L,C) PLGGetColValue(T,L,K_DataLen,C)
|
||||
#define PLGGetDecimal(T,L,C) PLGGetColValue(T,L,K_Prec,C)
|
||||
#define PLGGetType(T,L,C) PLGGetColValue(T,L,K_Type,C)
|
||||
#endif /* FNCMAC */
|
||||
#endif // NOT_USED
|
||||
|
||||
#endif /* !_PLGCNX_H */
|
||||
|
||||
/* ------------------------- End of Plgcnx.h ---------------------------- */
|
||||
510
storage/connect/plgdbsem.h
Normal file
510
storage/connect/plgdbsem.h
Normal file
@@ -0,0 +1,510 @@
|
||||
/************** PlgDBSem H Declares Source Code File (.H) **************/
|
||||
/* Name: PLGDBSEM.H Version 3.5 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
|
||||
/* */
|
||||
/* This file contains the PlugDB++ application type definitions. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/***********************************************************************/
|
||||
#include "checklvl.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* DB Constant definitions. */
|
||||
/***********************************************************************/
|
||||
#if defined(FRENCH)
|
||||
#define DEFAULT_LOCALE "French"
|
||||
#else // !FRENCH
|
||||
#define DEFAULT_LOCALE "English"
|
||||
#endif // !FRENCH
|
||||
|
||||
#define DOS_MAX_PATH 144 /* Must be the same across systems */
|
||||
#define DOS_BUFF_LEN 100 /* Number of lines in binary file buffer */
|
||||
#undef DOMAIN /* For Unix version */
|
||||
|
||||
enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Correl Block */
|
||||
TYPE_COLUMN = 51, /* Column Name/Correl Block */
|
||||
// TYPE_OPVAL = 52, /* Operator value (OPVAL) */
|
||||
TYPE_TDB = 53, /* Table Description Block */
|
||||
TYPE_COLBLK = 54, /* Column Description Block */
|
||||
TYPE_PSZ = 64, /* Pointer to String ended by 0 */
|
||||
TYPE_SQL = 65, /* Pointer to SQL block */
|
||||
TYPE_XOBJECT = 69, /* Extended DB object */
|
||||
TYPE_COLCRT = 71, /* Column creation block */
|
||||
TYPE_CONST = 72, /* Constant */
|
||||
// TYPE_INDEXDEF = 73, /* Index definition block */
|
||||
// TYPE_OPER = 74, /* Operator block (OPER) */
|
||||
|
||||
/*-------------------- type tokenized string --------------------------*/
|
||||
TYPE_DATE = 8, /* Timestamp */
|
||||
/*-------------------- additional values used by LNA ------------------*/
|
||||
TYPE_COLIST = 14, /* Column list */
|
||||
TYPE_COL = 41, /* Column */
|
||||
/*-------------------- types used by scalar functions -----------------*/
|
||||
TYPE_NUM = 12,
|
||||
TYPE_UNDEF = 13,
|
||||
/*-------------------- file blocks used when closing ------------------*/
|
||||
TYPE_FB_FILE = 22, /* File block (stream) */
|
||||
TYPE_FB_MAP = 23, /* Mapped file block (storage) */
|
||||
TYPE_FB_HANDLE = 24, /* File block (handle) */
|
||||
TYPE_FB_XML = 21, /* DOM XML file block */
|
||||
TYPE_FB_XML2 = 27}; /* libxml2 XML file block */
|
||||
|
||||
enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
|
||||
TYPE_AM_ROWID = 1, /* ROWID type (special column) */
|
||||
TYPE_AM_FILID = 2, /* FILEID type (special column) */
|
||||
TYPE_AM_TAB = 3, /* Table (any type) */
|
||||
TYPE_AM_VIEW = 4, /* VIEW (any type) */
|
||||
TYPE_AM_SRVID = 5, /* SERVID type (special column) */
|
||||
TYPE_AM_TABID = 6, /* TABID type (special column) */
|
||||
TYPE_AM_CNSID = 7, /* CONSTID type (special column) */
|
||||
TYPE_AM_COUNT = 10, /* CPT AM type no (count table) */
|
||||
TYPE_AM_DCD = 20, /* Decode access method type no */
|
||||
TYPE_AM_CMS = 30, /* CMS access method type no */
|
||||
TYPE_AM_MAP = 32, /* MAP access method type no */
|
||||
TYPE_AM_FMT = 33, /* DOS files with formatted recs */
|
||||
TYPE_AM_CSV = 34, /* DOS files with CSV records */
|
||||
TYPE_AM_MCV = 35, /* MAP files with CSV records */
|
||||
TYPE_AM_DOS = 36, /* DOS am with Lrecl = V */
|
||||
TYPE_AM_FIX = 38, /* DOS am with Lrecl = F */
|
||||
TYPE_AM_BIN = 39, /* DOS am with Lrecl = B */
|
||||
TYPE_AM_VCT = 40, /* VCT access method type no */
|
||||
TYPE_AM_VMP = 43, /* VMP access method type no */
|
||||
TYPE_AM_QRY = 50, /* QRY access method type no */
|
||||
TYPE_AM_QRS = 51, /* QRYRES access method type no */
|
||||
TYPE_AM_SQL = 60, /* SQL VIEW access method type */
|
||||
TYPE_AM_PLG = 70, /* PLG access method type no */
|
||||
TYPE_AM_PLM = 71, /* PDM access method type no */
|
||||
TYPE_AM_DOM = 80, /* DOM access method type no */
|
||||
TYPE_AM_DIR = 90, /* DIR access method type no */
|
||||
TYPE_AM_ODBC = 100, /* ODBC access method type no */
|
||||
TYPE_AM_OEM = 110, /* OEM access method type no */
|
||||
TYPE_AM_TBL = 115, /* TBL access method type no */
|
||||
TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
|
||||
TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
|
||||
TYPE_AM_FNC = 122, /* PIVOT source column type no */
|
||||
TYPE_AM_XTB = 130, /* SYS table access method type */
|
||||
TYPE_AM_MAC = 137, /* MAC table access method type */
|
||||
TYPE_AM_WMI = 139, /* WMI table access method type */
|
||||
TYPE_AM_XCL = 140, /* SYS column access method type */
|
||||
TYPE_AM_INI = 150, /* INI files access method */
|
||||
TYPE_AM_TFC = 155, /* TFC (Circa) (Fuzzy compare) */
|
||||
TYPE_AM_DBF = 160, /* DBF Dbase files am type no */
|
||||
TYPE_AM_JCT = 170, /* Junction tables am type no */
|
||||
TYPE_AM_DMY = 172, /* DMY Dummy tables am type no */
|
||||
TYPE_AM_SET = 180, /* SET Set tables am type no */
|
||||
TYPE_AM_MYSQL = 192, /* MYSQL access method type no */
|
||||
TYPE_AM_OUT = 200}; /* Output relations (storage) */
|
||||
|
||||
enum RECFM {RECFM_NAF = -2, /* Not a file */
|
||||
RECFM_OEM = -1, /* OEM file access method */
|
||||
RECFM_VAR = 0, /* Varying length DOS files */
|
||||
RECFM_FIX = 1, /* Fixed length DOS files */
|
||||
RECFM_BIN = 2, /* Binary DOS files (also fixed) */
|
||||
RECFM_VCT = 3, /* VCT formatted files */
|
||||
RECFM_ODBC = 4, /* Table accessed via ODBC */
|
||||
RECFM_PLG = 5, /* Table accessed via PLGconn */
|
||||
RECFM_DBF = 6}; /* DBase formatted file */
|
||||
|
||||
#if 0
|
||||
enum MISC {DB_TABNO = 1, /* DB routines in Utility Table */
|
||||
MAX_MULT_KEY = 10, /* Max multiple key number */
|
||||
NAM_LEN = 128, /* Length of col and tab names */
|
||||
ARRAY_SIZE = 50, /* Default array block size */
|
||||
MAXRES = 500, /* Default maximum result lines */
|
||||
MAXLIN = 10000, /* Default maximum data lines */
|
||||
MAXBMP = 32}; /* Default XDB2 max bitmap size */
|
||||
|
||||
enum ALGMOD {AMOD_AUTO = 0, /* PLG chooses best algorithm */
|
||||
AMOD_SQL = 1, /* Use SQL algorithm */
|
||||
AMOD_QRY = 2}; /* Use QUERY algorithm */
|
||||
#else // !0
|
||||
#define NAM_LEN 128
|
||||
#endif // !0
|
||||
|
||||
enum MODE {MODE_ANY = 0, /* Unspecified mode */
|
||||
MODE_READ = 10, /* Input/Output mode */
|
||||
MODE_WRITE = 20, /* Input/Output mode */
|
||||
MODE_UPDATE = 30, /* Input/Output mode */
|
||||
MODE_INSERT = 40, /* Input/Output mode */
|
||||
MODE_DELETE = 50}; /* Input/Output mode */
|
||||
|
||||
#if !defined(RC_OK_DEFINED)
|
||||
#define RC_OK_DEFINED
|
||||
enum RCODE {RC_OK = 0, /* No error return code */
|
||||
RC_NF = 1, /* Not found return code */
|
||||
RC_EF = 2, /* End of file return code */
|
||||
RC_FX = 3, /* Error return code */
|
||||
RC_INFO = 4}; /* Success with info */
|
||||
#endif // !RC_OK_DEFINED
|
||||
|
||||
enum OPVAL {OP_EQ = 1, /* Filtering operator = */
|
||||
OP_NE = 2, /* Filtering operator != */
|
||||
OP_GT = 3, /* Filtering operator > */
|
||||
OP_GE = 4, /* Filtering operator >= */
|
||||
OP_LT = 5, /* Filtering operator < */
|
||||
OP_LE = 6, /* Filtering operator <= */
|
||||
OP_IN = 7, /* Filtering operator IN */
|
||||
OP_NULL = 8, /* Filtering operator IS NULL */
|
||||
OP_EXIST = 9, /* Filtering operator EXISTS */
|
||||
OP_LIKE = 10, /* Filtering operator LIKE */
|
||||
OP_LOJ = -1, /* Filter op LEFT OUTER JOIN */
|
||||
OP_ROJ = -2, /* Filter op RIGHT OUTER JOIN */
|
||||
OP_DTJ = -3, /* Filter op DISTINCT JOIN */
|
||||
OP_XX = 11, /* Filtering operator unknown */
|
||||
OP_AND = 12, /* Filtering operator AND */
|
||||
OP_OR = 13, /* Filtering operator OR */
|
||||
OP_CNC = 14, /* Expression Concat operator */
|
||||
OP_NOT = 15, /* Filtering operator NOT */
|
||||
OP_SEP = 20, /* Filtering separator */
|
||||
OP_ADD = 16, /* Expression Add operator */
|
||||
OP_SUB = 17, /* Expression Substract operator */
|
||||
OP_MULT = 18, /* Expression Multiply operator */
|
||||
OP_DIV = 19, /* Expression Divide operator */
|
||||
OP_NOP = 21, /* Scalar function is nopped */
|
||||
OP_NUM = 22, /* Scalar function Op Num */
|
||||
OP_ABS = 23, /* Scalar function Op Abs */
|
||||
OP_MAX = 24, /* Scalar function Op Max */
|
||||
OP_MIN = 25, /* Scalar function Op Min */
|
||||
OP_CEIL = 26, /* Scalar function Op Ceil */
|
||||
OP_FLOOR = 27, /* Scalar function Op Floor */
|
||||
OP_MOD = 28, /* Scalar function Op Mod */
|
||||
OP_ROUND = 29, /* Scalar function Op Round */
|
||||
OP_SIGN = 30, /* Scalar function Op Sign */
|
||||
OP_LEN = 31, /* Scalar function Op Len */
|
||||
OP_INSTR = 32, /* Scalar function Op Instr */
|
||||
OP_LEFT = 33, /* Scalar function Op Left */
|
||||
OP_RIGHT = 34, /* Scalar function Op Right */
|
||||
OP_ASCII = 35, /* Scalar function Op Ascii */
|
||||
OP_EXP = 36, /* Scalar function Op Exp */
|
||||
OP_LN = 37, /* Scalar function Op Ln */
|
||||
OP_LOG = 38, /* Scalar function Op Log */
|
||||
OP_POWER = 39, /* Scalar function Op Power */
|
||||
OP_SQRT = 40, /* Scalar function Op Sqrt */
|
||||
OP_COS = 41, /* Scalar function Op Cos */
|
||||
OP_COSH = 42, /* Scalar function Op Cosh */
|
||||
OP_SIN = 43, /* Scalar function Op Sin */
|
||||
OP_SINH = 44, /* Scalar function Op Sinh */
|
||||
OP_TAN = 45, /* Scalar function Op Tan */
|
||||
OP_TANH = 46, /* Scalar function Op Tanh */
|
||||
OP_USER = 47, /* Scalar function Op User */
|
||||
OP_CHAR = 48, /* Scalar function Op Char */
|
||||
OP_UPPER = 49, /* Scalar function Op Upper */
|
||||
OP_LOWER = 50, /* Scalar function Op Lower */
|
||||
OP_RPAD = 51, /* Scalar function Op Rpad */
|
||||
OP_LPAD = 52, /* Scalar function Op Lpad */
|
||||
OP_LTRIM = 53, /* Scalar function Op Ltrim */
|
||||
OP_RTRIM = 54, /* Scalar function Op Rtrim */
|
||||
OP_REPL = 55, /* Scalar function Op Replace */
|
||||
OP_SUBST = 56, /* Scalar function Op Substr */
|
||||
OP_LJUST = 57, /* Scalar function Op Ljustify */
|
||||
OP_RJUST = 58, /* Scalar function Op Rjustify */
|
||||
OP_CJUST = 59, /* Scalar function Op Cjustify */
|
||||
OP_ENCODE = 60, /* Scalar function Op Encode */
|
||||
OP_DECODE = 61, /* Scalar function Op Decode */
|
||||
OP_SEQU = 62, /* Scalar function Op Sequence */
|
||||
OP_IF = 63, /* Scalar function Op If */
|
||||
OP_STRING = 64, /* Scalar function Op String */
|
||||
OP_TOKEN = 65, /* Scalar function Op Token */
|
||||
OP_SNDX = 66, /* Scalar function Op Soundex */
|
||||
OP_DATE = 67, /* Scalar function Op Date */
|
||||
OP_MDAY = 68, /* Scalar function Op Month Day */
|
||||
OP_MONTH = 69, /* Scalar function Op Month of */
|
||||
OP_YEAR = 70, /* Scalar function Op Year of */
|
||||
OP_WDAY = 71, /* Scalar function Op Week Day */
|
||||
OP_YDAY = 72, /* Scalar function Op Year Day */
|
||||
OP_DBTWN = 73, /* Scalar function Op Days betwn */
|
||||
OP_MBTWN = 74, /* Scalar function Op Months btw */
|
||||
OP_YBTWN = 75, /* Scalar function Op Years btwn */
|
||||
OP_ADDAY = 76, /* Scalar function Op Add Days */
|
||||
OP_ADDMTH = 77, /* Scalar function Op Add Months */
|
||||
OP_ADDYR = 78, /* Scalar function Op Add Years */
|
||||
OP_NXTDAY = 79, /* Scalar function Op Next Day */
|
||||
OP_SYSDT = 80, /* Scalar function Op SysDate */
|
||||
OP_DELTA = 81, /* Scalar function Op Delta */
|
||||
OP_LAST = 82, /* Scalar function Op Last */
|
||||
OP_IFF = 83, /* Scalar function Op Iff */
|
||||
OP_MAVG = 84, /* Scalar function Op Moving Avg */
|
||||
OP_VWAP = 85, /* Scalar function Op VWAP */
|
||||
OP_TIME = 86, /* Scalar function Op TIME */
|
||||
OP_SETLEN = 87, /* Scalar function Op Set Length */
|
||||
OP_TRANSL = 88, /* Scalar function Op Translate */
|
||||
OP_BITAND = 89, /* Expression BitAnd operator */
|
||||
OP_BITOR = 90, /* Expression BitOr operator */
|
||||
OP_BITXOR = 91, /* Expression XOR operator */
|
||||
OP_BITNOT = 92, /* Expression Complement operator*/
|
||||
OP_CNTIN = 93, /* Scalar function Count In */
|
||||
OP_FDISK = 94, /* Scalar function Disk of fileid*/
|
||||
OP_FPATH = 95, /* Scalar function Path of fileid*/
|
||||
OP_FNAME = 96, /* Scalar function Name of fileid*/
|
||||
OP_FTYPE = 97, /* Scalar function Type of fileid*/
|
||||
OP_XDATE = 98, /* Scalar function Op Fmt Date */
|
||||
OP_SWITCH = 99, /* Scalar function Op Switch */
|
||||
OP_EXIT = 100, /* Scalar function Op Exit */
|
||||
OP_LIT = 101, /* Scalar function Op Literal */
|
||||
OP_LOCALE = 102, /* Scalar function Op Locale */
|
||||
OP_FRNCH = 103, /* Scalar function Op French */
|
||||
OP_ENGLSH = 104, /* Scalar function Op English */
|
||||
OP_RAND = 105, /* Scalar function Op Rand(om) */
|
||||
OP_FIRST = 106, /* Index operator Find First */
|
||||
OP_NEXT = 107, /* Index operator Find Next */
|
||||
OP_SAME = 108, /* Index operator Find Next Same */
|
||||
OP_FSTDIF = 109, /* Index operator Find First dif */
|
||||
OP_NXTDIF = 110, /* Index operator Find Next dif */
|
||||
OP_VAL = 111, /* Scalar function Op Valist */
|
||||
OP_QUART = 112, /* Scalar function Op QUARTER */
|
||||
OP_CURDT = 113, /* Scalar function Op CurDate */
|
||||
OP_NWEEK = 114, /* Scalar function Op Week number*/
|
||||
OP_ROW = 115, /* Scalar function Op Row */
|
||||
OP_SYSTEM = 200, /* Scalar function Op System */
|
||||
OP_REMOVE = 201, /* Scalar function Op Remove */
|
||||
OP_RENAME = 202, /* Scalar function Op Rename */
|
||||
OP_FCOMP = 203}; /* Scalar function Op Compare */
|
||||
|
||||
enum TUSE {USE_NO = 0, /* Table is not yet linearized */
|
||||
USE_LIN = 1, /* Table is linearized */
|
||||
USE_READY = 2, /* Column buffers are allocated */
|
||||
USE_OPEN = 3, /* Table is open */
|
||||
USE_CNT = 4, /* Specific to LNA */
|
||||
USE_NOKEY = 5}; /* Specific to SqlToHql */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Following definitions are used to indicate the status of a column. */
|
||||
/***********************************************************************/
|
||||
enum STATUS {BUF_NO = 0x00, /* Column buffer not allocated */
|
||||
BUF_EMPTY = 0x01, /* Column buffer is empty */
|
||||
BUF_READY = 0x02, /* Column buffer is ready */
|
||||
BUF_READ = 0x04, /* Column buffer has read value */
|
||||
BUF_MAPPED = 0x08}; /* Used by the VMPFAM class */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Following definitions are used to indicate how a column is used. */
|
||||
/* Corresponding bits are ON if the column is used in: */
|
||||
/***********************************************************************/
|
||||
enum COLUSE {U_P = 0x01, /* the projection list. */
|
||||
U_J_EXT = 0x02, /* a join filter. */
|
||||
U_J_INT = 0x04, /* a join after linearisation. */
|
||||
/*-- Such a column have a constant value throughout a subquery eval. --*/
|
||||
U_CORREL = 0x08, /* a correlated sub-query */
|
||||
/*-------------------- additional values used by CONNECT --------------*/
|
||||
U_VAR = 0x10, /* a VARCHAR column */
|
||||
U_VIRTUAL = 0x20, /* a VIRTUAL column */
|
||||
U_NULLS = 0x40, /* The column may have nulls */
|
||||
U_IS_NULL = 0x80}; /* The column has a null value */
|
||||
|
||||
/***********************************************************************/
|
||||
/* DB description class and block pointer definitions. */
|
||||
/***********************************************************************/
|
||||
typedef class XTAB *PTABLE;
|
||||
typedef class COLUMN *PCOLUMN;
|
||||
typedef class XOBJECT *PXOB;
|
||||
typedef class COLBLK *PCOL;
|
||||
typedef class TBX *PTBX;
|
||||
typedef class TDB *PTDB;
|
||||
typedef void *PSQL; // Not used
|
||||
typedef class TDBASE *PTDBASE;
|
||||
typedef class TDBDOS *PTDBDOS;
|
||||
typedef class TDBFIX *PTDBFIX;
|
||||
typedef class TDBFMT *PTDBFMT;
|
||||
typedef class TDBCSV *PTDBCSV;
|
||||
typedef class TDBDOM *PTDBDOM;
|
||||
typedef class TDBDIR *PTDBDIR;
|
||||
typedef class DOSCOL *PDOSCOL;
|
||||
typedef class CSVCOL *PCSVCOL;
|
||||
typedef class MAPCOL *PMAPCOL;
|
||||
typedef class TDBMFT *PTDBMFT;
|
||||
typedef class TDBMCV *PTDBMCV;
|
||||
typedef class MCVCOL *PMCVCOL;
|
||||
typedef class RESCOL *PRESCOL;
|
||||
typedef class XXBASE *PKXBASE;
|
||||
typedef class KXYCOL *PXCOL;
|
||||
typedef class CATALOG *PCATLG;
|
||||
typedef class RELDEF *PRELDEF;
|
||||
typedef class TABDEF *PTABDEF;
|
||||
typedef class DOSDEF *PDOSDEF;
|
||||
typedef class CSVDEF *PCSVDEF;
|
||||
typedef class VCTDEF *PVCTDEF;
|
||||
typedef class PIVOTDEF *PPIVOTDEF;
|
||||
typedef class DOMDEF *PDOMDEF;
|
||||
typedef class DIRDEF *PDIRDEF;
|
||||
typedef class OEMDEF *POEMDEF;
|
||||
typedef class COLCRT *PCOLCRT;
|
||||
typedef class COLDEF *PCOLDEF;
|
||||
typedef class CONSTANT *PCONST;
|
||||
typedef class VALUE *PVAL;
|
||||
typedef class VALBLK *PVBLK;
|
||||
|
||||
typedef struct _fblock *PFBLOCK;
|
||||
typedef struct _mblock *PMBLOCK;
|
||||
typedef struct _cblock *PCBLOCK;
|
||||
typedef struct _tabs *PTABS;
|
||||
typedef struct _qryres *PQRYRES;
|
||||
typedef struct _colres *PCOLRES;
|
||||
typedef struct _datpar *PDTP;
|
||||
typedef struct indx_used *PXUSED;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Utility blocks for file and storage. */
|
||||
/***********************************************************************/
|
||||
typedef struct _fblock { /* Opened (mapped) file block */
|
||||
struct _fblock *Next;
|
||||
LPCSTR Fname; /* Point on file name */
|
||||
size_t Length; /* File length (<4GB) */
|
||||
short Count; /* Nb of times map is used */
|
||||
short Type; /* TYPE_FB_FILE or TYPE_FB_MAP */
|
||||
MODE Mode; /* Open mode */
|
||||
char *Memory; /* Pointer to file mapping view */
|
||||
void *File; /* FILE pointer */
|
||||
HANDLE Handle; /* File handle */
|
||||
} FBLOCK;
|
||||
|
||||
typedef struct _mblock { /* Memory block */
|
||||
PMBLOCK Next;
|
||||
bool Inlist; /* True if in mblock list */
|
||||
size_t Size; /* Size of allocation */
|
||||
bool Sub; /* True if suballocated */
|
||||
void *Memp; /* Memory pointer */
|
||||
} MBLOCK;
|
||||
|
||||
/***********************************************************************/
|
||||
/* The QUERY application User Block. */
|
||||
/***********************************************************************/
|
||||
typedef struct { /* User application block */
|
||||
//void *Act2; /* RePoint to activity block */
|
||||
//short LineLen; /* Current output line len */
|
||||
NAME Name; /* User application name */
|
||||
//NAME Password; /* User application password */
|
||||
//PSZ UserFile; /* User application filename */
|
||||
char Server[17]; /* Server name */
|
||||
char DBName[17]; /* Current database name */
|
||||
//char Host[65]; /* Caller's host name */
|
||||
//char User[17]; /* Caller's user name */
|
||||
//uint Granted; /* Grant bitmap */
|
||||
PCATLG Catalog; /* To CATALOG class */
|
||||
PQRYRES Result; /* To query result blocks */
|
||||
PFBLOCK Openlist; /* To file/map open list */
|
||||
PMBLOCK Memlist; /* To memory block list */
|
||||
PXUSED Xlist; /* To used index list */
|
||||
//int Maxres; /* Result Max nb of lines */
|
||||
//int Maxtmp; /* Intermediate tables Maxres */
|
||||
//int Maxlin; /* Query Max nb of data lines */
|
||||
//int Maxbmp; /* Maximum XDB2 bitmap size */
|
||||
int Check; /* General level of checking */
|
||||
int Numlines; /* Number of lines involved */
|
||||
//ALGMOD AlgChoice; /* Choice of algorithm mode */
|
||||
//AREADEF DescArea; /* Table desc. area size */
|
||||
USETEMP UseTemp; /* Use temporary file */
|
||||
//int Curtype; /* 0: static else: dynamic */
|
||||
int Vtdbno; /* Used for TDB number setting */
|
||||
bool Remote; /* true: if remotely called */
|
||||
//bool NotFinal; /* true: for intermediate table */
|
||||
bool Proginfo; /* true: return progress info */
|
||||
bool Subcor; /* Used for Progress info */
|
||||
size_t ProgMax; /* Used for Progress info */
|
||||
size_t ProgCur; /* Used for Progress info */
|
||||
size_t ProgSav; /* Used for Progress info */
|
||||
LPCSTR Step; /* Execution step name */
|
||||
//char Work[_MAX_PATH]; /* Local work path */
|
||||
} DBUSERBLK, *PDBUSER;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Column output format. */
|
||||
/***********************************************************************/
|
||||
typedef struct _format { /* Format descriptor block */
|
||||
char Type[2]; /* C:char, F:double, N:int, Dx: date */
|
||||
ushort Length; /* Output length */
|
||||
short Prec; /* Output precision */
|
||||
} FORMAT, *PFORMAT;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definition of blocks used in type and copy routines. */
|
||||
/***********************************************************************/
|
||||
typedef struct _tabptr { /* start=P1 */
|
||||
struct _tabptr *Next;
|
||||
int Num; /* alignement */
|
||||
void *Old[50];
|
||||
void *New[50]; /* old and new values of copied ptrs */
|
||||
} TABPTR, *PTABPTR;
|
||||
|
||||
typedef struct _tabadr { /* start=P3 */
|
||||
struct _tabadr *Next;
|
||||
int Num;
|
||||
void *Adx[50]; /* addr of pointers to be reset */
|
||||
} TABADR, *PTABADR;
|
||||
|
||||
typedef struct _tabs {
|
||||
PGLOBAL G;
|
||||
PTABPTR P1;
|
||||
PTABADR P3;
|
||||
} TABS;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Result of last SQL noconv query. */
|
||||
/***********************************************************************/
|
||||
typedef struct _qryres {
|
||||
PCOLRES Colresp; /* Points to columns of result */
|
||||
bool Continued; /* true when more rows to fetch */
|
||||
bool Truncated; /* true when truncated by maxres */
|
||||
bool Suball; /* true when entirely suballocated */
|
||||
bool Info; /* true when info msg generated */
|
||||
int Maxsize; /* Max query number of lines */
|
||||
int Maxres; /* Allocation size */
|
||||
int Nblin; /* Number of rows in result set */
|
||||
int Nbcol; /* Number of columns in result set */
|
||||
int Cursor; /* Starting position to get data */
|
||||
int BadLines; /* Skipped bad lines in table file */
|
||||
} QRYRES, *PQRYRES;
|
||||
|
||||
typedef struct _colres {
|
||||
PCOLRES Next; /* To next result column */
|
||||
PCOL Colp; /* To matching column block */
|
||||
PSZ Name; /* Column header */
|
||||
PVBLK Kdata; /* Column block of values */
|
||||
char *Nulls; /* Column null value array */
|
||||
int Type; /* Internal type */
|
||||
int DBtype; /* Data type */
|
||||
int Datasize; /* Overall data size */
|
||||
int Ncol; /* Column number */
|
||||
int Clen; /* Data individual internal size */
|
||||
int Length; /* Data individual print length */
|
||||
int Prec; /* Precision */
|
||||
} COLRES;
|
||||
|
||||
#if defined(WIN32) && !defined(NOEX)
|
||||
#define DllExport __declspec( dllexport )
|
||||
#else // !WIN32
|
||||
#define DllExport
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Utility routines. */
|
||||
/***********************************************************************/
|
||||
PPARM Vcolist(PGLOBAL, PTDB, PSZ, bool);
|
||||
void PlugPutOut(PGLOBAL, FILE *, short, void *, uint);
|
||||
void PlugLineDB(PGLOBAL, PSZ, short, void *, uint);
|
||||
char *PlgGetDataPath(PGLOBAL g);
|
||||
void *PlgDBalloc(PGLOBAL, void *, MBLOCK&);
|
||||
void *PlgDBrealloc(PGLOBAL, void *, MBLOCK&, size_t);
|
||||
void AddPointer(PTABS, void *);
|
||||
PDTP MakeDateFormat(PGLOBAL, PSZ, bool, bool, int);
|
||||
int ExtractDate(char *, PDTP, int, int val[6]);
|
||||
|
||||
/***********************************************************************/
|
||||
/* Exported utility routines. */
|
||||
/***********************************************************************/
|
||||
DllExport FILE *PlugOpenFile(PGLOBAL, LPCSTR, LPCSTR);
|
||||
DllExport int PlugCloseFile(PGLOBAL, PFBLOCK, bool all = false);
|
||||
DllExport void PlugCleanup(PGLOBAL, bool);
|
||||
DllExport bool GetPromptAnswer(PGLOBAL, char *);
|
||||
DllExport char *GetAmName(PGLOBAL g, AMT am, void *memp = NULL);
|
||||
DllExport PDBUSER PlgMakeUser(PGLOBAL g);
|
||||
DllExport PDBUSER PlgGetUser(PGLOBAL g);
|
||||
DllExport PCATLG PlgGetCatalog(PGLOBAL g, bool jump = true);
|
||||
DllExport bool PlgSetXdbPath(PGLOBAL g, PSZ, PSZ, char *, int, char *, int);
|
||||
DllExport void PlgDBfree(MBLOCK&);
|
||||
DllExport PSZ GetIniString(PGLOBAL, void *, LPCSTR, LPCSTR, LPCSTR, LPCSTR);
|
||||
DllExport int GetIniSize(char *, char *, char *, char *);
|
||||
DllExport bool WritePrivateProfileInt(LPCSTR, LPCSTR, int, LPCSTR);
|
||||
DllExport void NewPointer(PTABS, void *, void *);
|
||||
1475
storage/connect/plgdbutl.cpp
Normal file
1475
storage/connect/plgdbutl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
230
storage/connect/plgodbc.h
Normal file
230
storage/connect/plgodbc.h
Normal file
@@ -0,0 +1,230 @@
|
||||
/***********************************************************************/
|
||||
/* PLGODBC.H - This is the ODBC PlugDB driver include file. */
|
||||
/***********************************************************************/
|
||||
//efine WINVER 0x0300 // prevent Windows 3.1 feature usage
|
||||
#include <windows.h> /* Windows include file */
|
||||
#include <windowsx.h> /* Message crackers */
|
||||
#include <commctrl.h>
|
||||
|
||||
/***********************************************************************/
|
||||
/* Included C-definition files required by the interface. */
|
||||
/***********************************************************************/
|
||||
#include <string.h> /* String manipulation declares */
|
||||
#include <stdlib.h> /* C standard library */
|
||||
#include <ctype.h> /* C language specific types */
|
||||
#include <stdio.h> /* FOPEN_MAX declaration */
|
||||
#include <time.h> /* time_t type declaration */
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC interface of PlugDB driver declares. */
|
||||
/***********************************************************************/
|
||||
#include "podbcerr.h" /* Resource ID for PlugDB Driver */
|
||||
#if !defined(WIN32)
|
||||
#include "w16macro.h"
|
||||
#endif
|
||||
|
||||
#define ODBCVER 0x0300
|
||||
|
||||
#include "sqltypes.h"
|
||||
#include "sql.h"
|
||||
#include "sqlext.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definitions to be used in function prototypes. */
|
||||
/* The SQL_API is to be used only for those functions exported for */
|
||||
/* driver manager use. */
|
||||
/* The EXPFUNC is to be used only for those functions exported but */
|
||||
/* used internally, ie, dialog procs. */
|
||||
/* The INTFUNC is to be used for all other functions. */
|
||||
/***********************************************************************/
|
||||
#if defined(WIN32)
|
||||
#define INTFUNC __stdcall
|
||||
#define EXPFUNC __stdcall
|
||||
#else
|
||||
#define INTFUNC FAR PASCAL
|
||||
#define EXPFUNC __export CALLBACK
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* External variables. */
|
||||
/***********************************************************************/
|
||||
extern HINSTANCE NEAR s_hModule; // DLL handle.
|
||||
#ifdef DEBTRACE
|
||||
extern FILE *debug;
|
||||
#endif
|
||||
extern bool clearerror;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Additional values used by PlugDB for ODBC. */
|
||||
/***********************************************************************/
|
||||
#define RES_TYPE_PREPARE 1 /* Result from SQLPrepare */
|
||||
#define RES_TYPE_CATALOG 2 /* Result from catalog funcs */
|
||||
#define MAXPATHLEN _MAX_PATH /* Max path length */
|
||||
#define MAXKEYLEN 16 /* Max keyword length */
|
||||
#define MAXDESC 256 /* Max description length */
|
||||
#define MAXDSNAME 33 /* Max data source name length */
|
||||
#define MAXCRNAME 18 /* Max stmt cursor name length */
|
||||
#define DEFMAXRES 6300 /* Default MaxRes value */
|
||||
#define NAM_LEN 128 /* Length of col and tab names */
|
||||
|
||||
#define MAXRESULT 1000 /* ? */
|
||||
#define MAXCOMMAND 200 /* ? */
|
||||
#define RC_ERROR RC_LAST-1
|
||||
#define RC_FREE 3
|
||||
|
||||
#if !defined(NOLIB)
|
||||
#define CNXKEY uint /* C Key returned by Conn DLL */
|
||||
#else
|
||||
typedef struct _conninfo *PCONN;
|
||||
#endif /* !NOLIB */
|
||||
|
||||
#if defined(DEBTRACE)
|
||||
#define TRACE0(X) fprintf(debug,X);
|
||||
#define TRACE1(X,A) fprintf(debug,X,A);
|
||||
#define TRACE2(X,A,B) fprintf(debug,X,A,B);
|
||||
#define TRACE3(X,A,B,C) fprintf(debug,X,A,B,C);
|
||||
#define TRACE4(X,A,B,C,D) fprintf(debug,X,A,B,C,D);
|
||||
#define TRACE5(X,A,B,C,D,E) fprintf(debug,X,A,B,C,D,E);
|
||||
#define TRACE6(X,A,B,C,D,E,F) fprintf(debug,X,A,B,C,D,E,F);
|
||||
#else /* !DEBTRACE*/
|
||||
#define TRACE0(X)
|
||||
#define TRACE1(X,A)
|
||||
#define TRACE2(X,A,B)
|
||||
#define TRACE3(X,A,B,C)
|
||||
#define TRACE4(X,A,B,C,D)
|
||||
#define TRACE5(X,A,B,C,D,E)
|
||||
#define TRACE6(X,A,B,C,D,E,F)
|
||||
#endif /* !DEBTRACE*/
|
||||
|
||||
// This definition MUST be identical to the value in plgdbsem.h
|
||||
#define XMOD_PREPARE 1
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC.INI keywords (use extern definition in SETUP.C) */
|
||||
/***********************************************************************/
|
||||
extern char const *EMPTYSTR; /* Empty String */
|
||||
extern char const *OPTIONON;
|
||||
extern char const *OPTIONOFF;
|
||||
extern char const *INI_SDEFAULT; /* Default data source name */
|
||||
extern char const *ODBC_INI; /* ODBC initialization file */
|
||||
extern char const *INI_KDEFL; /* Is SQL to use by default? */
|
||||
extern char const *INI_KLANG; /* Application language */
|
||||
extern char const *INI_KDATA; /* Data description file */
|
||||
extern char const *INI_KSVR; /* PLG Server */
|
||||
|
||||
/************************************************************************/
|
||||
/* Attribute key indexes (into an array of Attr structs, see below) */
|
||||
/************************************************************************/
|
||||
#define KEY_DSN 0
|
||||
#define KEY_DEFL 1
|
||||
#define KEY_LANG 2
|
||||
#define KEY_DATA 3
|
||||
#define KEY_SERVER 4
|
||||
#define LAST_KEY 5 /* Number of keys in TAG's */
|
||||
#define KEY_DESC 5
|
||||
#define KEY_TRANSNAME 6
|
||||
#define KEY_TRANSOPTION 7
|
||||
#define KEY_TRANSDLL 8
|
||||
#define NUMOFKEYS 9 /* Number of keys supported */
|
||||
|
||||
#define FOURYEARS 126230400 // Four years in seconds (1 leap)
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is used when an "out of memory" error happens, because this */
|
||||
/* error recording system allocates memory when it logs an error, */
|
||||
/* and it would be bad if it tried to allocate memory when it got an */
|
||||
/* out of memory error. */
|
||||
/***********************************************************************/
|
||||
typedef enum _ERRSTAT {
|
||||
errstatOK,
|
||||
errstatNO_MEMORY,
|
||||
} ERRSTAT;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Types */
|
||||
/***********************************************************************/
|
||||
typedef struct TagAttr {
|
||||
bool fSupplied;
|
||||
char Attr[MAXPATHLEN];
|
||||
} TAG, *PTAG;
|
||||
|
||||
typedef struct _parscons { /* Parse constants */
|
||||
int Slen; /* String length */
|
||||
int Ntag; /* Number of entries in tags */
|
||||
int Nlook; /* Number of entries in lookup */
|
||||
char Sep; /* Separator */
|
||||
} PARC, *PPARC;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Attribute string look-up table (maps keys to associated indexes) */
|
||||
/***********************************************************************/
|
||||
typedef struct _Look {
|
||||
const char *szKey;
|
||||
int iKey;
|
||||
} LOOK, *PLOOK;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is info about a single error. */
|
||||
/***********************************************************************/
|
||||
typedef struct _ERRBLK *PERRBLK;
|
||||
|
||||
typedef struct _ERRBLK {
|
||||
PERRBLK Next; /* Next block in linked list of error blocks */
|
||||
DWORD Native_Error; /* Native error */
|
||||
DWORD Stderr; /* SQLC error code */
|
||||
PSZ Message; /* Points to text of message */
|
||||
} ERRBLK;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is a header block, it records information about a list of */
|
||||
/* errors (ERRBLOCK's). */
|
||||
/***********************************************************************/
|
||||
typedef struct _ERRINFO {
|
||||
PERRBLK First; /* First block in linked list of error blocks. */
|
||||
PERRBLK Last; /* Last block in above list. */
|
||||
ERRSTAT Errstat; /* Status for special condition out of memory */
|
||||
} ERRINFO, *PERRINFO;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Environment information. */
|
||||
/***********************************************************************/
|
||||
typedef struct _env {
|
||||
ERRINFO Errinfo; /* Error list */
|
||||
UDWORD ODBCver;
|
||||
UDWORD ODBCdateformat;
|
||||
} ENV, *PENV;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Classes used in the PlugDB ODBC Driver. */
|
||||
/***********************************************************************/
|
||||
typedef class DBC *PDBC;
|
||||
typedef class STMT *PSTMT;
|
||||
typedef class CURSOR *PCURSOR;
|
||||
typedef class RESULT *PRESULT;
|
||||
typedef class BINDDATA *PBIND;
|
||||
typedef class BINDPARM *PBDPARM;
|
||||
typedef class CPLGdrv *PSCDRV;
|
||||
typedef class DESCRIPTOR *PDSC;
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC Prototypes. */
|
||||
/***********************************************************************/
|
||||
void PostSQLError(HENV, HDBC, HSTMT, DWORD, DWORD, PSZ);
|
||||
void ClearSQLError(HENV, HDBC, HSTMT);
|
||||
short LoadRcString(UWORD, LPSTR, short);
|
||||
RETCODE RetcodeCopyBytes(HDBC, HSTMT, UCHAR FAR *, SWORD,
|
||||
SWORD FAR *, UCHAR FAR *, SWORD, bool);
|
||||
|
||||
/***********************************************************************/
|
||||
/* Private functions used by the driver. */
|
||||
/***********************************************************************/
|
||||
bool EXPFUNC FDriverConnectProc(HWND, WORD, WPARAM, LPARAM);
|
||||
extern void ParseAttrString(PLOOK, PTAG, UCHAR FAR *, PPARC);
|
||||
RETCODE PASCAL StringCopy(HDBC, HSTMT, PTR, SWORD, SWORD FAR *,
|
||||
char FAR *);
|
||||
RETCODE PASCAL ShortCopy(HDBC, HSTMT, PTR, SWORD, SWORD FAR *, short);
|
||||
RETCODE PASCAL LongCopy(HDBC, HSTMT, PTR, SWORD, SWORD FAR *, int);
|
||||
RETCODE PASCAL GeneralCopy(HDBC, HSTMT, PTR, SWORD,
|
||||
SWORD FAR *, PTR, SWORD);
|
||||
|
||||
/* --------------------- End of PLGODBC.H ---------------------------- */
|
||||
140
storage/connect/plgxml.cpp
Normal file
140
storage/connect/plgxml.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/******************************************************************/
|
||||
/* Implementation of XML document processing using PdbXML. */
|
||||
/* Author: Olivier Bertrand 2007-2012 */
|
||||
/******************************************************************/
|
||||
#include "my_global.h"
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "block.h"
|
||||
#include "plgxml.h"
|
||||
|
||||
#if !defined(DOMDOC_SUPPORT)
|
||||
PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf,
|
||||
char *enc, PFBLOCK fp)
|
||||
{
|
||||
strcpy(g->Message, MSG(DOM_NOT_SUPP));
|
||||
return NULL;
|
||||
} // end of GetDomDoc
|
||||
#endif // !DOMDOC_SUPPORT
|
||||
|
||||
#if defined(NOXML2)
|
||||
PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
|
||||
char *enc, PFBLOCK fp)
|
||||
{
|
||||
strcpy(g->Message, "libxml2 not supported");
|
||||
return NULL;
|
||||
} // end of GetLibxmlDoc
|
||||
#endif // NOXML2
|
||||
|
||||
/******************************************************************/
|
||||
/* XMLDOCUMENT constructor. */
|
||||
/******************************************************************/
|
||||
XMLDOCUMENT::XMLDOCUMENT(char *nsl, char *nsdf, char *enc)
|
||||
{
|
||||
Namespaces = NULL;
|
||||
Encoding = enc;
|
||||
Nslist = nsl;
|
||||
DefNs = nsdf;
|
||||
} // end of XMLDOCUMENT constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Make the namespace structure list. */
|
||||
/******************************************************************/
|
||||
bool XMLDOCUMENT::MakeNSlist(PGLOBAL g)
|
||||
{
|
||||
char *prefix, *href, *next = Nslist;
|
||||
PNS nsp, *ppns = &Namespaces;
|
||||
|
||||
while (next) {
|
||||
// Skip spaces
|
||||
while ((*next) == ' ')
|
||||
next++;
|
||||
|
||||
if ((*next) == '\0')
|
||||
break;
|
||||
|
||||
// Find prefix
|
||||
prefix = next;
|
||||
next = strchr(next, '=');
|
||||
|
||||
if (next == NULL) {
|
||||
strcpy(g->Message, MSG(BAS_NS_LIST));
|
||||
return true;
|
||||
} // endif next
|
||||
|
||||
*(next++) = '\0';
|
||||
|
||||
// Find href
|
||||
href = next;
|
||||
next = strchr(next, ' ');
|
||||
|
||||
if (next != NULL)
|
||||
*(next++) = '\0';
|
||||
|
||||
// Allocate and link NS structure
|
||||
nsp = (PNS)PlugSubAlloc(g, NULL, sizeof(NS));
|
||||
nsp->Next = NULL;
|
||||
nsp->Prefix = prefix;
|
||||
nsp->Uri = href;
|
||||
*ppns = nsp;
|
||||
ppns = &nsp->Next;
|
||||
} // endwhile next
|
||||
|
||||
return false;
|
||||
} // end of MakeNSlist
|
||||
|
||||
/******************************************************************/
|
||||
/* XMLNODE constructor. */
|
||||
/******************************************************************/
|
||||
XMLNODE::XMLNODE(PXDOC dp)
|
||||
{
|
||||
Doc = dp;
|
||||
Next = NULL;
|
||||
Children = NULL;
|
||||
Buf = NULL;
|
||||
Len = -1;
|
||||
} // end of XMLNODE constructor
|
||||
|
||||
/******************************************************************/
|
||||
/* Attach new node at the end of this node children list. */
|
||||
/******************************************************************/
|
||||
PXNODE XMLNODE::NewChild(PXNODE ncp)
|
||||
{
|
||||
PXNODE np, *pnp = &Children;
|
||||
|
||||
for (np = *pnp; np; np = np->Next)
|
||||
pnp = &np->Next;
|
||||
|
||||
*pnp = np;
|
||||
return ncp;
|
||||
} // end of NewChild
|
||||
|
||||
/******************************************************************/
|
||||
/* Delete a node from this node children list. */
|
||||
/******************************************************************/
|
||||
void XMLNODE::Delete(PXNODE dnp)
|
||||
{
|
||||
PXNODE *pnp = &Children;
|
||||
|
||||
for (PXNODE np = *pnp; np; np = np->Next)
|
||||
if (np == dnp) {
|
||||
*pnp = dnp->Next;
|
||||
break;
|
||||
} else
|
||||
pnp = &np->Next;
|
||||
|
||||
} // end of Delete
|
||||
|
||||
/******************************************************************/
|
||||
/* Store a string in Buf, enventually reallocating it. */
|
||||
/******************************************************************/
|
||||
char *XMLNODE::BufAlloc(PGLOBAL g, char *p, int n)
|
||||
{
|
||||
if (Len < n) {
|
||||
Len = n;
|
||||
Buf = (char*)PlugSubAlloc(g, NULL, n + 1);
|
||||
} // endif Len
|
||||
|
||||
*Buf = '\0';
|
||||
return strncat(Buf, p, n);
|
||||
} // end of BufAlloc
|
||||
177
storage/connect/plgxml.h
Normal file
177
storage/connect/plgxml.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/******************************************************************/
|
||||
/* Dual XML implementation base classes defines. */
|
||||
/******************************************************************/
|
||||
#if !defined(BASE_BUFFER_SIZE)
|
||||
enum ElementType { // libxml2
|
||||
XML_ELEMENT_NODE = 1,
|
||||
XML_ATTRIBUTE_NODE = 2,
|
||||
XML_TEXT_NODE = 3,
|
||||
XML_CDATA_SECTION_NODE = 4,
|
||||
XML_ENTITY_REF_NODE = 5,
|
||||
XML_ENTITY_NODE = 6,
|
||||
XML_PI_NODE = 7,
|
||||
XML_COMMENT_NODE = 8,
|
||||
XML_DOCUMENT_NODE = 9,
|
||||
XML_DOCUMENT_TYPE_NODE = 10,
|
||||
XML_DOCUMENT_FRAG_NODE = 11,
|
||||
XML_NOTATION_NODE = 12,
|
||||
XML_HTML_DOCUMENT_NODE = 13,
|
||||
XML_DTD_NODE = 14,
|
||||
XML_ELEMENT_DECL = 15,
|
||||
XML_ATTRIBUTE_DECL = 16,
|
||||
XML_ENTITY_DECL = 17,
|
||||
XML_NAMESPACE_DECL = 18,
|
||||
XML_XINCLUDE_START = 19,
|
||||
XML_XINCLUDE_END = 20,
|
||||
XML_DOCB_DOCUMENT_NODE = 21};
|
||||
#endif // !BASE_BUFFER_SIZE
|
||||
|
||||
//#if !defined(NODE_TYPE_LIST)
|
||||
#ifdef NOT_USED
|
||||
enum NodeType { // MS DOM
|
||||
NODE_ELEMENT = 1,
|
||||
NODE_ATTRIBUTE = 2,
|
||||
NODE_TEXT = 3,
|
||||
NODE_CDATA_SECTION = 4,
|
||||
NODE_ENTITY_REFERENCE = 5,
|
||||
NODE_ENTITY = 6,
|
||||
NODE_PROCESSING_INSTRUCTION = 7,
|
||||
NODE_COMMENT = 8,
|
||||
NODE_DOCUMENT = 9,
|
||||
NODE_DOCUMENT_TYPE = 10,
|
||||
NODE_DOCUMENT_FRAGMENT = 11,
|
||||
NODE_NOTATION = 12};
|
||||
#endif // !NODE_TYPE_LIST
|
||||
|
||||
typedef class XMLDOCUMENT *PXDOC; // Document
|
||||
typedef class XMLNODE *PXNODE; // Node (Element)
|
||||
typedef class XMLNODELIST *PXLIST; // Node list
|
||||
typedef class XMLATTRIBUTE *PXATTR; // Attribute
|
||||
|
||||
typedef struct _ns {
|
||||
struct _ns *Next;
|
||||
char *Prefix;
|
||||
char *Uri;
|
||||
} NS, *PNS;
|
||||
|
||||
PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
|
||||
char *enc, PFBLOCK fp = NULL);
|
||||
PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf,
|
||||
char *enc, PFBLOCK fp = NULL);
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of XML document. */
|
||||
/******************************************************************/
|
||||
class XMLDOCUMENT : public BLOCK {
|
||||
friend class XML2NODE;
|
||||
friend class DOMNODE;
|
||||
public:
|
||||
// Properties
|
||||
virtual short GetDocType(void) = 0;
|
||||
virtual void *GetDocPtr(void) = 0;
|
||||
|
||||
// Methods
|
||||
virtual bool Initialize(PGLOBAL) = 0;
|
||||
virtual bool ParseFile(char *) = 0;
|
||||
virtual bool NewDoc(PGLOBAL, char *) = 0;
|
||||
virtual void AddComment(PGLOBAL, char *) = 0;
|
||||
virtual PXNODE GetRoot(PGLOBAL) = 0;
|
||||
virtual PXNODE NewRoot(PGLOBAL, char *) = 0;
|
||||
virtual PXNODE NewPnode(PGLOBAL, char * = NULL) = 0;
|
||||
virtual PXATTR NewPattr(PGLOBAL) = 0;
|
||||
virtual PXLIST NewPlist(PGLOBAL) = 0;
|
||||
virtual int DumpDoc(PGLOBAL, char *) = 0;
|
||||
virtual void CloseDoc(PGLOBAL, PFBLOCK) = 0;
|
||||
virtual PFBLOCK LinkXblock(PGLOBAL, MODE, int, char *) = 0;
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
XMLDOCUMENT(char *nsl, char *nsdf, char *enc);
|
||||
|
||||
// Utility
|
||||
bool MakeNSlist(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
PNS Namespaces; /* To the namespaces */
|
||||
char *Encoding; /* The document encoding */
|
||||
char *Nslist; /* Namespace list */
|
||||
char *DefNs; /* Default namespace */
|
||||
}; // end of class XMLDOCUMENT
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of XML node. */
|
||||
/******************************************************************/
|
||||
class XMLNODE : public BLOCK {
|
||||
public:
|
||||
// Properties
|
||||
virtual char *GetName(PGLOBAL) = 0;
|
||||
virtual int GetType(void) = 0;
|
||||
virtual PXNODE GetNext(PGLOBAL) = 0;
|
||||
virtual PXNODE GetChild(PGLOBAL) = 0;
|
||||
|
||||
// Methods
|
||||
virtual char *GetText(char *, int) = 0;
|
||||
virtual bool SetContent(PGLOBAL, char *, int) = 0;
|
||||
virtual PXNODE Clone(PGLOBAL, PXNODE) = 0;
|
||||
virtual PXLIST GetChildElements(PGLOBAL, char * = NULL, PXLIST = NULL) = 0;
|
||||
virtual PXLIST SelectNodes(PGLOBAL, char *, PXLIST = NULL) = 0;
|
||||
virtual PXNODE SelectSingleNode(PGLOBAL, char *, PXNODE = NULL) = 0;
|
||||
virtual PXATTR GetAttribute(PGLOBAL, char *, PXATTR = NULL) = 0;
|
||||
virtual PXNODE AddChildNode(PGLOBAL, char *, PXNODE = NULL) = 0;
|
||||
virtual PXATTR AddProperty(PGLOBAL, char *, PXATTR = NULL) = 0;
|
||||
virtual void AddText(PGLOBAL, char *) = 0;
|
||||
virtual void DeleteChild(PGLOBAL, PXNODE) = 0;
|
||||
|
||||
protected:
|
||||
PXNODE NewChild(PXNODE ncp);
|
||||
void Delete(PXNODE dnp);
|
||||
char *BufAlloc(PGLOBAL g, char *p, int n);
|
||||
|
||||
// Constructor
|
||||
XMLNODE(PXDOC dp);
|
||||
|
||||
// Members
|
||||
PXDOC Doc;
|
||||
PXNODE Next;
|
||||
PXNODE Children;
|
||||
char *Buf;
|
||||
int Len;
|
||||
}; // end of class XMLNODE
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of XML node list. */
|
||||
/******************************************************************/
|
||||
class XMLNODELIST : public BLOCK {
|
||||
public:
|
||||
// Properties
|
||||
virtual int GetLength(void) = 0;
|
||||
virtual PXNODE GetItem(PGLOBAL, int, PXNODE = NULL) = 0;
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
XMLNODELIST(PXDOC dp) {Doc = dp;}
|
||||
|
||||
// Members
|
||||
PXDOC Doc;
|
||||
}; // end of class XMLNODELIST
|
||||
|
||||
/******************************************************************/
|
||||
/* Declaration of XML attribute. */
|
||||
/******************************************************************/
|
||||
class XMLATTRIBUTE : public BLOCK {
|
||||
public:
|
||||
// Properties
|
||||
//virtual char *GetText(void) = 0;
|
||||
|
||||
// Methods
|
||||
virtual bool SetText(PGLOBAL, char *, int) = 0;
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
XMLATTRIBUTE(PXDOC dp) {Doc = dp;}
|
||||
|
||||
// Members
|
||||
PXDOC Doc;
|
||||
}; // end of class XMLATTRIBUTE
|
||||
|
||||
|
||||
500
storage/connect/plugutil.c
Normal file
500
storage/connect/plugutil.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/************** PlugUtil C Program Source Code File (.C) ***************/
|
||||
/* */
|
||||
/* PROGRAM NAME: PLUGUTIL */
|
||||
/* ------------- */
|
||||
/* Version 2.7 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1993-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are initialization and utility Plug routines. */
|
||||
/* */
|
||||
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
||||
/* -------------------------------------- */
|
||||
/* */
|
||||
/* REQUIRED FILES: */
|
||||
/* --------------- */
|
||||
/* See Readme.C for a list and description of required SYSTEM files. */
|
||||
/* */
|
||||
/* PLUG.C - Source code */
|
||||
/* GLOBAL.H - Global declaration file */
|
||||
/* OPTION.H - Option declaration file */
|
||||
/* */
|
||||
/* REQUIRED LIBRARIES: */
|
||||
/* ------------------- */
|
||||
/* */
|
||||
/* OS2.LIB - OS2 libray */
|
||||
/* LLIBCE.LIB - Protect mode/standard combined large model C */
|
||||
/* library */
|
||||
/* */
|
||||
/* REQUIRED PROGRAMS: */
|
||||
/* ------------------ */
|
||||
/* */
|
||||
/* IBM C Compiler */
|
||||
/* IBM Linker */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
//efine DEBTRACE 3
|
||||
//efine DEBTRACE2
|
||||
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* Include relevant MariaDB header file. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
//#include <windows.h>
|
||||
#else
|
||||
#if defined(UNIX) || defined(UNIV_LINUX)
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
//#define __stdcall
|
||||
#else
|
||||
#include <dir.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN)
|
||||
#include <alloc.h>
|
||||
#endif
|
||||
#include <errno.h> /* definitions of ERANGE ENOMEM */
|
||||
#if !defined(UNIX) && !defined(UNIV_LINUX)
|
||||
#include <direct.h> /* Directory management library */
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* Include application header files */
|
||||
/* */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
#define STORAGE /* Initialize global variables */
|
||||
|
||||
#include "osutil.h"
|
||||
#include "global.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
extern HINSTANCE s_hModule; /* Saved module handle */
|
||||
#endif // WIN32
|
||||
|
||||
extern char plgini[];
|
||||
extern int trace;
|
||||
|
||||
#if defined(XMSG)
|
||||
extern char msglang[];
|
||||
#endif // XMSG
|
||||
|
||||
/***********************************************************************/
|
||||
/* Local Definitions and static variables */
|
||||
/***********************************************************************/
|
||||
typedef struct {
|
||||
ushort Segsize;
|
||||
ushort Size;
|
||||
} AREASIZE;
|
||||
|
||||
ACTIVITY defActivity = { /* Describes activity and language */
|
||||
NULL, /* Points to user work area(s) */
|
||||
"Unknown"}; /* Application name */
|
||||
|
||||
#if defined(XMSG) || defined(NEWMSG)
|
||||
static char stmsg[200];
|
||||
#endif // XMSG || NEWMSG
|
||||
|
||||
#if defined(UNIX) || defined(UNIV_LINUX)
|
||||
int GetRcString(int id, char *buf, int bufsize);
|
||||
#endif // UNIX
|
||||
|
||||
/**************************************************************************/
|
||||
/* Tracing output function. */
|
||||
/**************************************************************************/
|
||||
void htrc(char const *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
|
||||
//if (trace == 0 || (trace == 1 && !debug) || !fmt) {
|
||||
// printf("In %s wrong trace=%d debug=%p fmt=%p\n",
|
||||
// __FILE__, trace, debug, fmt);
|
||||
// trace = 0;
|
||||
// } // endif trace
|
||||
|
||||
//if (trace == 1)
|
||||
// vfprintf(debug, fmt, ap);
|
||||
//else
|
||||
vfprintf(stderr, fmt, ap);
|
||||
|
||||
va_end (ap);
|
||||
} // end of htrc
|
||||
|
||||
/***********************************************************************/
|
||||
/* Plug initialization routine. */
|
||||
/* Language points on initial language name and eventual path. */
|
||||
/* Return value is the pointer to the Global structure. */
|
||||
/***********************************************************************/
|
||||
PGLOBAL PlugInit(LPCSTR Language, uint worksize)
|
||||
{
|
||||
PGLOBAL g;
|
||||
|
||||
if (trace > 1)
|
||||
htrc("PlugInit: Language='%s'\n",
|
||||
((!Language) ? "Null" : (char*)Language));
|
||||
|
||||
if (!(g = malloc(sizeof(GLOBAL)))) {
|
||||
fprintf(stderr, MSG(GLOBAL_ERROR), (int)sizeof(GLOBAL));
|
||||
} else {
|
||||
g->Sarea_Size = worksize;
|
||||
g->Trace = 0;
|
||||
g->Activityp = g->ActivityStart = NULL;
|
||||
strcpy(g->Message, "");
|
||||
|
||||
/*******************************************************************/
|
||||
/* Allocate the main work segment. */
|
||||
/*******************************************************************/
|
||||
if (!(g->Sarea = PlugAllocMem(g, worksize))) {
|
||||
char errmsg[256];
|
||||
sprintf(errmsg, MSG(WORK_AREA), g->Message);
|
||||
strcpy(g->Message, errmsg);
|
||||
} /* endif Sarea */
|
||||
|
||||
} /* endif g */
|
||||
|
||||
g->jump_level = -1; /* New setting to allow recursive call of Plug */
|
||||
return(g);
|
||||
} /* end of PlugInit */
|
||||
|
||||
/***********************************************************************/
|
||||
/* PlugExit: Terminate Plug operations. */
|
||||
/***********************************************************************/
|
||||
int PlugExit(PGLOBAL g)
|
||||
{
|
||||
int rc = 0;
|
||||
PACTIVITY ap;
|
||||
|
||||
if (!g)
|
||||
return rc;
|
||||
else
|
||||
ap = g->ActivityStart;
|
||||
|
||||
free(g->Sarea);
|
||||
free(g);
|
||||
return rc;
|
||||
} /* end of PlugExit */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Remove the file type from a file name. */
|
||||
/* Note: this routine is not really implemented for Unix. */
|
||||
/***********************************************************************/
|
||||
LPSTR PlugRemoveType(LPSTR pBuff, LPCSTR FileName)
|
||||
{
|
||||
#if !defined(UNIX) && !defined(UNIV_LINUX)
|
||||
char drive[_MAX_DRIVE];
|
||||
#else
|
||||
char *drive = NULL;
|
||||
#endif
|
||||
char direc[_MAX_DIR];
|
||||
char fname[_MAX_FNAME];
|
||||
char ftype[_MAX_EXT];
|
||||
|
||||
_splitpath(FileName, drive, direc, fname, ftype);
|
||||
|
||||
if (trace > 1) {
|
||||
htrc("after _splitpath: FileName=%s\n", FileName);
|
||||
htrc("drive=%s dir=%s fname=%s ext=%s\n",
|
||||
SVP(drive), direc, fname, ftype);
|
||||
} // endif trace
|
||||
|
||||
_makepath(pBuff, drive, direc, fname, "");
|
||||
|
||||
if (trace > 1)
|
||||
htrc("buff='%s'\n", pBuff);
|
||||
|
||||
return pBuff;
|
||||
} // end of PlugRemoveType
|
||||
|
||||
/***********************************************************************/
|
||||
/* Set the full path of a file relatively to a given path. */
|
||||
/* Note: this routine is not really implemented for Unix. */
|
||||
/***********************************************************************/
|
||||
LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR FileName, LPCSTR defpath)
|
||||
{
|
||||
char newname[_MAX_PATH];
|
||||
char direc[_MAX_DIR], defdir[_MAX_DIR];
|
||||
char fname[_MAX_FNAME];
|
||||
char ftype[_MAX_EXT];
|
||||
#if !defined(UNIX) && !defined(UNIV_LINUX)
|
||||
char drive[_MAX_DRIVE], defdrv[_MAX_DRIVE];
|
||||
#else
|
||||
char *drive = NULL, *defdrv = NULL;
|
||||
#endif
|
||||
|
||||
if (!strncmp(FileName, "//", 2) || !strncmp(FileName, "\\\\", 2)) {
|
||||
strcpy(pBuff, FileName); // Remote file
|
||||
return pBuff;
|
||||
} // endif
|
||||
|
||||
_splitpath(FileName, drive, direc, fname, ftype);
|
||||
_splitpath(defpath, defdrv, defdir, NULL, NULL);
|
||||
|
||||
if (trace > 1) {
|
||||
htrc("after _splitpath: FileName=%s\n", FileName);
|
||||
#if defined(UNIX) || defined(UNIV_LINUX)
|
||||
htrc("dir=%s fname=%s ext=%s\n", direc, fname, ftype);
|
||||
#else
|
||||
htrc("drive=%s dir=%s fname=%s ext=%s\n", drive, direc, fname, ftype);
|
||||
htrc("defdrv=%s defdir=%s\n", defdrv, defdir);
|
||||
#endif
|
||||
} // endif trace
|
||||
|
||||
if (drive && !*drive)
|
||||
strcpy(drive, defdrv);
|
||||
|
||||
switch (*direc) {
|
||||
case '\0':
|
||||
strcpy(direc, defdir);
|
||||
break;
|
||||
case '\\':
|
||||
case '/':
|
||||
break;
|
||||
default:
|
||||
// This supposes that defdir ends with a SLASH
|
||||
strcpy(direc, strcat(defdir, direc));
|
||||
} // endswitch
|
||||
|
||||
_makepath(newname, drive, direc, fname, ftype);
|
||||
|
||||
if (trace > 1)
|
||||
htrc("newname='%s'\n", newname);
|
||||
|
||||
if (_fullpath(pBuff, newname, _MAX_PATH)) {
|
||||
if (trace > 1)
|
||||
htrc("pbuff='%s'\n", pBuff);
|
||||
|
||||
return pBuff;
|
||||
} else
|
||||
return FileName; // Error, return unchanged name
|
||||
|
||||
} // end of PlugSetPath
|
||||
|
||||
#if defined(XMSG)
|
||||
/***********************************************************************/
|
||||
/* PlugGetMessage: get a message from the message file. */
|
||||
/***********************************************************************/
|
||||
char *PlugReadMessage(PGLOBAL g, int mid, char *m)
|
||||
{
|
||||
char msgfile[_MAX_PATH], msgid[32], buff[256];
|
||||
char *msg;
|
||||
FILE *mfile = NULL;
|
||||
|
||||
GetPrivateProfileString("Message", msglang, "Message\\english.msg",
|
||||
msgfile, _MAX_PATH, plgini);
|
||||
|
||||
if (!(mfile = fopen(msgfile, "rt"))) {
|
||||
sprintf(stmsg, "Fail to open message file %s for %s", msgfile, msglang);
|
||||
goto err;
|
||||
} // endif mfile
|
||||
|
||||
for (;;)
|
||||
if (!fgets(buff, 256, mfile)) {
|
||||
sprintf(stmsg, "Cannot get message %d %s", mid, SVP(m));
|
||||
goto fin;
|
||||
} else
|
||||
if (atoi(buff) == mid)
|
||||
break;
|
||||
|
||||
if (sscanf(buff, " %*d %s \"%[^\"]", msgid, stmsg) < 2) {
|
||||
// Old message file
|
||||
if (!sscanf(buff, " %*d \"%[^\"]", stmsg)) {
|
||||
sprintf(stmsg, "Bad message file for %d %s", mid, SVP(m));
|
||||
goto fin;
|
||||
} else
|
||||
m = NULL;
|
||||
|
||||
} // endif sscanf
|
||||
|
||||
if (m && strcmp(m, msgid)) {
|
||||
// Message file is out of date
|
||||
strcpy(stmsg, m);
|
||||
goto fin;
|
||||
} // endif m
|
||||
|
||||
fin:
|
||||
fclose(mfile);
|
||||
|
||||
err:
|
||||
if (g) {
|
||||
// Called by STEP
|
||||
msg = (char *)PlugSubAlloc(g, NULL, strlen(stmsg) + 1);
|
||||
strcpy(msg, stmsg);
|
||||
} else // Called by MSG or PlgGetErrorMsg
|
||||
msg = stmsg;
|
||||
|
||||
return msg;
|
||||
} // end of PlugReadMessage
|
||||
|
||||
#elif defined(NEWMSG)
|
||||
/***********************************************************************/
|
||||
/* PlugGetMessage: get a message from the resource string table. */
|
||||
/***********************************************************************/
|
||||
char *PlugGetMessage(PGLOBAL g, int mid)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
#if !defined(UNIX) && !defined(UNIV_LINUX)
|
||||
int n = LoadString(s_hModule, (uint)mid, (LPTSTR)stmsg, 200);
|
||||
|
||||
if (n == 0) {
|
||||
DWORD rc = GetLastError();
|
||||
msg = (char*)PlugSubAlloc(g, NULL, 512); // Extend buf allocation
|
||||
n = sprintf(msg, "Message %d, rc=%d: ", mid, rc);
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
|
||||
(LPTSTR)(msg + n), 512 - n, NULL);
|
||||
return msg;
|
||||
} // endif n
|
||||
|
||||
#else // UNIX
|
||||
if (!GetRcString(mid, stmsg, 200))
|
||||
sprintf(stmsg, "Message %d not found", mid);
|
||||
#endif // UNIX
|
||||
|
||||
if (g) {
|
||||
// Called by STEP
|
||||
msg = (char *)PlugSubAlloc(g, NULL, strlen(stmsg) + 1);
|
||||
strcpy(msg, stmsg);
|
||||
} else // Called by MSG or PlgGetErrorMsg
|
||||
msg = stmsg;
|
||||
|
||||
return msg;
|
||||
} // end of PlugGetMessage
|
||||
#endif // NEWMSG
|
||||
|
||||
#if defined(WIN32)
|
||||
/***********************************************************************/
|
||||
/* Return the line length of the console screen buffer. */
|
||||
/***********************************************************************/
|
||||
short GetLineLength(PGLOBAL g)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
HANDLE hcons = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
BOOL b = GetConsoleScreenBufferInfo(hcons, &coninfo);
|
||||
|
||||
return (b) ? coninfo.dwSize.X : 0;
|
||||
} // end of GetLineLength
|
||||
#endif // WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Program for memory allocation of work and language areas. */
|
||||
/***********************************************************************/
|
||||
void *PlugAllocMem(PGLOBAL g, uint size)
|
||||
{
|
||||
void *areap; /* Pointer to allocated area */
|
||||
|
||||
/*********************************************************************/
|
||||
/* This is the allocation routine for the WIN32/UNIX/AIX version. */
|
||||
/*********************************************************************/
|
||||
if (!(areap = malloc(size)))
|
||||
sprintf(g->Message, MSG(MALLOC_ERROR), "malloc");
|
||||
|
||||
if (trace > 1) {
|
||||
if (areap)
|
||||
htrc("Memory of %u allocated at %p\n", size, areap);
|
||||
else
|
||||
htrc("PlugAllocMem: %s\n", g->Message);
|
||||
|
||||
} // endif trace
|
||||
|
||||
return (areap);
|
||||
} /* end of PlugAllocMem */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Program for SubSet initialization of memory pools. */
|
||||
/* Here there should be some verification done such as validity of */
|
||||
/* the address and size not larger than memory size. */
|
||||
/***********************************************************************/
|
||||
BOOL PlugSubSet(PGLOBAL g, void *memp, uint size)
|
||||
{
|
||||
PPOOLHEADER pph = memp;
|
||||
|
||||
pph->To_Free = (OFFSET)sizeof(POOLHEADER);
|
||||
pph->FreeBlk = size - pph->To_Free;
|
||||
|
||||
return FALSE;
|
||||
} /* end of PlugSubSet */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Program for sub-allocating one item in a storage area. */
|
||||
/* Note: SubAlloc routines of OS/2 are no more used to increase the */
|
||||
/* code portability and avoid problems when a grammar compiled under */
|
||||
/* one version of OS/2 is used under another version. */
|
||||
/* The simple way things are done here is also based on the fact */
|
||||
/* that no freeing of suballocated blocks is permitted in Plug. */
|
||||
/***********************************************************************/
|
||||
void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
|
||||
{
|
||||
PPOOLHEADER pph; /* Points on area header. */
|
||||
|
||||
if (!memp)
|
||||
/*******************************************************************/
|
||||
/* Allocation is to be done in the Sarea. */
|
||||
/*******************************************************************/
|
||||
memp = g->Sarea;
|
||||
|
||||
//size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
|
||||
size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */
|
||||
pph = (PPOOLHEADER)memp;
|
||||
|
||||
#if defined(DEBUG2) || defined(DEBUG3)
|
||||
htrc("SubAlloc in %p size=%d used=%d free=%d\n",
|
||||
memp, size, pph->To_Free, pph->FreeBlk);
|
||||
#endif
|
||||
|
||||
if ((uint)size > pph->FreeBlk) { /* Not enough memory left in pool */
|
||||
char *pname = "Work";
|
||||
|
||||
sprintf(g->Message,
|
||||
"Not enough memory in %s area for request of %u (used=%d free=%d)",
|
||||
pname, size, pph->To_Free, pph->FreeBlk);
|
||||
|
||||
#if defined(DEBUG2) || defined(DEBUG3)
|
||||
htrc("%s\n", g->Message);
|
||||
#endif
|
||||
|
||||
longjmp(g->jumper[g->jump_level], 1);
|
||||
} /* endif size OS32 code */
|
||||
|
||||
/*********************************************************************/
|
||||
/* Do the suballocation the simplest way. */
|
||||
/*********************************************************************/
|
||||
memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
|
||||
pph->To_Free += size; /* New offset of pool free block */
|
||||
pph->FreeBlk -= size; /* New size of pool free block */
|
||||
#if defined(DEBUG2) || defined(DEBUG3)
|
||||
htrc("Done memp=%p used=%d free=%d\n",
|
||||
memp, pph->To_Free, pph->FreeBlk);
|
||||
#endif
|
||||
return (memp);
|
||||
} /* end of PlugSubAlloc */
|
||||
|
||||
/***********************************************************************/
|
||||
/* This routine makes a pointer from an offset to a memory pointer. */
|
||||
/***********************************************************************/
|
||||
void *MakePtr(void *memp, OFFSET offset)
|
||||
{
|
||||
return ((offset == 0) ? NULL : &((char *)memp)[offset]);
|
||||
} /* end of MakePtr */
|
||||
|
||||
/***********************************************************************/
|
||||
/* This routine makes an offset from a pointer new format. */
|
||||
/***********************************************************************/
|
||||
OFFSET MakeOff(void *memp, void *ptr)
|
||||
{
|
||||
return ((!ptr) ? 0 : (OFFSET)((char *)ptr - (char *)memp));
|
||||
} /* end of MakeOff */
|
||||
|
||||
/*--------------------- End of PLUGUTIL program -----------------------*/
|
||||
61
storage/connect/preparse.h
Normal file
61
storage/connect/preparse.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#if !defined(PREPARSE_DEFINED)
|
||||
#define PREPARSE_DEFINED
|
||||
|
||||
#include "checklvl.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Struct of variables used by the SQL pre-parsers. */
|
||||
/***********************************************************************/
|
||||
typedef struct _prepar {
|
||||
struct _prepar *Next;
|
||||
char *Debinp; // Start of input buffer
|
||||
char *Endinp; // End of input buffer
|
||||
char *Pluginp; // Points on current parsing position
|
||||
char *Plugbuf; // Start of output buffer
|
||||
char *Plugptr; // Current output position
|
||||
char *Debchar; // Next/current start of command
|
||||
char *Debselp; // Beginning of selection
|
||||
char *Debline; // Start of current line
|
||||
char *Plugpar[32]; // Parameters
|
||||
int Numparms; // Number of defined parameters
|
||||
int Nprms; // Number of ODBC parameters
|
||||
int Lines; // Line number
|
||||
int Chars; // Index of selection start in line
|
||||
int Endchars; // Index of selection end in line
|
||||
int Frinp, Frbuf; // 0: no, 1: free, 2: delete Debinp/Plugbuf
|
||||
int Outsize; // Size of output buffer
|
||||
FILE *Argfile; // File containing arguments
|
||||
int Addargs; // 1 if arguments are added to the list
|
||||
} PREPAR, *PPREP;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Struct of variables used by the date format pre-parser. */
|
||||
/***********************************************************************/
|
||||
typedef struct _datpar {
|
||||
char *Format; // Points to format to decode
|
||||
char *Curp; // Points to current parsing position
|
||||
char *InFmt; // Start of input format
|
||||
char *OutFmt; // Start of output format
|
||||
int Index[8]; // Indexes of date values
|
||||
int Num; // Number of values to retrieve
|
||||
int Flag; // 1: Input, 2: Output, 4: no output blank
|
||||
int Outsize; // Size of output buffers
|
||||
} DATPAR, *PDTP;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Preparsers used by SQL language. */
|
||||
/***********************************************************************/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int sqlflex(PPREP pp);
|
||||
int sqpflex(PPREP pp);
|
||||
int fmdflex(PDTP pp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PREPARSE_DEFINED
|
||||
|
||||
209
storage/connect/rcmsg.c
Normal file
209
storage/connect/rcmsg.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/**************** RCMsg C Program Source Code File (.C) ****************/
|
||||
/* PROGRAM NAME: RCMSG */
|
||||
/* ------------- */
|
||||
/* Version 1.0 */
|
||||
/* */
|
||||
/* COPYRIGHT */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND: 2005 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES */
|
||||
/* ----------------------- */
|
||||
/* This program simulates LoadString for Unix and Linux. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "resource.h"
|
||||
|
||||
int GetRcString(int id, char *buf, int bufsize)
|
||||
{
|
||||
char *p = NULL, msg[32];
|
||||
|
||||
//printf("In GetRcString id=%d\n", id);
|
||||
|
||||
switch (id) {
|
||||
case IDS_00: p = "%s"; break;
|
||||
#if defined(FRENCH)
|
||||
case IDS_01: p = "%s: erreur d'allocation du buffer de communication de %d octets"; break;
|
||||
case IDS_02: p = "%s: erreur d'allocation m<>moire tampon pour %d colonnes"; break;
|
||||
case IDS_03: p = "%s: Commande sp<73>ciale invalide"; break;
|
||||
case IDS_04: p = "%s: Wrong number of arguments %d"; break;
|
||||
case IDS_05: p = "%s"; break;
|
||||
case IDS_06: p = "%s: Commande d<>passant la taille du buffer interne (%d octets)"; break;
|
||||
case IDS_07: p = "%s: Donn<6E>es (%d octets) tronqu<71>es <20> la taille du buffer"; break;
|
||||
case IDS_08: p = "%s: R<>sultat d<>passant la taille du buffer interne (%d octets)"; break;
|
||||
case IDS_09: p = "Erreur dans %s: %s"; break;
|
||||
case IDS_10: p = "%s: erreur d'allocating m<>moire de %d octets"; break;
|
||||
case IDS_11: p = "%s: mauvaise cl<63> de connexion %d"; break;
|
||||
case IDS_12: p = "%s: Pas plus de %d connexions autoris<69>es pour un programme"; break;
|
||||
case IDS_13: p = "%s: cl<63> de connexion invalide %d"; break;
|
||||
case IDS_14: p = "SafeDB: %s rc=%d"; break;
|
||||
case IDS_15: p = "Mauvaise Dll de communication appel<65>e par le moteur %s"; break;
|
||||
case IDS_TAB_01: p = "Qualificateur"; break;
|
||||
case IDS_TAB_02: p = "Propri<EFBFBD>taire"; break;
|
||||
case IDS_TAB_03: p = "Nom"; break;
|
||||
case IDS_TAB_04: p = "Type"; break;
|
||||
case IDS_TAB_05: p = "Remarque"; break;
|
||||
case IDS_COL_01: p = "Qualif_Table"; break;
|
||||
case IDS_COL_02: p = "Prop_Tabl"; break;
|
||||
case IDS_COL_03: p = "Nom_Table"; break;
|
||||
case IDS_COL_04: p = "Nom_Colonne"; break;
|
||||
case IDS_COL_05: p = "Type_Donn<EFBFBD>es"; break;
|
||||
case IDS_COL_06: p = "Nom_Type"; break;
|
||||
case IDS_COL_07: p = "Pr<EFBFBD>cision"; break;
|
||||
case IDS_COL_08: p = "Longueur"; break;
|
||||
case IDS_COL_09: p = "Echelle"; break;
|
||||
case IDS_COL_10: p = "Base"; break;
|
||||
case IDS_COL_11: p = "Nullifiable"; break;
|
||||
case IDS_COL_12: p = "Remarques"; break;
|
||||
case IDS_INF_01: p = "Nom_Type"; break;
|
||||
case IDS_INF_02: p = "Type_Donn<EFBFBD>es"; break;
|
||||
case IDS_INF_03: p = "Pr<EFBFBD>cision"; break;
|
||||
case IDS_INF_04: p = "Pr<EFBFBD>fixe_Lit<EFBFBD>ral"; break;
|
||||
case IDS_INF_05: p = "Suffixe_Lit<EFBFBD>ral"; break;
|
||||
case IDS_INF_06: p = "Cr<EFBFBD>ation_Params"; break;
|
||||
case IDS_INF_07: p = "Nullifiable"; break;
|
||||
case IDS_INF_08: p = "Maj_Minuscule"; break;
|
||||
case IDS_INF_09: p = "Localisable"; break;
|
||||
case IDS_INF_10: p = "Valeur_Absolue"; break;
|
||||
case IDS_INF_11: p = "Monnaie"; break;
|
||||
case IDS_INF_12: p = "Auto_Incr<EFBFBD>ment"; break;
|
||||
case IDS_INF_13: p = "Nom_Type_Local"; break;
|
||||
case IDS_INF_14: p = "Echelle_Minimum"; break;
|
||||
case IDS_INF_15: p = "Echelle_Maximum"; break;
|
||||
case IDS_PKY_01: p = "Qualif_Table"; break;
|
||||
case IDS_PKY_02: p = "Prop_Table"; break;
|
||||
case IDS_PKY_03: p = "Nom_Table"; break;
|
||||
case IDS_PKY_04: p = "Nom_Colonne"; break;
|
||||
case IDS_PKY_05: p = "Num<EFBFBD>ro_Cl<EFBFBD>"; break;
|
||||
case IDS_PKY_06: p = "Nom_Cl<EFBFBD>"; break;
|
||||
case IDS_FKY_01: p = "PKTable_Qualifier"; break;
|
||||
case IDS_FKY_02: p = "PKTable_Owner"; break;
|
||||
case IDS_FKY_03: p = "PKTable_Name"; break;
|
||||
case IDS_FKY_04: p = "PKColumn_Name"; break;
|
||||
case IDS_FKY_05: p = "FKTable_Qualifier"; break;
|
||||
case IDS_FKY_06: p = "FKTable_Owner"; break;
|
||||
case IDS_FKY_07: p = "FKTable_Name"; break;
|
||||
case IDS_FKY_08: p = "FKColumn_Name"; break;
|
||||
case IDS_FKY_09: p = "Key_Seq"; break;
|
||||
case IDS_FKY_10: p = "Update_Rule"; break;
|
||||
case IDS_FKY_11: p = "Delete_Rule"; break;
|
||||
case IDS_FKY_12: p = "FK_Name"; break;
|
||||
case IDS_FKY_13: p = "PK_Name"; break;
|
||||
case IDS_STA_01: p = "Table_Qualifier"; break;
|
||||
case IDS_STA_02: p = "Table_Owner"; break;
|
||||
case IDS_STA_03: p = "Table_Name"; break;
|
||||
case IDS_STA_04: p = "Non_Unique"; break;
|
||||
case IDS_STA_05: p = "Index_Qualifier"; break;
|
||||
case IDS_STA_06: p = "Index_Name"; break;
|
||||
case IDS_STA_07: p = "Type"; break;
|
||||
case IDS_STA_08: p = "Seq_in_Index"; break;
|
||||
case IDS_STA_09: p = "Column_Name"; break;
|
||||
case IDS_STA_10: p = "Collation"; break;
|
||||
case IDS_STA_11: p = "Cardinality"; break;
|
||||
case IDS_STA_12: p = "Pages"; break;
|
||||
case IDS_STA_13: p = "Filter_Condition"; break;
|
||||
case IDS_SPC_01: p = "Champ"; break;
|
||||
case IDS_SPC_02: p = "Nom_Colonne"; break;
|
||||
case IDS_SPC_03: p = "Type_Donn<EFBFBD>es"; break;
|
||||
case IDS_SPC_04: p = "Nom_Type"; break;
|
||||
case IDS_SPC_05: p = "Pr<EFBFBD>cision"; break;
|
||||
case IDS_SPC_06: p = "Longueur"; break;
|
||||
case IDS_SPC_07: p = "Echelle"; break;
|
||||
case IDS_SPC_08: p = "Pseudo_Colonne"; break;
|
||||
#else // English
|
||||
case IDS_01: p = "%s: error allocating communication buffer of %d bytes"; break;
|
||||
case IDS_02: p = "%s: error allocating parser memory for %d columns"; break;
|
||||
case IDS_03: p = "%s: Invalid special command"; break;
|
||||
case IDS_04: p = "%s: Wrong number of arguments %d"; break;
|
||||
case IDS_05: p = "%s"; break;
|
||||
case IDS_06: p = "%s: Command bigger than internal buffer of size = %d"; break;
|
||||
case IDS_07: p = "%s: Data truncated to buffer size, actual length is %d bytes"; break;
|
||||
case IDS_08: p = "%s: Result bigger than internal buffer of size = %d"; break;
|
||||
case IDS_09: p = "Error in %s: %s"; break;
|
||||
case IDS_10: p = "%s: error allocating instance memory of %d bytes"; break;
|
||||
case IDS_11: p = "%s: wrong connection key value %d"; break;
|
||||
case IDS_12: p = "%s: No more than %d connections allowed from one process"; break;
|
||||
case IDS_13: p = "%s: invalid connection key value %d"; break;
|
||||
case IDS_14: p = "SafeDB: %s rc=%d"; break;
|
||||
case IDS_15: p = "Wrong communication Dll called for engine %s"; break;
|
||||
case IDS_TAB_01: p = "Qualifier"; break;
|
||||
case IDS_TAB_02: p = "Owner"; break;
|
||||
case IDS_TAB_03: p = "Name"; break;
|
||||
case IDS_TAB_04: p = "Type"; break;
|
||||
case IDS_TAB_05: p = "Remark"; break;
|
||||
case IDS_COL_01: p = "Table_Qualif"; break;
|
||||
case IDS_COL_02: p = "Table_Owner"; break;
|
||||
case IDS_COL_03: p = "Table_Name"; break;
|
||||
case IDS_COL_04: p = "Column_Name"; break;
|
||||
case IDS_COL_05: p = "Data_Type"; break;
|
||||
case IDS_COL_06: p = "Type_Name"; break;
|
||||
case IDS_COL_07: p = "Precision"; break;
|
||||
case IDS_COL_08: p = "Length"; break;
|
||||
case IDS_COL_09: p = "Scale"; break;
|
||||
case IDS_COL_10: p = "Radix"; break;
|
||||
case IDS_COL_11: p = "Nullable"; break;
|
||||
case IDS_COL_12: p = "Remarks"; break;
|
||||
case IDS_INF_01: p = "Type_Name"; break;
|
||||
case IDS_INF_02: p = "Data_Type"; break;
|
||||
case IDS_INF_03: p = "Precision"; break;
|
||||
case IDS_INF_04: p = "Literal_Prefix"; break;
|
||||
case IDS_INF_05: p = "Literal_Suffix"; break;
|
||||
case IDS_INF_06: p = "Create_Params"; break;
|
||||
case IDS_INF_07: p = "Nullable"; break;
|
||||
case IDS_INF_08: p = "Case_Sensitive"; break;
|
||||
case IDS_INF_09: p = "Searchable"; break;
|
||||
case IDS_INF_10: p = "Unsigned_Attribute"; break;
|
||||
case IDS_INF_11: p = "Money"; break;
|
||||
case IDS_INF_12: p = "Auto_Increment"; break;
|
||||
case IDS_INF_13: p = "Local_Type_Name"; break;
|
||||
case IDS_INF_14: p = "Minimum_Scale"; break;
|
||||
case IDS_INF_15: p = "Maximum_Scale"; break;
|
||||
case IDS_PKY_01: p = "Table_Qualifier"; break;
|
||||
case IDS_PKY_02: p = "Table_Owner"; break;
|
||||
case IDS_PKY_03: p = "Table_Name"; break;
|
||||
case IDS_PKY_04: p = "Column_Name"; break;
|
||||
case IDS_PKY_05: p = "Key_Seq"; break;
|
||||
case IDS_PKY_06: p = "Pk_Name"; break;
|
||||
case IDS_FKY_01: p = "PKTable_Qualifier"; break;
|
||||
case IDS_FKY_02: p = "PKTable_Owner"; break;
|
||||
case IDS_FKY_03: p = "PKTable_Name"; break;
|
||||
case IDS_FKY_04: p = "PKColumn_Name"; break;
|
||||
case IDS_FKY_05: p = "FKTable_Qualifier"; break;
|
||||
case IDS_FKY_06: p = "FKTable_Owner"; break;
|
||||
case IDS_FKY_07: p = "FKTable_Name"; break;
|
||||
case IDS_FKY_08: p = "FKColumn_Name"; break;
|
||||
case IDS_FKY_09: p = "Key_Seq"; break;
|
||||
case IDS_FKY_10: p = "Update_Rule"; break;
|
||||
case IDS_FKY_11: p = "Delete_Rule"; break;
|
||||
case IDS_FKY_12: p = "FK_Name"; break;
|
||||
case IDS_FKY_13: p = "PK_Name"; break;
|
||||
case IDS_STA_01: p = "Table_Qualifier"; break;
|
||||
case IDS_STA_02: p = "Table_Owner"; break;
|
||||
case IDS_STA_03: p = "Table_Name"; break;
|
||||
case IDS_STA_04: p = "Non_Unique"; break;
|
||||
case IDS_STA_05: p = "Index_Qualifier"; break;
|
||||
case IDS_STA_06: p = "Index_Name"; break;
|
||||
case IDS_STA_07: p = "Type"; break;
|
||||
case IDS_STA_08: p = "Seq_in_Index"; break;
|
||||
case IDS_STA_09: p = "Column_Name"; break;
|
||||
case IDS_STA_10: p = "Collation"; break;
|
||||
case IDS_STA_11: p = "Cardinality"; break;
|
||||
case IDS_STA_12: p = "Pages"; break;
|
||||
case IDS_STA_13: p = "Filter_Condition"; break;
|
||||
case IDS_SPC_01: p = "Scope"; break;
|
||||
case IDS_SPC_02: p = "Column_Name"; break;
|
||||
case IDS_SPC_03: p = "Data_Type"; break;
|
||||
case IDS_SPC_04: p = "Type_Name"; break;
|
||||
case IDS_SPC_05: p = "Precision"; break;
|
||||
case IDS_SPC_06: p = "Length"; break;
|
||||
case IDS_SPC_07: p = "Scale"; break;
|
||||
case IDS_SPC_08: p = "Pseudo_Column"; break;
|
||||
#endif // English
|
||||
default:
|
||||
sprintf(msg, "ID=%d unknown", id);
|
||||
p = msg;
|
||||
} // endswitch(id)
|
||||
|
||||
return sprintf(buf, "%.*s", bufsize-1, p);
|
||||
} // end of GetRcString
|
||||
421
storage/connect/reldef.cpp
Normal file
421
storage/connect/reldef.cpp
Normal file
@@ -0,0 +1,421 @@
|
||||
/************* RelDef CPP Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: REFDEF */
|
||||
/* ------------- */
|
||||
/* Version 1.3 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2004-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the DB definition related routines. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#include <sqlext.h>
|
||||
#else
|
||||
#include <dlfcn.h> // dlopen(), dlclose(), dlsym() ...
|
||||
#include "osutil.h"
|
||||
//#include "sqlext.h"
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files */
|
||||
/* */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing DB application declarations. */
|
||||
/* catalog.h is header containing DB description declarations. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "reldef.h"
|
||||
#include "colblk.h"
|
||||
#include "filamap.h"
|
||||
#include "filamfix.h"
|
||||
#include "filamvct.h"
|
||||
#if defined(ZIP_SUPPORT)
|
||||
#include "filamzip.h"
|
||||
#endif // ZIP_SUPPORT
|
||||
#include "tabdos.h"
|
||||
#include "valblk.h"
|
||||
#include "tabmul.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* External static variables. */
|
||||
/***********************************************************************/
|
||||
//extern "C" char plgini[];
|
||||
|
||||
/* --------------------------- Class RELDEF -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* RELDEF Constructor. */
|
||||
/***********************************************************************/
|
||||
RELDEF::RELDEF(void)
|
||||
{
|
||||
Next = NULL;
|
||||
To_Cols = NULL;
|
||||
Name = NULL;
|
||||
Database = NULL;
|
||||
Cat = NULL;
|
||||
} // end of RELDEF constructor
|
||||
|
||||
/* --------------------------- Class TABDEF -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* TABDEF Constructor. */
|
||||
/***********************************************************************/
|
||||
TABDEF::TABDEF(void)
|
||||
{
|
||||
Owner = NULL;
|
||||
Desc = NULL;
|
||||
Card = 0;
|
||||
Elemt = 0;
|
||||
Sort = 0;
|
||||
Multiple = 0;
|
||||
Degree = 0;
|
||||
Pseudo = 0;
|
||||
Read_Only = false;
|
||||
} // end of TABDEF constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Define: initialize the table definition block from XDB file. */
|
||||
/***********************************************************************/
|
||||
bool TABDEF::Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am)
|
||||
{
|
||||
char buf[8];
|
||||
int poff = 0;
|
||||
void *memp = cat->Descp;
|
||||
|
||||
Name = (PSZ)PlugSubAlloc(g, memp, strlen(name) + 1);
|
||||
strcpy(Name, name);
|
||||
Cat = cat;
|
||||
Elemt = cat->GetIntCatInfo(name, "Elements", 0);
|
||||
Multiple = cat->GetIntCatInfo(name, "Multiple", 0);
|
||||
Degree = cat->GetIntCatInfo(name, "Degree", 0);
|
||||
cat->GetCharCatInfo(name, "ReadOnly", "No", buf, sizeof(buf));
|
||||
Read_Only = (toupper(*buf) == 'Y');
|
||||
|
||||
// Get The column definitions
|
||||
if ((poff = cat->GetColCatInfo(g, this)) < 0)
|
||||
return true;
|
||||
|
||||
// Do the definition of AM specific fields
|
||||
return DefineAM(g, am, poff);
|
||||
} // end of Define
|
||||
|
||||
/* --------------------------- Class OEMDEF -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetXdef: get the external TABDEF from OEM module. */
|
||||
/***********************************************************************/
|
||||
PTABDEF OEMDEF::GetXdef(PGLOBAL g)
|
||||
{
|
||||
typedef PTABDEF (__stdcall *XGETDEF) (PGLOBAL, void *);
|
||||
char c, getname[40] = "Get";
|
||||
PTABDEF xdefp;
|
||||
XGETDEF getdef = NULL;
|
||||
PCATLG cat = Cat;
|
||||
void *memp = cat->Descp;
|
||||
|
||||
#if defined(WIN32)
|
||||
// Is the DLL already loaded?
|
||||
if (!Hdll && !(Hdll = GetModuleHandle(Module)))
|
||||
// No, load the Dll implementing the function
|
||||
if (!(Hdll = LoadLibrary(Module))) {
|
||||
char buf[256];
|
||||
DWORD rc = GetLastError();
|
||||
|
||||
sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, Module);
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
|
||||
(LPTSTR)buf, sizeof(buf), NULL);
|
||||
strcat(strcat(g->Message, ": "), buf);
|
||||
return NULL;
|
||||
} // endif hDll
|
||||
|
||||
// The exported name is always in uppercase
|
||||
for (int i = 0; ; i++) {
|
||||
c = Subtype[i];
|
||||
getname[i + 3] = toupper(c);
|
||||
if (!c) break;
|
||||
} // endfor i
|
||||
|
||||
// Get the function returning an instance of the external DEF class
|
||||
if (!(getdef = (XGETDEF)GetProcAddress((HINSTANCE)Hdll, getname))) {
|
||||
sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), getname);
|
||||
FreeLibrary((HMODULE)Hdll);
|
||||
return NULL;
|
||||
} // endif getdef
|
||||
#else // !WIN32
|
||||
const char *error = NULL;
|
||||
// Is the library already loaded?
|
||||
// if (!Hdll && !(Hdll = ???))
|
||||
// Load the desired shared library
|
||||
if (!(Hdll = dlopen(Module, RTLD_LAZY))) {
|
||||
error = dlerror();
|
||||
sprintf(g->Message, MSG(SHARED_LIB_ERR), Module, SVP(error));
|
||||
return NULL;
|
||||
} // endif Hdll
|
||||
|
||||
// The exported name is always in uppercase
|
||||
for (int i = 0; ; i++) {
|
||||
c = Subtype[i];
|
||||
getname[i + 3] = toupper(c);
|
||||
if (!c) break;
|
||||
} // endfor i
|
||||
|
||||
// Get the function returning an instance of the external DEF class
|
||||
if (!(getdef = (XGETDEF)dlsym(Hdll, getname))) {
|
||||
error = dlerror();
|
||||
sprintf(g->Message, MSG(GET_FUNC_ERR), getname, SVP(error));
|
||||
dlclose(Hdll);
|
||||
return NULL;
|
||||
} // endif getdef
|
||||
#endif // !WIN32
|
||||
|
||||
// Just in case the external Get function does not set error messages
|
||||
sprintf(g->Message, MSG(DEF_ALLOC_ERROR), Subtype);
|
||||
|
||||
// Get the table definition block
|
||||
if (!(xdefp = getdef(g, memp)))
|
||||
return NULL;
|
||||
|
||||
// Have the external class do its complete definition
|
||||
if (!cat->Cbuf) {
|
||||
// Suballocate a temporary buffer for the entire column section
|
||||
cat->Cblen = cat->GetSizeCatInfo("Database", "Colsize", "8K");
|
||||
cat->Cbuf = (char*)PlugSubAlloc(g, NULL, cat->Cblen);
|
||||
} // endif Cbuf
|
||||
|
||||
// Here "OEM" should be replace by a more useful value
|
||||
if (xdefp->Define(g, cat, Name, "OEM"))
|
||||
return NULL;
|
||||
|
||||
// Ok, return external block
|
||||
return xdefp;
|
||||
} // end of GetXdef
|
||||
|
||||
/***********************************************************************/
|
||||
/* DeleteTableFile: Delete an OEM table file if applicable. */
|
||||
/***********************************************************************/
|
||||
bool OEMDEF::DeleteTableFile(PGLOBAL g)
|
||||
{
|
||||
if (!Pxdef)
|
||||
Pxdef = GetXdef(g);
|
||||
|
||||
return (Pxdef) ? Pxdef->DeleteTableFile(g) : true;
|
||||
} // end of DeleteTableFile
|
||||
|
||||
/***********************************************************************/
|
||||
/* Define: initialize the table definition block from XDB file. */
|
||||
/***********************************************************************/
|
||||
bool OEMDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
void *memp = Cat->Descp;
|
||||
|
||||
Module = Cat->GetStringCatInfo(g, Name, "Module", "");
|
||||
Subtype = Cat->GetStringCatInfo(g, Name, "Subtype", Module);
|
||||
|
||||
if (!*Module)
|
||||
Module = Subtype;
|
||||
|
||||
Desc = (char*)PlugSubAlloc(g, memp, strlen(Module)
|
||||
+ strlen(Subtype) + 3);
|
||||
sprintf(Desc, "%s(%s)", Module, Subtype);
|
||||
return false;
|
||||
} // end of DefineAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTable: makes a new Table Description Block. */
|
||||
/***********************************************************************/
|
||||
PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode)
|
||||
{
|
||||
RECFM rfm;
|
||||
PTDBASE tdbp = NULL;
|
||||
|
||||
// If define block not here yet, get it now
|
||||
if (!Pxdef && !(Pxdef = GetXdef(g)))
|
||||
return NULL; // Error
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate a TDB of the proper type. */
|
||||
/* Column blocks will be allocated only when needed. */
|
||||
/*********************************************************************/
|
||||
if (!(tdbp = (PTDBASE)Pxdef->GetTable(g, mode)))
|
||||
return NULL;
|
||||
else
|
||||
rfm = tdbp->GetFtype();
|
||||
|
||||
if (rfm == RECFM_NAF)
|
||||
return tdbp;
|
||||
else if (rfm == RECFM_OEM) {
|
||||
if (Multiple)
|
||||
tdbp = new(g) TDBMUL(tdbp); // No block optimization yet
|
||||
|
||||
return tdbp;
|
||||
} // endif OEM
|
||||
|
||||
/*********************************************************************/
|
||||
/* The OEM table is based on a file type (currently DOS+ only) */
|
||||
/*********************************************************************/
|
||||
assert (rfm == RECFM_VAR || rfm == RECFM_FIX ||
|
||||
rfm == RECFM_BIN || rfm == RECFM_VCT);
|
||||
|
||||
PTXF txfp = NULL;
|
||||
PDOSDEF defp = (PDOSDEF)Pxdef;
|
||||
bool map = defp->Mapped && mode != MODE_INSERT &&
|
||||
!(PlgGetUser(g)->UseTemp == TMP_FORCE &&
|
||||
(mode == MODE_UPDATE || mode == MODE_DELETE));
|
||||
int cmpr = defp->Compressed;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate table and file processing class of the proper type. */
|
||||
/* Column blocks will be allocated only when needed. */
|
||||
/*********************************************************************/
|
||||
if (!((PTDBDOS)tdbp)->GetTxfp()) {
|
||||
if (cmpr) {
|
||||
#if defined(ZIP_SUPPORT)
|
||||
if (cmpr == 1)
|
||||
txfp = new(g) ZIPFAM(defp);
|
||||
else {
|
||||
strcpy(g->Message, "Compress 2 not supported yet");
|
||||
// txfp = new(g) ZLBFAM(defp);
|
||||
return NULL;
|
||||
} // endelse
|
||||
#else // !ZIP_SUPPORT
|
||||
strcpy(g->Message, "Compress not supported");
|
||||
return NULL;
|
||||
#endif // !ZIP_SUPPORT
|
||||
} else if (rfm == RECFM_VAR) {
|
||||
if (map)
|
||||
txfp = new(g) MAPFAM(defp);
|
||||
else
|
||||
txfp = new(g) DOSFAM(defp);
|
||||
|
||||
} else if (rfm == RECFM_FIX || rfm == RECFM_FIX) {
|
||||
if (map)
|
||||
txfp = new(g) MPXFAM(defp);
|
||||
else
|
||||
txfp = new(g) FIXFAM(defp);
|
||||
|
||||
} else if (rfm == RECFM_VCT) {
|
||||
assert (Pxdef->GetDefType() == TYPE_AM_VCT);
|
||||
|
||||
if (map)
|
||||
txfp = new(g) VCMFAM((PVCTDEF)defp);
|
||||
else
|
||||
txfp = new(g) VCTFAM((PVCTDEF)defp);
|
||||
|
||||
} // endif's
|
||||
|
||||
((PTDBDOS)tdbp)->SetTxfp(txfp);
|
||||
} // endif Txfp
|
||||
|
||||
if (Multiple)
|
||||
tdbp = new(g) TDBMUL(tdbp);
|
||||
|
||||
return tdbp;
|
||||
} // end of GetTable
|
||||
|
||||
/* --------------------------- Class COLCRT -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* COLCRT Constructors. */
|
||||
/***********************************************************************/
|
||||
COLCRT::COLCRT(PSZ name)
|
||||
{
|
||||
Next = NULL;
|
||||
Name = name;
|
||||
Desc = NULL;
|
||||
Decode = NULL;
|
||||
Fmt = NULL;
|
||||
Offset = -1;
|
||||
Long = -1;
|
||||
//Freq = -1;
|
||||
Key = -1;
|
||||
Prec = -1;
|
||||
Opt = -1;
|
||||
DataType = '*';
|
||||
} // end of COLCRT constructor for table creation
|
||||
|
||||
COLCRT::COLCRT(void)
|
||||
{
|
||||
Next = NULL;
|
||||
Name = NULL;
|
||||
Desc = NULL;
|
||||
Decode = NULL;
|
||||
Fmt = NULL;
|
||||
Offset = 0;
|
||||
Long = 0;
|
||||
//Freq = 0;
|
||||
Key = 0;
|
||||
Prec = 0;
|
||||
Opt = 0;
|
||||
DataType = '*';
|
||||
} // end of COLCRT constructor for table & view definition
|
||||
|
||||
/* --------------------------- Class COLDEF -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* COLDEF Constructor. */
|
||||
/***********************************************************************/
|
||||
COLDEF::COLDEF(void) : COLCRT()
|
||||
{
|
||||
Buf_Type = TYPE_ERROR;
|
||||
Clen = 0;
|
||||
Poff = 0;
|
||||
memset(&F, 0, sizeof(FORMAT));
|
||||
Flags = 0;
|
||||
} // end of COLDEF constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Define: initialize a column definition from a COLINFO structure. */
|
||||
/***********************************************************************/
|
||||
int COLDEF::Define(PGLOBAL g, void *memp, PCOLINFO cfp, int poff)
|
||||
{
|
||||
Name = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Name) + 1);
|
||||
strcpy(Name, cfp->Name);
|
||||
|
||||
Poff = poff;
|
||||
Buf_Type = cfp->Type;
|
||||
|
||||
if ((Clen = GetTypeSize(Buf_Type, cfp->Length)) <= 0) {
|
||||
sprintf(g->Message, MSG(BAD_COL_TYPE), GetTypeName(Buf_Type), Name);
|
||||
return -1;
|
||||
} // endswitch
|
||||
|
||||
strcpy(F.Type, GetFormatType(Buf_Type));
|
||||
F.Length = cfp->Length;
|
||||
F.Prec = cfp->Prec;
|
||||
Offset = (cfp->Offset < 0) ? poff : cfp->Offset;
|
||||
Long = cfp->Length;
|
||||
Opt = cfp->Opt;
|
||||
Key = cfp->Key;
|
||||
//Freq = cfp->Freq;
|
||||
|
||||
if (cfp->Remark && *cfp->Remark) {
|
||||
Desc = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Remark) + 1);
|
||||
strcpy(Desc, cfp->Remark);
|
||||
} // endif Remark
|
||||
|
||||
if (cfp->Datefmt) {
|
||||
Decode = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Datefmt) + 1);
|
||||
strcpy(Decode, cfp->Datefmt);
|
||||
} // endif Datefmt
|
||||
|
||||
if (cfp->Fieldfmt) {
|
||||
Fmt = (PSZ)PlugSubAlloc(g, memp, strlen(cfp->Fieldfmt) + 1);
|
||||
strcpy(Fmt, cfp->Fieldfmt);
|
||||
} // endif Fieldfmt
|
||||
|
||||
Flags = cfp->Flags;
|
||||
return (Flags & U_VIRTUAL) ? 0 : Long;
|
||||
} // end of Define
|
||||
|
||||
/* ------------------------- End of RelDef --------------------------- */
|
||||
194
storage/connect/reldef.h
Normal file
194
storage/connect/reldef.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/*************** RelDef H Declares Source Code File (.H) ***************/
|
||||
/* Name: RELDEF.H Version 1.3 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2004-2012 */
|
||||
/* */
|
||||
/* This file contains the DEF classes definitions. */
|
||||
/***********************************************************************/
|
||||
|
||||
#ifndef __RELDEF_H
|
||||
#define __RELDEF_H
|
||||
|
||||
#include "block.h"
|
||||
#include "catalog.h"
|
||||
|
||||
typedef class INDEXDEF *PIXDEF;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Table or View (relation) definition block. */
|
||||
/***********************************************************************/
|
||||
class DllExport RELDEF : public BLOCK { // Relation definition block
|
||||
friend class CATALOG;
|
||||
friend class PLUGCAT;
|
||||
friend class MYCAT;
|
||||
public:
|
||||
RELDEF(void); // Constructor
|
||||
|
||||
// Implementation
|
||||
PRELDEF GetNext(void) {return Next;}
|
||||
PSZ GetName(void) {return Name;}
|
||||
PSZ GetDB(void) {return (PSZ)Database;}
|
||||
PCOLDEF GetCols(void) {return To_Cols;}
|
||||
void SetCols(PCOLDEF pcd) {To_Cols = pcd;}
|
||||
PCATLG GetCat(void) {return Cat;}
|
||||
virtual const char *GetType(void) = 0;
|
||||
virtual AMT GetDefType(void) = 0;
|
||||
|
||||
// Methods
|
||||
virtual bool DeleteTableFile(PGLOBAL g) {return true;}
|
||||
virtual bool Indexable(void) {return false;}
|
||||
virtual bool Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am) = 0;
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE mode) = 0;
|
||||
|
||||
protected:
|
||||
PRELDEF Next; /* To next definition block */
|
||||
PSZ Name; /* Name of the view */
|
||||
LPCSTR Database; /* Table database */
|
||||
PCOLDEF To_Cols; /* To a list of column desc */
|
||||
PCATLG Cat; /* To DB catalog info */
|
||||
}; // end of RELDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* These classes correspond to the data base description contained in */
|
||||
/* a .XDB file the A.M. DOS, FIX, CSV, MAP, BIN, VCT, PLG, ODBC, DOM. */
|
||||
/***********************************************************************/
|
||||
class DllExport TABDEF : public RELDEF { /* Logical table descriptor */
|
||||
friend class CATALOG;
|
||||
friend class PLUGCAT;
|
||||
friend class MYCAT;
|
||||
public:
|
||||
// Constructor
|
||||
TABDEF(void); // Constructor
|
||||
|
||||
// Implementation
|
||||
int GetDegree(void) {return Degree;}
|
||||
void SetDegree(int d) {Degree = d;}
|
||||
int GetElemt(void) {return Elemt;}
|
||||
void SetNext(PTABDEF tdfp) {Next = tdfp;}
|
||||
int GetMultiple(void) {return Multiple;}
|
||||
int GetPseudo(void) {return Pseudo;}
|
||||
PSZ GetPath(void)
|
||||
{return (Database) ? (PSZ)Database : Cat->GetDataPath();}
|
||||
bool SepIndex(void) {return Cat->GetSepIndex();}
|
||||
bool IsReadOnly(void) {return Read_Only;}
|
||||
virtual AMT GetDefType(void) {return TYPE_AM_TAB;}
|
||||
virtual PIXDEF GetIndx(void) {return NULL;}
|
||||
virtual void SetIndx(PIXDEF xp) {}
|
||||
virtual bool IsHuge(void) {return false;}
|
||||
|
||||
// Methods
|
||||
bool DropTable(PGLOBAL g, PSZ name);
|
||||
virtual bool Define(PGLOBAL g, PCATLG cat, LPCSTR name, LPCSTR am);
|
||||
virtual bool DefineAM(PGLOBAL, LPCSTR, int) = 0;
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PSZ Owner; /* Table owner (for ODBC) */
|
||||
PSZ Desc; /* Table description */
|
||||
int Card; /* (max) number of rows in table */
|
||||
int Elemt; /* Number of rows in blocks or rowset */
|
||||
int Sort; /* Table already sorted ??? */
|
||||
int Multiple; /* 0: No 1: DIR 2: Section 3: filelist */
|
||||
int Degree; /* Number of columns in the table */
|
||||
int Pseudo; /* Bit: 1 ROWID Ok, 2 FILEID Ok */
|
||||
bool Read_Only; /* true for read only tables */
|
||||
}; // end of TABDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* Externally defined OEM tables. */
|
||||
/***********************************************************************/
|
||||
class DllExport OEMDEF : public TABDEF { /* OEM table */
|
||||
friend class CATALOG;
|
||||
friend class PLUGCAT;
|
||||
friend class MYCAT;
|
||||
public:
|
||||
// Constructor
|
||||
OEMDEF(void) {Hdll = NULL; Pxdef = NULL; Module = Subtype = NULL;}
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "OEM";}
|
||||
virtual AMT GetDefType(void) {return TYPE_AM_OEM;}
|
||||
|
||||
// Methods
|
||||
virtual bool DeleteTableFile(PGLOBAL g);
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE mode);
|
||||
|
||||
protected:
|
||||
PTABDEF GetXdef(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
#if defined(WIN32)
|
||||
HANDLE Hdll; /* Handle to the external DLL */
|
||||
#else // !WIN32
|
||||
void *Hdll; /* Handle for the loaded shared library */
|
||||
#endif // !WIN32
|
||||
PTABDEF Pxdef; /* Pointer to the external TABDEF class */
|
||||
char *Module; /* Path/Name of the DLL implenting it */
|
||||
char *Subtype; /* The name of the OEM table sub type */
|
||||
}; // end of OEMDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* Column definition block used during creation. */
|
||||
/***********************************************************************/
|
||||
class DllExport COLCRT : public BLOCK { /* Column description block */
|
||||
friend class TABDEF;
|
||||
public:
|
||||
COLCRT(PSZ name); // Constructor
|
||||
COLCRT(void); // Constructor (for views)
|
||||
|
||||
// Implementation
|
||||
PSZ GetName(void) {return Name;}
|
||||
PSZ GetDecode(void) {return Decode;}
|
||||
PSZ GetFmt(void) {return Fmt;}
|
||||
int GetOpt(void) {return Opt;}
|
||||
int GetLong(void) {return Long;}
|
||||
int GetOffset(void) {return Offset;}
|
||||
void SetOffset(int offset) {Offset = offset;}
|
||||
|
||||
protected:
|
||||
PCOLCRT Next; /* To next block */
|
||||
PSZ Name; /* Column name */
|
||||
PSZ Desc; /* Column description */
|
||||
PSZ Decode; /* Date format */
|
||||
PSZ Fmt; /* Input format for formatted files */
|
||||
int Offset; /* Offset of field within record */
|
||||
int Long; /* Length of field in file record (!BIN) */
|
||||
int Key; /* Key (greater than 1 if multiple) */
|
||||
int Prec; /* Precision for float values */
|
||||
int Opt; /* 0:Not 1:clustered 2:sorted-asc 3:desc */
|
||||
char DataType; /* Internal data type (C, N, F, T) */
|
||||
}; // end of COLCRT
|
||||
|
||||
/***********************************************************************/
|
||||
/* Column definition block. */
|
||||
/***********************************************************************/
|
||||
class DllExport COLDEF : public COLCRT { /* Column description block */
|
||||
friend class CATALOG;
|
||||
friend class PLUGCAT;
|
||||
friend class MYCAT;
|
||||
friend class COLBLK;
|
||||
friend class DBFFAM;
|
||||
public:
|
||||
COLDEF(void); // Constructor
|
||||
|
||||
// Implementation
|
||||
PCOLDEF GetNext(void) {return (PCOLDEF)Next;}
|
||||
void SetNext(PCOLDEF pcdf) {Next = pcdf;}
|
||||
int GetLength(void) {return (int)F.Length;}
|
||||
int GetClen(void) {return Clen;}
|
||||
int GetType(void) {return Buf_Type;}
|
||||
int GetPoff(void) {return Poff;}
|
||||
int Define(PGLOBAL g, void *memp, PCOLINFO cfp, int poff);
|
||||
void Define(PGLOBAL g, PCOL colp);
|
||||
|
||||
protected:
|
||||
int Buf_Type; /* Internal data type */
|
||||
int Clen; /* Internal data size in chars (bytes) */
|
||||
int Poff; /* Calculated offset for Packed tables */
|
||||
FORMAT F; /* Output format (should be in COLCRT) */
|
||||
ushort Flags; /* Used by MariaDB CONNECT handler */
|
||||
}; // end of COLDEF
|
||||
|
||||
#endif // __RELDEF_H
|
||||
|
||||
136
storage/connect/resource.h
Normal file
136
storage/connect/resource.h
Normal file
@@ -0,0 +1,136 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by PlgSock.rc
|
||||
//
|
||||
#define IDS_00 115
|
||||
#define IDS_01 116
|
||||
#define IDS_02 117
|
||||
#define IDS_03 118
|
||||
#define IDS_04 119
|
||||
#define IDS_05 120
|
||||
#define IDS_06 121
|
||||
#define IDS_07 122
|
||||
#define IDS_08 123
|
||||
#define IDS_09 124
|
||||
#define IDS_10 125
|
||||
#define IDS_11 126
|
||||
#define IDS_12 127
|
||||
#define IDS_13 128
|
||||
#define IDS_14 129
|
||||
#define IDS_15 130
|
||||
#define IDS_16 131
|
||||
#define IDS_17 132
|
||||
#define IDS_18 133
|
||||
#define IDS_19 134
|
||||
#define IDS_20 135
|
||||
#define IDS_21 136
|
||||
#define IDS_TABLES 143
|
||||
#define IDS_TAB_01 144
|
||||
#define IDS_TAB_02 145
|
||||
#define IDS_TAB_03 146
|
||||
#define IDS_TAB_04 147
|
||||
#define IDS_TAB_05 148
|
||||
#define IDS_COLUMNS 159
|
||||
#define IDS_COL_01 160
|
||||
#define IDS_COL_02 161
|
||||
#define IDS_COL_03 162
|
||||
#define IDS_COL_04 163
|
||||
#define IDS_COL_05 164
|
||||
#define IDS_COL_06 165
|
||||
#define IDS_COL_07 166
|
||||
#define IDS_COL_08 167
|
||||
#define IDS_COL_09 168
|
||||
#define IDS_COL_10 169
|
||||
#define IDS_COL_11 170
|
||||
#define IDS_COL_12 171
|
||||
#define IDS_INFO 175
|
||||
#define IDS_INF_01 176
|
||||
#define IDS_INF_02 177
|
||||
#define IDS_INF_03 178
|
||||
#define IDS_INF_04 179
|
||||
#define IDS_INF_05 180
|
||||
#define IDS_INF_06 181
|
||||
#define IDS_INF_07 182
|
||||
#define IDS_INF_08 183
|
||||
#define IDS_INF_09 184
|
||||
#define IDS_INF_10 185
|
||||
#define IDS_INF_11 186
|
||||
#define IDS_INF_12 187
|
||||
#define IDS_INF_13 188
|
||||
#define IDS_INF_14 189
|
||||
#define IDS_INF_15 190
|
||||
#define IDS_PKEY 191
|
||||
#define IDS_PKY_01 192
|
||||
#define IDS_PKY_02 193
|
||||
#define IDS_PKY_03 194
|
||||
#define IDS_PKY_04 195
|
||||
#define IDS_PKY_05 196
|
||||
#define IDS_PKY_06 197
|
||||
#define IDS_FKEY 207
|
||||
#define IDS_FKY_01 208
|
||||
#define IDS_FKY_02 209
|
||||
#define IDS_FKY_03 210
|
||||
#define IDS_FKY_04 211
|
||||
#define IDS_FKY_05 212
|
||||
#define IDS_FKY_06 213
|
||||
#define IDS_FKY_07 214
|
||||
#define IDS_FKY_08 215
|
||||
#define IDS_FKY_09 216
|
||||
#define IDS_FKY_10 217
|
||||
#define IDS_FKY_11 218
|
||||
#define IDS_FKY_12 219
|
||||
#define IDS_FKY_13 220
|
||||
#define IDS_STAT 223
|
||||
#define IDS_STA_01 224
|
||||
#define IDS_STA_02 225
|
||||
#define IDS_STA_03 226
|
||||
#define IDS_STA_04 227
|
||||
#define IDS_STA_05 228
|
||||
#define IDS_STA_06 229
|
||||
#define IDS_STA_07 230
|
||||
#define IDS_STA_08 231
|
||||
#define IDS_STA_09 232
|
||||
#define IDS_STA_10 233
|
||||
#define IDS_STA_11 234
|
||||
#define IDS_STA_12 235
|
||||
#define IDS_STA_13 236
|
||||
#define IDS_SPCOLS 1247
|
||||
#define IDS_SPC_01 1248
|
||||
#define IDS_SPC_02 1249
|
||||
#define IDS_SPC_03 1250
|
||||
#define IDS_SPC_04 1251
|
||||
#define IDS_SPC_05 1252
|
||||
#define IDS_SPC_06 1253
|
||||
#define IDS_SPC_07 1254
|
||||
#define IDS_SPC_08 1255
|
||||
#define IDS_CNX 1263
|
||||
#define IDS_CNX_01 1264
|
||||
#define IDS_CNX_02 1265
|
||||
#define IDS_CNX_03 1266
|
||||
#define IDS_CNX_04 1267
|
||||
#define IDS_PLGCOL 1279
|
||||
#define IDS_PLG_01 1280
|
||||
#define IDS_PLG_02 1281
|
||||
#define IDS_PLG_03 1282
|
||||
#define IDS_PLG_04 1283
|
||||
#define IDS_PLG_05 1284
|
||||
#define IDS_PLG_06 1285
|
||||
#define IDS_PLG_07 1286
|
||||
#define IDS_PLG_08 1287
|
||||
#define IDS_PLG_09 1288
|
||||
#define IDS_DSC 1295
|
||||
#define IDS_DSC_01 1296
|
||||
#define IDS_DSC_02 1297
|
||||
#define IDS_DSC_03 1298
|
||||
#define IDS_DSC_04 1299
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 1300
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1440
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
30
storage/connect/sqlutil.h
Normal file
30
storage/connect/sqlutil.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#define SQL_UNKNOWN_TYPE 0
|
||||
#define SQL_CHAR 1
|
||||
#define SQL_NUMERIC 2
|
||||
#define SQL_DECIMAL 3
|
||||
#define SQL_INTEGER 4
|
||||
#define SQL_SMALLINT 5
|
||||
#define SQL_FLOAT 6
|
||||
#define SQL_REAL 7
|
||||
#define SQL_DOUBLE 8
|
||||
#define SQL_DATETIME 9
|
||||
#define SQL_VARCHAR 12
|
||||
#define SQL_TYPE_NULL 0
|
||||
#define SQL_DATE 9
|
||||
#define SQL_INTERVAL 10
|
||||
#define SQL_TIME 10
|
||||
#define SQL_TIMESTAMP 11
|
||||
#define SQL_LONGVARCHAR (-1)
|
||||
#define SQL_BINARY (-2)
|
||||
#define SQL_VARBINARY (-3)
|
||||
#define SQL_LONGVARBINARY (-4)
|
||||
#define SQL_BIGINT (-5)
|
||||
#define SQL_TINYINT (-6)
|
||||
#define SQL_BIT (-7)
|
||||
#define SQL_GUID (-11)
|
||||
#define SQL_C_CHAR SQL_CHAR /* CHAR, VARCHAR, DECIMAL, NUMERIC */
|
||||
#define SQL_C_LONG SQL_INTEGER /* INTEGER */
|
||||
#define SQL_C_SHORT SQL_SMALLINT /* SMALLINT */
|
||||
#define SQL_C_FLOAT SQL_REAL /* REAL */
|
||||
#define SQL_C_DOUBLE SQL_DOUBLE /* FLOAT, DOUBLE */
|
||||
#define SQL_C_TIMESTAMP SQL_TIMESTAMP
|
||||
174
storage/connect/tabcol.cpp
Normal file
174
storage/connect/tabcol.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/************* TabCol C++ Functions Source Code File (.CPP) ************/
|
||||
/* Name: TABCOL.CPP Version 2.6 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
|
||||
/* */
|
||||
/* This file contains the PlugDB++ XTAB, COLUMN and XORDER methods. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#if defined(OS16) || defined(OS32)
|
||||
#include <os2def.h>
|
||||
#else
|
||||
#include "my_global.h"
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/* global.h is header containing all global Plug declarations. */
|
||||
/* plgdbsem.h is header containing the DB applic. declarations. */
|
||||
/* tabcol.h is header containing XTAB, and XORDER declares. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "xtable.h"
|
||||
#include "tabcol.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* XTAB public constructor (in which Correl defaults to Name). */
|
||||
/***********************************************************************/
|
||||
XTAB::XTAB(LPCSTR name, LPCSTR correl) : Name(name)
|
||||
{
|
||||
Next = NULL;
|
||||
To_Tdb = NULL;
|
||||
Correl = (correl) ? correl : name;
|
||||
Creator = NULL;
|
||||
Qualifier = NULL;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" making new TABLE %s %s\n", Name, Correl);
|
||||
#endif
|
||||
} // end of XTAB constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* XTAB public constructor as a copy of another table. */
|
||||
/***********************************************************************/
|
||||
XTAB::XTAB(PTABLE tp) : Name(tp->Name)
|
||||
{
|
||||
Next = NULL;
|
||||
To_Tdb = NULL;
|
||||
Correl = tp->Correl;
|
||||
Creator = tp->Creator;
|
||||
Qualifier = tp->Qualifier;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" making copy TABLE %s %s\n", Name, Correl);
|
||||
#endif
|
||||
} // end of XTAB constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Link the tab2 tables to the tab1(this) table chain. */
|
||||
/***********************************************************************/
|
||||
PTABLE XTAB::Link(PTABLE tab2)
|
||||
{
|
||||
PTABLE tabp;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("Linking tables %s... to %s\n", Name, tab2->Name);
|
||||
#endif
|
||||
|
||||
for (tabp = this; tabp->Next; tabp = tabp->Next) ;
|
||||
|
||||
tabp->Next = tab2;
|
||||
return (this);
|
||||
} /* end of Link */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make file output of XTAB contents. */
|
||||
/***********************************************************************/
|
||||
void XTAB::Print(PGLOBAL g, FILE *f, uint n)
|
||||
{
|
||||
char m[64];
|
||||
|
||||
memset(m, ' ', n); /* Make margin string */
|
||||
m[n] = '\0';
|
||||
|
||||
for (PTABLE tp = this; tp; tp = tp->Next) {
|
||||
fprintf(f, "%sTABLE: %s.%s %s\n",
|
||||
m, SVP(tp->Creator), tp->Name, SVP(tp->Correl));
|
||||
PlugPutOut(g, f, TYPE_TDB, tp->To_Tdb, n + 2);
|
||||
} /* endfor tp */
|
||||
|
||||
} /* end of Print */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make string output of XTAB contents. */
|
||||
/***********************************************************************/
|
||||
void XTAB::Print(PGLOBAL g, char *ps, uint z)
|
||||
{
|
||||
char buf[128];
|
||||
int i, n = (int)z - 1;
|
||||
|
||||
*ps = '\0';
|
||||
|
||||
for (PTABLE tp = this; tp && n > 0; tp = tp->Next) {
|
||||
i = sprintf(buf, "TABLE: %s.%s %s To_Tdb=%p ",
|
||||
SVP(tp->Creator), tp->Name, SVP(tp->Correl), tp->To_Tdb);
|
||||
strncat(ps, buf, n);
|
||||
n -= i;
|
||||
} // endif tp
|
||||
|
||||
} /* end of Print */
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* COLUMN public constructor. */
|
||||
/***********************************************************************/
|
||||
COLUMN::COLUMN(LPCSTR name) : Name(name)
|
||||
{
|
||||
To_Table = NULL;
|
||||
To_Col = NULL;
|
||||
Qualifier = NULL;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" making new COLUMN %s\n", Name);
|
||||
#endif
|
||||
} // end of COLUMN constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* COLUMN SetFormat: should never be called. */
|
||||
/***********************************************************************/
|
||||
bool COLUMN::SetFormat(PGLOBAL g, FORMAT& fmt)
|
||||
{
|
||||
strcpy(g->Message, MSG(NO_FORMAT_COL));
|
||||
return true;
|
||||
} // end of SetFormat
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make file output of COLUMN contents. */
|
||||
/***********************************************************************/
|
||||
void COLUMN::Print(PGLOBAL g, FILE *f, uint n)
|
||||
{
|
||||
char m[64];
|
||||
|
||||
memset(m, ' ', n); // Make margin string
|
||||
m[n] = '\0';
|
||||
|
||||
if (Name)
|
||||
fprintf(f, "%sCOLUMN: %s.%s\n", m,
|
||||
((!Qualifier) ? (PSZ)"?" : Qualifier), Name);
|
||||
else // LNA
|
||||
fprintf(f, "%sC%d\n", m, (!Qualifier) ? 0 : *(int *)Qualifier);
|
||||
|
||||
PlugPutOut(g, f, TYPE_TABLE, To_Table, n + 2);
|
||||
PlugPutOut(g, f, TYPE_XOBJECT, To_Col, n + 2);
|
||||
} /* end of Print */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make string output of COLUMN contents. */
|
||||
/***********************************************************************/
|
||||
void COLUMN::Print(PGLOBAL g, char *ps, uint z)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
if (Name)
|
||||
sprintf(buf, "COLUMN: %s.%s table=%p col=%p",
|
||||
((!Qualifier) ? (PSZ)"?" : Qualifier), Name, To_Table, To_Col);
|
||||
else // LNA
|
||||
sprintf(buf, "C%d", (!Qualifier) ? 0 : *(int *)Qualifier);
|
||||
|
||||
strncpy(ps, buf, z);
|
||||
ps[z - 1] = '\0';
|
||||
} /* end of Print */
|
||||
110
storage/connect/tabcol.h
Normal file
110
storage/connect/tabcol.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*************** TabCol H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABCOL.H Version 2.7 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
|
||||
/* */
|
||||
/* This file contains the XTAB, COLUMN and XORDER class definitions. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/* block.h is header containing Block global declarations. */
|
||||
/***********************************************************************/
|
||||
#include "xobject.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definition of class XTAB with all its method functions. */
|
||||
/***********************************************************************/
|
||||
class DllExport XTAB: public BLOCK { // Table Name-Owner-Correl block.
|
||||
public:
|
||||
// Constructors
|
||||
XTAB(LPCSTR name, LPCSTR correl = NULL);
|
||||
XTAB(PTABLE tp);
|
||||
|
||||
// Implementation
|
||||
PTABLE GetNext(void) {return Next;}
|
||||
PTDB GetTo_Tdb(void) {return To_Tdb;}
|
||||
LPCSTR GetName(void) {return Name;}
|
||||
LPCSTR GetCorrel(void) {return Correl;}
|
||||
LPCSTR GetCreator(void) {return Creator;}
|
||||
LPCSTR GetQualifier(void) {return Qualifier;}
|
||||
void SetTo_Tdb(PTDB tdbp) {To_Tdb = tdbp;}
|
||||
void SetName(LPCSTR name) {Name = name;}
|
||||
void SetCorrel(LPCSTR correl) {Correl = correl;}
|
||||
void SetCreator(LPCSTR crname) {Creator = crname;}
|
||||
void SetQualifier(LPCSTR qname) {Qualifier = qname;}
|
||||
|
||||
// Methods
|
||||
PTABLE Link(PTABLE);
|
||||
void Print(PGLOBAL g, FILE *f, uint n);
|
||||
void Print(PGLOBAL g, char *ps, uint z);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PTABLE Next; // Points to next table in chain
|
||||
PTDB To_Tdb; // Points to Table description Block
|
||||
LPCSTR Name; // Table name (can be changed by LNA and PLG)
|
||||
LPCSTR Correl; // Correlation name
|
||||
LPCSTR Creator; // Creator name
|
||||
LPCSTR Qualifier; // Qualifier name
|
||||
}; // end of class XTAB
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definition of class COLUMN with all its method functions. */
|
||||
/* Note: because of LNA routines, the constantness of Name was */
|
||||
/* removed and constructing a COLUMN with null name was allowed. */
|
||||
/* Perhaps this should be replaced by the use of a specific class. */
|
||||
/***********************************************************************/
|
||||
class DllExport COLUMN: public XOBJECT { // Column Name/Qualifier block.
|
||||
public:
|
||||
// Constructor
|
||||
COLUMN(LPCSTR name);
|
||||
|
||||
// Implementation
|
||||
virtual int GetType(void) {return TYPE_COLUMN;}
|
||||
virtual int GetResultType(void) {assert(false); return TYPE_VOID;}
|
||||
virtual int GetLength(void) {assert(false); return 0;}
|
||||
virtual int GetLengthEx(void) {assert(false); return 0;}
|
||||
virtual int GetPrecision() {assert(false); return 0;};
|
||||
LPCSTR GetName(void) {return Name;}
|
||||
LPCSTR GetQualifier(void) {return Qualifier;}
|
||||
PTABLE GetTo_Table(void) {return To_Table;}
|
||||
PCOL GetTo_Col(void) {return To_Col;}
|
||||
void SetQualifier(LPCSTR qualif) {Qualifier = qualif;}
|
||||
void SetTo_Table(PTABLE tablep) {To_Table = tablep;}
|
||||
void SetTo_Col(PCOL colp) {To_Col = colp;}
|
||||
|
||||
// Methods
|
||||
virtual void Print(PGLOBAL g, FILE *f, uint n);
|
||||
virtual void Print(PGLOBAL g, char *ps, uint z);
|
||||
// All methods below should never be used for COLUMN's
|
||||
virtual void Reset(void) {assert(false);}
|
||||
virtual bool Compare(PXOB) {assert(false); return false;}
|
||||
virtual bool SetFormat(PGLOBAL, FORMAT&);
|
||||
virtual bool Eval(PGLOBAL) {assert(false); return true;}
|
||||
virtual int CheckSpcCol(PTDB, int) {assert(false); return 2;}
|
||||
virtual bool CheckSort(PTDB) {assert(false); return false;}
|
||||
virtual void MarkCol(ushort) {assert(false);}
|
||||
|
||||
private:
|
||||
// Members
|
||||
PTABLE To_Table; // Point to Table Name Block
|
||||
PCOL To_Col; // Points to Column Description Block
|
||||
LPCSTR const Name; // Column name
|
||||
LPCSTR Qualifier; // Qualifier name
|
||||
}; // end of class COLUMN
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definition of class SPCCOL with all its method functions. */
|
||||
/* Note: Currently the special columns are ROWID, ROWNUM, FILEID, */
|
||||
/* SERVID, TABID, and CONID. */
|
||||
/***********************************************************************/
|
||||
class SPCCOL: public COLUMN { // Special Column Name/Qualifier block.
|
||||
public:
|
||||
// Constructor
|
||||
SPCCOL(LPCSTR name) : COLUMN(name) {}
|
||||
|
||||
private:
|
||||
// Members
|
||||
}; // end of class SPCCOL
|
||||
1228
storage/connect/tabdos.cpp
Normal file
1228
storage/connect/tabdos.cpp
Normal file
File diff suppressed because it is too large
Load Diff
246
storage/connect/tabdos.h
Normal file
246
storage/connect/tabdos.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/*************** TabDos H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABDOS.H Version 3.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */
|
||||
/* */
|
||||
/* This file contains the DOS classes declares. */
|
||||
/***********************************************************************/
|
||||
|
||||
#ifndef __TABDOS_H
|
||||
#define __TABDOS_H
|
||||
|
||||
#include "xtable.h" // Table base class declares
|
||||
#include "colblk.h" // Column base class declares
|
||||
#include "xindex.h"
|
||||
|
||||
typedef struct _tabdesc *PTABD; // For friend setting
|
||||
typedef class TXTFAM *PTXF;
|
||||
|
||||
/***********************************************************************/
|
||||
/* DOS table. */
|
||||
/***********************************************************************/
|
||||
class DllExport DOSDEF : public TABDEF { /* Logical table description */
|
||||
friend class OEMDEF;
|
||||
friend class TDBDOS;
|
||||
friend class TDBFIX;
|
||||
friend class TXTFAM;
|
||||
friend class DBFBASE;
|
||||
public:
|
||||
// Constructor
|
||||
DOSDEF(void);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetDefType(void) {return TYPE_AM_DOS;}
|
||||
virtual const char *GetType(void) {return "DOS";}
|
||||
virtual PIXDEF GetIndx(void) {return To_Indx;}
|
||||
virtual void SetIndx(PIXDEF xdp) {To_Indx = xdp;}
|
||||
PSZ GetOfn(void) {return Ofn;}
|
||||
void SetBlock(int block) {Block = block;}
|
||||
int GetBlock(void) {return Block;}
|
||||
int GetLast(void) {return Last;}
|
||||
void SetLast(int last) {Last = last;}
|
||||
int GetLrecl(void) {return Lrecl;}
|
||||
void SetLrecl(int lrecl) {Lrecl = lrecl;}
|
||||
bool GetPadded(void) {return Padded;}
|
||||
bool GetEof(void) {return Eof;}
|
||||
int GetBlksize(void) {return Blksize;}
|
||||
int GetEnding(void) {return Ending;}
|
||||
int *GetTo_Pos(void) {return To_Pos;}
|
||||
virtual bool IsHuge(void) {return Huge;}
|
||||
|
||||
// Methods
|
||||
virtual bool DeleteTableFile(PGLOBAL g);
|
||||
virtual bool Indexable(void) {return Compressed != 1;}
|
||||
virtual bool DeleteIndexFile(PGLOBAL g, PIXDEF pxdf);
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE mode);
|
||||
bool InvalidateIndex(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
virtual bool Erase(char *filename);
|
||||
|
||||
// Members
|
||||
PSZ Fn; /* Path/Name of corresponding file */
|
||||
PSZ Ofn; /* Base Path/Name of matching index files*/
|
||||
PIXDEF To_Indx; /* To index definitions blocks */
|
||||
RECFM Recfm; /* 0:VAR, 1:FIX, 2:BIN, 3:VCT, 6:DBF */
|
||||
bool Mapped; /* 0: disk file, 1: memory mapped file */
|
||||
bool Padded; /* true for padded table file */
|
||||
bool Huge; /* true for files larger than 2GB */
|
||||
bool Accept; /* true if wrong lines are accepted (DBF)*/
|
||||
bool Eof; /* true if an EOF (0xA) character exists */
|
||||
int *To_Pos; /* To array of block starting positions */
|
||||
int Compressed; /* 0: No, 1: gz, 2:zlib compressed file */
|
||||
int Lrecl; /* Size of biggest record */
|
||||
int AvgLen; /* Average size of records */
|
||||
int Block; /* Number de blocks of FIX/VCT tables */
|
||||
int Last; /* Number of elements of last block */
|
||||
int Blksize; /* Size of padded blocks */
|
||||
int Maxerr; /* Maximum number of bad records (DBF) */
|
||||
int ReadMode; /* Specific to DBF */
|
||||
int Ending; /* Length of end of lines */
|
||||
}; // end of DOSDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* that are standard files with columns starting at fixed offset. */
|
||||
/* The last column (and record) is of variable length. */
|
||||
/***********************************************************************/
|
||||
class DllExport TDBDOS : public TDBASE {
|
||||
//friend class KINDEX;
|
||||
friend class XINDEX;
|
||||
friend class DOSCOL;
|
||||
friend class MAPCOL;
|
||||
friend class TXTFAM;
|
||||
friend class DOSFAM;
|
||||
friend class VCTCOL;
|
||||
//friend class TDBMUL;
|
||||
friend RCODE CntDeleteRow(PGLOBAL, PTDB, bool);
|
||||
public:
|
||||
// Constructors
|
||||
TDBDOS(PDOSDEF tdp, PTXF txfp);
|
||||
TDBDOS(PGLOBAL g, PTDBDOS tdbp);
|
||||
|
||||
// Inline functions
|
||||
inline void SetTxfp(PTXF txfp) {Txfp = txfp; Txfp->SetTdbp(this);}
|
||||
inline PTXF GetTxfp(void) {return Txfp;}
|
||||
inline char *GetLine(void) {return To_Line;}
|
||||
inline int GetCurBlk(void) {return Txfp->GetCurBlk();}
|
||||
inline void SetLine(char *toline) {To_Line = toline;}
|
||||
inline void IncLine(int inc) {To_Line += inc;}
|
||||
inline bool IsRead(void) {return Txfp->IsRead;}
|
||||
inline PXOB *GetLink(void) {return To_Link;}
|
||||
//inline PCOL *GetKeyCol(void) {return To_Key_Col;}
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return Txfp->GetAmType();}
|
||||
virtual PSZ GetFile(PGLOBAL g) {return Txfp->To_File;}
|
||||
virtual void SetFile(PGLOBAL g, PSZ fn) {Txfp->To_File = fn;}
|
||||
virtual RECFM GetFtype(void) {return Ftype;}
|
||||
virtual bool SkipHeader(PGLOBAL g) {return false;}
|
||||
virtual void RestoreNrec(void) {Txfp->SetNrec(1);}
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBDOS(g, this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual void ResetDB(void) {Txfp->Reset();}
|
||||
virtual bool IsUsingTemp(PGLOBAL g);
|
||||
//virtual bool NeedIndexing(PGLOBAL g);
|
||||
virtual void ResetSize(void) {MaxSize = Cardinal = -1;}
|
||||
virtual int ResetTableOpt(PGLOBAL g, bool dox);
|
||||
//virtual int MakeBlockValues(PGLOBAL g);
|
||||
//virtual bool SaveBlockValues(PGLOBAL g);
|
||||
//virtual bool GetBlockValues(PGLOBAL g);
|
||||
//virtual PBF InitBlockFilter(PGLOBAL g, PFIL filp);
|
||||
//virtual PBX InitBlockIndex(PGLOBAL g);
|
||||
//virtual int TestBlock(PGLOBAL g);
|
||||
virtual void PrintAM(FILE *f, char *m);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual char *GetOpenMode(PGLOBAL g, char *opmode) {return NULL;}
|
||||
virtual int GetFileLength(PGLOBAL g) {return Txfp->GetFileLength(g);}
|
||||
virtual int GetProgMax(PGLOBAL g);
|
||||
virtual int GetProgCur(void);
|
||||
virtual int GetAffectedRows(void) {return Txfp->GetDelRows();}
|
||||
virtual int GetRecpos(void) {return Txfp->GetPos();}
|
||||
virtual bool SetRecpos(PGLOBAL g, int recpos)
|
||||
{return Txfp->SetPos(g, recpos);}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false);
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g) {return Txfp->ReadBuffer(g);}
|
||||
|
||||
// Specific routine
|
||||
virtual int EstimatedLength(PGLOBAL g);
|
||||
|
||||
// Optimization routines
|
||||
// void ResetBlockFilter(PGLOBAL g);
|
||||
int MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add);
|
||||
// bool GetDistinctColumnValues(PGLOBAL g, int nrec);
|
||||
|
||||
protected:
|
||||
// PBF CheckBlockFilari(PGLOBAL g, PXOB *arg, int op, bool *cnv);
|
||||
|
||||
// Members
|
||||
PTXF Txfp; // To the File access method class
|
||||
//PBX To_BlkIdx; // To index test block
|
||||
//PBF To_BlkFil; // To evaluation block filter
|
||||
//PFIL SavFil; // Saved hidden filter
|
||||
char *To_Line; // Points to current processed line
|
||||
int Cardinal; // Table Cardinality
|
||||
RECFM Ftype; // File type: 0-var 1-fixed 2-binary (VCT)
|
||||
int Lrecl; // Logical Record Length
|
||||
int AvgLen; // Logical Record Average Length
|
||||
//int Xeval; // BlockTest return value
|
||||
//int Beval; // BlockEval return value
|
||||
}; // end of class TDBDOS
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class DOSCOL: DOS access method column descriptor. */
|
||||
/* This A.M. is used for text file tables under operating systems */
|
||||
/* DOS, OS2, UNIX, WIN16 and WIN32. */
|
||||
/***********************************************************************/
|
||||
class DllExport DOSCOL : public COLBLK {
|
||||
friend class TDBDOS;
|
||||
friend class TDBFIX;
|
||||
public:
|
||||
// Constructors
|
||||
DOSCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am = "DOS");
|
||||
DOSCOL(DOSCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_DOS;}
|
||||
//virtual int GetClustered(void) {return Clustered;}
|
||||
//virtual int IsClustered(void) {return (Clustered &&
|
||||
// ((PDOSDEF)(((PTDBDOS)To_Tdb)->To_Def))->IsOptimized());}
|
||||
//virtual int IsSorted(void) {return Sorted;}
|
||||
virtual void SetTo_Val(PVAL valp) {To_Val = valp;}
|
||||
//virtual PVBLK GetMin(void) {return Min;}
|
||||
//virtual PVBLK GetMax(void) {return Max;}
|
||||
//virtual int GetNdv(void) {return Ndv;}
|
||||
//virtual int GetNbm(void) {return Nbm;}
|
||||
//virtual PVBLK GetBmap(void) {return Bmap;}
|
||||
//virtual PVBLK GetDval(void) {return Dval;}
|
||||
|
||||
// Methods
|
||||
virtual bool VarSize(void);
|
||||
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
virtual void Print(PGLOBAL g, FILE *, uint);
|
||||
|
||||
protected:
|
||||
//virtual bool SetMinMax(PGLOBAL g);
|
||||
//virtual bool SetBitMap(PGLOBAL g);
|
||||
// bool CheckSorted(PGLOBAL g);
|
||||
// bool AddDistinctValue(PGLOBAL g);
|
||||
|
||||
// Default constructor not to be used
|
||||
DOSCOL(void) {}
|
||||
|
||||
// Members
|
||||
//PVBLK Min; // Array of block min values
|
||||
//PVBLK Max; // Array of block max values
|
||||
//PVBLK Bmap; // Array of block bitmap values
|
||||
//PVBLK Dval; // Array of column distinct values
|
||||
PVAL To_Val; // To value used for Update/Insert
|
||||
PVAL OldVal; // The previous value of the object.
|
||||
char *Buf; // Buffer used in write operations
|
||||
bool Ldz; // True if field contains leading zeros
|
||||
bool Nod; // True if no decimal point
|
||||
int Dcm; // Last Dcm digits are decimals
|
||||
//int Clustered; // 0:No 1:Yes
|
||||
//int Sorted; // 0:No 1:Asc (2:Desc - NIY)
|
||||
int Deplac; // Offset in dos_buf
|
||||
//int Ndv; // Number of distinct values
|
||||
//int Nbm; // Number of uint in bitmap
|
||||
}; // end of class DOSCOL
|
||||
|
||||
#endif // __TABDOS_H
|
||||
478
storage/connect/tabfix.cpp
Normal file
478
storage/connect/tabfix.cpp
Normal file
@@ -0,0 +1,478 @@
|
||||
/************* TabFix C++ Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: TABFIX */
|
||||
/* ------------- */
|
||||
/* Version 4.8 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the TDBFIX class DB routines. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant section of system dependant header files. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif // __BORLANDC__
|
||||
//#include <windows.h>
|
||||
#else // !WIN32
|
||||
#if defined(UNIX)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#else // !UNIX
|
||||
#include <io.h>
|
||||
#endif // !UNIX
|
||||
#include <fcntl.h>
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/***********************************************************************/
|
||||
#include "global.h" // global declares
|
||||
#include "plgdbsem.h" // DB application declares
|
||||
#include "filamfix.h"
|
||||
#include "filamdbf.h"
|
||||
#include "tabfix.h" // TDBFIX, FIXCOL classes declares
|
||||
|
||||
/***********************************************************************/
|
||||
/* DB static variables. */
|
||||
/***********************************************************************/
|
||||
extern "C" int trace;
|
||||
extern int num_read, num_there, num_eq[2]; // Statistics
|
||||
static const longlong M2G = 0x80000000;
|
||||
static const longlong M4G = (longlong)2 * M2G;
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBFIX class. */
|
||||
/***********************************************************************/
|
||||
TDBFIX::TDBFIX(PDOSDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
|
||||
{
|
||||
//Cardinal = -1;
|
||||
} // end of TDBFIX standard constructor
|
||||
|
||||
TDBFIX::TDBFIX(PGLOBAL g, PTDBFIX tdbp) : TDBDOS(g, tdbp)
|
||||
{
|
||||
//Cardinal = tdbp->Cardinal;
|
||||
} // end of TDBFIX copy constructor
|
||||
|
||||
// Method
|
||||
PTDB TDBFIX::CopyOne(PTABS t)
|
||||
{
|
||||
PTDB tp;
|
||||
PGLOBAL g = t->G;
|
||||
|
||||
tp = new(g) TDBFIX(g, this);
|
||||
|
||||
if (Ftype < 2) {
|
||||
// File is text
|
||||
PDOSCOL cp1, cp2;
|
||||
|
||||
for (cp1 = (PDOSCOL)Columns; cp1; cp1 = (PDOSCOL)cp1->GetNext()) {
|
||||
cp2 = new(g) DOSCOL(cp1, tp); // Make a copy
|
||||
NewPointer(t, cp1, cp2);
|
||||
} // endfor cp1
|
||||
|
||||
} else {
|
||||
// File is binary
|
||||
PBINCOL cp1, cp2;
|
||||
|
||||
for (cp1 = (PBINCOL)Columns; cp1; cp1 = (PBINCOL)cp1->GetNext()) {
|
||||
cp2 = new(g) BINCOL(cp1, tp); // Make a copy
|
||||
NewPointer(t, cp1, cp2);
|
||||
} // endfor cp1
|
||||
|
||||
} // endif Ftype
|
||||
|
||||
return tp;
|
||||
} // end of CopyOne
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset read/write position values. */
|
||||
/***********************************************************************/
|
||||
void TDBFIX::ResetDB(void)
|
||||
{
|
||||
TDBDOS::ResetDB();
|
||||
} // end of ResetDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate FIX (DOS) or BIN column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBFIX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
if (Ftype == RECFM_BIN)
|
||||
return new(g) BINCOL(g, cdp, this, cprec, n);
|
||||
else
|
||||
return new(g) DOSCOL(g, cdp, this, cprec, n);
|
||||
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* Remake the indexes after the table was modified. */
|
||||
/***********************************************************************/
|
||||
int TDBFIX::ResetTableOpt(PGLOBAL g, bool dox)
|
||||
{
|
||||
RestoreNrec(); // May have been modified
|
||||
return TDBDOS::ResetTableOpt(g, dox);
|
||||
} // end of ResetTableOpt
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset the Nrec and BlkSize values that can have been modified. */
|
||||
/***********************************************************************/
|
||||
void TDBFIX::RestoreNrec(void)
|
||||
{
|
||||
if (!Txfp->Padded) {
|
||||
Txfp->Nrec = (To_Def && To_Def->GetElemt()) ? To_Def->GetElemt()
|
||||
: DOS_BUFF_LEN;
|
||||
Txfp->Blksize = Txfp->Nrec * Txfp->Lrecl;
|
||||
} // endif Padded
|
||||
|
||||
} // end of RestoreNrec
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIX 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). */
|
||||
/***********************************************************************/
|
||||
int TDBFIX::Cardinality(PGLOBAL g)
|
||||
{
|
||||
if (!g)
|
||||
return Txfp->Cardinality(g);
|
||||
|
||||
if (Cardinal < 0)
|
||||
Cardinal = Txfp->Cardinality(g);
|
||||
|
||||
return Cardinal;
|
||||
} // end of Cardinality
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIX GetMaxSize: returns file size in number of lines. */
|
||||
/***********************************************************************/
|
||||
int TDBFIX::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (MaxSize < 0)
|
||||
MaxSize = Cardinality(g);
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIX ResetSize: Must reset Headlen for DBF tables only. */
|
||||
/***********************************************************************/
|
||||
void TDBFIX::ResetSize(void)
|
||||
{
|
||||
if (Txfp->GetAmType() == TYPE_AM_DBF)
|
||||
Txfp->Headlen = 0;
|
||||
|
||||
MaxSize = Cardinal = -1;
|
||||
} // end of ResetSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIX GetProgMax: get the max value for progress information. */
|
||||
/***********************************************************************/
|
||||
int TDBFIX::GetProgMax(PGLOBAL g)
|
||||
{
|
||||
return Cardinality(g);
|
||||
} // end of GetProgMax
|
||||
|
||||
/***********************************************************************/
|
||||
/* RowNumber: return the ordinal number of the current row. */
|
||||
/***********************************************************************/
|
||||
int TDBFIX::RowNumber(PGLOBAL g, bool b)
|
||||
{
|
||||
if (Txfp->GetAmType() == TYPE_AM_DBF) {
|
||||
if (!b && To_Kindex) {
|
||||
/*****************************************************************/
|
||||
/* Don't know how to retrieve Rows from DBF file address */
|
||||
/* because of eventual deleted lines still in the file. */
|
||||
/*****************************************************************/
|
||||
sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
|
||||
GetAmName(g, Txfp->GetAmType()));
|
||||
return 0;
|
||||
} // endif To_Kindex
|
||||
|
||||
if (!b)
|
||||
return Txfp->GetRows();
|
||||
|
||||
} // endif DBF
|
||||
|
||||
return Txfp->GetRowID();
|
||||
} // end of RowNumber
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIX tables don't use temporary files except if specified as do it. */
|
||||
/***********************************************************************/
|
||||
bool TDBFIX::IsUsingTemp(PGLOBAL g)
|
||||
{
|
||||
USETEMP usetemp = PlgGetUser(g)->UseTemp;
|
||||
|
||||
return (usetemp == TMP_YES || usetemp == TMP_FORCE);
|
||||
} // end of IsUsingTemp
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIX Access Method opening routine (also used by the BIN a.m.) */
|
||||
/* New method now that this routine is called recursively (last table */
|
||||
/* first in reverse order): index blocks are immediately linked to */
|
||||
/* join block of next table if it exists or else are discarted. */
|
||||
/***********************************************************************/
|
||||
bool TDBFIX::OpenDB(PGLOBAL g)
|
||||
{
|
||||
if (trace)
|
||||
htrc("FIX OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d Ftype=%d\n",
|
||||
this, Tdb_No, Use, To_Key_Col, Mode, Ftype);
|
||||
|
||||
if (Use == USE_OPEN) {
|
||||
/*******************************************************************/
|
||||
/* Table already open, just replace it at its beginning. */
|
||||
/*******************************************************************/
|
||||
if (To_Kindex)
|
||||
/*****************************************************************/
|
||||
/* Table is to be accessed through a sorted index table. */
|
||||
/*****************************************************************/
|
||||
To_Kindex->Reset();
|
||||
else
|
||||
Txfp->Rewind(); // see comment in Work.log
|
||||
|
||||
return false;
|
||||
} // endif use
|
||||
|
||||
/*********************************************************************/
|
||||
/* Call Cardinality to calculate Block in the case of Func queries. */
|
||||
/* and also in the case of multiple tables. */
|
||||
/*********************************************************************/
|
||||
if (Cardinality(g) < 0)
|
||||
return true;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Open according to required logical input/output mode. */
|
||||
/* Use conventionnal input/output functions. */
|
||||
/* Treat fixed length text files as binary. */
|
||||
/*********************************************************************/
|
||||
if (Txfp->OpenTableFile(g))
|
||||
return true;
|
||||
|
||||
Use = USE_OPEN; // Do it now in case we are recursively called
|
||||
|
||||
/*********************************************************************/
|
||||
/* Initialize To_Line at the beginning of the block buffer. */
|
||||
/*********************************************************************/
|
||||
To_Line = Txfp->GetBuf(); // For WriteDB
|
||||
|
||||
if (trace)
|
||||
htrc("OpenDos: R%hd mode=%d\n", Tdb_No, Mode);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Reset buffer access according to indexing and to mode. */
|
||||
/*********************************************************************/
|
||||
Txfp->ResetBuffer(g);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Reset statistics values. */
|
||||
/*********************************************************************/
|
||||
num_read = num_there = num_eq[0] = num_eq[1] = 0;
|
||||
return false;
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for FIX access method. */
|
||||
/***********************************************************************/
|
||||
int TDBFIX::WriteDB(PGLOBAL g)
|
||||
{
|
||||
return Txfp->WriteBuffer(g);
|
||||
} // end of WriteDB
|
||||
|
||||
// ------------------------ BINCOL functions ----------------------------
|
||||
|
||||
/***********************************************************************/
|
||||
/* BINCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
BINCOL::BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am)
|
||||
: DOSCOL(g, cdp, tp, cp, i, am)
|
||||
{
|
||||
Fmt = (cdp->GetFmt()) ? toupper(*cdp->GetFmt()) : 'X';
|
||||
} // end of BINCOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* FIXCOL constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
BINCOL::BINCOL(BINCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
|
||||
{
|
||||
Fmt = col1->Fmt;
|
||||
} // end of BINCOL copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to access the last line */
|
||||
/* read from the corresponding table and extract from it the field */
|
||||
/* corresponding to this column. */
|
||||
/***********************************************************************/
|
||||
void BINCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
char *p;
|
||||
int rc;
|
||||
PTDBFIX tdbp = (PTDBFIX)To_Tdb;
|
||||
|
||||
if (trace)
|
||||
htrc("BIN ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n",
|
||||
Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type);
|
||||
|
||||
/*********************************************************************/
|
||||
/* If physical reading of the line was deferred, do it now. */
|
||||
/*********************************************************************/
|
||||
if (!tdbp->IsRead())
|
||||
if ((rc = tdbp->ReadBuffer(g)) != RC_OK) {
|
||||
if (rc == RC_EF)
|
||||
sprintf(g->Message, MSG(INV_DEF_READ), rc);
|
||||
|
||||
longjmp(g->jumper[g->jump_level], 11);
|
||||
} // endif
|
||||
|
||||
p = tdbp->To_Line + Deplac;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Set Value from the line field. */
|
||||
/*********************************************************************/
|
||||
switch (Fmt) {
|
||||
case 'X': // Standard not converted values
|
||||
Value->SetBinValue(p);
|
||||
break;
|
||||
case 'S': // Short integer
|
||||
Value->SetValue((int)*(short*)p);
|
||||
break;
|
||||
case 'T': // Tiny integer
|
||||
Value->SetValue((int)*p);
|
||||
break;
|
||||
case 'I': // Integer or
|
||||
case 'L': // Long Integer
|
||||
Value->SetValue(*(int*)p);
|
||||
break;
|
||||
case 'F': // Float
|
||||
case 'R': // Real
|
||||
Value->SetValue((double)*(float*)p);
|
||||
break;
|
||||
case 'D': // Double
|
||||
Value->SetValue(*(double*)p);
|
||||
break;
|
||||
case 'C': // Text
|
||||
Value->SetValue_char(p, Long);
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name);
|
||||
longjmp(g->jumper[g->jump_level], 11);
|
||||
} // endswitch Fmt
|
||||
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteColumn: what this routine does is to access the last line */
|
||||
/* read from the corresponding table, and rewrite the field */
|
||||
/* corresponding to this column from the column buffer. */
|
||||
/***********************************************************************/
|
||||
void BINCOL::WriteColumn(PGLOBAL g)
|
||||
{
|
||||
char *p, *s;
|
||||
int n;
|
||||
PTDBFIX tdbp = (PTDBFIX)To_Tdb;
|
||||
|
||||
if (trace) {
|
||||
htrc("BIN WriteColumn: col %s R%d coluse=%.4X status=%.4X",
|
||||
Name, tdbp->GetTdb_No(), ColUse, Status);
|
||||
htrc(" Lrecl=%d\n", tdbp->Lrecl);
|
||||
htrc("Long=%d deplac=%d coltype=%d ftype=%c\n",
|
||||
Long, Deplac, Buf_Type, *Format.Type);
|
||||
} // endif trace
|
||||
|
||||
/*********************************************************************/
|
||||
/* Check whether the new value has to be converted to Buf_Type. */
|
||||
/*********************************************************************/
|
||||
if (Value != To_Val)
|
||||
Value->SetValue_pval(To_Val, false); // Convert the updated value
|
||||
|
||||
p = tdbp->To_Line + Deplac;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Check whether updating is Ok, meaning col value is not too long. */
|
||||
/* Updating will be done only during the second pass (Status=true) */
|
||||
/* Conversion occurs if the external format Fmt is specified. */
|
||||
/*********************************************************************/
|
||||
switch (Fmt) {
|
||||
case 'X':
|
||||
// Standard not converted values
|
||||
if (Value->GetBinValue(p, Long, Status)) {
|
||||
sprintf(g->Message, MSG(BIN_F_TOO_LONG),
|
||||
Name, Value->GetSize(), Long);
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} // endif Fmt
|
||||
|
||||
break;
|
||||
case 'S': // Short integer
|
||||
n = Value->GetIntValue();
|
||||
|
||||
if (n > 32767 || n < -32768) {
|
||||
sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} else if (Status)
|
||||
*(short *)p = (short)n;
|
||||
|
||||
break;
|
||||
case 'T': // Short integer
|
||||
n = Value->GetIntValue();
|
||||
|
||||
if (n > 255 || n < -256) {
|
||||
sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} else if (Status)
|
||||
*p = (char)n;
|
||||
|
||||
break;
|
||||
case 'I': // Integer or
|
||||
case 'L': // Long Integer
|
||||
if (Status)
|
||||
*(int *)p = Value->GetIntValue();
|
||||
|
||||
break;
|
||||
case 'F': // Float
|
||||
case 'R': // Real
|
||||
if (Status)
|
||||
*(float *)p = (float)Value->GetFloatValue();
|
||||
|
||||
break;
|
||||
case 'D': // Double
|
||||
if (Status)
|
||||
*(double *)p = Value->GetFloatValue();
|
||||
|
||||
break;
|
||||
case 'C': // Characters
|
||||
if ((n = (signed)strlen(Value->GetCharString(Buf))) > Long) {
|
||||
sprintf(g->Message, MSG(BIN_F_TOO_LONG), Name, n, Long);
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} // endif n
|
||||
|
||||
if (Status) {
|
||||
s = Value->GetCharString(Buf);
|
||||
memset(p, ' ', Long);
|
||||
memcpy(p, s, strlen(s));
|
||||
} // endif Status
|
||||
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name);
|
||||
longjmp(g->jumper[g->jump_level], 11);
|
||||
} // endswitch Fmt
|
||||
|
||||
} // end of WriteColumn
|
||||
|
||||
/* ------------------------ End of TabFix ---------------------------- */
|
||||
80
storage/connect/tabfix.h
Normal file
80
storage/connect/tabfix.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*************** TabDos H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABFIX.H Version 2.3 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */
|
||||
/* */
|
||||
/* This file contains the TDBFIX and (FIX/BIN)COL classes declares. */
|
||||
/***********************************************************************/
|
||||
#ifndef __TABFIX__
|
||||
#define __TABFIX__
|
||||
#include "tabdos.h" /* Base class declares */
|
||||
|
||||
typedef class FIXCOL *PFIXCOL;
|
||||
typedef class BINCOL *PBINCOL;
|
||||
typedef class TXTFAM *PTXF;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* that are standard files with columns starting at fixed offset. */
|
||||
/* This class is for fixed formatted files. */
|
||||
/***********************************************************************/
|
||||
class DllExport TDBFIX : public TDBDOS {
|
||||
friend class FIXCOL;
|
||||
friend class BINCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBFIX(PDOSDEF tdp, PTXF txfp);
|
||||
TDBFIX(PGLOBAL g, PTDBFIX tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_FIX;}
|
||||
virtual void RestoreNrec(void);
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBFIX(g, this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual void ResetDB(void);
|
||||
virtual bool IsUsingTemp(PGLOBAL g);
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false);
|
||||
virtual int ResetTableOpt(PGLOBAL g, bool dox);
|
||||
virtual void ResetSize(void);
|
||||
virtual int GetBadLines(void) {return Txfp->GetNerr();}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetProgMax(PGLOBAL g);
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Members are inherited from TDBDOS
|
||||
}; // end of class TDBFIX
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class BINCOL: BIN access method column descriptor. */
|
||||
/* This A.M. is used for file processed by blocks. */
|
||||
/***********************************************************************/
|
||||
class DllExport BINCOL : public DOSCOL {
|
||||
friend class TDBFIX;
|
||||
public:
|
||||
// Constructors
|
||||
BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am = "BIN");
|
||||
BINCOL(BINCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_BIN;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
BINCOL(void) {} // Default constructor not to be used
|
||||
|
||||
// Members
|
||||
char Fmt; // The column numeric format
|
||||
}; // end of class BINCOL
|
||||
#endif // __TABFIX__
|
||||
1089
storage/connect/tabfmt.cpp
Normal file
1089
storage/connect/tabfmt.cpp
Normal file
File diff suppressed because it is too large
Load Diff
164
storage/connect/tabfmt.h
Normal file
164
storage/connect/tabfmt.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/*************** TabFmt H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABFMT.H Version 2.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2001-2012 */
|
||||
/* */
|
||||
/* This file contains the CSV and FMT classes declares. */
|
||||
/***********************************************************************/
|
||||
#include "xtable.h" // Base class declares
|
||||
#include "tabdos.h"
|
||||
|
||||
//pedef struct _tabdesc *PTABD; // For friend setting
|
||||
typedef class TDBFMT *PTDBFMT;
|
||||
|
||||
/***********************************************************************/
|
||||
/* CSV table. */
|
||||
/***********************************************************************/
|
||||
class DllExport CSVDEF : public DOSDEF { /* Logical table description */
|
||||
friend class TDBCSV;
|
||||
//friend class TDBMCV;
|
||||
public:
|
||||
// Constructor
|
||||
CSVDEF(void);
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "CSV";}
|
||||
char GetSep(void) {return Sep;}
|
||||
char GetQot(void) {return Qot;}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE mode);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
bool Fmtd; /* true for formatted files */
|
||||
//bool Accept; /* true if wrong lines are accepted */
|
||||
bool Header; /* true if first line contains headers */
|
||||
//int Maxerr; /* Maximum number of bad records */
|
||||
int Quoted; /* Quoting level for quoted fields */
|
||||
char Sep; /* Separator for standard CSV files */
|
||||
char Qot; /* Character for quoted strings */
|
||||
}; // end of CSVDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* that are CSV files with columns separated by the Sep character. */
|
||||
/***********************************************************************/
|
||||
class TDBCSV : public TDBDOS {
|
||||
friend class CSVCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBCSV(PCSVDEF tdp, PTXF txfp);
|
||||
TDBCSV(PGLOBAL g, PTDBCSV tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_CSV;}
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBCSV(g, this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
//virtual bool IsUsingTemp(PGLOBAL g);
|
||||
virtual int GetBadLines(void) {return (int)Nerr;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int CheckWrite(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g); // Physical file read
|
||||
|
||||
// Specific routines
|
||||
virtual int EstimatedLength(PGLOBAL g);
|
||||
virtual bool SkipHeader(PGLOBAL g);
|
||||
virtual bool CheckErr(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PSZ *Field; // Field to write to current line
|
||||
int *Offset; // Column offsets for current record
|
||||
int *Fldlen; // Column field length for current record
|
||||
bool *Fldtyp; // true for numeric fields
|
||||
int Fields; // Number of fields to handle
|
||||
int Nerr; // Number of bad records
|
||||
int Maxerr; // Maximum number of bad records
|
||||
int Quoted; // Quoting level for quoted fields
|
||||
bool Accept; // true if bad lines are accepted
|
||||
bool Header; // true if first line contains column headers
|
||||
char Sep; // Separator
|
||||
char Qot; // Quoting character
|
||||
}; // end of class TDBCSV
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class CSVCOL: CSV access method column descriptor. */
|
||||
/* This A.M. is used for Comma Separated V(?) files. */
|
||||
/***********************************************************************/
|
||||
class CSVCOL : public DOSCOL {
|
||||
friend class TDBCSV;
|
||||
friend class TDBFMT;
|
||||
public:
|
||||
// Constructors
|
||||
CSVCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
|
||||
CSVCOL(CSVCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType() {return TYPE_AM_CSV;}
|
||||
|
||||
// Methods
|
||||
virtual bool VarSize(void);
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
// void Print(FILE *, uint);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
CSVCOL(void) {}
|
||||
|
||||
// Members
|
||||
int Fldnum; // Field ordinal number (0 based)
|
||||
}; // end of class CSVCOL
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* whose record format is described by a Format keyword. */
|
||||
/***********************************************************************/
|
||||
class TDBFMT : public TDBCSV {
|
||||
friend class CSVCOL;
|
||||
//friend class FMTCOL;
|
||||
public:
|
||||
// Standard constructor
|
||||
TDBFMT(PCSVDEF tdp, PTXF txfp) : TDBCSV(tdp, txfp)
|
||||
{FldFormat = NULL; To_Fld = NULL; FmtTest = NULL; Linenum = 0;}
|
||||
|
||||
// Copy constructor
|
||||
TDBFMT(PGLOBAL g, PTDBFMT tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_FMT;}
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBFMT(g, this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
//virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
//virtual int CheckWrite(PGLOBAL g);
|
||||
virtual int ReadBuffer(PGLOBAL g); // Physical file read
|
||||
|
||||
// Specific routines
|
||||
virtual int EstimatedLength(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PSZ *FldFormat; // Field read format
|
||||
void *To_Fld; // To field test buffer
|
||||
int *FmtTest; // Test on ending by %n or %m
|
||||
int Linenum; // Last read line
|
||||
}; // end of class TDBFMT
|
||||
|
||||
/* ------------------------- End of TabFmt.H ------------------------- */
|
||||
427
storage/connect/table.cpp
Normal file
427
storage/connect/table.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/************** Table C++ Functions Source Code File (.CPP) ************/
|
||||
/* Name: TABLE.CPP Version 2.5 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */
|
||||
/* */
|
||||
/* This file contains the TBX, TDB and OPJOIN classes functions. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/* global.h is header containing all global Plug declarations. */
|
||||
/* plgdbsem.h is header containing the DB applic. declarations. */
|
||||
/* xobject.h is header containing XOBJECT derived classes declares. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "xtable.h"
|
||||
#include "tabcol.h"
|
||||
#include "filamtxt.h"
|
||||
#include "tabdos.h"
|
||||
//#include "catalog.h"
|
||||
#include "reldef.h"
|
||||
|
||||
int TDB::Tnum = 0;
|
||||
|
||||
extern "C" int trace; // The general trace value
|
||||
|
||||
/***********************************************************************/
|
||||
/* Utility routines. */
|
||||
/***********************************************************************/
|
||||
void NewPointer(PTABS, void *, void *);
|
||||
void AddPointer(PTABS, void *);
|
||||
|
||||
/* ---------------------------- class TBX ---------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBX public constructors. */
|
||||
/***********************************************************************/
|
||||
TBX::TBX(void)
|
||||
{
|
||||
Use = USE_NO;
|
||||
To_Orig = NULL;
|
||||
To_Filter = NULL;
|
||||
} // end of TBX constructor
|
||||
|
||||
TBX::TBX(PTBX txp)
|
||||
{
|
||||
Use = txp->Use;
|
||||
To_Orig = txp;
|
||||
To_Filter = NULL;
|
||||
} // end of TBX copy constructor
|
||||
|
||||
// Methods
|
||||
|
||||
/* ---------------------------- class TDB ---------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* TDB public constructors. */
|
||||
/***********************************************************************/
|
||||
TDB::TDB(PTABDEF tdp) : Tdb_No(++Tnum)
|
||||
{
|
||||
Next = NULL;
|
||||
Name = (tdp) ? tdp->GetName() : NULL;
|
||||
To_Table = NULL;
|
||||
Columns = NULL;
|
||||
Degree = (tdp) ? tdp->GetDegree() : 0;
|
||||
Mode = MODE_READ;
|
||||
} // end of TDB standard constructor
|
||||
|
||||
TDB::TDB(PTDB tdbp) : TBX(tdbp), Tdb_No(++Tnum)
|
||||
{
|
||||
Next = NULL;
|
||||
Name = tdbp->Name;
|
||||
To_Table = tdbp->To_Table;
|
||||
Columns = NULL;
|
||||
Degree = tdbp->Degree;
|
||||
Mode = tdbp->Mode;
|
||||
} // end of TDB copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* OpenTable: Call AM open routine. */
|
||||
/***********************************************************************/
|
||||
bool TDB::OpenTable(PGLOBAL g, PSQL sqlp, MODE mode)
|
||||
{
|
||||
if (trace)
|
||||
htrc("Open Tdb_No=%d use=%d type=%d tdb.Mode=%d mode=%d\n",
|
||||
Tdb_No, Use, GetAmType(), Mode, mode);
|
||||
|
||||
switch (Use) {
|
||||
case USE_LIN:
|
||||
/*****************************************************************/
|
||||
/* If table is read/only, only MODE_READ is allowed. */
|
||||
/*****************************************************************/
|
||||
if (IsReadOnly() && mode != MODE_READ) {
|
||||
strcpy(g->Message, MSG(READ_ONLY));
|
||||
return true;
|
||||
} // endif ReadOnly
|
||||
|
||||
/*****************************************************************/
|
||||
/* This could be done in any order. */
|
||||
/* Note: for not Read only first table in open in that mode. */
|
||||
/*****************************************************************/
|
||||
if (Next)
|
||||
Next->OpenTable(g, sqlp, MODE_READ);
|
||||
|
||||
Mode = mode;
|
||||
|
||||
/*****************************************************************/
|
||||
/* Pre-opening is done, allocate select buffers now. */
|
||||
/*****************************************************************/
|
||||
Use = USE_READY;
|
||||
break;
|
||||
|
||||
case USE_READY:
|
||||
/*****************************************************************/
|
||||
/* This is to open files in reverse order. */
|
||||
/*****************************************************************/
|
||||
if (Next)
|
||||
if (Next->OpenTable(g, sqlp, mode))
|
||||
return true;
|
||||
|
||||
/*****************************************************************/
|
||||
/* This was moved after filter conversion so filtering can be */
|
||||
/* done when making index tables for DOS files. */
|
||||
/* Also it was moved after allocating select buffers so some */
|
||||
/* data can be pre-read during open to allow storage sorting. */
|
||||
/*****************************************************************/
|
||||
if (OpenDB(g)) // Do open the table file
|
||||
return true;
|
||||
|
||||
Use = USE_OPEN;
|
||||
break;
|
||||
|
||||
case USE_OPEN:
|
||||
/*****************************************************************/
|
||||
/* Table is already open. */
|
||||
/* Call open routine that will just "rewind" the files. */
|
||||
/*****************************************************************/
|
||||
if (OpenDB(g)) // Rewind the table file
|
||||
return true;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(g->Message, MSG(TDB_USE_ERROR), Use);
|
||||
return true;
|
||||
} // endswitch Use
|
||||
|
||||
return false;
|
||||
} // end of OpenTable
|
||||
|
||||
/***********************************************************************/
|
||||
/* CloseTable: Close a table of any AM type. */
|
||||
/***********************************************************************/
|
||||
void TDB::CloseTable(PGLOBAL g)
|
||||
{
|
||||
if (trace)
|
||||
htrc("CloseTable: tdb_no %d use=%d amtype=%d am.Mode=%d\n",
|
||||
Tdb_No, Use, GetAmType(), Mode);
|
||||
|
||||
CloseDB(g);
|
||||
Use = USE_READY; // x'7FFD'
|
||||
Mode = MODE_ANY;
|
||||
} // end of CloseTable
|
||||
|
||||
// Methods
|
||||
|
||||
/***********************************************************************/
|
||||
/* RowNumber: returns the current row ordinal number. */
|
||||
/***********************************************************************/
|
||||
int TDB::RowNumber(PGLOBAL g, bool b)
|
||||
{
|
||||
sprintf(g->Message, MSG(ROWID_NOT_IMPL), GetAmName(g, GetAmType()));
|
||||
return 0;
|
||||
} // end of RowNumber
|
||||
|
||||
PTBX TDB::Copy(PTABS t)
|
||||
{
|
||||
PTDB tp, tdb1, tdb2 = NULL, outp = NULL;
|
||||
//PGLOBAL g = t->G; // Is this really useful ???
|
||||
|
||||
for (tdb1 = this; tdb1; tdb1 = tdb1->Next) {
|
||||
tp = tdb1->CopyOne(t);
|
||||
|
||||
if (!outp)
|
||||
outp = tp;
|
||||
else
|
||||
tdb2->Next = tp;
|
||||
|
||||
tdb2 = tp;
|
||||
NewPointer(t, tdb1, tdb2);
|
||||
} // endfor tdb1
|
||||
|
||||
return outp;
|
||||
} // end of Copy
|
||||
|
||||
void TDB::Print(PGLOBAL g, FILE *f, uint n)
|
||||
{
|
||||
PCOL cp;
|
||||
char m[64];
|
||||
|
||||
memset(m, ' ', n); // Make margin string
|
||||
m[n] = '\0';
|
||||
|
||||
for (PTDB tp = this; tp; tp = tp->Next) {
|
||||
fprintf(f, "%sTDB (%p) %s no=%d use=%d type=%d\n", m,
|
||||
tp, tp->Name, tp->Tdb_No, tp->Use, tp->GetAmType());
|
||||
|
||||
tp->PrintAM(f, m);
|
||||
fprintf(f, "%s Columns (deg=%d):\n", m, tp->Degree);
|
||||
|
||||
for (cp = tp->Columns; cp; cp = cp->GetNext())
|
||||
cp->Print(g, f, n);
|
||||
|
||||
} /* endfor tp */
|
||||
|
||||
} // end of Print
|
||||
|
||||
void TDB::Print(PGLOBAL g, char *ps, uint z)
|
||||
{
|
||||
sprintf(ps, "R%d.%s", Tdb_No, Name);
|
||||
} // end of Print
|
||||
|
||||
/* -------------------------- class TDBASE --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBASE class. This is the base class to all */
|
||||
/* classes for tables that can be joined together. */
|
||||
/***********************************************************************/
|
||||
TDBASE::TDBASE(PTABDEF tdp) : TDB(tdp)
|
||||
{
|
||||
To_Def = tdp;
|
||||
To_Link = NULL;
|
||||
To_Key_Col = NULL;
|
||||
To_Kindex = NULL;
|
||||
To_SetCols = NULL;
|
||||
MaxSize = -1;
|
||||
Knum = 0;
|
||||
Read_Only = (tdp) ? tdp->IsReadOnly() : false;
|
||||
} // end of TDBASE constructor
|
||||
|
||||
TDBASE::TDBASE(PTDBASE tdbp) : TDB(tdbp)
|
||||
{
|
||||
To_Def = tdbp->To_Def;
|
||||
To_SetCols = tdbp->To_SetCols; // ???
|
||||
MaxSize = tdbp->MaxSize;
|
||||
Read_Only = tdbp->Read_Only;
|
||||
} // end of TDBASE copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Return the pointer on the DB catalog this table belongs to. */
|
||||
/***********************************************************************/
|
||||
PCATLG TDBASE::GetCat(void)
|
||||
{
|
||||
return (To_Def) ? To_Def->GetCat() : NULL;
|
||||
} // end of GetCat
|
||||
|
||||
/***********************************************************************/
|
||||
/* Return the datapath of the DB this table belongs to. */
|
||||
/***********************************************************************/
|
||||
PSZ TDBASE::GetPath(void)
|
||||
{
|
||||
return To_Def->GetPath();
|
||||
} // end of GetPath
|
||||
|
||||
/***********************************************************************/
|
||||
/* Initialize TDBASE based column description block construction. */
|
||||
/* name is used to call columns by name. */
|
||||
/* num is used by TBL to construct columns by index number. */
|
||||
/* Note: name=Null and num=0 for constructing all columns (select *) */
|
||||
/***********************************************************************/
|
||||
PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num)
|
||||
{
|
||||
int i;
|
||||
PCOLDEF cdp;
|
||||
PCOL cp, colp = NULL, cprec = NULL;
|
||||
|
||||
if (trace)
|
||||
htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n",
|
||||
GetAmType(), SVP(name), Name, num);
|
||||
|
||||
for (cdp = To_Def->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++)
|
||||
if ((!name && !num) ||
|
||||
(name && !stricmp(cdp->GetName(), name)) || num == i) {
|
||||
/*****************************************************************/
|
||||
/* Check for existence of desired column. */
|
||||
/* Also find where to insert the new block. */
|
||||
/*****************************************************************/
|
||||
for (cp = Columns; cp; cp = cp->GetNext())
|
||||
if (cp->GetIndex() < i)
|
||||
cprec = cp;
|
||||
else if (cp->GetIndex() == i)
|
||||
break;
|
||||
|
||||
if (trace)
|
||||
htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp);
|
||||
|
||||
/*****************************************************************/
|
||||
/* Now take care of Column Description Block. */
|
||||
/*****************************************************************/
|
||||
if (cp)
|
||||
colp = cp;
|
||||
else
|
||||
colp = MakeCol(g, cdp, cprec, i);
|
||||
|
||||
if (trace)
|
||||
htrc("colp=%p\n", colp);
|
||||
|
||||
if (name || num)
|
||||
break;
|
||||
else if (colp)
|
||||
cprec = colp;
|
||||
|
||||
} // endif Name
|
||||
|
||||
return (colp);
|
||||
} // end of ColDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* InsertSpecialColumn: Put a special column ahead of the column list.*/
|
||||
/***********************************************************************/
|
||||
PCOL TDBASE::InsertSpecialColumn(PGLOBAL g, PCOL colp)
|
||||
{
|
||||
if (!colp->IsSpecial())
|
||||
return NULL;
|
||||
|
||||
colp->SetNext(Columns);
|
||||
Columns = colp;
|
||||
return colp;
|
||||
} // end of InsertSpecialColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* Make a special COLBLK to insert in a table. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLUMN cp)
|
||||
{
|
||||
char *name = (char*)cp->GetName();
|
||||
PCOL colp;
|
||||
|
||||
if (!strcmp(name, "FILEID")) {
|
||||
// !strcmp(name, "SERVID")) {
|
||||
if (!To_Def || !(To_Def->GetPseudo() & 2)) {
|
||||
sprintf(g->Message, MSG(BAD_SPEC_COLUMN));
|
||||
return NULL;
|
||||
} // endif Pseudo
|
||||
|
||||
// if (!strcmp(name, "FILEID"))
|
||||
colp = new(g) FIDBLK(cp);
|
||||
// else
|
||||
// colp = new(g) SIDBLK(cp);
|
||||
|
||||
} else if (!strcmp(name, "TABID")) {
|
||||
colp = new(g) TIDBLK(cp);
|
||||
//} else if (!strcmp(name, "CONID")) {
|
||||
// colp = new(g) CIDBLK(cp);
|
||||
} else if (!strcmp(name, "ROWID")) {
|
||||
colp = new(g) RIDBLK(cp, false);
|
||||
} else if (!strcmp(name, "ROWNUM")) {
|
||||
colp = new(g) RIDBLK(cp, true);
|
||||
} else {
|
||||
sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
|
||||
return NULL;
|
||||
} // endif's name
|
||||
|
||||
if (!(colp = InsertSpecialColumn(g, colp))) {
|
||||
sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
|
||||
return NULL;
|
||||
} // endif Insert
|
||||
|
||||
return (colp);
|
||||
} // end of InsertSpcBlk
|
||||
|
||||
/***********************************************************************/
|
||||
/* ResetTableOpt: Wrong for this table type. */
|
||||
/***********************************************************************/
|
||||
int TDBASE::ResetTableOpt(PGLOBAL g, bool dox)
|
||||
{
|
||||
strcpy(g->Message, "This table is not indexable");
|
||||
return RC_INFO;
|
||||
} // end of ResetTableOpt
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetKindex: set or reset the index pointer. */
|
||||
/***********************************************************************/
|
||||
void TDBASE::SetKindex(PKXBASE kxp)
|
||||
{
|
||||
if (To_Kindex)
|
||||
To_Kindex->Close(); // Discard old index
|
||||
|
||||
To_Kindex = kxp;
|
||||
} // end of SetKindex
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetRecpos: Replace the table at the specified position. */
|
||||
/***********************************************************************/
|
||||
bool TDBASE::SetRecpos(PGLOBAL g, int recpos)
|
||||
{
|
||||
strcpy(g->Message, MSG(SETRECPOS_NIY));
|
||||
return true;
|
||||
} // end of SetRecpos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Methods */
|
||||
/***********************************************************************/
|
||||
void TDBASE::PrintAM(FILE *f, char *m)
|
||||
{
|
||||
fprintf(f, "%s AM(%d): mode=%d\n", m, GetAmType(), Mode);
|
||||
} // end of PrintAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* Marks DOS/MAP table columns used in internal joins. */
|
||||
/* tdb2 is the top of tree or first tdb in chained tdb's and tdbp */
|
||||
/* points to the currently marked tdb. */
|
||||
/* Two questions here: exact meaning of U_J_INT ? */
|
||||
/* Why is the eventual reference to To_Key_Col not marked U_J_EXT ? */
|
||||
/***********************************************************************/
|
||||
void TDBASE::MarkDB(PGLOBAL g, PTDB tdb2)
|
||||
{
|
||||
if (trace)
|
||||
htrc("DOS MarkDB: tdbp=%p tdb2=%p\n", this, tdb2);
|
||||
|
||||
} // end of MarkDB
|
||||
458
storage/connect/tabmac.cpp
Normal file
458
storage/connect/tabmac.cpp
Normal file
@@ -0,0 +1,458 @@
|
||||
/***********************************************************************/
|
||||
/* TABMAC: Author Olivier Bertrand -- PlugDB -- 2008-2012 */
|
||||
/* From the article and sample code by Khalid Shaikh. */
|
||||
/* TABMAC: virtual table to get the list of MAC addresses. */
|
||||
/***********************************************************************/
|
||||
#if defined(WIN32)
|
||||
#include "my_global.h"
|
||||
//#include <iphlpapi.h>
|
||||
#else // !WIN32
|
||||
#error This is a WIN32 only table type
|
||||
#endif // !WIN32
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
//#include "catalog.h"
|
||||
#include "reldef.h"
|
||||
#include "xtable.h"
|
||||
#include "colblk.h"
|
||||
#include "tabmac.h"
|
||||
|
||||
#if 0 // This is placed here just to know what are the actual values
|
||||
#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
|
||||
#define MAX_ADAPTER_NAME_LENGTH 256
|
||||
#define MAX_ADAPTER_ADDRESS_LENGTH 8
|
||||
#define DEFAULT_MINIMUM_ENTITIES 32
|
||||
#define MAX_HOSTNAME_LEN 128
|
||||
#define MAX_DOMAIN_NAME_LEN 128
|
||||
#define MAX_SCOPE_ID_LEN 256
|
||||
|
||||
#define BROADCAST_NODETYPE 1
|
||||
#define PEER_TO_PEER_NODETYPE 2
|
||||
#define MIXED_NODETYPE 4
|
||||
#define HYBRID_NODETYPE 8
|
||||
|
||||
#define IP_ADAPTER_DDNS_ENABLED 0x01
|
||||
#define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02
|
||||
#define IP_ADAPTER_DHCP_ENABLED 0x04
|
||||
#define IP_ADAPTER_RECEIVE_ONLY 0x08
|
||||
#define IP_ADAPTER_NO_MULTICAST 0x10
|
||||
#define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
|
||||
#endif // 0
|
||||
|
||||
/* -------------- Implementation of the MAC classes ------------------ */
|
||||
|
||||
/***********************************************************************/
|
||||
/* DefineAM: define specific AM block values from MAC file. */
|
||||
/***********************************************************************/
|
||||
bool MACDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
return false;
|
||||
} // end of DefineAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTable: makes a new TDB of the proper type. */
|
||||
/***********************************************************************/
|
||||
PTDB MACDEF::GetTable(PGLOBAL g, MODE m)
|
||||
{
|
||||
return new(g) TDBMAC(this);
|
||||
} // end of GetTable
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBMAC class. */
|
||||
/***********************************************************************/
|
||||
TDBMAC::TDBMAC(PMACDEF tdp) : TDBASE(tdp)
|
||||
{
|
||||
FixedInfo = NULL;
|
||||
Piaf = NULL;
|
||||
Curp = NULL;
|
||||
Next = NULL;
|
||||
Buflen = 0;
|
||||
Fix = false;
|
||||
Adap = false;
|
||||
N = 0;
|
||||
} // end of TDBMAC constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate MAC column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBMAC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
PCOL colp;
|
||||
|
||||
colp = new(g) MACCOL(cdp, this, n);
|
||||
|
||||
if (cprec) {
|
||||
colp->SetNext(cprec->GetNext());
|
||||
cprec->SetNext(colp);
|
||||
} else {
|
||||
colp->SetNext(Columns);
|
||||
Columns = colp;
|
||||
} // endif cprec
|
||||
|
||||
return colp;
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* MAC: Get the number of found adapters. */
|
||||
/***********************************************************************/
|
||||
void TDBMAC::MakeErrorMsg(PGLOBAL g, DWORD drc)
|
||||
{
|
||||
if (drc == ERROR_BUFFER_OVERFLOW)
|
||||
sprintf(g->Message,
|
||||
"GetAdaptersInfo: Buffer Overflow buflen=%d maxsize=%d",
|
||||
Buflen, MaxSize);
|
||||
else if (drc == ERROR_INVALID_PARAMETER)
|
||||
strcpy(g->Message, "GetAdaptersInfo: Invalid parameters");
|
||||
else if (drc == ERROR_NO_DATA)
|
||||
strcpy(g->Message,
|
||||
"No adapter information exists for the local computer");
|
||||
else if (drc == ERROR_NOT_SUPPORTED)
|
||||
strcpy(g->Message, "GetAdaptersInfo is not supported");
|
||||
else
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
|
||||
0, g->Message, sizeof(g->Message), NULL);
|
||||
|
||||
} // end of MakeErrorMsg
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetMacInfo: Get info for all found adapters. */
|
||||
/***********************************************************************/
|
||||
bool TDBMAC::GetMacInfo(PGLOBAL g)
|
||||
{
|
||||
DWORD drc;
|
||||
|
||||
if (GetMaxSize(g) < 0)
|
||||
return true;
|
||||
else if (MaxSize == 0)
|
||||
return false;
|
||||
|
||||
Piaf = (PIP_ADAPTER_INFO)PlugSubAlloc(g, NULL, Buflen);
|
||||
drc = GetAdaptersInfo(Piaf, &Buflen);
|
||||
|
||||
if (drc == ERROR_SUCCESS) {
|
||||
Next = Piaf; // Next is the first one
|
||||
return false; // Success
|
||||
} // endif drc
|
||||
|
||||
MakeErrorMsg(g, drc);
|
||||
return true;
|
||||
} // end of GetMacInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetFixedInfo: Get info for network parameters. */
|
||||
/***********************************************************************/
|
||||
bool TDBMAC::GetFixedInfo(PGLOBAL g)
|
||||
{
|
||||
ULONG len;
|
||||
DWORD drc;
|
||||
|
||||
FixedInfo = (FIXED_INFO*)PlugSubAlloc(g, NULL, sizeof(FIXED_INFO));
|
||||
len = sizeof(FIXED_INFO);
|
||||
drc = GetNetworkParams(FixedInfo, &len);
|
||||
|
||||
if (drc == ERROR_BUFFER_OVERFLOW) {
|
||||
FixedInfo = (FIXED_INFO*)PlugSubAlloc(g, NULL, len);
|
||||
drc = GetNetworkParams(FixedInfo, &len);
|
||||
} // endif drc
|
||||
|
||||
if (drc != ERROR_SUCCESS) {
|
||||
sprintf(g->Message, "GetNetworkParams failed. Rc=%08x\n", drc);
|
||||
return true;
|
||||
} // endif drc
|
||||
|
||||
return false;
|
||||
} // end of GetFixedInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* MAC: Get the number of found adapters. */
|
||||
/***********************************************************************/
|
||||
int TDBMAC::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (Use != USE_OPEN)
|
||||
// Called from info, Adap and Fix are not set yet
|
||||
return 1;
|
||||
|
||||
if (MaxSize < 0) {
|
||||
// Best method
|
||||
if (Adap) {
|
||||
DWORD drc = GetAdaptersInfo(NULL, &(Buflen = 0));
|
||||
|
||||
if (drc == ERROR_SUCCESS)
|
||||
MaxSize = (Fix) ? 1 : 0;
|
||||
else if (drc == ERROR_BUFFER_OVERFLOW) {
|
||||
// sizeof(IP_ADAPTER_INFO) was returning 640 but is now sometimes
|
||||
// returning 648 while the Buflen setting remains the same (n*640)
|
||||
// >> Of course, the code above contains a race condition....
|
||||
// if the size of the structure Windows wants to return grows after
|
||||
// the first call to GetAdaptersInfo() but before the second call
|
||||
// to GetAdaptersInfo(), the second call to GetAdaptersInfo() will
|
||||
// fail with ERROR_BUFFER_OVERFLOW as well, and your function won't
|
||||
// work (by Jeremy Friesner on stackoverflow.com).
|
||||
// That's why we add something to it to be comfortable.
|
||||
MaxSize = (Buflen + 600) / sizeof(IP_ADAPTER_INFO);
|
||||
|
||||
// Now Buflen must be updated if 648 is true.
|
||||
Buflen = MaxSize * sizeof(IP_ADAPTER_INFO);
|
||||
} else
|
||||
MakeErrorMsg(g, drc);
|
||||
|
||||
} else
|
||||
MaxSize = (Fix) ? 1 : 0;
|
||||
|
||||
#if 0
|
||||
// This method returns too many adapters
|
||||
DWORD dw, drc = GetNumberOfInterfaces((PDWORD)&dw);
|
||||
|
||||
if (drc == NO_ERROR) {
|
||||
MaxSize = (int)dw;
|
||||
Buflen = MaxSize * sizeof(IP_ADAPTER_INFO);
|
||||
} else
|
||||
MakeErrorMsg(g, 0);
|
||||
#endif
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* MAC Access Method opening routine. */
|
||||
/***********************************************************************/
|
||||
bool TDBMAC::OpenDB(PGLOBAL g)
|
||||
{
|
||||
if (Use == USE_OPEN) {
|
||||
/*******************************************************************/
|
||||
/* Table already open, this should not happen. */
|
||||
/*******************************************************************/
|
||||
strcpy(g->Message, "TDBMAC should not be reopened");
|
||||
return true;
|
||||
} // endif use
|
||||
|
||||
if (Mode != MODE_READ) {
|
||||
/*******************************************************************/
|
||||
/* MAC tables cannot be modified. */
|
||||
/*******************************************************************/
|
||||
strcpy(g->Message, "MAC tables are read only");
|
||||
return true;
|
||||
} else
|
||||
Use = USE_OPEN;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get the adapters info. */
|
||||
/*********************************************************************/
|
||||
if (Adap && GetMacInfo(g))
|
||||
return true;
|
||||
|
||||
if (Fix && GetFixedInfo(g))
|
||||
return true;
|
||||
|
||||
/*********************************************************************/
|
||||
/* All is done. */
|
||||
/*********************************************************************/
|
||||
return false;
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base read routine for MAC access method. */
|
||||
/***********************************************************************/
|
||||
int TDBMAC::ReadDB(PGLOBAL g)
|
||||
{
|
||||
Curp = Next;
|
||||
|
||||
if (Curp)
|
||||
Next = Curp->Next;
|
||||
else if (N || !Fix)
|
||||
return RC_EF;
|
||||
|
||||
N++;
|
||||
return RC_OK;
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for MAC access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBMAC::WriteDB(PGLOBAL g)
|
||||
{
|
||||
strcpy(g->Message, "MAC tables are read only");
|
||||
return RC_FX;
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for MAC access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBMAC::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
strcpy(g->Message, "Delete not enabled for MAC tables");
|
||||
return RC_FX;
|
||||
} // end of DeleteDB
|
||||
|
||||
// ------------------------ MACCOL functions ----------------------------
|
||||
|
||||
/***********************************************************************/
|
||||
/* MACCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
MACCOL::MACCOL(PCOLDEF cdp, PTDB tdbp, int n)
|
||||
: COLBLK(cdp, tdbp, n)
|
||||
{
|
||||
Tdbp = (PTDBMAC)tdbp;
|
||||
Flag = cdp->GetOffset();
|
||||
|
||||
if (Flag < 10)
|
||||
Tdbp->Fix = true;
|
||||
else
|
||||
Tdbp->Adap = true;
|
||||
|
||||
} // end of MACCOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Read the next MAC address elements. */
|
||||
/***********************************************************************/
|
||||
void MACCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
// Type conversion is handled by Value set routines
|
||||
char *p = NULL, buf[260] = "";
|
||||
unsigned int i;
|
||||
int n = 0;
|
||||
PIP_ADAPTER_INFO adp = Tdbp->Curp;
|
||||
FIXED_INFO *fip = Tdbp->FixedInfo;
|
||||
|
||||
if (!adp && Flag >= 10) {
|
||||
// Fix info row, no adapter info available
|
||||
switch (Flag) {
|
||||
case 13:
|
||||
case 14:
|
||||
case 19:
|
||||
case 22:
|
||||
case 23:
|
||||
n = 0;
|
||||
break;
|
||||
default:
|
||||
p = "";
|
||||
} // endswitch Flag
|
||||
|
||||
} else switch (Flag) {
|
||||
// FIXED INFO
|
||||
case 1: // Host Name
|
||||
p = fip->HostName;
|
||||
break;
|
||||
case 2: // Domain Name
|
||||
p = fip->DomainName;
|
||||
break;
|
||||
case 3: // DNS IPaddress
|
||||
p = (fip->CurrentDnsServer)
|
||||
? (char*)&fip->CurrentDnsServer->IpAddress
|
||||
: (char*)&fip->DnsServerList.IpAddress;
|
||||
break;
|
||||
case 4: // Node Type
|
||||
n = (int)fip->NodeType;
|
||||
break;
|
||||
case 5: // Scope ID ???
|
||||
p = fip->ScopeId;
|
||||
break;
|
||||
case 6: // Routing enabled
|
||||
n = (int)fip->EnableRouting;
|
||||
break;
|
||||
case 7: // Proxy enabled
|
||||
n = (int)fip->EnableProxy;
|
||||
break;
|
||||
case 8: // DNS enabled
|
||||
n = (int)fip->EnableDns;
|
||||
break;
|
||||
// ADAPTERS INFO
|
||||
case 10: // Name
|
||||
p = adp->AdapterName;
|
||||
break;
|
||||
case 11: // Description
|
||||
if ((p = strstr(adp->Description, " - Packet Scheduler Miniport"))) {
|
||||
strncpy(buf, adp->Description, p - adp->Description);
|
||||
i = p - adp->Description;
|
||||
strncpy(buf, adp->Description, i);
|
||||
buf[i] = 0;
|
||||
p = buf;
|
||||
} else if ((p = strstr(adp->Description,
|
||||
" - Miniport d'ordonnancement de paquets"))) {
|
||||
i = p - adp->Description;
|
||||
strncpy(buf, adp->Description, i);
|
||||
buf[i] = 0;
|
||||
p = buf;
|
||||
} else
|
||||
p = adp->Description;
|
||||
|
||||
break;
|
||||
case 12: // MAC Address
|
||||
for (p = buf, i = 0; i < adp->AddressLength; i++) {
|
||||
if (i)
|
||||
strcat(p++, "-");
|
||||
|
||||
p += sprintf(p, "%.2X", adp->Address[i]);
|
||||
} // endfor i
|
||||
|
||||
p = buf;
|
||||
break;
|
||||
case 13: // Type
|
||||
#if 0 // This is not found in the SDK
|
||||
switch (adp->Type) {
|
||||
case IF_ETHERNET_ADAPTERTYPE: p = "Ethernet Adapter"; break;
|
||||
case IF_TOKEN_RING_ADAPTERTYPE: p = "Token Ring Adapter"; break;
|
||||
case IF_FDDI_ADAPTERTYPE: p = "FDDI Adapter"; break;
|
||||
case IF_PPP_ADAPTERTYPE: p = "PPP Adapter"; break;
|
||||
case IF_LOOPBACK_ADAPTERTYPE: p = "Loop Back Adapter"; break;
|
||||
// case IF_SLIP_ADAPTERTYPE: p = "Generic Slip Adapter"; break;
|
||||
default:
|
||||
sprintf(buf, "Other Adapter, type=%d", adp->Type);
|
||||
p = buf;
|
||||
} // endswitch Type
|
||||
#endif // 0
|
||||
n = (int)adp->Type;
|
||||
break;
|
||||
case 14: // DHCP enabled
|
||||
n = (int)adp->DhcpEnabled;
|
||||
break;
|
||||
case 15: // IP Address
|
||||
p = (adp->CurrentIpAddress)
|
||||
? (char*)&adp->CurrentIpAddress->IpAddress
|
||||
: (char*)&adp->IpAddressList.IpAddress;
|
||||
break;
|
||||
case 16: // Subnet Mask
|
||||
p = (adp->CurrentIpAddress)
|
||||
? (char*)&adp->CurrentIpAddress->IpMask
|
||||
: (char*)&adp->IpAddressList.IpMask;
|
||||
break;
|
||||
case 17: // Gateway
|
||||
p = (char*)&adp->GatewayList.IpAddress;
|
||||
break;
|
||||
case 18: // DHCP Server
|
||||
p = (char*)&adp->DhcpServer.IpAddress;
|
||||
break;
|
||||
case 19: // Have WINS
|
||||
n = (adp->HaveWins) ? 1 : 0;
|
||||
break;
|
||||
case 20: // Primary WINS
|
||||
p = (char*)&adp->PrimaryWinsServer.IpAddress;
|
||||
break;
|
||||
case 21: // Secondary WINS
|
||||
p = (char*)&adp->SecondaryWinsServer.IpAddress;
|
||||
break;
|
||||
case 22: // Lease obtained
|
||||
n = (int)adp->LeaseObtained;
|
||||
break;
|
||||
case 23: // Lease expires
|
||||
n = (int)adp->LeaseExpires;
|
||||
break;
|
||||
default:
|
||||
if (Buf_Type == TYPE_STRING) {
|
||||
sprintf(buf, "Invalid flag value %d", Flag);
|
||||
p = buf;
|
||||
} else
|
||||
n = 0;
|
||||
|
||||
} // endswitch Flag
|
||||
|
||||
if (p)
|
||||
Value->SetValue_psz(p);
|
||||
else
|
||||
Value->SetValue(n);
|
||||
|
||||
} // end of ReadColumn
|
||||
107
storage/connect/tabmac.h
Normal file
107
storage/connect/tabmac.h
Normal file
@@ -0,0 +1,107 @@
|
||||
// TABMAC.H Olivier Bertrand 2011-2012
|
||||
// MAC: virtual table to Get Mac Addresses via GetAdaptersInfo
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
#include <iphlpapi.h>
|
||||
#else // !WIN32
|
||||
#error This is a WIN32 only table TYPE
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definitions. */
|
||||
/***********************************************************************/
|
||||
typedef class MACDEF *PMACDEF;
|
||||
typedef class TDBMAC *PTDBMAC;
|
||||
typedef class MACCOL *PMACCOL;
|
||||
|
||||
/* -------------------------- MAC classes ---------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* MAC: virtual table to get the list of MAC addresses. */
|
||||
/***********************************************************************/
|
||||
class DllExport MACDEF : public TABDEF { /* Logical table description */
|
||||
friend class TDBMAC;
|
||||
public:
|
||||
// Constructor
|
||||
MACDEF(void) {Pseudo = 3;}
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "MAC";}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
virtual bool DeleteTableFile(PGLOBAL g) {return true;}
|
||||
|
||||
protected:
|
||||
// Members
|
||||
}; // end of MACDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the MAC table. */
|
||||
/***********************************************************************/
|
||||
class TDBMAC : public TDBASE {
|
||||
friend class MACCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBMAC(PMACDEF tdp);
|
||||
//TDBMAC(PGLOBAL g, PTDBMAC tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_MAC;}
|
||||
//virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMAC(g, this);}
|
||||
|
||||
// Methods
|
||||
//virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void) {return N;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false) {return N;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g) {}
|
||||
|
||||
protected:
|
||||
// Specific routines
|
||||
bool GetMacInfo(PGLOBAL g);
|
||||
bool GetFixedInfo(PGLOBAL g);
|
||||
void MakeErrorMsg(PGLOBAL g, DWORD drc);
|
||||
|
||||
// Members
|
||||
FIXED_INFO *FixedInfo; // Points to fixed info structure
|
||||
PIP_ADAPTER_INFO Piaf; // Points on Adapter info array
|
||||
PIP_ADAPTER_INFO Curp; // Points on current Adapt info
|
||||
PIP_ADAPTER_INFO Next; // Points on next Adapt info
|
||||
ULONG Buflen; // Buffer length
|
||||
bool Fix; // true if FixedInfo is needed
|
||||
bool Adap; // true if Piaf is needed
|
||||
int N; // Row number
|
||||
}; // end of class TDBMAC
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class MACCOL: MAC Address column. */
|
||||
/***********************************************************************/
|
||||
class MACCOL : public COLBLK {
|
||||
friend class TDBMAC;
|
||||
public:
|
||||
// Constructors
|
||||
MACCOL(PCOLDEF cdp, PTDB tdbp, int n);
|
||||
//MACCOL(MACCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_MAC;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
MACCOL(void) {} // Default constructor not to be used
|
||||
|
||||
// Members
|
||||
PTDBMAC Tdbp; // Points to MAC table block
|
||||
int Flag; // Indicates what to display
|
||||
}; // end of class MACCOL
|
||||
1480
storage/connect/tabmul.cpp
Normal file
1480
storage/connect/tabmul.cpp
Normal file
File diff suppressed because it is too large
Load Diff
220
storage/connect/tabmul.h
Normal file
220
storage/connect/tabmul.h
Normal file
@@ -0,0 +1,220 @@
|
||||
/*************** Tabmul H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABMUL.H Version 1.4 */
|
||||
/* */
|
||||
/* (C) Copyright to PlugDB Software Development 2003-2012 */
|
||||
/* Author: Olivier BERTRAND */
|
||||
/* */
|
||||
/* This file contains the TDBMUL and TDBDIR classes declares. */
|
||||
/***********************************************************************/
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#else // !WIN32
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#endif // !WIN32
|
||||
//#include "osutil.h"
|
||||
#include "block.h"
|
||||
|
||||
typedef class TDBMUL *PTDBMUL;
|
||||
typedef class TDBSDR *PTDBSDR;
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the MUL Access Method class declaration for files that are */
|
||||
/* physically split in multiple files having the same format. */
|
||||
/***********************************************************************/
|
||||
class DllExport TDBMUL : public TDBASE {
|
||||
//friend class MULCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBMUL(PTDBASE tdbp);
|
||||
TDBMUL(PTDBMUL tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return Tdbp->GetAmType();}
|
||||
virtual PTDB Duplicate(PGLOBAL g);
|
||||
|
||||
// Methods
|
||||
virtual void ResetDB(void);
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual bool IsSame(PTBX tp) {return tp == (PTBX)Tdbp;}
|
||||
virtual PSZ GetFile(PGLOBAL g) {return Tdbp->GetFile(g);}
|
||||
virtual int GetRecpos(void) {return 0;}
|
||||
virtual PCOL ColDB(PGLOBAL g, PSZ name, int num);
|
||||
bool InitFileNames(PGLOBAL g);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{strcpy(g->Message, MSG(MUL_MAKECOL_ERR)); return NULL;}
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual int GetProgMax(PGLOBAL g);
|
||||
virtual int GetProgCur(void);
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
|
||||
// Members
|
||||
TDBASE *Tdbp; // Points to a (file) table class
|
||||
char* *Filenames; // Points to file names
|
||||
int Rows; // Total rows of already read files
|
||||
int Mul; // Type of multiple file list
|
||||
int NumFiles; // Number of physical files
|
||||
int iFile; // Index of currently processed file
|
||||
}; // end of class TDBMUL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Directory listing table. */
|
||||
/***********************************************************************/
|
||||
class DllExport DIRDEF : public TABDEF { /* Directory listing table */
|
||||
friend class CATALOG;
|
||||
friend class TDBDIR;
|
||||
public:
|
||||
// Constructor
|
||||
DIRDEF(void) {Fn = NULL; Incl = false; Huge = false;}
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "DIR";}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PSZ Fn; /* Path/Name of file search */
|
||||
bool Incl; /* true to include sub-directories */
|
||||
bool Huge; /* true if files can be larger than 2GB */
|
||||
}; // end of DIRDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DIR Access Method class declaration for tables that */
|
||||
/* represent a directory listing. The pathname is given at the create */
|
||||
/* time and can contain wildcard characters in the file name, and the */
|
||||
/* (virtual) table is populated when it is in use. */
|
||||
/***********************************************************************/
|
||||
class TDBDIR : public TDBASE {
|
||||
friend class DIRCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBDIR(PDIRDEF tdp);
|
||||
TDBDIR(PTDBDIR tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_DIR;}
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBDIR(this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void) {return iFile;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);}
|
||||
virtual int GetProgCur(void) {return iFile;}
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
char *Path(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
PSZ To_File; // Points to file search pathname
|
||||
int iFile; // Index of currently retrieved file
|
||||
#if defined(WIN32)
|
||||
_finddata_t FileData; // Find data structure
|
||||
int Hsearch; // Search handle
|
||||
char Drive[_MAX_DRIVE]; // Drive name
|
||||
#else // !WIN32
|
||||
struct stat Fileinfo; // File info structure
|
||||
struct dirent *Entry; // Point to directory entry structure
|
||||
DIR *Dir; // To searched directory structure
|
||||
bool Done; // true when _splipath is done
|
||||
char Pattern[_MAX_FNAME+_MAX_EXT];
|
||||
#endif // !WIN32
|
||||
char Fpath[_MAX_PATH]; // Absolute file search pattern
|
||||
char Direc[_MAX_DIR]; // Search path
|
||||
char Fname[_MAX_FNAME]; // File name
|
||||
char Ftype[_MAX_EXT]; // File extention
|
||||
}; // end of class TDBDIR
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DIR Access Method class declaration for tables that */
|
||||
/* represent a directory listing. The pathname is given at the create */
|
||||
/* time and can contain wildcard characters in the file name, and the */
|
||||
/* (virtual) table is populated when it is in use. In addition, this */
|
||||
/* class also includes files of included sub-directories. */
|
||||
/***********************************************************************/
|
||||
class TDBSDR : public TDBDIR {
|
||||
friend class DIRCOL;
|
||||
public:
|
||||
// Constructors
|
||||
TDBSDR(PDIRDEF tdp) : TDBDIR(tdp) {Sub = NULL;}
|
||||
TDBSDR(PTDBSDR tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBSDR(this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
|
||||
// Database routines
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);}
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
//virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
int FindInDir(PGLOBAL g);
|
||||
|
||||
typedef struct _Sub_Dir {
|
||||
struct _Sub_Dir *Next;
|
||||
struct _Sub_Dir *Prev;
|
||||
#if defined(WIN32)
|
||||
int H; // Search handle
|
||||
#else // !WIN32
|
||||
DIR *D;
|
||||
#endif // !WIN32
|
||||
size_t Len; // Initial directory name length
|
||||
} SUBDIR, *PSUBDIR;
|
||||
|
||||
// Members
|
||||
PSUBDIR Sub; // To current Subdir block
|
||||
}; // end of class TDBSDR
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class DIRCOL: DIR access method column descriptor. */
|
||||
/* This A.M. is used for tables populated by DIR file name list. */
|
||||
/***********************************************************************/
|
||||
class DIRCOL : public COLBLK {
|
||||
public:
|
||||
// Constructors
|
||||
DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "DIR");
|
||||
DIRCOL(DIRCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_DIR;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
DIRCOL(void) {}
|
||||
|
||||
// Members
|
||||
int N; // Column number
|
||||
}; // end of class DIRCOL
|
||||
1096
storage/connect/tabmysql.cpp
Normal file
1096
storage/connect/tabmysql.cpp
Normal file
File diff suppressed because it is too large
Load Diff
139
storage/connect/tabmysql.h
Normal file
139
storage/connect/tabmysql.h
Normal file
@@ -0,0 +1,139 @@
|
||||
// TDBMYSQL.H Olivier Bertrand 2007-2012
|
||||
#include "myconn.h" // MySQL connection declares
|
||||
|
||||
typedef class MYSQLDEF *PMYDEF;
|
||||
typedef class TDBMYSQL *PTDBMY;
|
||||
typedef class MYSQLC *PMYC;
|
||||
typedef class MYSQLCOL *PMYCOL;
|
||||
|
||||
/* ------------------------- MYSQL classes --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* MYSQL: table type that are MySQL tables. */
|
||||
/* Using embedded MySQL library (or optionally calling a MySQL server)*/
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* MYSQL table. */
|
||||
/***********************************************************************/
|
||||
class MYSQLDEF : public TABDEF {/* Logical table description */
|
||||
friend class TDBMYSQL;
|
||||
public:
|
||||
// Constructor
|
||||
MYSQLDEF(void);
|
||||
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "MYSQL";}
|
||||
inline PSZ GetHostname(void) {return Hostname;};
|
||||
inline PSZ GetDatabase(void) {return Database;};
|
||||
inline PSZ GetTabname(void) {return Tabname;}
|
||||
inline PSZ GetUsername(void) {return Username;};
|
||||
inline PSZ GetPassword(void) {return Password;};
|
||||
inline int GetPortnumber(void) {return Portnumber;}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PSZ Hostname; /* Host machine to use */
|
||||
PSZ Database; /* Database to be used by server */
|
||||
PSZ Tabname; /* External table name */
|
||||
PSZ Username; /* User logon name */
|
||||
PSZ Password; /* Password logon info */
|
||||
int Portnumber; /* MySQL port number (0 = default) */
|
||||
bool Bind; /* Use prepared statement on insert */
|
||||
bool Delayed; /* Delayed insert */
|
||||
}; // end of MYSQLDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the MYSQL table. */
|
||||
/***********************************************************************/
|
||||
class TDBMYSQL : public TDBASE {
|
||||
friend class MYSQLCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBMYSQL(PMYDEF tdp);
|
||||
TDBMYSQL(PGLOBAL g, PTDBMY tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_MYSQL;}
|
||||
virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMYSQL(g, this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetAffectedRows(void) {return AftRows;}
|
||||
virtual int GetRecpos(void) {return N;}
|
||||
virtual int GetProgMax(PGLOBAL g);
|
||||
virtual void ResetDB(void) {N = 0;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = FALSE);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Internal functions
|
||||
bool MakeSelect(PGLOBAL g);
|
||||
bool MakeInsert(PGLOBAL g);
|
||||
//bool MakeUpdate(PGLOBAL g);
|
||||
//bool MakeDelete(PGLOBAL g);
|
||||
int BindColumns(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
MYSQLC Myc; // MySQL connection class
|
||||
MYSQL_BIND *Bind; // To the MySQL bind structure array
|
||||
char *Host; // Host machine to use
|
||||
char *User; // User logon info
|
||||
char *Pwd; // Password logon info
|
||||
char *Database; // Database to be used by server
|
||||
char *Tabname; // External table name
|
||||
char *Query; // Points to SQL query
|
||||
char *Qbuf; // Used for not prepared insert
|
||||
bool Fetched; // True when fetch was done
|
||||
bool Prep; // Use prepared statement on insert
|
||||
bool Delayed; // Use delayed insert
|
||||
int m_Rc; // Return code from command
|
||||
int AftRows; // The number of affected rows
|
||||
int N; // The current table index
|
||||
int Port; // MySQL port number (0 = default)
|
||||
int Nparm; // The number of statement parameters
|
||||
}; // end of class TDBMYSQL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class MYSQLCOL: MySQL table column. */
|
||||
/***********************************************************************/
|
||||
class MYSQLCOL : public COLBLK {
|
||||
friend class TDBMYSQL;
|
||||
public:
|
||||
// Constructors
|
||||
MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "MYSQL");
|
||||
MYSQLCOL(MYSQLCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_MYSQL;}
|
||||
void InitBind(PGLOBAL g);
|
||||
|
||||
// Methods
|
||||
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
MYSQLCOL(void) {}
|
||||
|
||||
// Members
|
||||
MYSQL_BIND *Bind; // This column bind structure pointer
|
||||
PVAL To_Val; // To value used for Update/Insert
|
||||
unsigned long Slen; // Bind string lengh
|
||||
int Rank; // Rank (position) number in the query
|
||||
}; // end of class MYSQLCOL
|
||||
|
||||
893
storage/connect/tabodbc.cpp
Normal file
893
storage/connect/tabodbc.cpp
Normal file
@@ -0,0 +1,893 @@
|
||||
/************* Tabodbc C++ Program Source Code File (.CPP) *************/
|
||||
/* PROGRAM NAME: TABODBC */
|
||||
/* ------------- */
|
||||
/* Version 2.3 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2000-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the TABODBC class DB execution routines. */
|
||||
/* */
|
||||
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
||||
/* -------------------------------------- */
|
||||
/* */
|
||||
/* REQUIRED FILES: */
|
||||
/* --------------- */
|
||||
/* TABODBC.CPP - Source code */
|
||||
/* PLGDBSEM.H - DB application declaration file */
|
||||
/* TABODBC.H - TABODBC 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 MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif
|
||||
//#include <windows.h>
|
||||
#include <sqltypes.h>
|
||||
#else
|
||||
#if defined(UNIX)
|
||||
#include <errno.h>
|
||||
#include "osutil.h"
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#define NODW
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing the DB application declarations. */
|
||||
/* kindex.h is kindex header that also includes tabdos.h. */
|
||||
/* tabodbc.h is header containing the TABODBC class declarations. */
|
||||
/* odbconn.h is header containing ODBC connection declarations. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
//#include "sqry.h"
|
||||
#include "xtable.h"
|
||||
#include "tabodbc.h"
|
||||
#include "tabmul.h"
|
||||
#include "reldef.h"
|
||||
#include "tabcol.h"
|
||||
#include "valblk.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* DB static variables. */
|
||||
/***********************************************************************/
|
||||
// int num_read, num_there, num_eq[2], num_nf; // Statistics
|
||||
extern int num_read, num_there, num_eq[2]; // Statistics
|
||||
|
||||
/* -------------------------- Class ODBCDEF -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* DefineAM: define specific AM block values from XDB file. */
|
||||
/***********************************************************************/
|
||||
bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
//void *memp = Cat->GetDescp();
|
||||
//PSZ dbfile = Cat->GetDescFile();
|
||||
int dop = ODBConn::noOdbcDialog; // Default for options
|
||||
|
||||
Desc = Connect = Cat->GetStringCatInfo(g, Name, "Connect", "");
|
||||
Tabname = Cat->GetStringCatInfo(g, Name, "Name", Name); // Deprecated
|
||||
Tabname = Cat->GetStringCatInfo(g, Name, "Tabname", Tabname);
|
||||
Tabowner = Cat->GetStringCatInfo(g, Name, "Owner", "");
|
||||
Tabqual = Cat->GetStringCatInfo(g, Name, "Qualifier", "");
|
||||
Qchar = Cat->GetStringCatInfo(g, Name, "Qchar", "");
|
||||
Catver = Cat->GetIntCatInfo(Name, "Catver", 2);
|
||||
Options = Cat->GetIntCatInfo(Name, "Options", dop);
|
||||
//Options = Cat->GetIntCatInfo(Name, "Options", 0);
|
||||
Pseudo = 2; // FILID is Ok but not ROWID
|
||||
return false;
|
||||
} // end of DefineAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTable: makes a new Table Description Block. */
|
||||
/***********************************************************************/
|
||||
PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m)
|
||||
{
|
||||
PTDBASE tdbp = NULL;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate a TDB of the proper type. */
|
||||
/* Column blocks will be allocated only when needed. */
|
||||
/*********************************************************************/
|
||||
tdbp = new(g) TDBODBC(this);
|
||||
|
||||
if (Multiple == 1)
|
||||
tdbp = new(g) TDBMUL(tdbp);
|
||||
else if (Multiple == 2)
|
||||
strcpy(g->Message, MSG(NO_ODBC_MUL));
|
||||
|
||||
return tdbp;
|
||||
} // end of GetTable
|
||||
|
||||
/* -------------------------- Class TDBODBC -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBODBC class. */
|
||||
/***********************************************************************/
|
||||
TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
|
||||
{
|
||||
Ocp = NULL;
|
||||
Cnp = NULL;
|
||||
|
||||
if (tdp) {
|
||||
Connect = tdp->GetConnect();
|
||||
TableName = tdp->GetTabname();
|
||||
Owner = tdp->GetTabowner();
|
||||
Qualifier = tdp->GetTabqual();
|
||||
Quote = tdp->GetQchar();
|
||||
Options = tdp->GetOptions();
|
||||
Rows = tdp->GetElemt();
|
||||
Catver = tdp->GetCatver();
|
||||
} else {
|
||||
Connect = NULL;
|
||||
TableName = NULL;
|
||||
Owner = NULL;
|
||||
Qualifier = NULL;
|
||||
Quote = NULL;
|
||||
Options = 0;
|
||||
Rows = 0;
|
||||
Catver = 0;
|
||||
} // endif tdp
|
||||
|
||||
Query = NULL;
|
||||
Count = NULL;
|
||||
//Where = NULL;
|
||||
MulConn = NULL;
|
||||
DBQ = NULL;
|
||||
Fpos = 0;
|
||||
AftRows = 0;
|
||||
CurNum = 0;
|
||||
Rbuf = 0;
|
||||
BufSize = 0;
|
||||
Nparm = 0;
|
||||
} // end of TDBODBC standard constructor
|
||||
|
||||
TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
|
||||
{
|
||||
Ocp = tdbp->Ocp; // is that right ?
|
||||
Cnp = tdbp->Cnp;
|
||||
Connect = tdbp->Connect;
|
||||
TableName = tdbp->TableName;
|
||||
Owner = tdbp->Owner;
|
||||
Qualifier = tdbp->Qualifier;
|
||||
Quote = tdbp->Quote;
|
||||
Query = tdbp->Query;
|
||||
Count = tdbp->Count;
|
||||
//Where = tdbp->Where;
|
||||
MulConn = tdbp->MulConn;
|
||||
DBQ = tdbp->DBQ;
|
||||
Options = tdbp->Options;
|
||||
Rows = tdbp->Rows;
|
||||
Fpos = tdbp->Fpos;
|
||||
AftRows = tdbp->AftRows;
|
||||
//Tpos = tdbp->Tpos;
|
||||
//Spos = tdbp->Spos;
|
||||
CurNum = tdbp->CurNum;
|
||||
Rbuf = tdbp->Rbuf;
|
||||
BufSize = tdbp->BufSize;
|
||||
Nparm = tdbp->Nparm;
|
||||
} // end of TDBODBC copy constructor
|
||||
|
||||
// Method
|
||||
PTDB TDBODBC::CopyOne(PTABS t)
|
||||
{
|
||||
PTDB tp;
|
||||
PODBCCOL cp1, cp2;
|
||||
PGLOBAL g = t->G; // Is this really useful ???
|
||||
|
||||
tp = new(g) TDBODBC(this);
|
||||
|
||||
for (cp1 = (PODBCCOL)Columns; cp1; cp1 = (PODBCCOL)cp1->GetNext()) {
|
||||
cp2 = new(g) ODBCCOL(cp1, tp); // Make a copy
|
||||
NewPointer(t, cp1, cp2);
|
||||
} // endfor cp1
|
||||
|
||||
return tp;
|
||||
} // end of CopyOne
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate ODBC column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBODBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
return new(g) ODBCCOL(cdp, this, cprec, n);
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* Extract the filename from connect string and return it. */
|
||||
/* This used for Multiple(1) tables. Also prepare a connect string */
|
||||
/* with a place holder to be used by SetFile. */
|
||||
/***********************************************************************/
|
||||
PSZ TDBODBC::GetFile(PGLOBAL g)
|
||||
{
|
||||
if (Connect) {
|
||||
char *p1, *p2;
|
||||
size_t n;
|
||||
|
||||
if ((p1 = strstr(Connect, "DBQ="))) {
|
||||
p1 += 4; // Beginning of file name
|
||||
p2 = strchr(p1, ';'); // End of file path/name
|
||||
|
||||
// Make the File path/name from the connect string
|
||||
n = (p2) ? p2 - p1 : strlen(p1);
|
||||
DBQ = (PSZ)PlugSubAlloc(g, NULL, n + 1);
|
||||
memcpy(DBQ, p1, n);
|
||||
DBQ[n] = '\0';
|
||||
|
||||
// Make the Format used to re-generate Connect (3 = "%s" + 1)
|
||||
MulConn = (char*)PlugSubAlloc(g, NULL, strlen(Connect) - n + 3);
|
||||
memcpy(MulConn, Connect, p1 - Connect);
|
||||
MulConn[p1 - Connect] = '\0';
|
||||
strcat(strcat(MulConn, "%s"), (p2) ? p2 : ";");
|
||||
} // endif p1
|
||||
|
||||
} // endif Connect
|
||||
|
||||
return (DBQ) ? DBQ : (PSZ)"???";
|
||||
} // end of GetFile
|
||||
|
||||
/***********************************************************************/
|
||||
/* Set DBQ and get the new file name into the connect string. */
|
||||
/***********************************************************************/
|
||||
void TDBODBC::SetFile(PGLOBAL g, PSZ fn)
|
||||
{
|
||||
if (MulConn) {
|
||||
int n = strlen(MulConn) + strlen(fn) - 1;
|
||||
|
||||
if (n > BufSize) {
|
||||
// Allocate a buffer larger than needed so the chance
|
||||
// of having to reallocate it is reduced.
|
||||
BufSize = n + 6;
|
||||
Connect = (char*)PlugSubAlloc(g, NULL, BufSize);
|
||||
} // endif n
|
||||
|
||||
// Make the complete connect string
|
||||
sprintf(Connect, MulConn, fn);
|
||||
} // endif MultConn
|
||||
|
||||
DBQ = fn;
|
||||
} // end of SetFile
|
||||
|
||||
#if !defined(NO_ICONV)
|
||||
/******************************************************************/
|
||||
/* Convert an UTF-8 string to latin characters. */
|
||||
/******************************************************************/
|
||||
int TDBODBC::Decode(iconv_t cd, char *utf, char *buf, size_t n)
|
||||
{
|
||||
#if defined(WIN32) || defined(AIX)
|
||||
const char *inp = (const char *)utf;
|
||||
#else
|
||||
char *inp = (char *)utf;
|
||||
#endif
|
||||
char *outp = buf;
|
||||
size_t i = strlen(inp), o = n;
|
||||
int rc = iconv(cd, &inp, &i, &outp, &o);
|
||||
|
||||
buf[n - o] = '\0';
|
||||
return rc;
|
||||
} // end of Decode
|
||||
#endif // !NO_ICONV
|
||||
|
||||
/***********************************************************************/
|
||||
/* MakeSQL: make the SQL statement use with ODBC connection. */
|
||||
/* Note: when implementing EOM filtering, column only used in local */
|
||||
/* filter should be removed from column list. */
|
||||
/***********************************************************************/
|
||||
char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
|
||||
{
|
||||
char *colist, *tabname, *sql, buf[64];
|
||||
LPCSTR ownp = NULL, qualp = NULL;
|
||||
int rc, len, ncol = 0;
|
||||
bool first = true;
|
||||
PTABLE tablep = To_Table;
|
||||
PCOL colp;
|
||||
#if !defined(NO_ICONV)
|
||||
iconv_t cd = iconv_open("ISO-8859-1", "UTF-8");
|
||||
#else
|
||||
void *cd = NULL;
|
||||
#endif // !NO_ICONV
|
||||
|
||||
if (!cnt) {
|
||||
// Normal SQL statement to retrieve results
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (!colp->IsSpecial())
|
||||
ncol++;
|
||||
|
||||
if (ncol) {
|
||||
colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol);
|
||||
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (!colp->IsSpecial()) {
|
||||
// Column name can be in UTF-8 encoding
|
||||
rc = Decode(cd, colp->GetName(), buf, sizeof(buf));
|
||||
|
||||
if (Quote) {
|
||||
if (first) {
|
||||
strcat(strcat(strcpy(colist, Quote), buf), Quote);
|
||||
first = false;
|
||||
} else
|
||||
strcat(strcat(strcat(strcat(colist, ", "),
|
||||
Quote), buf), Quote);
|
||||
|
||||
} else {
|
||||
if (first) {
|
||||
strcpy(colist, buf);
|
||||
first = false;
|
||||
} else
|
||||
strcat(strcat(colist, ", "), buf);
|
||||
|
||||
} // endif Quote
|
||||
|
||||
} // endif !Special
|
||||
|
||||
} else {
|
||||
// ncol == 0 can occur for queries such that sql count(*) from...
|
||||
// for which we will count the rows from sql * from...
|
||||
colist = (char*)PlugSubAlloc(g, NULL, 2);
|
||||
strcpy(colist, "*");
|
||||
} // endif ncol
|
||||
|
||||
} else {
|
||||
// SQL statement used to retrieve the size of the result
|
||||
colist = (char*)PlugSubAlloc(g, NULL, 9);
|
||||
strcpy(colist, "count(*)");
|
||||
} // endif cnt
|
||||
|
||||
// Table name can be encoded in UTF-8
|
||||
rc = Decode(cd, TableName, buf, sizeof(buf));
|
||||
|
||||
// Put table name between identifier quotes in case in contains blanks
|
||||
tabname = (char*)PlugSubAlloc(g, NULL, strlen(buf) + 3);
|
||||
|
||||
if (Quote)
|
||||
strcat(strcat(strcpy(tabname, Quote), buf), Quote);
|
||||
else
|
||||
strcpy(tabname, buf);
|
||||
|
||||
// Below 14 is length of 'select ' + length of ' from ' + 1
|
||||
len = (strlen(colist) + strlen(buf) + 14);
|
||||
len += (To_Filter ? strlen(To_Filter) + 7 : 0);
|
||||
|
||||
// if (tablep->GetQualifier()) This is used when using a table
|
||||
// qualp = tablep->GetQualifier(); from anotherPlugDB database but
|
||||
// else makes no sense for ODBC.
|
||||
if (Qualifier && *Qualifier)
|
||||
qualp = Qualifier;
|
||||
|
||||
if (qualp)
|
||||
len += (strlen(qualp) + 2);
|
||||
|
||||
if (tablep->GetCreator())
|
||||
ownp = tablep->GetCreator();
|
||||
else if (Owner && *Owner)
|
||||
ownp = Owner;
|
||||
|
||||
if (ownp)
|
||||
len += (strlen(ownp) + 1);
|
||||
|
||||
sql = (char*)PlugSubAlloc(g, NULL, len);
|
||||
strcat(strcat(strcpy(sql, "SELECT "), colist), " FROM ");
|
||||
|
||||
if (qualp) {
|
||||
strcat(sql, qualp);
|
||||
|
||||
if (ownp)
|
||||
strcat(strcat(sql, "."), ownp);
|
||||
else
|
||||
strcat(sql, ".");
|
||||
|
||||
strcat(sql, ".");
|
||||
} else if (ownp)
|
||||
strcat(strcat(sql, ownp), ".");
|
||||
|
||||
strcat(sql, tabname);
|
||||
#if !defined(NO_ICONV)
|
||||
iconv_close(cd);
|
||||
#endif // !NO_ICONV
|
||||
|
||||
if (To_Filter)
|
||||
strcat(strcat(sql, " WHERE "), To_Filter);
|
||||
|
||||
return sql;
|
||||
} // end of MakeSQL
|
||||
|
||||
/***********************************************************************/
|
||||
/* ResetSize: call by TDBMUL when calculating size estimate. */
|
||||
/***********************************************************************/
|
||||
void TDBODBC::ResetSize(void)
|
||||
{
|
||||
MaxSize = -1;
|
||||
|
||||
if (Ocp && Ocp->IsOpen())
|
||||
Ocp->Close();
|
||||
|
||||
} // end of ResetSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC GetMaxSize: returns table size estimate in number of lines. */
|
||||
/***********************************************************************/
|
||||
int TDBODBC::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (MaxSize < 0) {
|
||||
if (!Ocp)
|
||||
Ocp = new(g) ODBConn(g, this);
|
||||
|
||||
if (!Ocp->IsOpen())
|
||||
if (Ocp->Open(Connect, Options) < 1)
|
||||
return -1;
|
||||
|
||||
if (!Count && !(Count = MakeSQL(g, true)))
|
||||
return -2;
|
||||
|
||||
if (!Cnp) {
|
||||
// Allocate a Count(*) column (must not use the default constructor)
|
||||
Cnp = new(g) ODBCCOL;
|
||||
Cnp->InitValue(g);
|
||||
} // endif Cnp
|
||||
|
||||
if ((MaxSize = Ocp->GetResultSize(Count, Cnp)) < 0)
|
||||
return -3;
|
||||
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* Return 0 in mode DELETE or UPDATE to tell that it is done. */
|
||||
/***********************************************************************/
|
||||
int TDBODBC::GetProgMax(PGLOBAL g)
|
||||
{
|
||||
return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0
|
||||
: GetMaxSize(g);
|
||||
} // end of GetProgMax
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC Access Method opening routine. */
|
||||
/* New method now that this routine is called recursively (last table */
|
||||
/* first in reverse order): index blocks are immediately linked to */
|
||||
/* join block of next table if it exists or else are discarted. */
|
||||
/***********************************************************************/
|
||||
bool TDBODBC::OpenDB(PGLOBAL g)
|
||||
{
|
||||
bool rc = false;
|
||||
|
||||
if (g->Trace)
|
||||
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
|
||||
this, Tdb_No, Use, Mode);
|
||||
|
||||
if (Use == USE_OPEN) {
|
||||
/*******************************************************************/
|
||||
/* Table already open, just replace it at its beginning. */
|
||||
/*******************************************************************/
|
||||
// if (To_Kindex)
|
||||
/*****************************************************************/
|
||||
/* Table is to be accessed through a sorted index table. */
|
||||
/*****************************************************************/
|
||||
// To_Kindex->Reset();
|
||||
|
||||
// rewind(Stream); >>>>>>> Something to be done with Cursor <<<<<<<
|
||||
return false;
|
||||
} // endif use
|
||||
|
||||
/*********************************************************************/
|
||||
/* Open an ODBC connection for this table. */
|
||||
/* Note: this may not be the proper way to do. Perhaps it is better */
|
||||
/* to test whether a connection is already open for this datasource */
|
||||
/* and if so to allocate just a new result set. But this only for */
|
||||
/* drivers allowing concurency in getting results ??? */
|
||||
/*********************************************************************/
|
||||
if (!Ocp)
|
||||
Ocp = new(g) ODBConn(g, this);
|
||||
else if (Ocp->IsOpen())
|
||||
Ocp->Close();
|
||||
|
||||
if (Ocp->Open(Connect, Options) < 1)
|
||||
return true;
|
||||
|
||||
Use = USE_OPEN; // Do it now in case we are recursively called
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate whatever is used for getting results. */
|
||||
/*********************************************************************/
|
||||
if (Mode == MODE_READ) {
|
||||
/*******************************************************************/
|
||||
/* The issue here is that if max result size is needed, it must be */
|
||||
/* calculated before the result set for the final data retrieval is*/
|
||||
/* allocated and the final statement prepared so we call GetMaxSize*/
|
||||
/* here. It can be a waste of time if the max size is not needed */
|
||||
/* but currently we always are asking for it (for progress info). */
|
||||
/*******************************************************************/
|
||||
GetMaxSize(g); // Will be set for next call
|
||||
|
||||
if (!Query)
|
||||
if ((Query = MakeSQL(g, false))) {
|
||||
for (PODBCCOL colp = (PODBCCOL)Columns;
|
||||
colp; colp = (PODBCCOL)colp->GetNext())
|
||||
if (!colp->IsSpecial())
|
||||
colp->AllocateBuffers(g, Rows);
|
||||
|
||||
} else
|
||||
rc = true;
|
||||
|
||||
if (!rc)
|
||||
rc = ((Rows = Ocp->ExecDirectSQL(Query, (PODBCCOL)Columns)) < 0);
|
||||
|
||||
} else {
|
||||
strcpy(g->Message, "ODBC tables are read only in this version");
|
||||
return true;
|
||||
} // endelse
|
||||
|
||||
if (rc) {
|
||||
Ocp->Close();
|
||||
return true;
|
||||
} // endif rc
|
||||
|
||||
/*********************************************************************/
|
||||
/* Reset statistics values. */
|
||||
/*********************************************************************/
|
||||
num_read = num_there = num_eq[0] = num_eq[1] = 0;
|
||||
return false;
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetRecpos: return the position of last read record. */
|
||||
/***********************************************************************/
|
||||
int TDBODBC::GetRecpos(void)
|
||||
{
|
||||
return Fpos; // To be really implemented
|
||||
} // end of GetRecpos
|
||||
|
||||
/***********************************************************************/
|
||||
/* VRDNDOS: Data Base read routine for odbc access method. */
|
||||
/***********************************************************************/
|
||||
int TDBODBC::ReadDB(PGLOBAL g)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("ODBC ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
|
||||
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
|
||||
#endif
|
||||
|
||||
if (To_Kindex) {
|
||||
// Direct access of ODBC tables is not implemented yet
|
||||
strcpy(g->Message, MSG(NO_ODBC_DIRECT));
|
||||
longjmp(g->jumper[g->jump_level], GetAmType());
|
||||
|
||||
#if 0
|
||||
/*******************************************************************/
|
||||
/* Reading is by an index table. */
|
||||
/*******************************************************************/
|
||||
int recpos = To_Kindex->Fetch(g);
|
||||
|
||||
switch (recpos) {
|
||||
case -1: // End of file reached
|
||||
return RC_EF;
|
||||
case -2: // No match for join
|
||||
return RC_NF;
|
||||
case -3: // Same record as current one
|
||||
num_there++;
|
||||
return RC_OK;
|
||||
default:
|
||||
/***************************************************************/
|
||||
/* Set the cursor position according to record to read. */
|
||||
/***************************************************************/
|
||||
//--------------------------------- TODO --------------------------------
|
||||
break;
|
||||
} // endswitch recpos
|
||||
#endif // 0
|
||||
|
||||
} // endif To_Kindex
|
||||
|
||||
/*********************************************************************/
|
||||
/* Now start the reading process. */
|
||||
/* Here is the place to fetch the line(s). */
|
||||
/*********************************************************************/
|
||||
if (++CurNum >= Rbuf) {
|
||||
Rbuf = Ocp->Fetch();
|
||||
CurNum = 0;
|
||||
} // endif CurNum
|
||||
|
||||
rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
|
||||
Fpos++; // Used for progress info
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
|
||||
#endif
|
||||
return rc;
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base Insert write routine for ODBC access method. */
|
||||
/***********************************************************************/
|
||||
int TDBODBC::WriteDB(PGLOBAL g)
|
||||
{
|
||||
strcpy(g->Message, "ODBC tables are read only");
|
||||
return RC_FX;
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for ODBC access method. */
|
||||
/***********************************************************************/
|
||||
int TDBODBC::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
strcpy(g->Message, MSG(NO_ODBC_DELETE));
|
||||
return RC_FX;
|
||||
} // end of DeleteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for ODBC access method. */
|
||||
/***********************************************************************/
|
||||
void TDBODBC::CloseDB(PGLOBAL g)
|
||||
{
|
||||
//if (To_Kindex) {
|
||||
// To_Kindex->Close();
|
||||
// To_Kindex = NULL;
|
||||
// } // endif
|
||||
|
||||
Ocp->Close();
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc("ODBC CloseDB: closing %s\n", Name);
|
||||
#endif
|
||||
} // end of CloseDB
|
||||
|
||||
/* --------------------------- ODBCCOL ------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBCCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
ODBCCOL::ODBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
|
||||
: COLBLK(cdp, tdbp, i)
|
||||
{
|
||||
if (cprec) {
|
||||
Next = cprec->GetNext();
|
||||
cprec->SetNext(this);
|
||||
} else {
|
||||
Next = tdbp->GetColumns();
|
||||
tdbp->SetColumns(this);
|
||||
} // endif cprec
|
||||
|
||||
// Set additional ODBC access method information for column.
|
||||
Long = cdp->GetLong();
|
||||
//strcpy(F_Date, cdp->F_Date);
|
||||
To_Val = NULL;
|
||||
Slen = 0;
|
||||
StrLen = &Slen;
|
||||
Sqlbuf = NULL;
|
||||
Bufp = NULL;
|
||||
Blkp = NULL;
|
||||
Rank = 0; // Not known yet
|
||||
|
||||
#ifdef DEBTRACE
|
||||
htrc(" making new %sCOL C%d %s at %p\n",
|
||||
am, Index, Name, this);
|
||||
#endif
|
||||
} // end of ODBCCOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBCCOL private constructor. */
|
||||
/***********************************************************************/
|
||||
ODBCCOL::ODBCCOL(void) : COLBLK()
|
||||
{
|
||||
Buf_Type = TYPE_INT; // This is a count(*) column
|
||||
// Set additional Dos access method information for column.
|
||||
Long = sizeof(int);
|
||||
To_Val = NULL;
|
||||
Slen = 0;
|
||||
StrLen = &Slen;
|
||||
Sqlbuf = NULL;
|
||||
Bufp = NULL;
|
||||
Blkp = NULL;
|
||||
Rank = 1;
|
||||
} // end of ODBCCOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBCCOL constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
ODBCCOL::ODBCCOL(ODBCCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
|
||||
{
|
||||
Long = col1->Long;
|
||||
//strcpy(F_Date, col1->F_Date);
|
||||
To_Val = col1->To_Val;
|
||||
Slen = col1->Slen;
|
||||
StrLen = col1->StrLen;
|
||||
Sqlbuf = col1->Sqlbuf;
|
||||
Bufp = col1->Bufp;
|
||||
Blkp = col1->Blkp;
|
||||
Rank = col1->Rank;
|
||||
} // end of ODBCCOL copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetBuffer: prepare a column block for write operation. */
|
||||
/***********************************************************************/
|
||||
bool ODBCCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
|
||||
{
|
||||
if (!(To_Val = value)) {
|
||||
sprintf(g->Message, MSG(VALUE_ERROR), Name);
|
||||
return true;
|
||||
} else if (Buf_Type == value->GetType()) {
|
||||
// Values are of the (good) column type
|
||||
if (Buf_Type == TYPE_DATE) {
|
||||
// If any of the date values is formatted
|
||||
// output format must be set for the receiving table
|
||||
if (GetDomain() || ((DTVAL *)value)->IsFormatted())
|
||||
goto newval; // This will make a new value;
|
||||
|
||||
} else if (Buf_Type == TYPE_FLOAT)
|
||||
// Float values must be written with the correct (column) precision
|
||||
// Note: maybe this should be forced by ShowValue instead of this ?
|
||||
((DFVAL *)value)->SetPrec(GetPrecision());
|
||||
|
||||
Value = value; // Directly access the external value
|
||||
} else {
|
||||
// Values are not of the (good) column type
|
||||
if (check) {
|
||||
sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
|
||||
GetTypeName(Buf_Type), GetTypeName(value->GetType()));
|
||||
return true;
|
||||
} // endif check
|
||||
|
||||
newval:
|
||||
if (InitValue(g)) // Allocate the matching value block
|
||||
return true;
|
||||
|
||||
} // endif's Value, Buf_Type
|
||||
|
||||
// Because Colblk's have been made from a copy of the original TDB in
|
||||
// case of Update, we must reset them to point to the original one.
|
||||
if (To_Tdb->GetOrig())
|
||||
To_Tdb = (PTDB)To_Tdb->GetOrig();
|
||||
|
||||
// Set the Column
|
||||
Status = (ok) ? BUF_EMPTY : BUF_NO;
|
||||
return false;
|
||||
} // end of SetBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: when SQLFetch is used there is nothing to do as the */
|
||||
/* column buffer was bind to the record set. This is also the case */
|
||||
/* when calculating MaxSize (Bufp is NULL even when Rows is not). */
|
||||
/***********************************************************************/
|
||||
void ODBCCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
PTDBODBC tdbp = (PTDBODBC)To_Tdb;
|
||||
int n = tdbp->CurNum;
|
||||
|
||||
if (StrLen[n] == SQL_NULL_DATA) {
|
||||
// Null value
|
||||
Value->Reset();
|
||||
return;
|
||||
} // endif StrLen
|
||||
|
||||
if (Bufp && tdbp->Rows)
|
||||
if (Buf_Type == TYPE_DATE)
|
||||
*Sqlbuf = ((TIMESTAMP_STRUCT*)Bufp)[n];
|
||||
else
|
||||
Value->SetValue_pvblk(Blkp, n);
|
||||
|
||||
if (Buf_Type == TYPE_DATE) {
|
||||
struct tm dbtime = {0,0,0,0,0,0,0,0,0};
|
||||
|
||||
dbtime.tm_sec = (int)Sqlbuf->second;
|
||||
dbtime.tm_min = (int)Sqlbuf->minute;
|
||||
dbtime.tm_hour = (int)Sqlbuf->hour;
|
||||
dbtime.tm_mday = (int)Sqlbuf->day;
|
||||
dbtime.tm_mon = (int)Sqlbuf->month - 1;
|
||||
dbtime.tm_year = (int)Sqlbuf->year - 1900;
|
||||
((DTVAL*)Value)->MakeTime(&dbtime);
|
||||
} // endif Buf_Type
|
||||
|
||||
if (g->Trace) {
|
||||
char buf[32];
|
||||
|
||||
htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n",
|
||||
Name, tdbp->Rows, Bufp, Buf_Type, Value->GetCharString(buf));
|
||||
} // endif Trace
|
||||
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* AllocateBuffers: allocate the extended buffer for SQLExtendedFetch */
|
||||
/* or Fetch. Note: we use Long+1 here because ODBC must have space */
|
||||
/* for the ending null character. */
|
||||
/***********************************************************************/
|
||||
void ODBCCOL::AllocateBuffers(PGLOBAL g, int rows)
|
||||
{
|
||||
if (Buf_Type == TYPE_DATE)
|
||||
Sqlbuf = (TIMESTAMP_STRUCT*)PlugSubAlloc(g, NULL,
|
||||
sizeof(TIMESTAMP_STRUCT));
|
||||
|
||||
if (!rows)
|
||||
return;
|
||||
|
||||
if (Buf_Type == TYPE_DATE)
|
||||
Bufp = PlugSubAlloc(g, NULL, rows * sizeof(TIMESTAMP_STRUCT));
|
||||
else {
|
||||
Blkp = AllocValBlock(g, NULL, Buf_Type, rows, Long+1, 0, true, false);
|
||||
Bufp = Blkp->GetValPointer();
|
||||
} // endelse
|
||||
|
||||
if (rows > 1)
|
||||
StrLen = (SQLLEN *)PlugSubAlloc(g, NULL, rows * sizeof(int));
|
||||
|
||||
} // end of AllocateBuffers
|
||||
|
||||
/***********************************************************************/
|
||||
/* Returns the buffer to use for Fetch or Extended Fetch. */
|
||||
/***********************************************************************/
|
||||
void *ODBCCOL::GetBuffer(DWORD rows)
|
||||
{
|
||||
if (rows && To_Tdb) {
|
||||
assert(rows == (DWORD)((TDBODBC*)To_Tdb)->Rows);
|
||||
return Bufp;
|
||||
} else
|
||||
return (Buf_Type == TYPE_DATE) ? Sqlbuf : Value->GetTo_Val();
|
||||
|
||||
} // end of GetBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* Returns the buffer length to use for Fetch or Extended Fetch. */
|
||||
/***********************************************************************/
|
||||
SWORD ODBCCOL::GetBuflen(void)
|
||||
{
|
||||
if (Buf_Type == TYPE_DATE)
|
||||
return (SWORD)sizeof(TIMESTAMP_STRUCT);
|
||||
else if (Buf_Type == TYPE_STRING)
|
||||
return (SWORD)Value->GetClen() + 1;
|
||||
else
|
||||
return (SWORD)Value->GetClen();
|
||||
|
||||
} // end of GetBuflen
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteColumn: make sure the bind buffer is updated. */
|
||||
/***********************************************************************/
|
||||
void ODBCCOL::WriteColumn(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* Do convert the column value if necessary. */
|
||||
/*********************************************************************/
|
||||
if (Value != To_Val)
|
||||
Value->SetValue_pval(To_Val, false); // Convert the inserted value
|
||||
|
||||
if (Buf_Type == TYPE_DATE) {
|
||||
struct tm *dbtime = ((DTVAL*)Value)->GetGmTime();
|
||||
|
||||
Sqlbuf->second = dbtime->tm_sec;
|
||||
Sqlbuf->minute = dbtime->tm_min;
|
||||
Sqlbuf->hour = dbtime->tm_hour;
|
||||
Sqlbuf->day = dbtime->tm_mday;
|
||||
Sqlbuf->month = dbtime->tm_mon + 1;
|
||||
Sqlbuf->year = dbtime->tm_year + 1900;
|
||||
} // endif Buf_Type
|
||||
|
||||
} // end of WriteColumn
|
||||
|
||||
/* ------------------------ End of Tabodbc --------------------------- */
|
||||
170
storage/connect/tabodbc.h
Normal file
170
storage/connect/tabodbc.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/*************** Tabodbc H Declares Source Code File (.H) **************/
|
||||
/* Name: TABODBC.H Version 1.4 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2000-2012 */
|
||||
/* */
|
||||
/* This file contains the TDBODBC classes declares. */
|
||||
/***********************************************************************/
|
||||
#if !defined(NO_ICONV)
|
||||
#include <iconv.h>
|
||||
#endif // !NO_ICONV
|
||||
#include "colblk.h"
|
||||
|
||||
typedef class ODBCDEF *PODEF;
|
||||
typedef class TDBODBC *PTDBODBC;
|
||||
typedef class ODBCCOL *PODBCCOL;
|
||||
|
||||
/***********************************************************************/
|
||||
/* ODBC table. */
|
||||
/***********************************************************************/
|
||||
class DllExport ODBCDEF : public TABDEF { /* Logical table description */
|
||||
public:
|
||||
// Constructor
|
||||
ODBCDEF(void)
|
||||
{Connect = Tabname = Tabowner = Tabqual = Qchar = NULL; Options = 0;}
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "ODBC";}
|
||||
PSZ GetConnect(void) {return Connect;}
|
||||
PSZ GetTabname(void) {return Tabname;}
|
||||
PSZ GetTabowner(void) {return Tabowner;}
|
||||
PSZ GetTabqual(void) {return Tabqual;}
|
||||
PSZ GetQchar(void) {return (Qchar && *Qchar) ? Qchar : NULL;}
|
||||
int GetCatver(void) {return Catver;}
|
||||
int GetOptions(void) {return Options;}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PSZ Connect; /* ODBC connection string */
|
||||
PSZ Tabname; /* External table name */
|
||||
PSZ Tabowner; /* External table owner */
|
||||
PSZ Tabqual; /* External table qualifier */
|
||||
PSZ Qchar; /* Identifier quoting character */
|
||||
int Catver; /* ODBC version for catalog functions */
|
||||
int Options; /* Open connection options */
|
||||
}; // end of ODBCDEF
|
||||
|
||||
#if !defined(NODBC)
|
||||
#include "odbconn.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the ODBC Access Method class declaration for files from */
|
||||
/* other DB drivers to be accessed via ODBC. */
|
||||
/***********************************************************************/
|
||||
class TDBODBC : public TDBASE {
|
||||
friend class ODBCCOL;
|
||||
friend class ODBConn;
|
||||
public:
|
||||
// Constructor
|
||||
TDBODBC(PODEF tdp = NULL);
|
||||
TDBODBC(PTDBODBC tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBODBC(this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void);
|
||||
virtual PSZ GetFile(PGLOBAL g);
|
||||
virtual void SetFile(PGLOBAL g, PSZ fn);
|
||||
virtual void ResetSize(void);
|
||||
virtual int GetAffectedRows(void) {return AftRows;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetProgMax(PGLOBAL g);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Internal functions
|
||||
#if !defined(NO_ICONV)
|
||||
int Decode(iconv_t cd, char *utf, char *buf, size_t n);
|
||||
#else // NO_ICONV
|
||||
inline int Decode(void *cd, char *str, char *buf, size_t n)
|
||||
{strncpy(buf, str, n); return 0;}
|
||||
#endif // NO_ICONV
|
||||
char *MakeSQL(PGLOBAL g, bool cnt);
|
||||
//bool MakeUpdate(PGLOBAL g, PSELECT selist);
|
||||
//bool MakeInsert(PGLOBAL g);
|
||||
//bool MakeDelete(PGLOBAL g);
|
||||
//bool MakeFilter(PGLOBAL g, bool c);
|
||||
//bool BindParameters(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
ODBConn *Ocp; // Points to an ODBC connection class
|
||||
ODBCCOL *Cnp; // Points to count(*) column
|
||||
char *Connect; // Points to connection string
|
||||
char *TableName; // Points to EOM table name
|
||||
char *Owner; // Points to EOM table Owner
|
||||
char *Qualifier; // Points to EOM table Qualifier
|
||||
char *Query; // Points to SQL statement
|
||||
char *Count; // Points to count(*) SQL statement
|
||||
//char *Where; // Points to local where clause
|
||||
char *Quote; // The identifier quoting character
|
||||
char *MulConn; // Used for multiple ODBC tables
|
||||
char *DBQ; // The address part of Connect string
|
||||
int Options; // Connect options
|
||||
int Fpos; // Position of last read record
|
||||
int AftRows; // The number of affected rows
|
||||
int Rows; // Rowset size
|
||||
int Catver; // Catalog ODBC version
|
||||
int CurNum; // Current buffer line number
|
||||
int Rbuf; // Number of lines read in buffer
|
||||
int BufSize; // Size of connect string buffer
|
||||
int Nparm; // The number of statement parameters
|
||||
}; // end of class TDBODBC
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class ODBCCOL: DOS access method column descriptor. */
|
||||
/* This A.M. is used for ODBC tables. */
|
||||
/***********************************************************************/
|
||||
class ODBCCOL : public COLBLK {
|
||||
friend class TDBODBC;
|
||||
public:
|
||||
// Constructors
|
||||
ODBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "ODBC");
|
||||
ODBCCOL(ODBCCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_ODBC;}
|
||||
SQLLEN *GetStrLen(void) {return StrLen;}
|
||||
int GetRank(void) {return Rank;}
|
||||
// PVBLK GetBlkp(void) {return Blkp;}
|
||||
|
||||
// Methods
|
||||
//virtual bool CheckLocal(PTDB tdbp);
|
||||
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
void AllocateBuffers(PGLOBAL g, int rows);
|
||||
void *GetBuffer(DWORD rows);
|
||||
SWORD GetBuflen(void);
|
||||
// void Print(PGLOBAL g, FILE *, uint);
|
||||
|
||||
protected:
|
||||
// Constructor used by GetMaxSize
|
||||
ODBCCOL(void);
|
||||
|
||||
// Members
|
||||
TIMESTAMP_STRUCT *Sqlbuf; // To get SQL_TIMESTAMP's
|
||||
void *Bufp; // To extended buffer
|
||||
PVBLK Blkp; // To Value Block
|
||||
//char F_Date[12]; // Internal Date format
|
||||
PVAL To_Val; // To value used for Insert
|
||||
SQLLEN *StrLen; // As returned by ODBC
|
||||
SQLLEN Slen; // Used with Fetch
|
||||
int Rank; // Rank (position) number in the query
|
||||
}; // end of class ODBCCOL
|
||||
#endif // !NODBC
|
||||
|
||||
1202
storage/connect/tabpivot.cpp
Normal file
1202
storage/connect/tabpivot.cpp
Normal file
File diff suppressed because it is too large
Load Diff
241
storage/connect/tabpivot.h
Normal file
241
storage/connect/tabpivot.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/************** TabPivot H Declares Source Code File (.H) **************/
|
||||
/* Name: TABPIVOT.H Version 1.3 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the PIVOT classes declares. */
|
||||
/***********************************************************************/
|
||||
typedef class TDBPIVOT *PTDBPIVOT;
|
||||
typedef class FNCCOL *PFNCCOL;
|
||||
typedef class SRCCOL *PSRCCOL;
|
||||
typedef class TDBQRS *PTDBQRS;
|
||||
typedef class QRSCOL *PQRSCOL;
|
||||
|
||||
/* -------------------------- PIVOT classes -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* PIVOT: table that provides a view of a source table where the */
|
||||
/* pivot column is expended in as many columns as there are distinct */
|
||||
/* values in it and containing the function value matching other cols.*/
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* PIVOT table. */
|
||||
/***********************************************************************/
|
||||
//ass DllExport PIVOTDEF : public TABDEF {/* Logical table description */
|
||||
class PIVOTDEF : public TABDEF { /* Logical table description */
|
||||
friend class TDBPIVOT;
|
||||
public:
|
||||
// Constructor
|
||||
PIVOTDEF(void) {Pseudo = 3;
|
||||
Tabname = Tabsrc = Picol = Fncol = Function = NULL;}
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "PIVOT";}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *Host; /* Host machine to use */
|
||||
char *User; /* User logon info */
|
||||
char *Pwd; /* Password logon info */
|
||||
char *DB; /* Database to be used by server */
|
||||
char *Tabname; /* Name of source table */
|
||||
char *Tabsrc; /* The source table SQL description */
|
||||
char *Picol; /* The pivot column */
|
||||
char *Fncol; /* The function column */
|
||||
char *Function; /* The function applying to group by */
|
||||
bool GBdone; /* True if tabname as group by format */
|
||||
int Port; /* MySQL port number */
|
||||
}; // end of PIVOTDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the PIVOT table. */
|
||||
/***********************************************************************/
|
||||
//ass DllExport TDBPIVOT : public TDBASE, public CSORT {
|
||||
class TDBPIVOT : public TDBASE, public CSORT {
|
||||
friend class FNCCOL;
|
||||
friend class SRCCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBPIVOT(PPIVOTDEF tdp);
|
||||
//TDBPIVOT(PTDBPIVOT tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_PIVOT;}
|
||||
//virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBPIVOT(this);}
|
||||
// void SetTdbp(PTDB tdbp) {Tdbp = tdbp;}
|
||||
|
||||
// Methods
|
||||
//virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void) {return N;}
|
||||
virtual void ResetDB(void) {N = 0;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = FALSE);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
// The sorting function
|
||||
virtual int Qcompare(int *, int *);
|
||||
|
||||
protected:
|
||||
PQRYRES GetSourceTable(PGLOBAL g);
|
||||
int MakePivotColumns(PGLOBAL g);
|
||||
bool UpdateTableFields(PGLOBAL g, int n);
|
||||
|
||||
// Members
|
||||
MYSQLC Myc; // MySQL connection class
|
||||
PTDBQRS Tqrp; // To the source table result
|
||||
char *Host; // Host machine to use
|
||||
char *User; // User logon info
|
||||
char *Pwd; // Password logon info
|
||||
char *Database; // Database to be used by server
|
||||
PQRYRES Qryp; // Points to Query result block
|
||||
char *Tabname; // Name of source table
|
||||
char *Tabsrc; // SQL of source table
|
||||
char *Picol; // Pivot column name
|
||||
char *Fncol; // Function column name
|
||||
char *Function; // The function applying to group by
|
||||
PQRSCOL Fcolp; // To the function column in source
|
||||
PQRSCOL Xcolp; // To the pivot column in source
|
||||
PCOLRES Xresp; // To the pivot result column
|
||||
//PCOLRES To_Sort; // Saved Qryp To_Sort pointer
|
||||
PVBLK Rblkp; // The value block of the pivot column
|
||||
bool GBdone; // True when subtable is "Group by"
|
||||
int Mult; // Multiplication factor
|
||||
int Ncol; // The number of generated columns
|
||||
int N; // The current table index
|
||||
int M; // The occurence rank
|
||||
int Port; // MySQL port number
|
||||
BYTE FileStatus; // 0: First 1: Rows 2: End-of-File
|
||||
BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip
|
||||
}; // end of class TDBPIVOT
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class FNCCOL: for the multiple generated column. */
|
||||
/***********************************************************************/
|
||||
class FNCCOL : public COLBLK {
|
||||
friend class TDBPIVOT;
|
||||
public:
|
||||
// Constructor
|
||||
FNCCOL(PCOL colp, PTDBPIVOT tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_FNC;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void) {}
|
||||
bool InitColumn(PGLOBAL g, PVAL valp);
|
||||
|
||||
protected:
|
||||
// Member
|
||||
PVAL Hval; // The original value used to generate the header
|
||||
}; // end of class FNCCOL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class SRCCOL: for other source columns. */
|
||||
/***********************************************************************/
|
||||
class SRCCOL : public COLBLK {
|
||||
friend class TDBPIVOT;
|
||||
public:
|
||||
// Constructors
|
||||
//SRCCOL(PCOLDEF cdp, PTDBPIVOT tdbp, int n);
|
||||
SRCCOL(PCOL cp, PTDBPIVOT tdbp, int n);
|
||||
//SRCCOL(SRCCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_SRC;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void) {}
|
||||
void SetColumn(void);
|
||||
bool Init(PGLOBAL g, PTDBPIVOT tdbp);
|
||||
bool CompareColumn(void);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
SRCCOL(void) {}
|
||||
|
||||
// Members
|
||||
PQRSCOL Colp;
|
||||
PVAL Cnval;
|
||||
}; // end of class SRCCOL
|
||||
|
||||
/***********************************************************************/
|
||||
/* TDBQRS: This is the Access Method class declaration for the Query */
|
||||
/* Result stored in memory in the current work area (volatil). */
|
||||
/***********************************************************************/
|
||||
class DllExport TDBQRS : public TDBASE {
|
||||
friend class QRSCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBQRS(PQRYRES qrp) : TDBASE() {Qrp = qrp; CurPos = 0;}
|
||||
TDBQRS(PTDBQRS tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_QRS;}
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBQRS(this);}
|
||||
PQRYRES GetQrp(void) {return Qrp;}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual int RowNumber(PGLOBAL g, BOOL b = FALSE);
|
||||
virtual int GetRecpos(void);
|
||||
//virtual PCATLG GetCat(void);
|
||||
//virtual PSZ GetPath(void);
|
||||
virtual int GetBadLines(void) {return Qrp->BadLines;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL ColDB(PGLOBAL g, PSZ name, int num);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
private:
|
||||
TDBQRS(void) : TDBASE() {} // Standard constructor not to be used
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PQRYRES Qrp; // Points to Query Result block
|
||||
int CurPos; // Current line position
|
||||
}; // end of class TDBQRS
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class QRSCOL: QRS access method column descriptor. */
|
||||
/***********************************************************************/
|
||||
class DllExport QRSCOL : public COLBLK {
|
||||
friend class TDBQRS;
|
||||
public:
|
||||
// Constructors
|
||||
QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i);
|
||||
QRSCOL(QRSCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_QRS;}
|
||||
PCOLRES GetCrp(void) {return Crp;}
|
||||
void *GetQrsData(void) {return Crp->Kdata;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void Print(PGLOBAL g, FILE *, UINT);
|
||||
|
||||
protected:
|
||||
QRSCOL(void) {} // Default constructor not to be used
|
||||
|
||||
// Members
|
||||
PCOLRES Crp;
|
||||
}; // end of class QRSCOL
|
||||
|
||||
877
storage/connect/tabsys.cpp
Normal file
877
storage/connect/tabsys.cpp
Normal file
@@ -0,0 +1,877 @@
|
||||
/************* TabSys C++ Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: TABSYS */
|
||||
/* ------------- */
|
||||
/* Version 2.2 */
|
||||
/* */
|
||||
/* Author Olivier BERTRAND 2004-2013 */
|
||||
/* */
|
||||
/* This program are the INI/CFG tables classes. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant sections of the System header files. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif // __BORLANDC__
|
||||
//#include <windows.h>
|
||||
#else // !WIN32
|
||||
#if defined(UNIX)
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#else // !UNIX
|
||||
#include <io.h>
|
||||
#endif // !UNIX
|
||||
#include <fcntl.h>
|
||||
#endif // !WIN32
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing the DB application declarations. */
|
||||
/* tabdos.h is header containing the TABDOS class declarations. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "reldef.h"
|
||||
//#include "xobject.h"
|
||||
#include "filamtxt.h"
|
||||
#include "tabdos.h"
|
||||
#include "tabsys.h"
|
||||
#include "tabmul.h"
|
||||
#if defined(UNIX)
|
||||
#include "osutil.h"
|
||||
#endif // UNIX
|
||||
|
||||
#define CSZ 36 // Column section name length
|
||||
#define CDZ 256 // Column definition length
|
||||
|
||||
#if !defined(WIN32)
|
||||
#define GetPrivateProfileSectionNames(S,L,I) \
|
||||
GetPrivateProfileString(NULL,NULL,"",S,L,I)
|
||||
#endif // !WIN32
|
||||
|
||||
extern "C" int trace;
|
||||
|
||||
/* -------------- Implementation of the INI classes ------------------ */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Constructor. */
|
||||
/***********************************************************************/
|
||||
INIDEF::INIDEF(void)
|
||||
{
|
||||
Pseudo = 3;
|
||||
Fn = NULL;
|
||||
Xname = NULL;
|
||||
Subtype = '?';
|
||||
Layout = '?';
|
||||
Ln = 0;
|
||||
} // end of INIDEF constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* DefineAM: define specific AM block values from XDB file. */
|
||||
/***********************************************************************/
|
||||
bool INIDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
char buf[8], ds[2];
|
||||
void *memp = Cat->GetDescp();
|
||||
|
||||
if (!stricmp(am, "SYS"))
|
||||
strcpy(ds, "T"); // SYS tables default to T(able)
|
||||
else
|
||||
strcpy(ds, "I"); // INI tables default to I(ni)
|
||||
|
||||
Fn = Cat->GetStringCatInfo(g, Name, "Filename", "?");
|
||||
Cat->GetCharCatInfo(Name, "Subtype", ds, buf, sizeof(buf));
|
||||
Subtype = toupper(*buf);
|
||||
Cat->GetCharCatInfo(Name, "Layout", "C", buf, sizeof(buf));
|
||||
Layout = toupper(*buf);
|
||||
|
||||
switch (Subtype) {
|
||||
#if 0
|
||||
case 'C':
|
||||
case 'T':
|
||||
// Restricted table
|
||||
Xname = Cat->GetStringCatInfo(g, Name, "Name", "?");
|
||||
|
||||
if (!strcmp(Xname, "?"))
|
||||
Xname = NULL;
|
||||
|
||||
if (*Fn == '?')
|
||||
Fn = Cat->GetStringCatInfo(g, Name, "Database", "?");
|
||||
|
||||
if (*Fn != '?') {
|
||||
char *p = (char*)PlugSubAlloc(g, memp, _MAX_PATH);
|
||||
|
||||
if (!PlgSetXdbPath(g, Fn, NULL, p, _MAX_PATH, NULL, 0))
|
||||
Fn = p;
|
||||
|
||||
} else
|
||||
Fn = Cat->GetDescFile();
|
||||
|
||||
Ln = GetIniSize("Database", "Tabsize", "2K", Fn);
|
||||
break;
|
||||
#endif // 0
|
||||
case 'I':
|
||||
if (*Fn != '?') {
|
||||
char *p = (char*)PlugSubAlloc(g, memp, _MAX_PATH);
|
||||
|
||||
PlugSetPath(p, Fn, GetPath());
|
||||
Fn = p;
|
||||
} else {
|
||||
strcpy(g->Message, MSG(MISSING_FNAME));
|
||||
return true;
|
||||
} // endif Fn
|
||||
|
||||
Ln = Cat->GetSizeCatInfo((char*)Name, "Secsize", "8K");
|
||||
break;
|
||||
default:
|
||||
sprintf(g->Message, MSG(INV_SUBTYPE), buf);
|
||||
return true;
|
||||
} // endswitch Subtype
|
||||
|
||||
Desc = Fn;
|
||||
return false;
|
||||
} // end of DefineAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTable: makes a new TDB of the proper type. */
|
||||
/***********************************************************************/
|
||||
PTDB INIDEF::GetTable(PGLOBAL g, MODE m)
|
||||
{
|
||||
PTDBASE tdbp;
|
||||
|
||||
switch (Subtype) {
|
||||
case 'I':
|
||||
if (Layout == 'C')
|
||||
tdbp = new(g) TDBINI(this);
|
||||
else
|
||||
tdbp = new(g) TDBXIN(this);
|
||||
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
} // endswitch Subtype
|
||||
|
||||
if (Multiple)
|
||||
tdbp = new(g) TDBMUL(tdbp); // No block optimization yet
|
||||
|
||||
return tdbp;
|
||||
} // end of GetTable
|
||||
|
||||
/***********************************************************************/
|
||||
/* DeleteTableFile: Delete INI table files using platform API. */
|
||||
/* SysTable and SysColumn tables are readonly and not erasable. */
|
||||
/***********************************************************************/
|
||||
bool INIDEF::DeleteTableFile(PGLOBAL g)
|
||||
{
|
||||
char filename[_MAX_PATH];
|
||||
bool rc;
|
||||
|
||||
// Delete the INI table file if not protected
|
||||
if (Subtype == 'I' && !IsReadOnly()) {
|
||||
PlugSetPath(filename, Fn, GetPath());
|
||||
#if defined(WIN32)
|
||||
rc = !DeleteFile(filename);
|
||||
#else // UNIX
|
||||
rc = remove(filename);
|
||||
#endif // UNIX
|
||||
} else
|
||||
rc =true;
|
||||
|
||||
return rc; // Return true if error
|
||||
} // end of DeleteTableFile
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBINI class. */
|
||||
/***********************************************************************/
|
||||
TDBINI::TDBINI(PINIDEF tdp) : TDBASE(tdp)
|
||||
{
|
||||
Ifile = tdp->Fn;
|
||||
Seclist = NULL;
|
||||
Section = NULL;
|
||||
Seclen = tdp->Ln;
|
||||
N = 0;
|
||||
} // end of TDBINI constructor
|
||||
|
||||
TDBINI::TDBINI(PTDBINI tdbp) : TDBASE(tdbp)
|
||||
{
|
||||
Ifile = tdbp->Ifile;
|
||||
Seclist = tdbp->Seclist;
|
||||
Section = tdbp->Section;
|
||||
Seclen = tdbp->Seclen;
|
||||
N = tdbp->N;
|
||||
} // end of TDBINI copy constructor
|
||||
|
||||
// Is this really useful ???
|
||||
PTDB TDBINI::CopyOne(PTABS t)
|
||||
{
|
||||
PTDB tp;
|
||||
PINICOL cp1, cp2;
|
||||
PGLOBAL g = t->G;
|
||||
|
||||
tp = new(g) TDBINI(this);
|
||||
|
||||
for (cp1 = (PINICOL)Columns; cp1; cp1 = (PINICOL)cp1->GetNext()) {
|
||||
cp2 = new(g) INICOL(cp1, tp); // Make a copy
|
||||
NewPointer(t, cp1, cp2);
|
||||
} // endfor cp1
|
||||
|
||||
return tp;
|
||||
} // end of CopyOne
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get the section list from the INI file. */
|
||||
/***********************************************************************/
|
||||
char *TDBINI::GetSeclist(PGLOBAL g)
|
||||
{
|
||||
if (trace)
|
||||
htrc("GetSeclist: Seclist=%p\n", Seclist);
|
||||
|
||||
if (!Seclist) {
|
||||
// Result will be retrieved from the INI file
|
||||
Seclist = (char*)PlugSubAlloc(g, NULL, Seclen);
|
||||
GetPrivateProfileSectionNames(Seclist, Seclen, Ifile);
|
||||
} // endif Seclist
|
||||
|
||||
return Seclist;
|
||||
} // end of GetSeclist
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate INI column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBINI::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
return new(g) INICOL(cdp, this, cprec, n);
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* INI GetMaxSize: returns the number of sections in the INI file. */
|
||||
/***********************************************************************/
|
||||
int TDBINI::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (MaxSize < 0 && GetSeclist(g)) {
|
||||
// Count the number of sections from the section list
|
||||
char *p;
|
||||
|
||||
for (MaxSize = 0, p = Seclist; *p; p += (strlen(p) + 1))
|
||||
MaxSize++;
|
||||
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* INI Access Method opening routine. */
|
||||
/***********************************************************************/
|
||||
bool TDBINI::OpenDB(PGLOBAL g)
|
||||
{
|
||||
PINICOL colp;
|
||||
|
||||
if (Use == USE_OPEN) {
|
||||
if (To_Kindex)
|
||||
/*****************************************************************/
|
||||
/* Table is to be accessed through a sorted index table. */
|
||||
/*****************************************************************/
|
||||
To_Kindex->Reset();
|
||||
|
||||
Section = NULL;
|
||||
N = 0;
|
||||
return false;
|
||||
} // endif use
|
||||
|
||||
/*********************************************************************/
|
||||
/* OpenDB: initialize the INI file processing. */
|
||||
/*********************************************************************/
|
||||
GetSeclist(g);
|
||||
Use = USE_OPEN; // Do it now in case we are recursively called
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate the buffers that will contain key values. */
|
||||
/*********************************************************************/
|
||||
for (colp = (PINICOL)Columns; colp; colp = (PINICOL)colp->GetNext())
|
||||
if (!colp->IsSpecial()) // Not a pseudo column
|
||||
colp->AllocBuf(g);
|
||||
|
||||
if (trace)
|
||||
htrc("INI OpenDB: seclist=%s seclen=%d ifile=%s\n",
|
||||
Seclist, Seclen, Ifile);
|
||||
|
||||
return false;
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base read routine for INI access method. */
|
||||
/***********************************************************************/
|
||||
int TDBINI::ReadDB(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* Now start the pseudo reading process. */
|
||||
/*********************************************************************/
|
||||
if (To_Kindex) {
|
||||
/*******************************************************************/
|
||||
/* Reading is by an index table. */
|
||||
/*******************************************************************/
|
||||
int recpos = To_Kindex->Fetch(g);
|
||||
|
||||
switch (recpos) {
|
||||
case -1: // End of file reached
|
||||
return RC_EF;
|
||||
case -2: // No match for join
|
||||
return RC_NF;
|
||||
case -3: // Same record as last non null one
|
||||
return RC_OK;
|
||||
default:
|
||||
Section = (char*)recpos;
|
||||
} // endswitch recpos
|
||||
|
||||
} else {
|
||||
if (!Section)
|
||||
Section = Seclist;
|
||||
else
|
||||
Section += (strlen(Section) + 1);
|
||||
|
||||
if (trace > 1)
|
||||
htrc("INI ReadDB: section=%s N=%d\n", Section, N);
|
||||
|
||||
N++;
|
||||
} // endif To_Kindex
|
||||
|
||||
return (*Section) ? RC_OK : RC_EF;
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for INI access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBINI::WriteDB(PGLOBAL g)
|
||||
{
|
||||
// This is to check that section name was given when inserting
|
||||
if (Mode == MODE_INSERT)
|
||||
Section = NULL;
|
||||
|
||||
// Nothing else to do because all was done in WriteColumn
|
||||
return RC_OK;
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for INI access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBINI::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
switch (irc) {
|
||||
case RC_EF:
|
||||
break;
|
||||
case RC_FX:
|
||||
while (ReadDB(g) == RC_OK)
|
||||
WritePrivateProfileString(Section, NULL, NULL, Ifile);
|
||||
|
||||
break;
|
||||
default:
|
||||
if (!Section) {
|
||||
strcpy(g->Message, MSG(NO_SECTION_NAME));
|
||||
return RC_FX;
|
||||
} else
|
||||
WritePrivateProfileString(Section, NULL, NULL, Ifile);
|
||||
|
||||
} // endswitch irc
|
||||
|
||||
return RC_OK;
|
||||
} // end of DeleteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for INI access methods. */
|
||||
/***********************************************************************/
|
||||
void TDBINI::CloseDB(PGLOBAL g)
|
||||
{
|
||||
// Nothing to do
|
||||
} // end of CloseDB
|
||||
|
||||
// ------------------------ INICOL functions ----------------------------
|
||||
|
||||
/***********************************************************************/
|
||||
/* INICOL public constructor. */
|
||||
/***********************************************************************/
|
||||
INICOL::INICOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
|
||||
: COLBLK(cdp, tdbp, i)
|
||||
{
|
||||
if (cprec) {
|
||||
Next = cprec->GetNext();
|
||||
cprec->SetNext(this);
|
||||
} else {
|
||||
Next = tdbp->GetColumns();
|
||||
tdbp->SetColumns(this);
|
||||
} // endif cprec
|
||||
|
||||
// Set additional INI access method information for column.
|
||||
Valbuf = NULL;
|
||||
Flag = cdp->GetOffset();
|
||||
Long = cdp->GetLong();
|
||||
To_Val = NULL;
|
||||
} // end of INICOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* INICOL constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
INICOL::INICOL(INICOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
|
||||
{
|
||||
Valbuf = col1->Valbuf;
|
||||
Flag = col1->Flag;
|
||||
Long = col1->Long;
|
||||
To_Val = col1->To_Val;
|
||||
} // end of INICOL copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate a buffer of the proper size. */
|
||||
/***********************************************************************/
|
||||
void INICOL::AllocBuf(PGLOBAL g)
|
||||
{
|
||||
if (!Valbuf)
|
||||
Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1);
|
||||
|
||||
} // end of AllocBuf
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetBuffer: prepare a column block for write operation. */
|
||||
/***********************************************************************/
|
||||
bool INICOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
|
||||
{
|
||||
if (!(To_Val = value)) {
|
||||
sprintf(g->Message, MSG(VALUE_ERROR), Name);
|
||||
return true;
|
||||
} else if (Buf_Type == value->GetType()) {
|
||||
// Values are of the (good) column type
|
||||
if (Buf_Type == TYPE_DATE) {
|
||||
// If any of the date values is formatted
|
||||
// output format must be set for the receiving table
|
||||
if (GetDomain() || ((DTVAL *)value)->IsFormatted())
|
||||
goto newval; // This will make a new value;
|
||||
|
||||
} else if (Buf_Type == TYPE_FLOAT)
|
||||
// Float values must be written with the correct (column) precision
|
||||
// Note: maybe this should be forced by ShowValue instead of this ?
|
||||
((DFVAL *)value)->SetPrec(GetPrecision());
|
||||
|
||||
Value = value; // Directly access the external value
|
||||
} else {
|
||||
// Values are not of the (good) column type
|
||||
if (check) {
|
||||
sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
|
||||
GetTypeName(Buf_Type), GetTypeName(value->GetType()));
|
||||
return true;
|
||||
} // endif check
|
||||
|
||||
newval:
|
||||
if (InitValue(g)) // Allocate the matching value block
|
||||
return true;
|
||||
|
||||
} // endif's Value, Buf_Type
|
||||
|
||||
// Allocate the internal value buffer
|
||||
AllocBuf(g);
|
||||
|
||||
// Because Colblk's have been made from a copy of the original TDB in
|
||||
// case of Update, we must reset them to point to the original one.
|
||||
if (To_Tdb->GetOrig())
|
||||
To_Tdb = (PTDB)To_Tdb->GetOrig();
|
||||
|
||||
// Set the Column
|
||||
Status = (ok) ? BUF_EMPTY : BUF_NO;
|
||||
return false;
|
||||
} // end of SetBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to access the key buffer set */
|
||||
/* from the corresponding section, extract from it the key value */
|
||||
/* corresponding to this column name and convert it to buffer type. */
|
||||
/***********************************************************************/
|
||||
void INICOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
PTDBINI tdbp = (PTDBINI)To_Tdb;
|
||||
|
||||
if (trace > 1)
|
||||
htrc("INI ReadColumn: col %s R%d flag=%d\n",
|
||||
Name, tdbp->GetTdb_No(), Flag);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get the key value from the INI file. */
|
||||
/*********************************************************************/
|
||||
switch (Flag) {
|
||||
case 1:
|
||||
strncpy(Valbuf, tdbp->Section, Long); // Section name
|
||||
Valbuf[Long] = '\0';
|
||||
break;
|
||||
default:
|
||||
GetPrivateProfileString(tdbp->Section, Name, "",
|
||||
Valbuf, Long + 1, tdbp->Ifile);
|
||||
break;
|
||||
} // endswitch Flag
|
||||
|
||||
Value->SetValue_psz(Valbuf);
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteColumn: what this routine does is to access the last line */
|
||||
/* read from the corresponding table, and rewrite the field */
|
||||
/* corresponding to this column from the column buffer and type. */
|
||||
/***********************************************************************/
|
||||
void INICOL::WriteColumn(PGLOBAL g)
|
||||
{
|
||||
char *p;
|
||||
PTDBINI tdbp = (PTDBINI)To_Tdb;
|
||||
|
||||
if (trace > 1)
|
||||
htrc("INI WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
|
||||
Name, tdbp->GetTdb_No(), ColUse, Status);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get the string representation of Value according to column type. */
|
||||
/*********************************************************************/
|
||||
if (Value != To_Val)
|
||||
Value->SetValue_pval(To_Val, false); // Convert the updated value
|
||||
|
||||
p = Value->GetCharString(Valbuf);
|
||||
|
||||
if (strlen(p) > (unsigned)Long) {
|
||||
sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} else if (Flag == 1) {
|
||||
if (tdbp->Mode == MODE_UPDATE) {
|
||||
strcpy(g->Message, MSG(NO_SEC_UPDATE));
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} else {
|
||||
tdbp->Section = p;
|
||||
return;
|
||||
} // endif Mode
|
||||
|
||||
} else if (!tdbp->Section) {
|
||||
strcpy(g->Message, MSG(SEC_NAME_FIRST));
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} // endif's
|
||||
|
||||
/*********************************************************************/
|
||||
/* Updating must be done only when not in checking pass. */
|
||||
/*********************************************************************/
|
||||
if (Status)
|
||||
WritePrivateProfileString(tdbp->Section, Name, p, tdbp->Ifile);
|
||||
|
||||
} // end of WriteColumn
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBXIN class. */
|
||||
/***********************************************************************/
|
||||
TDBXIN::TDBXIN(PINIDEF tdp) : TDBINI(tdp)
|
||||
{
|
||||
Keylist = NULL;
|
||||
Keycur = NULL;
|
||||
Keylen = Seclen;
|
||||
Oldsec = -1;
|
||||
} // end of TDBXIN constructor
|
||||
|
||||
TDBXIN::TDBXIN(PTDBXIN tdbp) : TDBINI(tdbp)
|
||||
{
|
||||
Keylist = tdbp->Keylist;
|
||||
Keycur = tdbp->Keycur;
|
||||
Keylen = tdbp->Keylen;
|
||||
Oldsec = tdbp->Oldsec;
|
||||
} // end of TDBXIN copy constructor
|
||||
|
||||
// Is this really useful ???
|
||||
PTDB TDBXIN::CopyOne(PTABS t)
|
||||
{
|
||||
PTDB tp;
|
||||
PXINCOL cp1, cp2;
|
||||
PGLOBAL g = t->G;
|
||||
|
||||
tp = new(g) TDBXIN(this);
|
||||
|
||||
for (cp1 = (PXINCOL)Columns; cp1; cp1 = (PXINCOL)cp1->GetNext()) {
|
||||
cp2 = new(g) XINCOL(cp1, tp); // Make a copy
|
||||
NewPointer(t, cp1, cp2);
|
||||
} // endfor cp1
|
||||
|
||||
return tp;
|
||||
} // end of CopyOne
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get the key list from the INI file. */
|
||||
/***********************************************************************/
|
||||
char *TDBXIN::GetKeylist(PGLOBAL g, char *sec)
|
||||
{
|
||||
if (!Keylist)
|
||||
Keylist = (char*)PlugSubAlloc(g, NULL, Keylen);
|
||||
|
||||
GetPrivateProfileString(sec, NULL, "", Keylist, Keylen, Ifile);
|
||||
return Keylist;
|
||||
} // end of GetKeylist
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate XIN column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBXIN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
return new(g) XINCOL(cdp, this, cprec, n);
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* XIN GetMaxSize: returns the number of sections in the XIN file. */
|
||||
/***********************************************************************/
|
||||
int TDBXIN::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (MaxSize < 0 && GetSeclist(g)) {
|
||||
// Count the number of keys from the section list
|
||||
char *p, *k;
|
||||
|
||||
for (MaxSize = 0, p = Seclist; *p; p += (strlen(p) + 1))
|
||||
for (k = GetKeylist(g, p); *k; k += (strlen(k) + 1))
|
||||
MaxSize++;
|
||||
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* Record position is Section+Key. */
|
||||
/***********************************************************************/
|
||||
int TDBXIN::GetRecpos(void)
|
||||
{
|
||||
union {
|
||||
short X[2]; // Section and Key offsets
|
||||
int Xpos; // File position
|
||||
}; // end of union
|
||||
|
||||
X[0] = (short)(Section - Seclist);
|
||||
X[1] = (short)(Keycur - Keylist);
|
||||
return Xpos;
|
||||
} // end of GetRecpos
|
||||
|
||||
/***********************************************************************/
|
||||
/* Record position is Section+Key. */
|
||||
/***********************************************************************/
|
||||
bool TDBXIN::SetRecpos(PGLOBAL g, int recpos)
|
||||
{
|
||||
union {
|
||||
short X[2]; // Section and Key offsets
|
||||
int Xpos; // File position
|
||||
}; // end of union
|
||||
|
||||
Xpos = recpos;
|
||||
|
||||
if (X[0] != Oldsec) {
|
||||
Section = Seclist + X[0];
|
||||
Keycur = GetKeylist(g, Section) + X[1];
|
||||
Oldsec = X[0];
|
||||
} else
|
||||
Keycur = Keylist + X[1];
|
||||
|
||||
return false;
|
||||
} // end of SetRecpos
|
||||
|
||||
/***********************************************************************/
|
||||
/* XIN Access Method opening routine. */
|
||||
/***********************************************************************/
|
||||
bool TDBXIN::OpenDB(PGLOBAL g)
|
||||
{
|
||||
Oldsec = -1; // To replace the table at its beginning
|
||||
return TDBINI::OpenDB(g);
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base read routine for XIN access method. */
|
||||
/***********************************************************************/
|
||||
int TDBXIN::ReadDB(PGLOBAL g)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* Now start the pseudo reading process. */
|
||||
/*********************************************************************/
|
||||
if (To_Kindex) {
|
||||
/*******************************************************************/
|
||||
/* Reading is by an index table. */
|
||||
/*******************************************************************/
|
||||
int recpos = To_Kindex->Fetch(g);
|
||||
|
||||
switch (recpos) {
|
||||
case -1: // End of file reached
|
||||
return RC_EF;
|
||||
case -2: // No match for join
|
||||
return RC_NF;
|
||||
case -3: // Same record as last non null one
|
||||
return RC_OK;
|
||||
default:
|
||||
SetRecpos(g, recpos);
|
||||
} // endswitch recpos
|
||||
|
||||
} else {
|
||||
do {
|
||||
if (!Keycur || !*Keycur) {
|
||||
if (!Section)
|
||||
Section = Seclist;
|
||||
else
|
||||
Section += (strlen(Section) + 1);
|
||||
|
||||
if (*Section)
|
||||
Keycur = GetKeylist(g, Section);
|
||||
else
|
||||
return RC_EF;
|
||||
|
||||
} else
|
||||
Keycur += (strlen(Keycur) + 1);
|
||||
|
||||
} while (!*Keycur);
|
||||
|
||||
N++;
|
||||
} // endif To_Kindex
|
||||
|
||||
return RC_OK;
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for XIN access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBXIN::WriteDB(PGLOBAL g)
|
||||
{
|
||||
// To check that section and key names were given when inserting
|
||||
if (Mode == MODE_INSERT) {
|
||||
Section = NULL;
|
||||
Keycur = NULL;
|
||||
} // endif Mode
|
||||
|
||||
// Nothing else to do because all was done in WriteColumn
|
||||
return RC_OK;
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for XIN access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBXIN::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
if (irc == RC_EF) {
|
||||
} else if (irc == RC_FX) {
|
||||
for (Section = Seclist; *Section; Section += (strlen(Section) + 1))
|
||||
WritePrivateProfileString(Section, NULL, NULL, Ifile);
|
||||
|
||||
} else if (Section) {
|
||||
WritePrivateProfileString(Section, Keycur, NULL, Ifile);
|
||||
} else {
|
||||
strcpy(g->Message, MSG(NO_SECTION_NAME));
|
||||
return RC_FX;
|
||||
} // endif's
|
||||
|
||||
return RC_OK;
|
||||
} // end of DeleteDB
|
||||
|
||||
// ------------------------ XINCOL functions ----------------------------
|
||||
|
||||
/***********************************************************************/
|
||||
/* XINCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
XINCOL::XINCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
|
||||
: INICOL(cdp, tdbp, cprec, i, am)
|
||||
{
|
||||
} // end of XINCOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* XINCOL constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
XINCOL::XINCOL(XINCOL *col1, PTDB tdbp) : INICOL(col1, tdbp)
|
||||
{
|
||||
} // end of XINCOL copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to access the key buffer set */
|
||||
/* from the corresponding section, extract from it the key value */
|
||||
/* corresponding to this column name and convert it to buffer type. */
|
||||
/***********************************************************************/
|
||||
void XINCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
PTDBXIN tdbp = (PTDBXIN)To_Tdb;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get the key value from the XIN file. */
|
||||
/*********************************************************************/
|
||||
switch (Flag) {
|
||||
case 1:
|
||||
strncpy(Valbuf, tdbp->Section, Long); // Section name
|
||||
Valbuf[Long] = '\0';
|
||||
break;
|
||||
case 2:
|
||||
strncpy(Valbuf, tdbp->Keycur, Long); // Key name
|
||||
Valbuf[Long] = '\0';
|
||||
break;
|
||||
default:
|
||||
GetPrivateProfileString(tdbp->Section, tdbp->Keycur, "",
|
||||
Valbuf, Long + 1, tdbp->Ifile);
|
||||
break;
|
||||
} // endswitch Flag
|
||||
|
||||
Value->SetValue_psz(Valbuf);
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteColumn: what this routine does is to access the last line */
|
||||
/* read from the corresponding table, and rewrite the field */
|
||||
/* corresponding to this column from the column buffer and type. */
|
||||
/***********************************************************************/
|
||||
void XINCOL::WriteColumn(PGLOBAL g)
|
||||
{
|
||||
char *p;
|
||||
PTDBXIN tdbp = (PTDBXIN)To_Tdb;
|
||||
|
||||
if (trace > 1)
|
||||
htrc("XIN WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
|
||||
Name, tdbp->GetTdb_No(), ColUse, Status);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Get the string representation of Value according to column type. */
|
||||
/*********************************************************************/
|
||||
if (Value != To_Val)
|
||||
Value->SetValue_pval(To_Val, false); // Convert the updated value
|
||||
|
||||
p = Value->GetCharString(Valbuf);
|
||||
|
||||
if (strlen(p) > (unsigned)Long) {
|
||||
sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} else if (Flag == 1) {
|
||||
if (tdbp->Mode == MODE_UPDATE) {
|
||||
strcpy(g->Message, MSG(NO_SEC_UPDATE));
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} else {
|
||||
tdbp->Section = p;
|
||||
return;
|
||||
} // endif Mode
|
||||
|
||||
} else if (Flag == 2) {
|
||||
if (tdbp->Mode == MODE_UPDATE) {
|
||||
strcpy(g->Message, MSG(NO_KEY_UPDATE));
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} else {
|
||||
tdbp->Keycur = p;
|
||||
return;
|
||||
} // endif Mode
|
||||
|
||||
} else if (!tdbp->Section || !tdbp->Keycur) {
|
||||
strcpy(g->Message, MSG(SEC_KEY_FIRST));
|
||||
longjmp(g->jumper[g->jump_level], 31);
|
||||
} // endif's
|
||||
|
||||
/*********************************************************************/
|
||||
/* Updating must be done only when not in checking pass. */
|
||||
/*********************************************************************/
|
||||
if (Status)
|
||||
WritePrivateProfileString(tdbp->Section, tdbp->Keycur, p, tdbp->Ifile);
|
||||
|
||||
} // end of WriteColumn
|
||||
|
||||
/* ------------------------ End of System ---------------------------- */
|
||||
|
||||
|
||||
184
storage/connect/tabsys.h
Normal file
184
storage/connect/tabsys.h
Normal file
@@ -0,0 +1,184 @@
|
||||
|
||||
/*************** TabSys H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABSYS.H Version 2.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2004-2013 */
|
||||
/* */
|
||||
/* This file contains the XDB system tables classes declares. */
|
||||
/***********************************************************************/
|
||||
typedef class INIDEF *PINIDEF;
|
||||
typedef class TDBINI *PTDBINI;
|
||||
typedef class INICOL *PINICOL;
|
||||
typedef class TDBXIN *PTDBXIN;
|
||||
typedef class XINCOL *PXINCOL;
|
||||
|
||||
/* --------------------------- INI classes --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* INI, XDB and XCL tables. */
|
||||
/***********************************************************************/
|
||||
class DllExport INIDEF : public TABDEF { /* INI table description */
|
||||
friend class TDBINI;
|
||||
friend class TDBXIN;
|
||||
friend class TDBXTB;
|
||||
friend class TDBRTB;
|
||||
friend class TDBXCL;
|
||||
public:
|
||||
// Constructor
|
||||
INIDEF(void);
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "INI";}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
virtual bool DeleteTableFile(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *Fn; /* Path/Name of corresponding file */
|
||||
char *Xname; /* The eventual table name */
|
||||
char Subtype; /* I: INI, T: Table, C: Column */
|
||||
char Layout; /* R: Row, C: Column */
|
||||
int Ln; /* Length of section list buffer */
|
||||
}; // end of INIDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the INI tables. */
|
||||
/* These are tables represented by a INI like file. */
|
||||
/***********************************************************************/
|
||||
class TDBINI : public TDBASE {
|
||||
friend class INICOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBINI(PINIDEF tdp);
|
||||
TDBINI(PTDBINI tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_INI;}
|
||||
virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBINI(this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void) {return (int)Section;}
|
||||
virtual int GetProgCur(void) {return N;}
|
||||
virtual int GetAffectedRows(void) {return 0;}
|
||||
virtual PSZ GetFile(PGLOBAL g) {return Ifile;}
|
||||
virtual void SetFile(PGLOBAL g, PSZ fn) {Ifile = fn;}
|
||||
virtual void ResetDB(void) {Seclist = Section = NULL; N = 0;}
|
||||
virtual void ResetSize(void) {MaxSize = -1; Seclist = NULL;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false) {return N;}
|
||||
char *GetSeclist(PGLOBAL g);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *Ifile; // The INI file
|
||||
char *Seclist; // The section list
|
||||
char *Section; // The current section
|
||||
int Seclen; // Length of seclist buffer
|
||||
int N; // The current section index
|
||||
}; // end of class TDBINI
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class INICOL: XDB table access method column descriptor. */
|
||||
/***********************************************************************/
|
||||
class INICOL : public COLBLK {
|
||||
public:
|
||||
// Constructors
|
||||
INICOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "INI");
|
||||
INICOL(INICOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_INI;}
|
||||
virtual void SetTo_Val(PVAL valp) {To_Val = valp;}
|
||||
|
||||
// Methods
|
||||
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
virtual void AllocBuf(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
INICOL(void) {}
|
||||
|
||||
// Members
|
||||
char *Valbuf; // To the key value buffer
|
||||
int Flag; // Tells what set in value
|
||||
int Long; // Buffer length
|
||||
PVAL To_Val; // To value used for Update/Insert
|
||||
}; // end of class INICOL
|
||||
|
||||
/* --------------------------- XINI class ---------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the XINI tables. */
|
||||
/* These are tables represented by a INI like file */
|
||||
/* having 3 columns Section, Key, and Value. */
|
||||
/***********************************************************************/
|
||||
class TDBXIN : public TDBINI {
|
||||
friend class XINCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBXIN(PINIDEF tdp);
|
||||
TDBXIN(PTDBXIN tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_INI;}
|
||||
virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBXIN(this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void);
|
||||
virtual bool SetRecpos(PGLOBAL g, int recpos);
|
||||
virtual void ResetDB(void)
|
||||
{Seclist = Section = Keycur = NULL; N = 0; Oldsec = -1;}
|
||||
char *GetKeylist(PGLOBAL g, char *sec);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *Keylist; // The key list
|
||||
char *Keycur; // The current key
|
||||
int Keylen; // Length of keylist buffer
|
||||
short Oldsec; // Last current section
|
||||
}; // end of class TDBXIN
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class XINCOL: XIN table access method column descriptor. */
|
||||
/***********************************************************************/
|
||||
class XINCOL : public INICOL {
|
||||
public:
|
||||
// Constructors
|
||||
XINCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "INI");
|
||||
XINCOL(XINCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
XINCOL(void) {}
|
||||
|
||||
// Members
|
||||
}; // end of class XINICOL
|
||||
777
storage/connect/tabtbl.cpp
Normal file
777
storage/connect/tabtbl.cpp
Normal file
@@ -0,0 +1,777 @@
|
||||
/************* TabTbl C++ Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: TABTBL */
|
||||
/* ------------- */
|
||||
/* Version 1.3 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to PlugDB Software Development 2008-2012 */
|
||||
/* Author: Olivier BERTRAND */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This program are the TDBTBL class DB routines. */
|
||||
/* */
|
||||
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
||||
/* -------------------------------------- */
|
||||
/* */
|
||||
/* REQUIRED FILES: */
|
||||
/* --------------- */
|
||||
/* TABTBL.CPP - Source code */
|
||||
/* PLGDBSEM.H - DB application declaration file */
|
||||
/* TABDOS.H - TABDOS classes declaration file */
|
||||
/* TABTBL.H - TABTBL classes declaration file */
|
||||
/* GLOBAL.H - Global declaration file */
|
||||
/* */
|
||||
/* REQUIRED LIBRARIES: */
|
||||
/* ------------------- */
|
||||
/* Large model C library */
|
||||
/* */
|
||||
/* REQUIRED PROGRAMS: */
|
||||
/* ------------------ */
|
||||
/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include relevant section of system dependant header files. */
|
||||
/***********************************************************************/
|
||||
//#include "sql_base.h"
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif
|
||||
//#include <windows.h>
|
||||
#else
|
||||
#if defined(UNIX)
|
||||
#include <fnmatch.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "osutil.h"
|
||||
#else
|
||||
//#include <io.h>
|
||||
#endif
|
||||
//#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/***********************************************************************/
|
||||
#include "table.h" // MySQL table definitions
|
||||
#include "global.h" // global declarations
|
||||
#include "plgdbsem.h" // DB application declarations
|
||||
#include "reldef.h" // DB definition declares
|
||||
//#include "filter.h" // FILTER classes dcls
|
||||
#include "filamtxt.h"
|
||||
#include "tabcol.h"
|
||||
#include "tabdos.h" // TDBDOS and DOSCOL class dcls
|
||||
#include "tabtbl.h" // TDBTBL and TBLCOL classes dcls
|
||||
#include "ha_connect.h"
|
||||
#include "mycat.h" // For GetHandler
|
||||
|
||||
extern "C" int trace;
|
||||
|
||||
int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags);
|
||||
|
||||
/* ---------------------------- Class TBLDEF ---------------------------- */
|
||||
|
||||
/**************************************************************************/
|
||||
/* Constructor. */
|
||||
/**************************************************************************/
|
||||
TBLDEF::TBLDEF(void)
|
||||
{
|
||||
To_Tables = NULL;
|
||||
Ntables = 0;
|
||||
Pseudo = 3;
|
||||
} // end of TBLDEF constructor
|
||||
|
||||
/**************************************************************************/
|
||||
/* DefineAM: define specific AM block values from XDB file. */
|
||||
/**************************************************************************/
|
||||
bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
char *tablist, *dbname;
|
||||
|
||||
Desc = "Table list table";
|
||||
tablist = Cat->GetStringCatInfo(g, Name, "Tablist", "");
|
||||
dbname = Cat->GetStringCatInfo(g, Name, "Database", NULL);
|
||||
Ntables = 0;
|
||||
|
||||
if (*tablist) {
|
||||
char *p, *pn, *pdb;
|
||||
PTBL *ptbl = &To_Tables, tbl;
|
||||
|
||||
for (pdb = tablist; ;) {
|
||||
if ((p = strchr(pdb, ',')))
|
||||
*p = 0;
|
||||
|
||||
// Analyze the table name, it has the format:
|
||||
// [dbname.]tabname
|
||||
if ((pn = strchr(pdb, '.'))) {
|
||||
*pn++ = 0;
|
||||
} else {
|
||||
pn = pdb;
|
||||
pdb = dbname;
|
||||
} // endif p
|
||||
|
||||
// Allocate the TBLIST block for that table
|
||||
tbl = (PTBL)PlugSubAlloc(g, NULL, sizeof(TBLIST));
|
||||
tbl->Next = NULL;
|
||||
tbl->Name = pn;
|
||||
tbl->DB = pdb;
|
||||
|
||||
if (trace)
|
||||
htrc("TBL: Name=%s db=%s\n", tbl->Name, SVP(tbl->DB));
|
||||
|
||||
// Link the blocks
|
||||
*ptbl = tbl;
|
||||
ptbl = &tbl->Next;
|
||||
Ntables++;
|
||||
|
||||
if (p)
|
||||
pdb = pn + strlen(pn) + 1;
|
||||
else
|
||||
break;
|
||||
|
||||
} // endfor pdb
|
||||
|
||||
Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0);
|
||||
Accept = (Cat->GetBoolCatInfo(Name, "Accept", 0) != 0);
|
||||
} // endif fsec || tablist
|
||||
|
||||
return FALSE;
|
||||
} // end of DefineAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTable: makes a new Table Description Block. */
|
||||
/***********************************************************************/
|
||||
PTDB TBLDEF::GetTable(PGLOBAL g, MODE m)
|
||||
{
|
||||
PTDB tdbp;
|
||||
|
||||
/*********************************************************************/
|
||||
/* Allocate a TDB of the proper type. */
|
||||
/* Column blocks will be allocated only when needed. */
|
||||
/*********************************************************************/
|
||||
tdbp = new(g) TDBTBL(this);
|
||||
|
||||
return tdbp;
|
||||
} // end of GetTable
|
||||
|
||||
/* ------------------------- Class TDBTBL ---------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* TDBTBL constructors. */
|
||||
/***********************************************************************/
|
||||
TDBTBL::TDBTBL(PTBLDEF tdp) : TDBASE(tdp)
|
||||
{
|
||||
Tablist = NULL;
|
||||
CurTable = NULL;
|
||||
Tdbp = NULL;
|
||||
Accept = tdp->Accept;
|
||||
Maxerr = tdp->Maxerr;
|
||||
Nbf = 0;
|
||||
Rows = 0;
|
||||
Crp = 0;
|
||||
// NTables = 0;
|
||||
// iTable = 0;
|
||||
} // end of TDBTBL standard constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate TBL column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
return new(g) TBLCOL(cdp, this, cprec, n);
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* InsertSpecialColumn: Put a special column ahead of the column list.*/
|
||||
/***********************************************************************/
|
||||
PCOL TDBTBL::InsertSpecialColumn(PGLOBAL g, PCOL scp)
|
||||
{
|
||||
PCOL colp;
|
||||
|
||||
if (!scp->IsSpecial())
|
||||
return NULL;
|
||||
|
||||
if (scp->GetAmType() == TYPE_AM_TABID)
|
||||
// This special column is handled locally
|
||||
colp = new((TIDBLK*)scp) TBTBLK(scp->GetValue());
|
||||
else // Other special columns are treated normally
|
||||
colp = scp;
|
||||
|
||||
colp->SetNext(Columns);
|
||||
Columns = colp;
|
||||
return colp;
|
||||
} // end of InsertSpecialColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* Get the PTDB of a table of the list. */
|
||||
/***********************************************************************/
|
||||
PTDB TDBTBL::GetSubTable(PGLOBAL g, PTBL tblp, PTABLE tabp)
|
||||
{
|
||||
char *db, key[128];
|
||||
uint k, flags;
|
||||
PTDB tdbp = NULL;
|
||||
TABLE_LIST table_list;
|
||||
TABLE_SHARE *s;
|
||||
PCATLG cat = To_Def->GetCat();
|
||||
PHC hc = ((MYCAT*)cat)->GetHandler();
|
||||
THD *thd = (hc->GetTable())->in_use;
|
||||
|
||||
if (!thd)
|
||||
return NULL; // Should not happen anymore
|
||||
|
||||
if (tblp->DB)
|
||||
db = tblp->DB;
|
||||
else
|
||||
db = (char*)hc->GetDBName(NULL);
|
||||
|
||||
table_list.init_one_table(db, strlen(db),
|
||||
tblp->Name, strlen(tblp->Name),
|
||||
NULL, TL_IGNORE);
|
||||
k = sprintf(key, "%s\0%s\0", db, tblp->Name);
|
||||
|
||||
if (!(s = alloc_table_share(&table_list, key, k))) {
|
||||
strcpy(g->Message, "Error allocating share\n");
|
||||
return NULL;
|
||||
} // endif s
|
||||
|
||||
// 1 8 16
|
||||
//flags = READ_ALL | DONT_OPEN_TABLES | DONT_OPEN_MASTER_REG;
|
||||
//flags = 25;
|
||||
flags = 24;
|
||||
|
||||
if (!open_table_def(thd, s, flags)) {
|
||||
hc->tshp = s;
|
||||
tdbp = cat->GetTable(g, tabp);
|
||||
hc->tshp = NULL;
|
||||
} else
|
||||
sprintf(g->Message, "Error %d opening share\n", s->error);
|
||||
|
||||
if (trace && tdbp)
|
||||
htrc("Subtable %s in %s\n",
|
||||
tblp->Name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB()));
|
||||
|
||||
free_table_share(s);
|
||||
return tdbp;
|
||||
} // end of GetSubTable
|
||||
|
||||
/***********************************************************************/
|
||||
/* Initializes the table table list. */
|
||||
/***********************************************************************/
|
||||
bool TDBTBL::InitTableList(PGLOBAL g)
|
||||
{
|
||||
char *colname;
|
||||
int n, colpos;
|
||||
PTBL tblp;
|
||||
PTABLE tabp;
|
||||
PTDB tdbp;
|
||||
PCOL colp;
|
||||
PTBLDEF tdp = (PTBLDEF)To_Def;
|
||||
|
||||
// PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
|
||||
|
||||
for (n = 0, tblp = tdp->GetTables(); tblp; tblp = tblp->Next) {
|
||||
if (TestFil(g, To_Filter, tblp)) {
|
||||
// Table or named view
|
||||
tabp = new(g) XTAB(tblp->Name);
|
||||
tabp->SetQualifier(tblp->DB);
|
||||
|
||||
// Get the table description block of this table
|
||||
if (!(tdbp = GetSubTable(g, tblp, tabp))) {
|
||||
if (++Nbf > Maxerr)
|
||||
return TRUE; // Error return
|
||||
else
|
||||
continue; // Skip this table
|
||||
|
||||
} // endif tdbp
|
||||
|
||||
// We must allocate subtable columns before GetMaxSize is called
|
||||
// because some (PLG, ODBC?) need to have their columns attached.
|
||||
// Real initialization will be done later.
|
||||
for (PCOL cp = Columns; cp; cp = cp->GetNext())
|
||||
if (!cp->IsSpecial()) {
|
||||
colname = cp->GetName();
|
||||
colpos = ((PTBLCOL)cp)->Colnum;
|
||||
|
||||
// We try first to get the column by name
|
||||
if (!(colp = tdbp->ColDB(g, colname, 0)) && colpos)
|
||||
// When unsuccessful, if a column number was specified
|
||||
// try to get the column by its position in the table
|
||||
colp = tdbp->ColDB(g, NULL, colpos);
|
||||
|
||||
if (!colp) {
|
||||
if (!Accept) {
|
||||
sprintf(g->Message, MSG(NO_MATCHING_COL),
|
||||
colname, tdbp->GetName());
|
||||
return TRUE; // Error return
|
||||
} // endif !Accept
|
||||
|
||||
} else // this is needed in particular by PLG tables
|
||||
colp->SetColUse(cp->GetColUse());
|
||||
|
||||
} // endif !special
|
||||
|
||||
if (Tablist)
|
||||
Tablist->Link(tabp);
|
||||
else
|
||||
Tablist = tabp;
|
||||
|
||||
n++;
|
||||
} // endif filp
|
||||
|
||||
} // endfor tblp
|
||||
|
||||
//NumTables = n;
|
||||
To_Filter = NULL; // To avoid doing it several times
|
||||
return FALSE;
|
||||
} // end of InitTableList
|
||||
|
||||
/***********************************************************************/
|
||||
/* Test the tablename against the pseudo "local" filter. */
|
||||
/***********************************************************************/
|
||||
bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp)
|
||||
{
|
||||
char *fil, op[8], tn[NAME_LEN];
|
||||
bool neg;
|
||||
|
||||
if (!filp)
|
||||
return TRUE;
|
||||
else if (strstr(filp, " OR ") || strstr(filp, " AND "))
|
||||
return TRUE; // Not handled yet
|
||||
else
|
||||
fil = filp + (*filp == '(' ? 1 : 0);
|
||||
|
||||
if (sscanf(fil, "TABID %s", op) != 1)
|
||||
return TRUE; // ignore invalid filter
|
||||
|
||||
if ((neg = !strcmp(op, "NOT")))
|
||||
strcpy(op, "IN");
|
||||
|
||||
if (!strcmp(op, "=")) {
|
||||
// Temporarily, filter must be "TABID = 'value'" only
|
||||
if (sscanf(fil, "TABID = '%[^']'", tn) != 1)
|
||||
return TRUE; // ignore invalid filter
|
||||
|
||||
return !stricmp(tn, tblp->Name);
|
||||
} else if (!strcmp(op, "IN")) {
|
||||
char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10);
|
||||
int n;
|
||||
|
||||
if (neg)
|
||||
n = sscanf(fil, "TABID NOT IN (%[^)])", tnl);
|
||||
else
|
||||
n = sscanf(fil, "TABID IN (%[^)])", tnl);
|
||||
|
||||
if (n != 1)
|
||||
return TRUE; // ignore invalid filter
|
||||
|
||||
while (tnl) {
|
||||
if ((p = strchr(tnl, ',')))
|
||||
*p++ = 0;
|
||||
|
||||
if (sscanf(tnl, "'%[^']'", tn) != 1)
|
||||
return TRUE; // ignore invalid filter
|
||||
else if (!stricmp(tn, tblp->Name))
|
||||
return !neg; // Found
|
||||
|
||||
tnl = p;
|
||||
} // endwhile
|
||||
|
||||
return neg; // Not found
|
||||
} // endif op
|
||||
|
||||
return TRUE; // invalid operator
|
||||
} // end of TestFil
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBL GetProgMax: get the max value for progress information. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::GetProgMax(PGLOBAL g)
|
||||
{
|
||||
PTABLE tblp;
|
||||
int n, pmx = 0;
|
||||
|
||||
if (!Tablist && InitTableList(g))
|
||||
return -1;
|
||||
|
||||
for (tblp = Tablist; tblp; tblp = tblp->GetNext())
|
||||
if ((n = tblp->GetTo_Tdb()->GetProgMax(g)) > 0)
|
||||
pmx += n;
|
||||
|
||||
return pmx;
|
||||
} // end of GetProgMax
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBL GetProgCur: get the current value for progress information. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::GetProgCur(void)
|
||||
{
|
||||
return Crp + Tdbp->GetProgCur();
|
||||
} // end of GetProgCur
|
||||
|
||||
#if 0
|
||||
/***********************************************************************/
|
||||
/* TBL Cardinality: returns table cardinality in number of rows. */
|
||||
/* This function can be called with a null argument to test the */
|
||||
/* availability of Cardinality implementation (1 yes, 0 no). */
|
||||
/* Can be used on Multiple FIX table only. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::Cardinality(PGLOBAL g)
|
||||
{
|
||||
if (!g)
|
||||
return Tdbp->Cardinality(g);
|
||||
|
||||
if (!Tablist && InitTableList(g))
|
||||
return -1;
|
||||
|
||||
int n, card = 0;
|
||||
|
||||
for (int i = 0; i < NumFiles; i++) {
|
||||
Tdbp->SetFile(g, Filenames[i]);
|
||||
Tdbp->ResetSize();
|
||||
|
||||
if ((n = Tdbp->Cardinality(g)) < 0) {
|
||||
// strcpy(g->Message, MSG(BAD_CARDINALITY));
|
||||
return -1;
|
||||
} // endif n
|
||||
|
||||
card += n;
|
||||
} // endfor i
|
||||
|
||||
return card;
|
||||
} // end of Cardinality
|
||||
#endif // 0
|
||||
|
||||
/***********************************************************************/
|
||||
/* Sum up the sizes of all sub-tables. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (MaxSize < 0) {
|
||||
PTABLE tblp;
|
||||
int mxsz;
|
||||
|
||||
if (!Tablist && InitTableList(g))
|
||||
return 0; // Cannot be calculated at this stage
|
||||
|
||||
// if (Use == USE_OPEN) {
|
||||
// strcpy(g->Message, MSG(MAXSIZE_ERROR));
|
||||
// return -1;
|
||||
// } else
|
||||
MaxSize = 0;
|
||||
|
||||
for (tblp = Tablist; tblp; tblp = tblp->GetNext()) {
|
||||
if ((mxsz = tblp->GetTo_Tdb()->GetMaxSize(g)) < 0) {
|
||||
MaxSize = -1;
|
||||
return mxsz;
|
||||
} // endif mxsz
|
||||
|
||||
MaxSize += mxsz;
|
||||
} // endfor i
|
||||
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* Reset read/write position values. */
|
||||
/***********************************************************************/
|
||||
void TDBTBL::ResetDB(void)
|
||||
{
|
||||
for (PCOL colp = Columns; colp; colp = colp->GetNext())
|
||||
if (colp->GetAmType() == TYPE_AM_TABID)
|
||||
colp->COLBLK::Reset();
|
||||
|
||||
for (PTABLE tblp = Tablist; tblp; tblp = tblp->GetNext())
|
||||
((PTDBASE)tblp->GetTo_Tdb())->ResetDB();
|
||||
|
||||
Tdbp = (PTDBASE)Tablist->GetTo_Tdb();
|
||||
Crp = 0;
|
||||
} // end of ResetDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Returns RowId if b is false or Rownum if b is true. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::RowNumber(PGLOBAL g, bool b)
|
||||
{
|
||||
return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
|
||||
} // end of RowNumber
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBL Access Method opening routine. */
|
||||
/* Open first file, other will be opened sequencially when reading. */
|
||||
/***********************************************************************/
|
||||
bool TDBTBL::OpenDB(PGLOBAL g)
|
||||
{
|
||||
if (trace)
|
||||
htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
|
||||
this, Tdb_No, Use, To_Key_Col, Mode);
|
||||
|
||||
if (Use == USE_OPEN) {
|
||||
/*******************************************************************/
|
||||
/* Table already open, replace it at its beginning. */
|
||||
/*******************************************************************/
|
||||
ResetDB();
|
||||
return Tdbp->OpenDB(g); // Re-open fist table
|
||||
} // endif use
|
||||
|
||||
#if 0
|
||||
/*********************************************************************/
|
||||
/* Direct access needed for join or sorting. */
|
||||
/*********************************************************************/
|
||||
if (NeedIndexing(g)) {
|
||||
// Direct access of TBL tables is not implemented yet
|
||||
strcpy(g->Message, MSG(NO_MUL_DIR_ACC));
|
||||
return TRUE;
|
||||
} // endif NeedIndexing
|
||||
#endif // 0
|
||||
|
||||
/*********************************************************************/
|
||||
/* When GetMaxsize was called, To_Filter was not set yet. */
|
||||
/*********************************************************************/
|
||||
if (To_Filter && Tablist) {
|
||||
Tablist = NULL;
|
||||
Nbf = 0;
|
||||
} // endif To_Filter
|
||||
|
||||
/*********************************************************************/
|
||||
/* Open the first table of the list. */
|
||||
/*********************************************************************/
|
||||
if (!Tablist && InitTableList(g)) // done in GetMaxSize
|
||||
return TRUE;
|
||||
|
||||
if ((CurTable = Tablist)) {
|
||||
Tdbp = (PTDBASE)CurTable->GetTo_Tdb();
|
||||
Tdbp->SetMode(Mode);
|
||||
// Tdbp->ResetDB();
|
||||
// Tdbp->ResetSize();
|
||||
|
||||
// Check and initialize the subtable columns
|
||||
for (PCOL cp = Columns; cp; cp = cp->GetNext())
|
||||
if (cp->GetAmType() == TYPE_AM_TABID)
|
||||
cp->COLBLK::Reset();
|
||||
else if (((PTBLCOL)cp)->Init(g))
|
||||
return TRUE;
|
||||
|
||||
if (trace)
|
||||
htrc("Opening subtable %s\n", Tdbp->GetName());
|
||||
|
||||
// Now we can safely open the table
|
||||
if (Tdbp->OpenDB(g))
|
||||
return TRUE;
|
||||
|
||||
} // endif *Tablist
|
||||
|
||||
Use = USE_OPEN;
|
||||
return FALSE;
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadDB: Data Base read routine for MUL access method. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::ReadDB(PGLOBAL g)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!CurTable)
|
||||
return RC_EF;
|
||||
else if (To_Kindex) {
|
||||
/*******************************************************************/
|
||||
/* Reading is by an index table. */
|
||||
/*******************************************************************/
|
||||
strcpy(g->Message, MSG(NO_INDEX_READ));
|
||||
rc = RC_FX;
|
||||
} else {
|
||||
/*******************************************************************/
|
||||
/* Now start the reading process. */
|
||||
/*******************************************************************/
|
||||
retry:
|
||||
rc = Tdbp->ReadDB(g);
|
||||
|
||||
if (rc == RC_EF) {
|
||||
// Total number of rows met so far
|
||||
Rows += Tdbp->RowNumber(g) - 1;
|
||||
Crp += Tdbp->GetProgMax(g);
|
||||
|
||||
if ((CurTable = CurTable->GetNext())) {
|
||||
/***************************************************************/
|
||||
/* Continue reading from next table file. */
|
||||
/***************************************************************/
|
||||
Tdbp->CloseDB(g);
|
||||
Tdbp = (PTDBASE)CurTable->GetTo_Tdb();
|
||||
|
||||
// Check and initialize the subtable columns
|
||||
for (PCOL cp = Columns; cp; cp = cp->GetNext())
|
||||
if (cp->GetAmType() == TYPE_AM_TABID)
|
||||
cp->COLBLK::Reset();
|
||||
else if (((PTBLCOL)cp)->Init(g))
|
||||
return RC_FX;
|
||||
|
||||
if (trace)
|
||||
htrc("Opening subtable %s\n", Tdbp->GetName());
|
||||
|
||||
// Now we can safely open the table
|
||||
if (Tdbp->OpenDB(g)) // Open next table
|
||||
return RC_FX;
|
||||
|
||||
goto retry;
|
||||
} // endif iFile
|
||||
|
||||
} else if (rc == RC_FX)
|
||||
strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
|
||||
|
||||
} // endif To_Kindex
|
||||
|
||||
return rc;
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base write routine for MUL access method. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::WriteDB(PGLOBAL g)
|
||||
{
|
||||
strcpy(g->Message, MSG(TABMUL_READONLY));
|
||||
return RC_FX; // NIY
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for MUL access method. */
|
||||
/***********************************************************************/
|
||||
int TDBTBL::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
strcpy(g->Message, MSG(TABMUL_READONLY));
|
||||
return RC_FX; // NIY
|
||||
} // end of DeleteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for MUL access method. */
|
||||
/***********************************************************************/
|
||||
void TDBTBL::CloseDB(PGLOBAL g)
|
||||
{
|
||||
if (Tdbp)
|
||||
Tdbp->CloseDB(g);
|
||||
|
||||
} // end of CloseDB
|
||||
|
||||
/* ---------------------------- TBLCOL ------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBLCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
TBLCOL::TBLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
|
||||
: COLBLK(cdp, tdbp, i)
|
||||
{
|
||||
if (cprec) {
|
||||
Next = cprec->GetNext();
|
||||
cprec->SetNext(this);
|
||||
} else {
|
||||
Next = tdbp->GetColumns();
|
||||
tdbp->SetColumns(this);
|
||||
} // endif cprec
|
||||
|
||||
// Set additional Dos access method information for column.
|
||||
Long = cdp->GetLong(); // ???
|
||||
//strcpy(F_Date, cdp->F_Date);
|
||||
Colp = NULL;
|
||||
To_Val = NULL;
|
||||
Pseudo = FALSE;
|
||||
Colnum = cdp->GetOffset(); // If columns are retrieved by number
|
||||
|
||||
if (trace)
|
||||
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
|
||||
|
||||
} // end of TBLCOL constructor
|
||||
|
||||
#if 0
|
||||
/***********************************************************************/
|
||||
/* TBLCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
TBLCOL::TBLCOL(SPCBLK *scp, PTDB tdbp) : COLBLK(scp->GetName(), tdbp, 0)
|
||||
{
|
||||
// Set additional TBL access method information for pseudo column.
|
||||
Is_Key = Was_Key = scp->IsKey();
|
||||
Long = scp->GetLength();
|
||||
Buf_Type = scp->GetResultType();
|
||||
*Format.Type = (Buf_Type == TYPE_INT) ? 'N' : 'C';
|
||||
Format.Length = Long;
|
||||
Colp = NULL;
|
||||
To_Val = NULL;
|
||||
Pseudo = TRUE;
|
||||
} // end of TBLCOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBLCOL constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
TBLCOL::TBLCOL(TBLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
|
||||
{
|
||||
Long = col1->Long;
|
||||
Colp = col1->Colp;
|
||||
To_Val = col1->To_Val;
|
||||
Pseudo = col1->Pseudo;
|
||||
} // end of TBLCOL copy constructor
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBLCOL initialization routine. */
|
||||
/* Look for the matching column in the current table. */
|
||||
/***********************************************************************/
|
||||
bool TBLCOL::Init(PGLOBAL g)
|
||||
{
|
||||
PTDBTBL tdbp = (PTDBTBL)To_Tdb;
|
||||
|
||||
To_Val = NULL;
|
||||
|
||||
if (!(Colp = tdbp->Tdbp->ColDB(g, Name, 0)) && Colnum)
|
||||
Colp = tdbp->Tdbp->ColDB(g, NULL, Colnum);
|
||||
|
||||
if (Colp) {
|
||||
Colp->InitValue(g); // May not have been done elsewhere
|
||||
To_Val = Colp->GetValue();
|
||||
} else if (!tdbp->Accept) {
|
||||
sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tdbp->Tdbp->GetName());
|
||||
return TRUE;
|
||||
} else
|
||||
Value->Reset();
|
||||
|
||||
return FALSE;
|
||||
} // end of Init
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: */
|
||||
/***********************************************************************/
|
||||
void TBLCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
if (trace)
|
||||
htrc("TBL ReadColumn: name=%s\n", Name);
|
||||
|
||||
if (Colp) {
|
||||
Colp->ReadColumn(g);
|
||||
Value->SetValue_pval(To_Val);
|
||||
} // endif Colp
|
||||
|
||||
} // end of ReadColumn
|
||||
|
||||
/* ---------------------------- TBTBLK ------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: */
|
||||
/***********************************************************************/
|
||||
void TBTBLK::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
if (trace)
|
||||
htrc("TBT ReadColumn: name=%s\n", Name);
|
||||
|
||||
Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName());
|
||||
} // end of ReadColumn
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
162
storage/connect/tabtbl.h
Normal file
162
storage/connect/tabtbl.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*************** TabTbl H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABTBL.H Version 1.2 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2008-2012 */
|
||||
/* */
|
||||
/* This file contains the TDBTBL classes declares. */
|
||||
/***********************************************************************/
|
||||
//#include "osutil.h"
|
||||
#include "block.h"
|
||||
#include "colblk.h"
|
||||
|
||||
typedef class TBLDEF *PTBLDEF;
|
||||
typedef class TDBTBL *PTDBTBL;
|
||||
typedef class TBLCOL *PTBLCOL;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Defines the structure used for multiple tables. */
|
||||
/***********************************************************************/
|
||||
typedef struct _tablist *PTBL;
|
||||
|
||||
typedef struct _tablist {
|
||||
PTBL Next;
|
||||
char *Name;
|
||||
char *DB;
|
||||
} TBLIST;
|
||||
|
||||
/***********************************************************************/
|
||||
/* TBL table. */
|
||||
/***********************************************************************/
|
||||
class DllExport TBLDEF : public TABDEF { /* Logical table description */
|
||||
friend class TDBTBL;
|
||||
public:
|
||||
// Constructor
|
||||
TBLDEF(void);
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "TBL";}
|
||||
PTBL GetTables(void) {return To_Tables;}
|
||||
//int GetNtables(void) {return Ntables;}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PTBL To_Tables; /* To the list of tables */
|
||||
bool Accept; /* TRUE if bad tables are accepted */
|
||||
int Maxerr; /* Maximum number of bad tables */
|
||||
int Ntables; /* Number of tables */
|
||||
}; // end of TBLDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the TBL Access Method class declaration. */
|
||||
/***********************************************************************/
|
||||
class DllExport TDBTBL : public TDBASE {
|
||||
friend class TBLCOL;
|
||||
friend class TBTBLK;
|
||||
friend class TDBPLG;
|
||||
public:
|
||||
// Constructor
|
||||
TDBTBL(PTBLDEF tdp = NULL);
|
||||
//TDBTBL(PTDBTBL tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_TBL;}
|
||||
//virtual PTDB Duplicate(PGLOBAL g)
|
||||
// {return (PTDB)new(g) TDBTBL(this);}
|
||||
|
||||
// Methods
|
||||
virtual void ResetDB(void);
|
||||
//virtual PTABLE GetTablist(void) {return (PSZ)Tablist;}
|
||||
//virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void) {return Rows;}
|
||||
virtual int GetBadLines(void) {return (int)Nbf;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual int GetProgMax(PGLOBAL g);
|
||||
virtual int GetProgCur(void);
|
||||
virtual int RowNumber(PGLOBAL g, bool b = FALSE);
|
||||
virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL scp);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Internal functions
|
||||
PTDB GetSubTable(PGLOBAL g, PTBL tblp, PTABLE tabp);
|
||||
bool InitTableList(PGLOBAL g);
|
||||
bool TestFil(PGLOBAL g, PFIL filp, PTBL tblp);
|
||||
|
||||
// Members
|
||||
PTABLE Tablist; // Points to the table list
|
||||
PTABLE CurTable; // Points to the current table
|
||||
PTDBASE Tdbp; // Current table PTDB
|
||||
bool Accept; // TRUE if bad tables are accepted
|
||||
int Maxerr; // Maximum number of bad tables
|
||||
int Nbf; // Number of bad connections
|
||||
int Rows; // Used for RowID
|
||||
int Crp; // Used for CurPos
|
||||
}; // end of class TDBTBL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class TBLCOL: TBL access method column descriptor. */
|
||||
/* This A.M. is used for TBL tables. */
|
||||
/***********************************************************************/
|
||||
class DllExport TBLCOL : public COLBLK {
|
||||
friend class TDBTBL;
|
||||
public:
|
||||
// Constructors
|
||||
TBLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "TBL");
|
||||
TBLCOL(TBLCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
//TBLCOL(SPCBLK *colp, PTDB tdbp); // Constructor used for pseudo columns
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_TBL;}
|
||||
|
||||
// Methods
|
||||
virtual bool IsSpecial(void) {return Pseudo;}
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
//virtual void WriteColumn(PGLOBAL g);
|
||||
// void Print(PGLOBAL g, FILE *, UINT);
|
||||
bool Init(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
TBLCOL(void) {}
|
||||
|
||||
// Members
|
||||
PCOL Colp; // Points to matching table column
|
||||
PVAL To_Val; // To the matching column value
|
||||
bool Pseudo; // TRUE for special columns
|
||||
int Colnum; // Used when retrieving columns by number
|
||||
}; // end of class TBLCOL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class TBTBLK: TDBPLG TABID special column descriptor. */
|
||||
/***********************************************************************/
|
||||
class TBTBLK : public TIDBLK {
|
||||
public:
|
||||
// The constructor must restore Value because XOBJECT has a void
|
||||
// constructor called by default that set Value to NULL
|
||||
TBTBLK(PVAL valp) {Value = valp;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
// Fake operator new used to change TIDBLK into SDTBLK
|
||||
void * operator new(size_t size, TIDBLK *sp) {return sp;}
|
||||
|
||||
#if !defined(__BORLANDC__)
|
||||
// Avoid warning C4291 by defining a matching dummy delete operator
|
||||
void operator delete(void *, TIDBLK*) {}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Must not have additional members
|
||||
}; // end of class TBTBLK
|
||||
563
storage/connect/tabvct.cpp
Normal file
563
storage/connect/tabvct.cpp
Normal file
@@ -0,0 +1,563 @@
|
||||
/************* TabVct C++ Program Source Code File (.CPP) **************/
|
||||
/* PROGRAM NAME: TABVCT */
|
||||
/* ------------- */
|
||||
/* Version 3.7 */
|
||||
/* */
|
||||
/* COPYRIGHT: */
|
||||
/* ---------- */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */
|
||||
/* */
|
||||
/* WHAT THIS PROGRAM DOES: */
|
||||
/* ----------------------- */
|
||||
/* This is the TDBVCT and VCTCOL classes implementation routines. */
|
||||
/* */
|
||||
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
||||
/* -------------------------------------- */
|
||||
/* */
|
||||
/* REQUIRED FILES: */
|
||||
/* --------------- */
|
||||
/* TABVCT.C - Source code */
|
||||
/* PLGDBSEM.H - DB application declaration file */
|
||||
/* TABDOS.H - TABDOS 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 MariaDB header file. */
|
||||
/***********************************************************************/
|
||||
#include "my_global.h"
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#if defined(__BORLANDC__)
|
||||
#define __MFC_COMPAT__ // To define min/max as macro
|
||||
#endif
|
||||
//#include <windows.h>
|
||||
#include <sys/stat.h>
|
||||
#else
|
||||
#if defined(UNIX)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
//#define strerror(X) _strerror(X)
|
||||
#define NO_ERROR 0
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include application header files: */
|
||||
/* global.h is header containing all global declarations. */
|
||||
/* plgdbsem.h is header containing the DB application declarations. */
|
||||
/* tabdos.h is header containing the TABDOS class declarations. */
|
||||
/***********************************************************************/
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "reldef.h"
|
||||
#include "osutil.h"
|
||||
#include "filamvct.h"
|
||||
#include "tabdos.h"
|
||||
#include "tabvct.h"
|
||||
#include "valblk.h"
|
||||
|
||||
#if defined(UNIX)
|
||||
//add dummy strerror (NGC)
|
||||
char *strerror(int num);
|
||||
#endif // UNIX
|
||||
|
||||
/***********************************************************************/
|
||||
/* Char VCT column blocks are right filled with blanks (blank = true) */
|
||||
/* Conversion of block values allowed conditionally for insert only. */
|
||||
/***********************************************************************/
|
||||
PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
|
||||
bool check = true, bool blank = true);
|
||||
|
||||
|
||||
/* --------------------------- Class VCTDEF -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* DefineAM: define specific AM block values from XDB file. */
|
||||
/***********************************************************************/
|
||||
bool VCTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
DOSDEF::DefineAM(g, "BIN", poff);
|
||||
|
||||
Estimate = Cat->GetIntCatInfo(Name, "Estimate", 0);
|
||||
Split = Cat->GetIntCatInfo(Name, "Split", (Estimate) ? 0 : 1);
|
||||
Header = Cat->GetIntCatInfo(Name, "Header", 0);
|
||||
|
||||
// CONNECT must have Block/Last info for VEC tables
|
||||
if (Estimate && !Split && !Header)
|
||||
Header = 2;
|
||||
|
||||
Recfm = RECFM_VCT;
|
||||
|
||||
// For packed files the logical record length is calculated in poff
|
||||
if (poff != Lrecl) {
|
||||
Lrecl = poff;
|
||||
Cat->SetIntCatInfo(Name, "Lrecl", poff);
|
||||
} // endif poff
|
||||
|
||||
Padded = false;
|
||||
Blksize = 0;
|
||||
return false;
|
||||
} // end of DefineAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* Erase: This was made a separate routine because a strange thing */
|
||||
/* happened when DeleteTablefile was defined for the VCTDEF class: */
|
||||
/* when called from Catalog, the DOSDEF routine was still called even */
|
||||
/* for a VCTDEF class. It also minimizes the specific code. */
|
||||
/***********************************************************************/
|
||||
bool VCTDEF::Erase(char *filename)
|
||||
{
|
||||
bool rc = false;
|
||||
|
||||
if (Split) {
|
||||
char fpat[_MAX_PATH];
|
||||
int i;
|
||||
PCOLDEF cdp;
|
||||
|
||||
MakeFnPattern(fpat);
|
||||
|
||||
for (i = 1, cdp = To_Cols; cdp; i++, cdp = cdp->GetNext()) {
|
||||
sprintf(filename, fpat, i);
|
||||
//#if defined(WIN32)
|
||||
// rc |= !DeleteFile(filename);
|
||||
//#else // UNIX
|
||||
rc |= remove(filename);
|
||||
//#endif // UNIX
|
||||
} // endfor cdp
|
||||
|
||||
} else {
|
||||
rc = DOSDEF::Erase(filename);
|
||||
|
||||
if (Estimate && Header == 2) {
|
||||
PlugSetPath(filename, Fn, GetPath());
|
||||
strcat(PlugRemoveType(filename, filename), ".blk");
|
||||
rc |= remove(filename);
|
||||
} // endif Header
|
||||
|
||||
} // endif Split
|
||||
|
||||
return rc; // Return true if error
|
||||
} // end of Erase
|
||||
|
||||
/***********************************************************************/
|
||||
/* Prepare the column file name pattern for a split table. */
|
||||
/* This function returns the number of columns of the table. */
|
||||
/***********************************************************************/
|
||||
int VCTDEF::MakeFnPattern(char *fpat)
|
||||
{
|
||||
char pat[8];
|
||||
#if !defined(UNIX)
|
||||
char drive[_MAX_DRIVE];
|
||||
#else
|
||||
char *drive = NULL;
|
||||
#endif
|
||||
char direc[_MAX_DIR];
|
||||
char fname[_MAX_FNAME];
|
||||
char ftype[_MAX_EXT]; // File extention
|
||||
int n, m, ncol = 0;
|
||||
PCOLDEF cdp;
|
||||
|
||||
for (cdp = To_Cols; cdp; cdp = cdp->GetNext())
|
||||
ncol++;
|
||||
|
||||
for (n = 1, m = ncol; m /= 10; n++) ;
|
||||
|
||||
sprintf(pat, "%%0%dd", n);
|
||||
_splitpath(Fn, drive, direc, fname, ftype);
|
||||
strcat(fname, pat);
|
||||
_makepath(fpat, drive, direc, fname, ftype);
|
||||
PlugSetPath(fpat, fpat, GetPath());
|
||||
return ncol;
|
||||
} // end of MakeFnPattern
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTable: makes a new Table Description Block. */
|
||||
/***********************************************************************/
|
||||
PTDB VCTDEF::GetTable(PGLOBAL g, MODE mode)
|
||||
{
|
||||
/*********************************************************************/
|
||||
/* Allocate a TDB of the proper type. */
|
||||
/* Column blocks will be allocated only when needed. */
|
||||
/*********************************************************************/
|
||||
// Mapping not used for insert (except for true VEC not split tables)
|
||||
// or when UseTemp is forced
|
||||
bool map = Mapped && (Estimate || mode != MODE_INSERT) &&
|
||||
!(PlgGetUser(g)->UseTemp == TMP_FORCE &&
|
||||
(mode == MODE_UPDATE || mode == MODE_DELETE));
|
||||
PTXF txfp;
|
||||
PTDB tdbp;
|
||||
|
||||
if (Multiple) {
|
||||
strcpy(g->Message, MSG(NO_MUL_VCT));
|
||||
return NULL;
|
||||
} // endif Multiple
|
||||
|
||||
if (Split) {
|
||||
if (map)
|
||||
txfp = new(g) VMPFAM(this);
|
||||
else
|
||||
txfp = new(g) VECFAM(this);
|
||||
|
||||
} else if (Huge)
|
||||
txfp = new(g) BGVFAM(this);
|
||||
else if (map)
|
||||
txfp = new(g) VCMFAM(this);
|
||||
else
|
||||
txfp = new(g) VCTFAM(this);
|
||||
|
||||
tdbp = new(g) TDBVCT(this, txfp);
|
||||
|
||||
/*********************************************************************/
|
||||
/* For block tables, get eventually saved optimization values. */
|
||||
/*********************************************************************/
|
||||
if (mode != MODE_INSERT)
|
||||
if (tdbp->GetBlockValues(g))
|
||||
return NULL;
|
||||
|
||||
return tdbp;
|
||||
} // end of GetTable
|
||||
|
||||
/* --------------------------- Class TDBVCT -------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBVCT class. */
|
||||
/***********************************************************************/
|
||||
TDBVCT::TDBVCT(PVCTDEF tdp, PTXF txfp) : TDBFIX(tdp, txfp)
|
||||
{
|
||||
To_SetCols = NULL;
|
||||
} // end of TDBVCT standard constructor
|
||||
|
||||
TDBVCT::TDBVCT(PGLOBAL g, PTDBVCT tdbp) : TDBFIX(g, tdbp)
|
||||
{
|
||||
To_SetCols = tdbp->To_SetCols;
|
||||
} // end of TDBVCT copy constructor
|
||||
|
||||
// Method
|
||||
PTDB TDBVCT::CopyOne(PTABS t)
|
||||
{
|
||||
PTDB tp;
|
||||
PVCTCOL cp1, cp2;
|
||||
PGLOBAL g = t->G; // Is this really useful ???
|
||||
|
||||
tp = new(g) TDBVCT(g, this);
|
||||
|
||||
for (cp1 = (PVCTCOL)Columns; cp1; cp1 = (PVCTCOL)cp1->Next) {
|
||||
cp2 = new(g) VCTCOL(cp1, tp); // Make a copy
|
||||
NewPointer(t, cp1, cp2);
|
||||
} // endfor cp1
|
||||
|
||||
return tp;
|
||||
} // end of CopyOne
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate VCT column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBVCT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
return new(g) VCTCOL(g, cdp, this, cprec, n);
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* VCT Access Method opening routine. */
|
||||
/* New method now that this routine is called recursively (last table */
|
||||
/* first in reverse order): index blocks are immediately linked to */
|
||||
/* join block of next table if it exists or else are discarted. */
|
||||
/***********************************************************************/
|
||||
bool TDBVCT::OpenDB(PGLOBAL g)
|
||||
{
|
||||
#ifdef DEBTRACE
|
||||
htrc("VCT OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
|
||||
this, Tdb_No, Use, To_Key_Col, Mode);
|
||||
#endif
|
||||
|
||||
if (Use == USE_OPEN) {
|
||||
/*******************************************************************/
|
||||
/* Table already open, just replace it at its beginning. */
|
||||
/*******************************************************************/
|
||||
if (To_Kindex)
|
||||
// Table is to be accessed through a sorted index table
|
||||
To_Kindex->Reset();
|
||||
|
||||
Txfp->Rewind();
|
||||
return false;
|
||||
} // endif Use
|
||||
|
||||
/*********************************************************************/
|
||||
/* Insert is not handled using file mapping. */
|
||||
/*********************************************************************/
|
||||
if (Mode == MODE_INSERT && !((PVCTDEF)To_Def)->GetEstimate() &&
|
||||
Txfp->GetAmType() == TYPE_AM_VMP) {
|
||||
if (!((PVCTFAM)Txfp)->Split) {
|
||||
Txfp = new(g) VCTFAM((PVCTDEF)To_Def);
|
||||
Txfp->SetTdbp(this);
|
||||
} else {
|
||||
Txfp = new(g) VECFAM((PVCTDEF)To_Def);
|
||||
Txfp->SetTdbp(this);
|
||||
} // endif Split
|
||||
|
||||
} // endif Mode
|
||||
|
||||
/*********************************************************************/
|
||||
/* Open according to input/output mode required and */
|
||||
/* allocate the block buffers for columns used in the query. */
|
||||
/*********************************************************************/
|
||||
if (Txfp->OpenTableFile(g))
|
||||
return true;
|
||||
|
||||
// This was not done in previous version
|
||||
Use = USE_OPEN; // Do it now in case we are recursively called
|
||||
|
||||
/*********************************************************************/
|
||||
/* Reset buffer access according to indexing and to mode. */
|
||||
/*********************************************************************/
|
||||
Txfp->ResetBuffer(g);
|
||||
|
||||
return false;
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base read routine for VCT access method. */
|
||||
/* This routine just set the new block index and record position. */
|
||||
/* For index accessed tables the physical reading is deferred to the */
|
||||
/* ReadColumn routine so only really used column are physically read. */
|
||||
/***********************************************************************/
|
||||
int TDBVCT::ReadDB(PGLOBAL g)
|
||||
{
|
||||
#ifdef DEBTRACE
|
||||
fprintf(debug,
|
||||
"VCT ReadDB: R%d Mode=%d CurBlk=%d CurNum=%d key=%p link=%p Kindex=%p\n",
|
||||
GetTdb_No(), Mode, Txfp->CurBlk, Txfp->CurNum,
|
||||
To_Key_Col, To_Link, To_Kindex);
|
||||
#endif
|
||||
|
||||
if (To_Kindex) {
|
||||
/*******************************************************************/
|
||||
/* Reading is by an index table. */
|
||||
/*******************************************************************/
|
||||
int recpos = To_Kindex->Fetch(g);
|
||||
|
||||
switch (recpos) {
|
||||
case -1: // End of file reached
|
||||
return RC_EF;
|
||||
case -2: // No match for join
|
||||
return RC_NF;
|
||||
case -3: // Same record as last non null one
|
||||
// num_there++;
|
||||
return RC_OK;
|
||||
default:
|
||||
/***************************************************************/
|
||||
/* Set the file position according to record to read. */
|
||||
/***************************************************************/
|
||||
if (SetRecpos(g, recpos))
|
||||
return RC_FX;
|
||||
|
||||
} // endswitch recpos
|
||||
|
||||
} // endif To_Kindex
|
||||
|
||||
return ReadBuffer(g);
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for VEC access method. */
|
||||
/***********************************************************************/
|
||||
void TDBVCT::CloseDB(PGLOBAL g)
|
||||
{
|
||||
if (To_Kindex) {
|
||||
To_Kindex->Close();
|
||||
To_Kindex = NULL;
|
||||
} // endif
|
||||
|
||||
Txfp->CloseTableFile(g);
|
||||
} // end of CloseDB
|
||||
|
||||
// ------------------------ VCTCOL functions ----------------------------
|
||||
|
||||
/***********************************************************************/
|
||||
/* VCTCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
VCTCOL::VCTCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
|
||||
: DOSCOL(g, cdp, tdbp, cprec, i, "VCT")
|
||||
{
|
||||
Deplac = cdp->GetPoff();
|
||||
Clen = cdp->GetClen(); // Length of the field in the file
|
||||
ColBlk = -1;
|
||||
ColPos = -1;
|
||||
Blk = NULL;
|
||||
Modif = 0;
|
||||
} // end of VCTCOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* VCTCOL constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
VCTCOL::VCTCOL(VCTCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
|
||||
{
|
||||
ColBlk = col1->ColBlk;
|
||||
ColPos = col1->ColPos;
|
||||
Blk = col1->Blk; // Should be NULL when copying ????
|
||||
Modif = col1->Modif; // Should be 0 ????
|
||||
} // end of VCTCOL copy constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* SetBuffer: allocate and set the buffers needed for write operation.*/
|
||||
/***********************************************************************/
|
||||
bool VCTCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
|
||||
{
|
||||
// Eventual conversion will be done when setting ValBlk from Value.
|
||||
Value = value; // Force To_Val == Value
|
||||
|
||||
if (DOSCOL::SetBuffer(g, value, ok, check))
|
||||
return true;
|
||||
|
||||
if (To_Tdb->GetMode() != MODE_INSERT) {
|
||||
// Allocate the block buffer to use for read/writing except when
|
||||
// updating a mapped VCT table and Ok is true.
|
||||
PTDBVCT tdbp = (PTDBVCT)To_Tdb;
|
||||
|
||||
if (tdbp->Txfp->GetAmType() == TYPE_AM_VMP && ok) {
|
||||
Blk = AllocValBlock(g, (void*)1, Buf_Type, tdbp->Txfp->Nrec,
|
||||
Format.Length,
|
||||
Format.Prec, check);
|
||||
Status |= BUF_MAPPED; // Will point into mapped file
|
||||
} else
|
||||
Blk = AllocValBlock(g, NULL, Buf_Type, tdbp->Txfp->Nrec,
|
||||
Format.Length,
|
||||
Format.Prec, check);
|
||||
} // endif Mode
|
||||
|
||||
return false;
|
||||
} // end of SetBuffer
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBlock: Indicate it is Ok to make updates. */
|
||||
/***********************************************************************/
|
||||
void VCTCOL::SetOk(void)
|
||||
{
|
||||
if (((PTDBVCT)To_Tdb)->Txfp->GetAmType() == TYPE_AM_VMP)
|
||||
Status |= BUF_MAPPED;
|
||||
|
||||
Status |= BUF_EMPTY;
|
||||
Modif = 0;
|
||||
} // end of SetOk
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadBlock: Read column values from current block. */
|
||||
/***********************************************************************/
|
||||
void VCTCOL::ReadBlock(PGLOBAL g)
|
||||
{
|
||||
PVCTFAM txfp = (PVCTFAM)((PTDBVCT)To_Tdb)->Txfp;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (!Blk) {
|
||||
strcpy(g->Message, MSG(TO_BLK_IS_NULL));
|
||||
longjmp(g->jumper[g->jump_level], 58);
|
||||
} // endif
|
||||
#endif
|
||||
|
||||
/*********************************************************************/
|
||||
/* Read column block according to used access method. */
|
||||
/*********************************************************************/
|
||||
if (txfp->ReadBlock(g, this))
|
||||
longjmp(g->jumper[g->jump_level], 6);
|
||||
|
||||
ColBlk = txfp->CurBlk;
|
||||
ColPos = -1; // Any invalid position
|
||||
} // end of ReadBlock
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteBlock: Write back current column values for one block. */
|
||||
/* Note: the test of Status is meant to prevent physical writing of */
|
||||
/* the block during the checking loop in mode Update. It is set to */
|
||||
/* BUF_EMPTY when reopening the table between the two loops. */
|
||||
/***********************************************************************/
|
||||
void VCTCOL::WriteBlock(PGLOBAL g)
|
||||
{
|
||||
if (Modif && (Status & BUF_EMPTY)) {
|
||||
PVCTFAM txfp = (PVCTFAM)((PTDBVCT)To_Tdb)->Txfp;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (!Blk) {
|
||||
strcpy(g->Message, MSG(BLK_IS_NULL));
|
||||
longjmp(g->jumper[g->jump_level], 56);
|
||||
} // endif
|
||||
#endif
|
||||
|
||||
/*******************************************************************/
|
||||
/* Write column block according to used access method. */
|
||||
/*******************************************************************/
|
||||
if (txfp->WriteBlock(g, this))
|
||||
longjmp(g->jumper[g->jump_level], 6);
|
||||
|
||||
Modif = 0;
|
||||
} // endif Modif
|
||||
|
||||
} // end of WriteBlock
|
||||
|
||||
/***********************************************************************/
|
||||
/* ReadColumn: what this routine does is to check whether a column */
|
||||
/* block has been read from the file, then to extract from it the */
|
||||
/* field corresponding to this column and convert it to buffer type. */
|
||||
/***********************************************************************/
|
||||
void VCTCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
PTXF txfp = ((PTDBVCT)To_Tdb)->Txfp;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBTRACE)
|
||||
assert (!To_Kcol);
|
||||
#endif
|
||||
|
||||
#ifdef DEBTRACE
|
||||
fprintf(debug,
|
||||
"VCT ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n",
|
||||
Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type);
|
||||
#endif
|
||||
|
||||
if (ColBlk != txfp->CurBlk)
|
||||
ReadBlock(g);
|
||||
else if (ColPos == txfp->CurNum)
|
||||
return; // Value is already there
|
||||
|
||||
//ColBlk = txfp->CurBlk; done in ReadBlock
|
||||
ColPos = txfp->CurNum;
|
||||
Value->SetValue_pvblk(Blk, ColPos);
|
||||
} // end of ReadColumn
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteColumn: Modifications are written back into column buffer. */
|
||||
/* On each change of block the buffer is written back to file and */
|
||||
/* in mode Insert the buffer is filled with the block to update. */
|
||||
/***********************************************************************/
|
||||
void VCTCOL::WriteColumn(PGLOBAL g)
|
||||
{
|
||||
PTXF txfp = ((PTDBVCT)To_Tdb)->Txfp;;
|
||||
|
||||
#ifdef DEBTRACE
|
||||
fprintf(debug,
|
||||
"VCT WriteColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n",
|
||||
Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type);
|
||||
#endif
|
||||
|
||||
ColBlk = txfp->CurBlk;
|
||||
ColPos = txfp->CurNum;
|
||||
Blk->SetValue(Value, ColPos);
|
||||
Modif++;
|
||||
} // end of WriteColumn
|
||||
|
||||
/* ------------------------ End of TabVct ---------------------------- */
|
||||
123
storage/connect/tabvct.h
Normal file
123
storage/connect/tabvct.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*************** TabVct H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABVCT.H Version 3.4 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 1999-2011 */
|
||||
/* */
|
||||
/* This file contains the TDBVCT class declares. */
|
||||
/***********************************************************************/
|
||||
#ifndef __TABVCT__
|
||||
#define __TABVCT__
|
||||
|
||||
#include "tabfix.h"
|
||||
#if defined(UNIX)
|
||||
//#include <string.h.SUNWCCh>
|
||||
#endif
|
||||
|
||||
typedef class TDBVCT *PTDBVCT;
|
||||
typedef class VCTCOL *PVCTCOL;
|
||||
|
||||
/***********************************************************************/
|
||||
/* VCT table. */
|
||||
/***********************************************************************/
|
||||
class DllExport VCTDEF : public DOSDEF { /* Logical table description */
|
||||
friend class VCTFAM;
|
||||
friend class VECFAM;
|
||||
friend class VMPFAM;
|
||||
public:
|
||||
// Constructor
|
||||
VCTDEF(void) {Split = Estimate = Header = 0;}
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "VCT";}
|
||||
int GetEstimate(void) {return Estimate;}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE mode);
|
||||
|
||||
protected:
|
||||
// Specific file erase routine for vertical tables
|
||||
virtual bool Erase(char *filename);
|
||||
int MakeFnPattern(char *fpat);
|
||||
|
||||
// Members
|
||||
int Split; /* Columns in separate files */
|
||||
int Estimate; /* Estimated maximum size of table */
|
||||
int Header; /* 0: no, 1: separate, 2: in data file */
|
||||
}; // end of VCTDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the DOS/UNIX Access Method class declaration for files */
|
||||
/* in blocked vector format. In each block containing "Elements" */
|
||||
/* records, values of each columns are consecutively stored (vector). */
|
||||
/***********************************************************************/
|
||||
class DllExport TDBVCT : public TDBFIX {
|
||||
friend class VCTCOL;
|
||||
friend class VCTFAM;
|
||||
friend class VCMFAM;
|
||||
friend class VECFAM;
|
||||
friend class VMPFAM;
|
||||
public:
|
||||
// Constructors
|
||||
TDBVCT(PVCTDEF tdp, PTXF txfp);
|
||||
TDBVCT(PGLOBAL g, PTDBVCT tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_VCT;}
|
||||
virtual PTDB Duplicate(PGLOBAL g)
|
||||
{return (PTDB)new(g) TDBVCT(g, this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
}; // end of class TDBVCT
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class VCTCOL: VCT access method column descriptor. */
|
||||
/* This A.M. is used for file having column wise organization. */
|
||||
/***********************************************************************/
|
||||
class DllExport VCTCOL : public DOSCOL {
|
||||
friend class TDBVCT;
|
||||
friend class VCTFAM;
|
||||
friend class VCMFAM;
|
||||
friend class VECFAM;
|
||||
friend class VMPFAM;
|
||||
friend class BGVFAM;
|
||||
public:
|
||||
// Constructors
|
||||
VCTCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
|
||||
VCTCOL(VCTCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_VCT;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
|
||||
virtual void SetOk(void);
|
||||
|
||||
protected:
|
||||
virtual void ReadBlock(PGLOBAL g);
|
||||
virtual void WriteBlock(PGLOBAL g);
|
||||
|
||||
VCTCOL(void) {} // Default constructor not to be used
|
||||
|
||||
// Members
|
||||
PVBLK Blk; // Block buffer
|
||||
int Clen; // Internal length in table
|
||||
int ColBlk; // Block pointed by column
|
||||
int ColPos; // Last position read
|
||||
int Modif; // Number of modified lines in block
|
||||
}; // end of class VCTCOL
|
||||
|
||||
#endif // __TABVCT__
|
||||
|
||||
840
storage/connect/tabwmi.cpp
Normal file
840
storage/connect/tabwmi.cpp
Normal file
@@ -0,0 +1,840 @@
|
||||
/***********************************************************************/
|
||||
/* TABWMI: Author Olivier Bertrand -- PlugDB -- 2012 */
|
||||
/* TABWMI: Virtual table to get WMI information. */
|
||||
/***********************************************************************/
|
||||
#if !defined(WIN32)
|
||||
#error This is a WIN32 only table type
|
||||
#endif // !WIN32
|
||||
#include "my_global.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
//#include "catalog.h"
|
||||
#include "reldef.h"
|
||||
#include "xtable.h"
|
||||
#include "colblk.h"
|
||||
#include "filter.h"
|
||||
//#include "xindex.h"
|
||||
#include "tabwmi.h"
|
||||
#include "valblk.h"
|
||||
#include "plgcnx.h" // For DB types
|
||||
#include "resource.h"
|
||||
|
||||
/* -------------- Implementation of the WMI classes ------------------ */
|
||||
|
||||
/***********************************************************************/
|
||||
/* DefineAM: define specific AM values for WMI table. */
|
||||
/***********************************************************************/
|
||||
bool WMIDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||||
{
|
||||
Nspace = Cat->GetStringCatInfo(g, Name, "Namespace", "Root\\CimV2");
|
||||
Wclass = Cat->GetStringCatInfo(g, Name, "Class",
|
||||
(!stricmp(Nspace, "root\\cimv2") ? "ComputerSystemProduct" :
|
||||
!stricmp(Nspace, "root\\cli") ? "Msft_CliAlias" : ""));
|
||||
|
||||
if (!*Wclass) {
|
||||
sprintf(g->Message, "Missing class name for %s", Nspace);
|
||||
return true;
|
||||
} else if (!strchr(Wclass, '_')) {
|
||||
char *p = (char*)PlugSubAlloc(g, NULL, strlen(Wclass) + 7);
|
||||
Wclass = strcat(strcpy(p, "Win32_"), Wclass);
|
||||
} // endif Wclass
|
||||
|
||||
if (!(Info = Cat->GetBoolCatInfo(Name, "Info", false)))
|
||||
Ems = Cat->GetIntCatInfo(Name, "Estimate", 100);
|
||||
|
||||
return false;
|
||||
} // end of DefineAM
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetTable: makes a new TDB of the proper type. */
|
||||
/***********************************************************************/
|
||||
PTDB WMIDEF::GetTable(PGLOBAL g, MODE m)
|
||||
{
|
||||
if (Info)
|
||||
return new(g) TDBWCL(this);
|
||||
else
|
||||
return new(g) TDBWMI(this);
|
||||
|
||||
} // end of GetTable
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBWMI class. */
|
||||
/***********************************************************************/
|
||||
TDBWMI::TDBWMI(PWMIDEF tdp) : TDBASE(tdp)
|
||||
{
|
||||
Svc = NULL;
|
||||
Enumerator = NULL;
|
||||
ClsObj = NULL;
|
||||
Nspace = tdp->Nspace;
|
||||
Wclass = tdp->Wclass;
|
||||
ObjPath = NULL;
|
||||
Kvp = NULL;
|
||||
Ems = tdp->Ems;
|
||||
Kcol = NULL;
|
||||
Vbp = NULL;
|
||||
Init = false;
|
||||
Done = false;
|
||||
Res = 0;
|
||||
Rc = 0;
|
||||
N = -1;
|
||||
} // end of TDBWMI constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate WMI column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBWMI::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
PCOL colp;
|
||||
|
||||
colp = new(g) WMICOL(cdp, this, n);
|
||||
|
||||
if (cprec) {
|
||||
colp->SetNext(cprec->GetNext());
|
||||
cprec->SetNext(colp);
|
||||
} else {
|
||||
colp->SetNext(Columns);
|
||||
Columns = colp;
|
||||
} // endif cprec
|
||||
|
||||
return colp;
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* Initialize: Initialize WMI operations. */
|
||||
/***********************************************************************/
|
||||
bool TDBWMI::Initialize(PGLOBAL g)
|
||||
{
|
||||
if (Init)
|
||||
return false;
|
||||
|
||||
// Initialize COM.
|
||||
Res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "Failed to initialize COM library. "
|
||||
"Error code = %p", Res);
|
||||
return true; // Program has failed.
|
||||
} // endif Res
|
||||
|
||||
// Obtain the initial locator to Windows Management
|
||||
// on a particular host computer.
|
||||
IWbemLocator *loc; // Initial Windows Management locator
|
||||
|
||||
Res = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
|
||||
IID_IWbemLocator, (LPVOID*) &loc);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "Failed to create Locator. "
|
||||
"Error code = %p", Res);
|
||||
CoUninitialize();
|
||||
return true; // Program has failed.
|
||||
} // endif Res
|
||||
|
||||
// Connect to the specified namespace with the
|
||||
// current user and obtain pointer to Svc
|
||||
// to make IWbemServices calls.
|
||||
Res = loc->ConnectServer(_bstr_t(Nspace),
|
||||
NULL, NULL,0, NULL, 0, 0, &Svc);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "Could not connect. Error code = %p", Res);
|
||||
loc->Release();
|
||||
CoUninitialize();
|
||||
return true; // Program has failed.
|
||||
} // endif hres
|
||||
|
||||
loc->Release(); // Not used anymore
|
||||
|
||||
// Set the IWbemServices proxy so that impersonation
|
||||
// of the user (client) occurs.
|
||||
Res = CoSetProxyBlanket(Svc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
|
||||
NULL, RPC_C_AUTHN_LEVEL_CALL,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "Could not set proxy. Error code = 0x", Res);
|
||||
Svc->Release();
|
||||
CoUninitialize();
|
||||
return true; // Program has failed.
|
||||
} // endif Res
|
||||
|
||||
Init = true;
|
||||
return false;
|
||||
} // end of Initialize
|
||||
|
||||
/***********************************************************************/
|
||||
/* Changes '\' into '\\' in the filter. */
|
||||
/***********************************************************************/
|
||||
void TDBWMI::DoubleSlash(PGLOBAL g)
|
||||
{
|
||||
if (To_Filter && strchr(To_Filter, '\\')) {
|
||||
char *buf = (char*)PlugSubAlloc(g, NULL, strlen(To_Filter) * 2);
|
||||
int i = 0, k = 0;
|
||||
|
||||
do {
|
||||
if (To_Filter[i] == '\\')
|
||||
buf[k++] = '\\';
|
||||
|
||||
buf[k++] = To_Filter[i];
|
||||
} while (To_Filter[i++]);
|
||||
|
||||
To_Filter = buf;
|
||||
} // endif To_Filter
|
||||
|
||||
} // end of DoubleSlash
|
||||
|
||||
/***********************************************************************/
|
||||
/* MakeWQL: make the WQL statement use with WMI ExecQuery. */
|
||||
/***********************************************************************/
|
||||
char *TDBWMI::MakeWQL(PGLOBAL g)
|
||||
{
|
||||
char *colist, *wql/*, *pw = NULL*/;
|
||||
int len, ncol = 0;
|
||||
bool first = true, noloc = false;
|
||||
PCOL colp;
|
||||
|
||||
// Normal WQL statement to retrieve results
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (!colp->IsSpecial() && (colp->GetColUse(U_P | U_J_EXT) || noloc))
|
||||
ncol++;
|
||||
|
||||
if (ncol) {
|
||||
colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol);
|
||||
|
||||
for (colp = Columns; colp; colp = colp->GetNext())
|
||||
if (!colp->IsSpecial()) {
|
||||
if (colp->GetResultType() == TYPE_DATE)
|
||||
((DTVAL*)colp->GetValue())->SetFormat(g, "YYYYMMDDhhmmss", 19);
|
||||
|
||||
if (colp->GetColUse(U_P | U_J_EXT) || noloc) {
|
||||
if (first) {
|
||||
strcpy(colist, colp->GetName());
|
||||
first = false;
|
||||
} else
|
||||
strcat(strcat(colist, ", "), colp->GetName());
|
||||
|
||||
} // endif ColUse
|
||||
|
||||
} // endif Special
|
||||
|
||||
} else {
|
||||
// ncol == 0 can occur for queries such that sql count(*) from...
|
||||
// for which we will count the rows from sql * from...
|
||||
colist = (char*)PlugSubAlloc(g, NULL, 2);
|
||||
strcpy(colist, "*");
|
||||
} // endif ncol
|
||||
|
||||
// Below 14 is length of 'select ' + length of ' from ' + 1
|
||||
len = (strlen(colist) + strlen(Wclass) + 14);
|
||||
len += (To_Filter ? strlen(To_Filter) + 7 : 0);
|
||||
wql = (char*)PlugSubAlloc(g, NULL, len);
|
||||
strcat(strcat(strcpy(wql, "SELECT "), colist), " FROM ");
|
||||
strcat(wql, Wclass);
|
||||
|
||||
if (To_Filter)
|
||||
strcat(strcat(wql, " WHERE "), To_Filter);
|
||||
|
||||
return wql;
|
||||
} // end of MakeWQL
|
||||
|
||||
/***********************************************************************/
|
||||
/* GetWMIInfo: Get info for the WMI class. */
|
||||
/***********************************************************************/
|
||||
bool TDBWMI::GetWMIInfo(PGLOBAL g)
|
||||
{
|
||||
if (Done)
|
||||
return false;
|
||||
|
||||
char *cmd = MakeWQL(g);
|
||||
|
||||
if (cmd == NULL) {
|
||||
sprintf(g->Message, "Error making WQL statement");
|
||||
Svc->Release();
|
||||
CoUninitialize();
|
||||
return true; // Program has failed.
|
||||
} // endif cmd
|
||||
|
||||
// Query for Wclass in Nspace
|
||||
Rc = Svc->ExecQuery(bstr_t("WQL"), bstr_t(cmd),
|
||||
// WBEM_FLAG_BIDIRECTIONAL | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
NULL, &Enumerator);
|
||||
|
||||
if (FAILED(Rc)) {
|
||||
sprintf(g->Message, "Query %s failed. Error code = %p", cmd, Rc);
|
||||
Svc->Release();
|
||||
CoUninitialize();
|
||||
return true; // Program has failed.
|
||||
} // endif Rc
|
||||
|
||||
Done = true;
|
||||
return false;
|
||||
} // end of GetWMIInfo
|
||||
|
||||
/***********************************************************************/
|
||||
/* WMI: Get the number returned instances. */
|
||||
/***********************************************************************/
|
||||
int TDBWMI::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (MaxSize < 0) {
|
||||
/*******************************************************************/
|
||||
/* Loop enumerating to get the count. This is prone to last a */
|
||||
/* very long time for some classes such as DataFile, this is why */
|
||||
/* we just return an estimated value that will be ajusted later. */
|
||||
/*******************************************************************/
|
||||
MaxSize = Ems;
|
||||
#if 0
|
||||
if (Initialize(g))
|
||||
return -1;
|
||||
else if (GetWMIInfo(g))
|
||||
return -1;
|
||||
else
|
||||
MaxSize = 0;
|
||||
|
||||
PDBUSER dup = PlgGetUser(g);
|
||||
|
||||
while (Enumerator) {
|
||||
Res = Enumerator->Next(WBEM_INFINITE, 1, &ClsObj, &Rc);
|
||||
|
||||
if (Rc == 0)
|
||||
break;
|
||||
|
||||
MaxSize++;
|
||||
} // endwile Enumerator
|
||||
|
||||
Res = Enumerator->Reset();
|
||||
#endif // 0
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* When making a Kindex, must provide the Key column info. */
|
||||
/***********************************************************************/
|
||||
int TDBWMI::GetRecpos(void)
|
||||
{
|
||||
if (!Kcol || !Vbp)
|
||||
return N;
|
||||
|
||||
Kcol->Reset();
|
||||
Kcol->Eval(NULL);
|
||||
Vbp->SetValue(Kcol->GetValue(), N);
|
||||
return N;
|
||||
} // end of GetRecpos
|
||||
|
||||
/***********************************************************************/
|
||||
/* WMI Access Method opening routine. */
|
||||
/***********************************************************************/
|
||||
bool TDBWMI::OpenDB(PGLOBAL g)
|
||||
{
|
||||
if (Use == USE_OPEN) {
|
||||
/*******************************************************************/
|
||||
/* Table already open. */
|
||||
/*******************************************************************/
|
||||
Res = Enumerator->Reset();
|
||||
N = 0;
|
||||
return false;
|
||||
} // endif use
|
||||
|
||||
if (Mode != MODE_READ) {
|
||||
/*******************************************************************/
|
||||
/* WMI tables cannot be modified. */
|
||||
/*******************************************************************/
|
||||
strcpy(g->Message, "WMI tables are read only");
|
||||
return true;
|
||||
} // endif Mode
|
||||
|
||||
if (!To_Filter && !stricmp(Wclass, "CIM_Datafile")
|
||||
&& !stricmp(Nspace, "root\\cimv2")) {
|
||||
strcpy(g->Message,
|
||||
"Would last forever when not filtered, use DIR table instead");
|
||||
return true;
|
||||
} else
|
||||
DoubleSlash(g);
|
||||
|
||||
/*********************************************************************/
|
||||
/* Initialize the WMI processing. */
|
||||
/*********************************************************************/
|
||||
if (Initialize(g))
|
||||
return true;
|
||||
else
|
||||
return GetWMIInfo(g);
|
||||
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base read routine for WMI access method. */
|
||||
/***********************************************************************/
|
||||
int TDBWMI::ReadDB(PGLOBAL g)
|
||||
{
|
||||
Res = Enumerator->Next(WBEM_INFINITE, 1, &ClsObj, &Rc);
|
||||
|
||||
if (Rc == 0)
|
||||
return RC_EF;
|
||||
|
||||
N++;
|
||||
return RC_OK;
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for WMI access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBWMI::WriteDB(PGLOBAL g)
|
||||
{
|
||||
strcpy(g->Message, "WMI tables are read only");
|
||||
return RC_FX;
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for WMI access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBWMI::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
strcpy(g->Message, "Delete not enabled for WMI tables");
|
||||
return RC_FX;
|
||||
} // end of DeleteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for WMI access method. */
|
||||
/***********************************************************************/
|
||||
void TDBWMI::CloseDB(PGLOBAL g)
|
||||
{
|
||||
// Cleanup
|
||||
if (ClsObj)
|
||||
ClsObj->Release();
|
||||
|
||||
if (Enumerator)
|
||||
Enumerator->Release();
|
||||
|
||||
if (Svc)
|
||||
Svc->Release();
|
||||
|
||||
CoUninitialize();
|
||||
} // end of CloseDB
|
||||
|
||||
// ------------------------ WMICOL functions ----------------------------
|
||||
|
||||
/***********************************************************************/
|
||||
/* WMICOL public constructor. */
|
||||
/***********************************************************************/
|
||||
WMICOL::WMICOL(PCOLDEF cdp, PTDB tdbp, int n)
|
||||
: COLBLK(cdp, tdbp, n)
|
||||
{
|
||||
Tdbp = (PTDBWMI)tdbp;
|
||||
VariantInit(&Prop);
|
||||
Ctype = CIM_ILLEGAL;
|
||||
Res = 0;
|
||||
} // end of WMICOL constructor
|
||||
|
||||
#if 0
|
||||
/***********************************************************************/
|
||||
/* WMICOL constructor used for copying columns. */
|
||||
/* tdbp is the pointer to the new table descriptor. */
|
||||
/***********************************************************************/
|
||||
WMICOL::WMICOL(WMICOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
|
||||
{
|
||||
} // end of WMICOL copy constructor
|
||||
#endif // 0
|
||||
|
||||
/***********************************************************************/
|
||||
/* Read the next WMI address elements. */
|
||||
/***********************************************************************/
|
||||
void WMICOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
// Get the value of the Name property
|
||||
Res = Tdbp->ClsObj->Get(_bstr_t(Name), 0, &Prop, &Ctype, 0);
|
||||
|
||||
switch (Prop.vt) {
|
||||
case VT_EMPTY:
|
||||
case VT_NULL:
|
||||
case VT_VOID:
|
||||
Value->Reset();
|
||||
break;
|
||||
case VT_BSTR:
|
||||
Value->SetValue_psz(_com_util::ConvertBSTRToString(Prop.bstrVal));
|
||||
break;
|
||||
case VT_I4:
|
||||
case VT_UI4:
|
||||
Value->SetValue(Prop.lVal);
|
||||
break;
|
||||
case VT_I2:
|
||||
case VT_UI2:
|
||||
Value->SetValue(Prop.iVal);
|
||||
break;
|
||||
case VT_INT:
|
||||
case VT_UINT:
|
||||
Value->SetValue((int)Prop.intVal);
|
||||
break;
|
||||
case VT_BOOL:
|
||||
Value->SetValue(((int)Prop.boolVal) ? 1 : 0);
|
||||
break;
|
||||
case VT_R8:
|
||||
Value->SetValue(Prop.dblVal);
|
||||
break;
|
||||
case VT_R4:
|
||||
Value->SetValue((double)Prop.fltVal);
|
||||
break;
|
||||
case VT_DATE:
|
||||
switch (Value->GetType()) {
|
||||
case TYPE_DATE:
|
||||
{SYSTEMTIME stm;
|
||||
struct tm ptm;
|
||||
int rc = VariantTimeToSystemTime(Prop.date, &stm);
|
||||
|
||||
ptm.tm_year = stm.wYear;
|
||||
ptm.tm_mon = stm.wMonth;
|
||||
ptm.tm_mday = stm.wDay;
|
||||
ptm.tm_hour = stm.wHour;
|
||||
ptm.tm_min = stm.wMinute;
|
||||
ptm.tm_sec = stm.wSecond;
|
||||
((DTVAL*)Value)->MakeTime(&ptm);
|
||||
}break;
|
||||
case TYPE_STRING:
|
||||
{SYSTEMTIME stm;
|
||||
char buf[24];
|
||||
int rc = VariantTimeToSystemTime(Prop.date, &stm);
|
||||
|
||||
sprintf(buf, "%02d/%02d/%d %02d:%02d:%02d",
|
||||
stm.wDay, stm.wMonth, stm.wYear,
|
||||
stm.wHour, stm.wMinute, stm.wSecond);
|
||||
Value->SetValue_psz(buf);
|
||||
}break;
|
||||
default:
|
||||
Value->SetValue((double)Prop.fltVal);
|
||||
} // endswitch Type
|
||||
|
||||
break;
|
||||
default:
|
||||
// This will reset numeric column value
|
||||
Value->SetValue_psz("Type not supported");
|
||||
break;
|
||||
} // endswitch vt
|
||||
|
||||
VariantClear(&Prop);
|
||||
} // end of ReadColumn
|
||||
|
||||
/* ---------------------------TDBWCL class --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Implementation of the TDBWCL class. */
|
||||
/***********************************************************************/
|
||||
TDBWCL::TDBWCL(PWMIDEF tdp) : TDBASE(tdp)
|
||||
{
|
||||
Svc = NULL;
|
||||
ClsObj = NULL;
|
||||
Propname = NULL;
|
||||
Nspace = tdp->Nspace;
|
||||
Wclass = tdp->Wclass;
|
||||
Init = false;
|
||||
Done = false;
|
||||
Res = 0;
|
||||
N = -1;
|
||||
Lng = 0;
|
||||
Typ = 0;
|
||||
Prec = 0;
|
||||
} // end of TDBWCL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Allocate WCL column description block. */
|
||||
/***********************************************************************/
|
||||
PCOL TDBWCL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||||
{
|
||||
PWCLCOL colp;
|
||||
|
||||
colp = (PWCLCOL)new(g) WCLCOL(cdp, this, n);
|
||||
|
||||
if (cprec) {
|
||||
colp->SetNext(cprec->GetNext());
|
||||
cprec->SetNext(colp);
|
||||
} else {
|
||||
colp->SetNext(Columns);
|
||||
Columns = colp;
|
||||
} // endif cprec
|
||||
|
||||
if (!colp->Flag) {
|
||||
if (!stricmp(colp->Name, "Column_Name"))
|
||||
colp->Flag = 1;
|
||||
else if (!stricmp(colp->Name, "Data_Type"))
|
||||
colp->Flag = 2;
|
||||
else if (!stricmp(colp->Name, "Type_Name"))
|
||||
colp->Flag = 3;
|
||||
else if (!stricmp(colp->Name, "Precision"))
|
||||
colp->Flag = 4;
|
||||
else if (!stricmp(colp->Name, "Length"))
|
||||
colp->Flag = 5;
|
||||
else if (!stricmp(colp->Name, "Scale"))
|
||||
colp->Flag = 6;
|
||||
|
||||
} // endif Flag
|
||||
|
||||
return colp;
|
||||
} // end of MakeCol
|
||||
|
||||
/***********************************************************************/
|
||||
/* Initialize: Initialize WMI operations. */
|
||||
/***********************************************************************/
|
||||
bool TDBWCL::Initialize(PGLOBAL g)
|
||||
{
|
||||
if (Init)
|
||||
return false;
|
||||
|
||||
// Initialize COM.
|
||||
Res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "Failed to initialize COM library. "
|
||||
"Error code = %p", Res);
|
||||
return true; // Program has failed.
|
||||
} // endif Res
|
||||
|
||||
// Obtain the initial locator to Windows Management
|
||||
// on a particular host computer.
|
||||
IWbemLocator *loc; // Initial Windows Management locator
|
||||
|
||||
Res = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
|
||||
IID_IWbemLocator, (LPVOID*) &loc);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "Failed to create Locator. "
|
||||
"Error code = %p", Res);
|
||||
CoUninitialize();
|
||||
return true; // Program has failed.
|
||||
} // endif Res
|
||||
|
||||
// Connect to the specified namespace with the
|
||||
// current user and obtain pointer to Svc
|
||||
// to make IWbemServices calls.
|
||||
Res = loc->ConnectServer(_bstr_t(Nspace),
|
||||
NULL, NULL,0, NULL, 0, 0, &Svc);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "Could not connect. Error code = %p", Res);
|
||||
loc->Release();
|
||||
CoUninitialize();
|
||||
return true; // Program has failed.
|
||||
} // endif hres
|
||||
|
||||
loc->Release(); // Not used anymore
|
||||
|
||||
// Perform a full class object retrieval
|
||||
Res = Svc->GetObject(bstr_t(Wclass), 0, 0, &ClsObj, 0);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "failed GetObject %s in %s\n", Wclass, Nspace);
|
||||
Svc->Release();
|
||||
Svc = NULL; // MUST be set to NULL (why?)
|
||||
return true;
|
||||
} // endif res
|
||||
|
||||
Init = true;
|
||||
return false;
|
||||
} // end of Initialize
|
||||
|
||||
/***********************************************************************/
|
||||
/* WCL: Get the number of properties. */
|
||||
/***********************************************************************/
|
||||
int TDBWCL::GetMaxSize(PGLOBAL g)
|
||||
{
|
||||
if (MaxSize < 0) {
|
||||
VARIANT val;
|
||||
|
||||
if (Initialize(g))
|
||||
return -1;
|
||||
|
||||
Res = ClsObj->Get(bstr_t("__Property_Count"), 0, &val, NULL, NULL);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "failed Get(Property_Count) res=%d\n", Res);
|
||||
return -1;
|
||||
} // endif Res
|
||||
|
||||
MaxSize = val.lVal;
|
||||
} // endif MaxSize
|
||||
|
||||
return MaxSize;
|
||||
} // end of GetMaxSize
|
||||
|
||||
/***********************************************************************/
|
||||
/* WCL Access Method opening routine. */
|
||||
/***********************************************************************/
|
||||
bool TDBWCL::OpenDB(PGLOBAL g)
|
||||
{
|
||||
if (Use == USE_OPEN) {
|
||||
/*******************************************************************/
|
||||
/* Table already open. */
|
||||
/*******************************************************************/
|
||||
ClsObj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
|
||||
N = 0;
|
||||
return false;
|
||||
} // endif use
|
||||
|
||||
if (Mode != MODE_READ) {
|
||||
/*******************************************************************/
|
||||
/* WMI tables cannot be modified. */
|
||||
/*******************************************************************/
|
||||
strcpy(g->Message, "WCL tables are read only");
|
||||
return true;
|
||||
} // endif Mode
|
||||
|
||||
/*********************************************************************/
|
||||
/* Initialize the WMI processing. */
|
||||
/*********************************************************************/
|
||||
if (Initialize(g))
|
||||
return true;
|
||||
|
||||
Res = ClsObj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "failed BeginEnumeration hr=%d\n", Res);
|
||||
return NULL;
|
||||
} // endif hr
|
||||
|
||||
return false;
|
||||
} // end of OpenDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base read routine for WCL access method. */
|
||||
/***********************************************************************/
|
||||
int TDBWCL::ReadDB(PGLOBAL g)
|
||||
{
|
||||
VARIANT val;
|
||||
CIMTYPE type;
|
||||
|
||||
Res = ClsObj->Next(0, &Propname, &val, &type, NULL);
|
||||
|
||||
if (FAILED(Res)) {
|
||||
sprintf(g->Message, "failed getting Next hr=%d\n", Res);
|
||||
return RC_FX;
|
||||
} else if (Res == WBEM_S_NO_MORE_DATA) {
|
||||
VariantClear(&val);
|
||||
return RC_EF;
|
||||
} // endif res
|
||||
|
||||
Prec = 0;
|
||||
|
||||
switch (type) {
|
||||
case CIM_STRING:
|
||||
Typ = TYPE_STRING;
|
||||
Lng = 255;
|
||||
Prec = 1; // Case insensitive
|
||||
break;
|
||||
case CIM_SINT32:
|
||||
case CIM_UINT32:
|
||||
case CIM_BOOLEAN:
|
||||
Typ = TYPE_INT;
|
||||
Lng = 9;
|
||||
break;
|
||||
case CIM_SINT8:
|
||||
case CIM_UINT8:
|
||||
case CIM_SINT16:
|
||||
case CIM_UINT16:
|
||||
Typ = TYPE_SHORT;
|
||||
Lng = 6;
|
||||
break;
|
||||
case CIM_REAL64:
|
||||
case CIM_REAL32:
|
||||
Prec = 2;
|
||||
case CIM_SINT64:
|
||||
case CIM_UINT64:
|
||||
Typ = TYPE_FLOAT;
|
||||
Lng = 15;
|
||||
break;
|
||||
case CIM_DATETIME:
|
||||
Typ = TYPE_DATE;
|
||||
Lng = 19;
|
||||
break;
|
||||
case CIM_CHAR16:
|
||||
Typ = TYPE_STRING;
|
||||
Lng = 16;
|
||||
break;
|
||||
case CIM_EMPTY:
|
||||
Typ = TYPE_STRING;
|
||||
Lng = 24; // ???
|
||||
break;
|
||||
default:
|
||||
return RC_NF;
|
||||
} // endswitch type
|
||||
|
||||
N++;
|
||||
return RC_OK;
|
||||
} // end of ReadDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* WriteDB: Data Base write routine for WCL access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBWCL::WriteDB(PGLOBAL g)
|
||||
{
|
||||
strcpy(g->Message, "WCL tables are read only");
|
||||
return RC_FX;
|
||||
} // end of WriteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base delete line routine for WCL access methods. */
|
||||
/***********************************************************************/
|
||||
int TDBWCL::DeleteDB(PGLOBAL g, int irc)
|
||||
{
|
||||
strcpy(g->Message, "Delete not enabled for WCL tables");
|
||||
return RC_FX;
|
||||
} // end of DeleteDB
|
||||
|
||||
/***********************************************************************/
|
||||
/* Data Base close routine for WMI access method. */
|
||||
/***********************************************************************/
|
||||
void TDBWCL::CloseDB(PGLOBAL g)
|
||||
{
|
||||
// Cleanup
|
||||
if (ClsObj)
|
||||
ClsObj->Release();
|
||||
|
||||
if (Svc)
|
||||
Svc->Release();
|
||||
|
||||
CoUninitialize();
|
||||
} // end of CloseDB
|
||||
|
||||
// ------------------------ WCLCOL functions ----------------------------
|
||||
|
||||
/***********************************************************************/
|
||||
/* WCLCOL public constructor. */
|
||||
/***********************************************************************/
|
||||
WCLCOL::WCLCOL(PCOLDEF cdp, PTDB tdbp, int n)
|
||||
: COLBLK(cdp, tdbp, n)
|
||||
{
|
||||
Tdbp = (PTDBWCL)tdbp;
|
||||
Flag = cdp->GetOffset();
|
||||
Res = 0;
|
||||
} // end of WMICOL constructor
|
||||
|
||||
/***********************************************************************/
|
||||
/* Read the next WCL elements. */
|
||||
/***********************************************************************/
|
||||
void WCLCOL::ReadColumn(PGLOBAL g)
|
||||
{
|
||||
// Get the value of the Name property
|
||||
switch (Flag) {
|
||||
case 1:
|
||||
Value->SetValue_psz(_com_util::ConvertBSTRToString(Tdbp->Propname));
|
||||
break;
|
||||
case 2:
|
||||
Value->SetValue(Tdbp->Typ);
|
||||
break;
|
||||
case 3:
|
||||
Value->SetValue_psz(GetTypeName(Tdbp->Typ));
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
Value->SetValue(Tdbp->Lng);
|
||||
break;
|
||||
case 6:
|
||||
Value->SetValue(Tdbp->Prec);
|
||||
break;
|
||||
default:
|
||||
Value->Reset();
|
||||
} // endswitch Flag
|
||||
|
||||
} // end of ReadColumn
|
||||
191
storage/connect/tabwmi.h
Normal file
191
storage/connect/tabwmi.h
Normal file
@@ -0,0 +1,191 @@
|
||||
// TABWMI.H Olivier Bertrand 2012
|
||||
// WMI: Virtual table to Get WMI information
|
||||
#define _WIN32_DCOM
|
||||
#include <wbemidl.h>
|
||||
# pragma comment(lib, "wbemuuid.lib")
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
#include <comdef.h>
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definitions. */
|
||||
/***********************************************************************/
|
||||
typedef class WMIDEF *PWMIDEF;
|
||||
typedef class TDBWMI *PTDBWMI;
|
||||
typedef class WMICOL *PWMICOL;
|
||||
typedef class TDBWCL *PTDBWCL;
|
||||
typedef class WCLCOL *PWCLCOL;
|
||||
|
||||
/* -------------------------- WMI classes ---------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* WMI: Virtual table to get the WMI information. */
|
||||
/***********************************************************************/
|
||||
class WMIDEF : public TABDEF { /* Logical table description */
|
||||
friend class TDBWMI;
|
||||
friend class TDBWCL;
|
||||
public:
|
||||
// Constructor
|
||||
WMIDEF(void)
|
||||
{Pseudo = 3; Nspace = NULL; Wclass = NULL; Ems = 0; Info = false;}
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "WMI";}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
virtual bool DeleteTableFile(PGLOBAL g) {return true;}
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *Nspace;
|
||||
char *Wclass;
|
||||
int Ems;
|
||||
bool Info;
|
||||
}; // end of WMIDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the WMI table. */
|
||||
/***********************************************************************/
|
||||
class TDBWMI : public TDBASE {
|
||||
friend class WMICOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBWMI(PWMIDEF tdp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_WMI;}
|
||||
|
||||
// Methods
|
||||
virtual int GetRecpos(void);
|
||||
virtual int GetProgCur(void) {return N;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false) {return N + 1;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Specific routines
|
||||
bool Initialize(PGLOBAL g);
|
||||
char *MakeWQL(PGLOBAL g);
|
||||
void DoubleSlash(PGLOBAL g);
|
||||
bool GetWMIInfo(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
IWbemServices *Svc; // IWbemServices pointer
|
||||
IEnumWbemClassObject *Enumerator;
|
||||
IWbemClassObject *ClsObj;
|
||||
char *Nspace; // Namespace
|
||||
char *Wclass; // Class name
|
||||
char *ObjPath; // Used for direct access
|
||||
char *Kvp; // Itou
|
||||
int Ems; // Estimated max size
|
||||
PCOL Kcol; // Key column
|
||||
HRESULT Res;
|
||||
PVBLK Vbp;
|
||||
bool Init;
|
||||
bool Done;
|
||||
ULONG Rc;
|
||||
int N; // Row number
|
||||
}; // end of class TDBWMI
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class WMICOL: WMI Address column. */
|
||||
/***********************************************************************/
|
||||
class WMICOL : public COLBLK {
|
||||
friend class TDBWMI;
|
||||
public:
|
||||
// Constructors
|
||||
WMICOL(PCOLDEF cdp, PTDB tdbp, int n);
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_WMI;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
WMICOL(void) {} // Default constructor not to be used
|
||||
|
||||
// Members
|
||||
PTDBWMI Tdbp; // Points to WMI table block
|
||||
VARIANT Prop; // Property value
|
||||
CIMTYPE Ctype; // CIM Type
|
||||
HRESULT Res;
|
||||
}; // end of class WMICOL
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the WCL table. */
|
||||
/***********************************************************************/
|
||||
class TDBWCL : public TDBASE {
|
||||
friend class WCLCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBWCL(PWMIDEF tdp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_WMI;}
|
||||
|
||||
// Methods
|
||||
virtual int GetRecpos(void) {return N;}
|
||||
virtual int GetProgCur(void) {return N;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false) {return N + 1;}
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Specific routines
|
||||
bool Initialize(PGLOBAL g);
|
||||
|
||||
// Members
|
||||
IWbemServices *Svc; // IWbemServices pointer
|
||||
IWbemClassObject *ClsObj;
|
||||
BSTR Propname;
|
||||
char *Nspace; // Namespace
|
||||
char *Wclass; // Class name
|
||||
HRESULT Res;
|
||||
bool Init;
|
||||
bool Done;
|
||||
int N; // Row number
|
||||
int Lng;
|
||||
int Typ;
|
||||
int Prec;
|
||||
}; // end of class TDBWCL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class WMICOL: WMI Address column. */
|
||||
/***********************************************************************/
|
||||
class WCLCOL : public COLBLK {
|
||||
friend class TDBWCL;
|
||||
public:
|
||||
// Constructors
|
||||
WCLCOL(PCOLDEF cdp, PTDB tdbp, int n);
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_WMI;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
WCLCOL(void) {} // Default constructor not to be used
|
||||
|
||||
// Members
|
||||
PTDBWCL Tdbp; // Points to WMI table block
|
||||
HRESULT Res;
|
||||
int Flag;
|
||||
}; // end of class WCLCOL
|
||||
1709
storage/connect/tabxml.cpp
Normal file
1709
storage/connect/tabxml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
246
storage/connect/tabxml.h
Normal file
246
storage/connect/tabxml.h
Normal file
@@ -0,0 +1,246 @@
|
||||
|
||||
/*************** Tabxml H Declares Source Code File (.H) ***************/
|
||||
/* Name: TABXML.H Version 1.6 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2007-2013 */
|
||||
/* */
|
||||
/* This file contains the XML table classes declares. */
|
||||
/***********************************************************************/
|
||||
#define TYPE_AM_XML (AMT)127
|
||||
|
||||
typedef class XMLDEF *PXMLDEF;
|
||||
typedef class TDBXML *PTDBXML;
|
||||
typedef class XMLCOL *PXMLCOL;
|
||||
|
||||
// These functions are exported from the Extended.dll
|
||||
//PTABDEF __stdcall GetXML(PGLOBAL g, void *memp);
|
||||
|
||||
/* --------------------------- XML classes --------------------------- */
|
||||
|
||||
/***********************************************************************/
|
||||
/* XML table. */
|
||||
/***********************************************************************/
|
||||
class DllExport XMLDEF : public TABDEF { /* Logical table description */
|
||||
friend class TDBXML;
|
||||
public:
|
||||
// Constructor
|
||||
XMLDEF(void);
|
||||
|
||||
// Implementation
|
||||
virtual const char *GetType(void) {return "XML";}
|
||||
|
||||
// Methods
|
||||
virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
|
||||
virtual PTDB GetTable(PGLOBAL g, MODE m);
|
||||
virtual bool DeleteTableFile(PGLOBAL g);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char *Fn; /* Path/Name of corresponding file */
|
||||
char *Encoding; /* New XML table file encoding */
|
||||
char *Tabname; /* Name of Table node */
|
||||
char *Rowname; /* Name of first level nodes */
|
||||
char *Colname; /* Name of second level nodes */
|
||||
char *Mulnode; /* Name of multiple node */
|
||||
char *XmlDB; /* Name of XML DB node */
|
||||
char *Nslist; /* List of namespaces to register */
|
||||
char *DefNs; /* Dummy name of default namespace */
|
||||
char *Attrib; /* Table node attributes */
|
||||
char *Hdattr; /* Header node attributes */
|
||||
int Coltype; /* Default column type */
|
||||
int Limit; /* Limit of multiple values */
|
||||
int Header; /* n first rows are header rows */
|
||||
bool Xpand; /* Put multiple tags in several rows */
|
||||
bool Usedom; /* True: DOM, False: libxml2 */
|
||||
bool Skipnull; /* True: skip writing null nodes */
|
||||
}; // end of XMLDEF
|
||||
|
||||
#if defined(INCLUDE_TDBXML)
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the class declaration for the simple XML tables. */
|
||||
/***********************************************************************/
|
||||
class DllExport TDBXML : public TDBASE {
|
||||
friend class XMLCOL;
|
||||
friend class XMULCOL;
|
||||
friend class XPOSCOL;
|
||||
public:
|
||||
// Constructor
|
||||
TDBXML(PXMLDEF tdp);
|
||||
TDBXML(PTDBXML tdbp);
|
||||
|
||||
// Implementation
|
||||
virtual AMT GetAmType(void) {return TYPE_AM_XML;}
|
||||
virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBXML(this);}
|
||||
|
||||
// Methods
|
||||
virtual PTDB CopyOne(PTABS t);
|
||||
virtual int GetRecpos(void);
|
||||
virtual int GetProgCur(void) {return N;}
|
||||
virtual PSZ GetFile(PGLOBAL g) {return Xfile;}
|
||||
virtual void SetFile(PGLOBAL g, PSZ fn) {Xfile = fn;}
|
||||
virtual void ResetDB(void) {N = 0;}
|
||||
virtual void ResetSize(void) {MaxSize = -1;}
|
||||
virtual int RowNumber(PGLOBAL g, bool b = false);
|
||||
int LoadTableFile(PGLOBAL g);
|
||||
bool Initialize(PGLOBAL g);
|
||||
bool SetTabNode(PGLOBAL g);
|
||||
void SetNodeAttr(PGLOBAL g, char *attr, PXNODE node);
|
||||
bool CheckRow(PGLOBAL g, bool b);
|
||||
|
||||
// Database routines
|
||||
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
|
||||
virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL colp);
|
||||
//virtual int GetMaxSame(PGLOBAL g) {return (Xpand) ? Limit : 1;}
|
||||
virtual int Cardinality(PGLOBAL g);
|
||||
virtual int GetMaxSize(PGLOBAL g);
|
||||
//virtual bool NeedIndexing(PGLOBAL g);
|
||||
virtual bool OpenDB(PGLOBAL g);
|
||||
virtual int ReadDB(PGLOBAL g);
|
||||
virtual int WriteDB(PGLOBAL g);
|
||||
virtual int DeleteDB(PGLOBAL g, int irc);
|
||||
virtual void CloseDB(PGLOBAL g);
|
||||
virtual int CheckWrite(PGLOBAL g) {Checked = true; return 0;}
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PXDOC Docp;
|
||||
PXNODE Root;
|
||||
PXNODE Curp;
|
||||
PXNODE DBnode;
|
||||
PXNODE TabNode;
|
||||
PXNODE RowNode;
|
||||
PXNODE ColNode;
|
||||
PXLIST Nlist;
|
||||
PXLIST Clist;
|
||||
PFBLOCK To_Xb; // Pointer to XML file block
|
||||
PCOL Colp; // The multiple column
|
||||
bool Changed; // After Update, Insert or Delete
|
||||
bool Checked; // After Update check pass
|
||||
bool NextSame; // Same next row
|
||||
bool Xpand; // Put multiple tags in several rows
|
||||
bool NewRow; // True when inserting a new row
|
||||
bool Hasnod; // True if rows have subnodes
|
||||
bool Write; // True for Insert and Update
|
||||
bool Usedom; // True for DOM, False for libxml2
|
||||
bool Bufdone; // True when column buffers allocated
|
||||
bool Nodedone; // True when column nodes allocated
|
||||
bool Skipnull; // True to skip writing nullnodes
|
||||
bool Void; // True if the file does not exist
|
||||
char *Xfile; // The XML file
|
||||
char *Enc; // New XML table file encoding
|
||||
char *Tabname; // Name of Table node
|
||||
char *Rowname; // Name of first level nodes
|
||||
char *Colname; // Name of second level nodes
|
||||
char *Mulnode; // Name of multiple node
|
||||
char *XmlDB; // Name of XML DB node
|
||||
char *Nslist; // List of namespaces to register
|
||||
char *DefNs; // Dummy name of default namespace
|
||||
char *Attrib; // Table node attribut(s)
|
||||
char *Hdattr; // Header node attribut(s)
|
||||
int Coltype; // Default column type
|
||||
int Limit; // Limit of multiple values
|
||||
int Header; // n first rows are header rows
|
||||
int Nrow; // The table cardinality
|
||||
int Irow; // The current row index
|
||||
int Nsub; // The current subrow index
|
||||
int N; // The current Rowid
|
||||
}; // end of class TDBXML
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class XMLCOL: XDB table access method column descriptor. */
|
||||
/***********************************************************************/
|
||||
class XMLCOL : public COLBLK {
|
||||
public:
|
||||
// Constructors
|
||||
XMLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "XML");
|
||||
XMLCOL(XMLCOL *colp, PTDB tdbp); // Constructor used in copy process
|
||||
|
||||
// Implementation
|
||||
virtual int GetAmType(void) {return TYPE_AM_XML;}
|
||||
virtual void SetTo_Val(PVAL valp) {To_Val = valp;}
|
||||
bool ParseXpath(PGLOBAL g, bool mode);
|
||||
|
||||
// Methods
|
||||
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
bool AllocBuf(PGLOBAL g, bool mode);
|
||||
void AllocNodes(PGLOBAL g, PXDOC dp);
|
||||
|
||||
protected:
|
||||
//xmlNodePtr SelectSingleNode(xmlNodePtr node, char *name);
|
||||
|
||||
// Default constructor not to be used
|
||||
XMLCOL(void) : COLBLK(1) {}
|
||||
|
||||
// Members
|
||||
PXLIST Nl;
|
||||
PXLIST Nlx;
|
||||
PXNODE ColNode;
|
||||
PXNODE ValNode;
|
||||
PXNODE Cxnp;
|
||||
PXNODE Vxnp;
|
||||
PXATTR Vxap;
|
||||
PXATTR AttNode;
|
||||
PTDBXML Tdbp;
|
||||
char *Valbuf; // To the node value buffer
|
||||
char *Xname; // The node or attribute name
|
||||
char* *Nodes; // The intermediate nodes
|
||||
int Type; // 0: Attribute, 1: Tag, 2: position
|
||||
int Nod; // The number of intermediate nodes
|
||||
int Inod; // Index of multiple node
|
||||
int Rank; // Position
|
||||
bool Mul; // true for multiple column
|
||||
bool Checked; // Was checked while Updating
|
||||
int Long; // Buffer length
|
||||
int Nx; // The last read row
|
||||
int Sx; // The last read sub-row
|
||||
PVAL To_Val; // To value used for Update/Insert
|
||||
}; // end of class XMLCOL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Derived class XMLCOLX: used to replace a multiple XMLCOL by the */
|
||||
/* derived class XMULCOL that has specialize read and write functions.*/
|
||||
/* Note: this works only if the members of the derived class are the */
|
||||
/* same than the ones of the original class (NO added members). */
|
||||
/***********************************************************************/
|
||||
class XMLCOLX : public XMLCOL {
|
||||
public:
|
||||
// Fake operator new used to change a filter into a derived filter
|
||||
void * operator new(size_t size, PXMLCOL colp) {return colp;}
|
||||
#if !defined(__BORLANDC__)
|
||||
// Avoid warning C4291 by defining a matching dummy delete operator
|
||||
void operator delete(void *, PXMLCOL) {}
|
||||
#endif
|
||||
}; // end of class XMLCOLX
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class XMULCOL: XML table access method multiple column descriptor. */
|
||||
/***********************************************************************/
|
||||
class XMULCOL : public XMLCOLX {
|
||||
public:
|
||||
// The constructor must restore Value because XOBJECT has a void
|
||||
// constructor called by default that set Value to NULL
|
||||
XMULCOL(PVAL valp) {Value = valp; Mul = true;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
}; // end of class XMULCOL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class XPOSCOL: XML table column accessed by position. */
|
||||
/***********************************************************************/
|
||||
class XPOSCOL : public XMLCOLX {
|
||||
public:
|
||||
// The constructor must restore Value because XOBJECT has a void
|
||||
// constructor called by default that set Value to NULL
|
||||
XPOSCOL(PVAL valp) {Value = valp;}
|
||||
|
||||
// Methods
|
||||
virtual void ReadColumn(PGLOBAL g);
|
||||
virtual void WriteColumn(PGLOBAL g);
|
||||
}; // end of class XPOSCOL
|
||||
|
||||
#endif // INCLUDE_TDBXML
|
||||
155
storage/connect/user_connect.cc
Normal file
155
storage/connect/user_connect.cc
Normal file
@@ -0,0 +1,155 @@
|
||||
/* Copyright (C) Olivier Bertrand 2004 - 2012
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/**
|
||||
@file user_connect.cc
|
||||
|
||||
@brief
|
||||
Implements the user_connect class.
|
||||
|
||||
@details
|
||||
To support multi_threading, each query creates and use a PlugDB "user"
|
||||
that is a connection with its personnal memory allocation.
|
||||
|
||||
@note
|
||||
|
||||
*/
|
||||
|
||||
/****************************************************************************/
|
||||
/* Author: Olivier Bertrand -- bertrandop@gmail.com -- 2004-2012 */
|
||||
/****************************************************************************/
|
||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||
#pragma implementation // gcc: Class implementation
|
||||
#endif
|
||||
|
||||
#define DONT_DEFINE_VOID
|
||||
#define MYSQL_SERVER
|
||||
#include "sql_class.h"
|
||||
#undef OFFSET
|
||||
|
||||
#define NOPARSE
|
||||
#include "osutil.h"
|
||||
#include "global.h"
|
||||
#include "plgdbsem.h"
|
||||
#include "user_connect.h"
|
||||
#include "mycat.h"
|
||||
|
||||
extern "C" char plgxini[];
|
||||
extern int xtrace;
|
||||
|
||||
/****************************************************************************/
|
||||
/* Initialize the user_connect static member. */
|
||||
/****************************************************************************/
|
||||
PCONNECT user_connect::to_users= NULL;
|
||||
|
||||
/****************************************************************************/
|
||||
/* CONNECT functions called externally. */
|
||||
/****************************************************************************/
|
||||
PGLOBAL CntExit(PGLOBAL g);
|
||||
|
||||
/* -------------------------- class user_connect -------------------------- */
|
||||
|
||||
/****************************************************************************/
|
||||
/* Constructor. */
|
||||
/****************************************************************************/
|
||||
user_connect::user_connect(THD *thd, const char *dbn)
|
||||
{
|
||||
thdp= thd;
|
||||
next= NULL;
|
||||
previous= NULL;
|
||||
g= NULL;
|
||||
tabp= NULL;
|
||||
last_query_id= 0;
|
||||
count= 0;
|
||||
|
||||
// Statistics
|
||||
nrd= fnd= nfd= 0;
|
||||
bzero((char*) &tb1, sizeof(struct timeb));
|
||||
bzero((char*) &tb2, sizeof(struct timeb));
|
||||
} // end of user_connect constructor
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* Destructor. */
|
||||
/****************************************************************************/
|
||||
user_connect::~user_connect()
|
||||
{
|
||||
// Terminate CONNECT and Plug-like environment, should return NULL
|
||||
g= CntExit(g);
|
||||
} // end of user_connect destructor
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* Initialization. */
|
||||
/****************************************************************************/
|
||||
bool user_connect::user_init(PHC hc)
|
||||
{
|
||||
// Initialize Plug-like environment
|
||||
PACTIVITY ap= NULL;
|
||||
PDBUSER dup= NULL;
|
||||
|
||||
// Areasize= 64M because of VEC tables. Should be parameterisable
|
||||
g= PlugInit(NULL, 67108864);
|
||||
|
||||
// Check whether the initialization is complete
|
||||
if (!g || !g->Sarea || PlugSubSet(g, g->Sarea, g->Sarea_Size)
|
||||
|| !(dup= PlgMakeUser(g))) {
|
||||
if (g)
|
||||
printf("%s\n", g->Message);
|
||||
|
||||
int rc= PlugExit(g);
|
||||
g= NULL;
|
||||
free(dup);
|
||||
return true;
|
||||
} // endif g->
|
||||
|
||||
dup->Catalog= new MYCAT(hc);
|
||||
|
||||
ap= new ACTIVITY;
|
||||
memset(ap, 0, sizeof(ACTIVITY));
|
||||
strcpy(ap->Ap_Name, "CONNECT");
|
||||
g->Activityp= ap;
|
||||
g->Activityp->Aptr= dup;
|
||||
next= to_users;
|
||||
to_users= this;
|
||||
|
||||
if (next)
|
||||
next->previous= this;
|
||||
|
||||
last_query_id= thdp->query_id;
|
||||
count= 1;
|
||||
return false;
|
||||
} // end of user_init
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* Check whether we begin a new query and if so cleanup the previous one. */
|
||||
/****************************************************************************/
|
||||
bool user_connect::CheckCleanup(void)
|
||||
{
|
||||
if (thdp->query_id > last_query_id) {
|
||||
PlugCleanup(g, true);
|
||||
PlugSubSet(g, g->Sarea, g->Sarea_Size);
|
||||
last_query_id= thdp->query_id;
|
||||
|
||||
if (xtrace)
|
||||
printf("=====> Begin new query %d\n", last_query_id);
|
||||
|
||||
return true;
|
||||
} // endif query_id
|
||||
|
||||
return false;
|
||||
} // end of CheckCleanup
|
||||
|
||||
80
storage/connect/user_connect.h
Normal file
80
storage/connect/user_connect.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* Copyright (C) Olivier Bertrand 2004 - 2011
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/** @file user_connect.h
|
||||
|
||||
@brief
|
||||
Declaration of the user_connect class.
|
||||
|
||||
@note
|
||||
|
||||
@see
|
||||
/sql/handler.h and /storage/connect/user_connect.cc
|
||||
*/
|
||||
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <sys\timeb.h>
|
||||
#else
|
||||
#include <sys/timeb.h>
|
||||
#endif // UBUNTU
|
||||
|
||||
/*****************************************************************************/
|
||||
/* This is the global structure having all CONNECT information. */
|
||||
/*****************************************************************************/
|
||||
//typedef struct _global *PGLOBAL;
|
||||
typedef class user_connect *PCONNECT;
|
||||
typedef class ha_connect *PHC;
|
||||
static int connect_done_func(void *);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* The CONNECT users. There should be one by connected users. */
|
||||
/*****************************************************************************/
|
||||
class user_connect
|
||||
{
|
||||
friend class ha_connect;
|
||||
friend int connect_done_func(void *);
|
||||
public:
|
||||
// Constructor
|
||||
user_connect(THD *thd, const char *dbn);
|
||||
|
||||
// Destructor
|
||||
virtual ~user_connect();
|
||||
|
||||
// Implementation
|
||||
bool user_init(ha_connect *hc);
|
||||
bool CheckCleanup(void);
|
||||
bool CheckQueryID(void) {return thdp->query_id > last_query_id;}
|
||||
bool CheckQuery(query_id_t vid) {return last_query_id > vid;}
|
||||
|
||||
protected:
|
||||
// Members
|
||||
static PCONNECT to_users; // To the chain of users
|
||||
THD *thdp; // To the user thread
|
||||
PCONNECT next; // Next user in chain
|
||||
PCONNECT previous; // Previous user in chain
|
||||
PGLOBAL g; // The common handle to CONNECT
|
||||
//char dbname[32]; // The DBCONNECT database
|
||||
PTDBDOS tabp; // The table used on create
|
||||
query_id_t last_query_id; // the latest user query id
|
||||
int count; // if used by several handlers
|
||||
// Statistics
|
||||
ulong nrd, fnd, nfd;
|
||||
struct timeb tb1, tb2;
|
||||
}; // end of user_connect class definition
|
||||
|
||||
1212
storage/connect/valblk.cpp
Normal file
1212
storage/connect/valblk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
308
storage/connect/valblk.h
Normal file
308
storage/connect/valblk.h
Normal file
@@ -0,0 +1,308 @@
|
||||
/*************** Valblk H Declares Source Code File (.H) ***************/
|
||||
/* Name: VALBLK.H Version 1.6 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||||
/* */
|
||||
/* This file contains the VALBLK and derived classes declares. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/* assert.h is header required when using the assert function. */
|
||||
/* block.h is header containing Block global declarations. */
|
||||
/***********************************************************************/
|
||||
#ifndef __VALBLK__H__
|
||||
#define __VALBLK__H__
|
||||
#include "value.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Utility used to allocate value blocks. */
|
||||
/***********************************************************************/
|
||||
DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int, bool, bool);
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class VALBLK represent a base class for variable blocks. */
|
||||
/***********************************************************************/
|
||||
class VALBLK : public BLOCK {
|
||||
//friend void SemColData(PGLOBAL g, PSEM semp);
|
||||
public:
|
||||
// Constructors
|
||||
VALBLK(void *mp, int type, int nval)
|
||||
{Blkp = mp; Type = type; Nval = nval; Check = true;}
|
||||
|
||||
// Implementation
|
||||
int GetNval(void) {return Nval;}
|
||||
void SetNval(int n) {Nval = n;}
|
||||
void *GetValPointer(void) {return Blkp;}
|
||||
void SetValPointer(void *mp) {Blkp = mp;}
|
||||
int GetType(void) {return Type;}
|
||||
void SetCheck(bool b) {Check = b;}
|
||||
virtual void Init(PGLOBAL g, bool check) = 0;
|
||||
virtual int GetVlen(void) = 0;
|
||||
virtual PSZ GetCharValue(int n);
|
||||
virtual short GetShortValue(int n) = 0;
|
||||
virtual int GetIntValue(int n) = 0;
|
||||
virtual double GetFloatValue(int n) = 0;
|
||||
virtual void ReAlloc(void *mp, int n) {Blkp = mp; Nval = n;}
|
||||
virtual void Reset(int n) = 0;
|
||||
virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0);
|
||||
virtual void SetPrec(int p) {}
|
||||
virtual bool IsCi(void) {return false;}
|
||||
|
||||
// Methods
|
||||
virtual void SetValue(short sval, int n) {assert(false);}
|
||||
virtual void SetValue(int lval, int n) {assert(false);}
|
||||
virtual void SetValue(PSZ sp, int n) {assert(false);}
|
||||
virtual void SetValue(PVAL valp, int n) = 0;
|
||||
virtual void SetMin(PVAL valp, int n) = 0;
|
||||
virtual void SetMax(PVAL valp, int n) = 0;
|
||||
virtual void SetValue(PVBLK pv, int n1, int n2) = 0;
|
||||
virtual void SetValues(PVBLK pv, int i, int n) = 0;
|
||||
virtual void AddMinus1(PVBLK pv, int n1, int n2) {assert(false);}
|
||||
virtual void Move(int i, int j) = 0;
|
||||
virtual int CompVal(PVAL vp, int n) = 0;
|
||||
virtual int CompVal(int i1, int i2) = 0;
|
||||
virtual void *GetValPtr(int n) = 0;
|
||||
virtual void *GetValPtrEx(int n) = 0;
|
||||
virtual int Find(PVAL vp) = 0;
|
||||
virtual int GetMaxLength(void) = 0;
|
||||
bool Locate(PVAL vp, int& i);
|
||||
|
||||
protected:
|
||||
#if defined(_DEBUG) || defined(DEBTRACE)
|
||||
void ChkIndx(int n);
|
||||
void ChkPrm(PVAL v, int n);
|
||||
void ChkTyp(PVAL v);
|
||||
void ChkTyp(PVBLK vb);
|
||||
#endif // _DEBUG) || DEBTRACE
|
||||
|
||||
// Members
|
||||
PGLOBAL Global; // Used for messages and allocation
|
||||
void *Blkp; // To value block
|
||||
int Type; // Type of individual values
|
||||
int Nval; // Max number of values in block
|
||||
bool Check; // If true SetValue types must match
|
||||
}; // end of class VALBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class CHRBLK: represent a block of fixed length strings. */
|
||||
/***********************************************************************/
|
||||
class CHRBLK : public VALBLK {
|
||||
public:
|
||||
// Constructors
|
||||
CHRBLK(void *mp, int size, int len, int prec, bool b);
|
||||
|
||||
// Implementation
|
||||
virtual void Init(PGLOBAL g, bool check);
|
||||
virtual int GetVlen(void) {return Long;}
|
||||
virtual PSZ GetCharValue(int n);
|
||||
virtual short GetShortValue(int n);
|
||||
virtual int GetIntValue(int n);
|
||||
virtual double GetFloatValue(int n);
|
||||
virtual void Reset(int n);
|
||||
virtual void SetPrec(int p) {Ci = (p != 0);}
|
||||
virtual bool IsCi(void) {return Ci;}
|
||||
|
||||
// Methods
|
||||
virtual void SetValue(PSZ sp, int n);
|
||||
virtual void SetValue(PVAL valp, int n);
|
||||
virtual void SetMin(PVAL valp, int n);
|
||||
virtual void SetMax(PVAL valp, int n);
|
||||
virtual void SetValue(PVBLK pv, int n1, int n2);
|
||||
virtual void SetValues(PVBLK pv, int k, int n);
|
||||
virtual void Move(int i, int j);
|
||||
virtual int CompVal(PVAL vp, int n);
|
||||
virtual int CompVal(int i1, int i2);
|
||||
virtual void *GetValPtr(int n);
|
||||
virtual void *GetValPtrEx(int n);
|
||||
virtual int Find(PVAL vp);
|
||||
virtual int GetMaxLength(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
char* const &Chrp; // Pointer to char buffer
|
||||
PSZ Valp; // Used to make a zero ended value
|
||||
bool Blanks; // True for right filling with blanks
|
||||
bool Ci; // True if case insensitive
|
||||
int Long; // Length of each string
|
||||
}; // end of class CHRBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class STRBLK: represent a block of string pointers. */
|
||||
/* Currently this class is used only by the DECODE scalar function */
|
||||
/* and by the MyColumn function to store date formats. */
|
||||
/***********************************************************************/
|
||||
class STRBLK : public VALBLK {
|
||||
public:
|
||||
// Constructors
|
||||
STRBLK(PGLOBAL g, void *mp, int size);
|
||||
|
||||
// Implementation
|
||||
virtual void Init(PGLOBAL g, bool check);
|
||||
virtual int GetVlen(void) {return sizeof(PSZ);}
|
||||
virtual PSZ GetCharValue(int n) {return Strp[n];}
|
||||
virtual short GetShortValue(int n) {return (short)atoi(Strp[n]);}
|
||||
virtual int GetIntValue(int n) {return atol(Strp[n]);}
|
||||
virtual double GetFloatValue(int n) {return atof(Strp[n]);}
|
||||
virtual void Reset(int n) {Strp[n] = NULL;}
|
||||
|
||||
// Methods
|
||||
virtual void SetValue(PSZ sp, int n);
|
||||
virtual void SetValue(PVAL valp, int n);
|
||||
virtual void SetMin(PVAL valp, int n);
|
||||
virtual void SetMax(PVAL valp, int n);
|
||||
virtual void SetValue(PVBLK pv, int n1, int n2);
|
||||
virtual void SetValues(PVBLK pv, int k, int n);
|
||||
virtual void Move(int i, int j);
|
||||
virtual int CompVal(PVAL vp, int n);
|
||||
virtual int CompVal(int i1, int i2);
|
||||
virtual void *GetValPtr(int n);
|
||||
virtual void *GetValPtrEx(int n);
|
||||
virtual int Find(PVAL vp);
|
||||
virtual int GetMaxLength(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PSZ* const &Strp; // Pointer to PSZ buffer
|
||||
}; // end of class STRBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class SHRBLK: represents a block of int integer values. */
|
||||
/***********************************************************************/
|
||||
class SHRBLK : public VALBLK {
|
||||
public:
|
||||
// Constructors
|
||||
SHRBLK(void *mp, int size);
|
||||
|
||||
// Implementation
|
||||
virtual void Init(PGLOBAL g, bool check);
|
||||
virtual int GetVlen(void) {return sizeof(short);}
|
||||
//virtual PSZ GetCharValue(int n);
|
||||
virtual short GetShortValue(int n) {return Shrp[n];}
|
||||
virtual int GetIntValue(int n) {return (int)Shrp[n];}
|
||||
virtual double GetFloatValue(int n) {return (double)Shrp[n];}
|
||||
virtual void Reset(int n) {Shrp[n] = 0;}
|
||||
|
||||
// Methods
|
||||
virtual void SetValue(PSZ sp, int n);
|
||||
virtual void SetValue(short sval, int n) {Shrp[n] = sval;}
|
||||
virtual void SetValue(int lval, int n) {Shrp[n] = (short)lval;}
|
||||
virtual void SetValue(PVAL valp, int n);
|
||||
virtual void SetMin(PVAL valp, int n);
|
||||
virtual void SetMax(PVAL valp, int n);
|
||||
virtual void SetValue(PVBLK pv, int n1, int n2);
|
||||
virtual void SetValues(PVBLK pv, int k, int n);
|
||||
virtual void AddMinus1(PVBLK pv, int n1, int n2);
|
||||
virtual void Move(int i, int j);
|
||||
virtual int CompVal(PVAL vp, int n);
|
||||
virtual int CompVal(int i1, int i2);
|
||||
virtual void *GetValPtr(int n);
|
||||
virtual void *GetValPtrEx(int n);
|
||||
virtual int Find(PVAL vp);
|
||||
virtual int GetMaxLength(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
short* const &Shrp;
|
||||
}; // end of class SHRBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class LNGBLK: represents a block of int integer values. */
|
||||
/***********************************************************************/
|
||||
class LNGBLK : public VALBLK {
|
||||
public:
|
||||
// Constructors
|
||||
LNGBLK(void *mp, int size);
|
||||
|
||||
// Implementation
|
||||
virtual void Init(PGLOBAL g, bool check);
|
||||
virtual int GetVlen(void) {return sizeof(int);}
|
||||
//virtual PSZ GetCharValue(int n);
|
||||
virtual short GetShortValue(int n) {return (short)Lngp[n];}
|
||||
virtual int GetIntValue(int n) {return Lngp[n];}
|
||||
virtual double GetFloatValue(int n) {return (double)Lngp[n];}
|
||||
virtual void Reset(int n) {Lngp[n] = 0;}
|
||||
|
||||
// Methods
|
||||
virtual void SetValue(PSZ sp, int n);
|
||||
virtual void SetValue(short sval, int n) {Lngp[n] = (int)sval;}
|
||||
virtual void SetValue(int lval, int n) {Lngp[n] = lval;}
|
||||
virtual void SetValue(PVAL valp, int n);
|
||||
virtual void SetMin(PVAL valp, int n);
|
||||
virtual void SetMax(PVAL valp, int n);
|
||||
virtual void SetValue(PVBLK pv, int n1, int n2);
|
||||
virtual void SetValues(PVBLK pv, int k, int n);
|
||||
virtual void AddMinus1(PVBLK pv, int n1, int n2);
|
||||
virtual void Move(int i, int j);
|
||||
virtual int CompVal(PVAL vp, int n);
|
||||
virtual int CompVal(int i1, int i2);
|
||||
virtual void *GetValPtr(int n);
|
||||
virtual void *GetValPtrEx(int n);
|
||||
virtual int Find(PVAL vp);
|
||||
virtual int GetMaxLength(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
int* const &Lngp;
|
||||
}; // end of class LNGBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class DATBLK: represents a block of time stamp values. */
|
||||
/***********************************************************************/
|
||||
class DATBLK : public LNGBLK {
|
||||
public:
|
||||
// Constructor
|
||||
DATBLK(void *mp, int size);
|
||||
|
||||
// Implementation
|
||||
virtual bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0);
|
||||
|
||||
// Methods
|
||||
virtual void SetValue(PSZ sp, int n);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PVAL Dvalp; // Date value used to convert string
|
||||
}; // end of class DATBLK
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class DBLBLK: represents a block of double float values. */
|
||||
/***********************************************************************/
|
||||
class DBLBLK : public VALBLK {
|
||||
public:
|
||||
// Constructors
|
||||
DBLBLK(void *mp, int size, int prec);
|
||||
|
||||
// Implementation
|
||||
virtual void Init(PGLOBAL g, bool check);
|
||||
virtual int GetVlen(void) {return sizeof(double);}
|
||||
//virtual PSZ GetCharValue(int n);
|
||||
virtual short GetShortValue(int n) {return (short)Dblp[n];}
|
||||
virtual int GetIntValue(int n) {return (int)Dblp[n];}
|
||||
virtual double GetFloatValue(int n) {return Dblp[n];}
|
||||
virtual void Reset(int n) {Dblp[n] = 0.0;}
|
||||
virtual void SetPrec(int p) {Prec = p;}
|
||||
|
||||
// Methods
|
||||
virtual void SetValue(PSZ sp, int n);
|
||||
virtual void SetValue(PVAL valp, int n);
|
||||
virtual void SetMin(PVAL valp, int n);
|
||||
virtual void SetMax(PVAL valp, int n);
|
||||
virtual void SetValue(PVBLK pv, int n1, int n2);
|
||||
virtual void SetValues(PVBLK pv, int k, int n);
|
||||
virtual void Move(int i, int j);
|
||||
virtual int CompVal(PVAL vp, int n);
|
||||
virtual int CompVal(int i1, int i2);
|
||||
virtual void *GetValPtr(int n);
|
||||
virtual void *GetValPtrEx(int n);
|
||||
virtual int Find(PVAL vp);
|
||||
virtual int GetMaxLength(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
double* const &Dblp;
|
||||
int Prec;
|
||||
}; // end of class DBLBLK
|
||||
|
||||
#endif // __VALBLK__H__
|
||||
|
||||
4099
storage/connect/value.cpp
Normal file
4099
storage/connect/value.cpp
Normal file
File diff suppressed because it is too large
Load Diff
496
storage/connect/value.h
Normal file
496
storage/connect/value.h
Normal file
@@ -0,0 +1,496 @@
|
||||
/**************** Value H Declares Source Code File (.H) ***************/
|
||||
/* Name: VALUE.H Version 1.6 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2001-2012 */
|
||||
/* */
|
||||
/* This file contains the VALUE and derived classes declares. */
|
||||
/***********************************************************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* Include required application header files */
|
||||
/* assert.h is header required when using the assert function. */
|
||||
/* block.h is header containing Block global declarations. */
|
||||
/***********************************************************************/
|
||||
#ifndef __VALUE__H__
|
||||
#define __VALUE__H__
|
||||
#include "assert.h"
|
||||
#include "block.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Types used in some class definitions. */
|
||||
/***********************************************************************/
|
||||
enum CONV {CNV_ANY = 0, /* Convert to any type */
|
||||
CNV_CHAR = 1, /* Convert to character type */
|
||||
CNV_NUM = 2}; /* Convert to numeric type */
|
||||
|
||||
/***********************************************************************/
|
||||
/* Types used in some class definitions. */
|
||||
/***********************************************************************/
|
||||
class CONSTANT; // For friend setting
|
||||
typedef struct _datpar *PDTP; // For DTVAL
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* Utilities used to test types and to allocated values. */
|
||||
/***********************************************************************/
|
||||
int GetPLGType(int);
|
||||
short GetSQLType(int);
|
||||
int GetSQLCType(int);
|
||||
PVAL AllocateValue(PGLOBAL, void *, short);
|
||||
|
||||
// Exported functions
|
||||
DllExport PSZ GetTypeName(int);
|
||||
DllExport int GetTypeSize(int, int);
|
||||
DllExport int TranslateSQLType(int stp, int prec, int& len);
|
||||
DllExport char *GetFormatType(int);
|
||||
DllExport int GetFormatType(char);
|
||||
DllExport int GetDBType(int);
|
||||
DllExport bool IsTypeChar(int type);
|
||||
DllExport bool IsTypeNum(int type);
|
||||
DllExport int ConvertType(int, int, CONV, bool match = false);
|
||||
DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID);
|
||||
DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 2,
|
||||
PSZ dom = NULL, PCATLG cat = NULL);
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class VALUE represents a constant or variable of any valid type. */
|
||||
/***********************************************************************/
|
||||
class DllExport VALUE : public BLOCK {
|
||||
friend class CONSTANT; // The only object allowed to use SetConstFormat
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
// Implementation
|
||||
virtual bool IsTypeNum(void) = 0;
|
||||
virtual bool IsZero(void) = 0;
|
||||
virtual bool IsCi(void) {return false;}
|
||||
virtual void Reset(void) = 0;
|
||||
virtual int GetSize(void) = 0;
|
||||
virtual int GetValLen(void) = 0;
|
||||
virtual int GetValPrec(void) = 0;
|
||||
virtual int GetLength(void) {return 1;}
|
||||
virtual PSZ GetCharValue(void) {assert(false); return NULL;}
|
||||
virtual short GetShortValue(void) {assert(false); return 0;}
|
||||
virtual int GetIntValue(void) = 0;
|
||||
virtual double GetFloatValue(void) = 0;
|
||||
virtual void *GetTo_Val(void) = 0;
|
||||
int GetType(void) {return Type;}
|
||||
int GetClen(void) {return Clen;}
|
||||
void SetGlobal(PGLOBAL g) {Global = g;}
|
||||
|
||||
// Methods
|
||||
virtual bool SetValue_pval(PVAL valp, bool chktype = false) = 0;
|
||||
virtual void SetValue_char(char *p, int n) = 0;
|
||||
virtual void SetValue_psz(PSZ s) = 0;
|
||||
virtual void SetValue_bool(bool b) {assert(false);}
|
||||
virtual void SetValue(short i) {assert(false);}
|
||||
virtual void SetValue(int n) {assert(false);}
|
||||
virtual void SetValue(double f) {assert(false);}
|
||||
virtual void SetValue_pvblk(PVBLK blk, int n) = 0;
|
||||
virtual void SetBinValue(void *p) = 0;
|
||||
virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
|
||||
virtual void GetBinValue(void *buf, int len) = 0;
|
||||
virtual bool IsEqual(PVAL vp, bool chktype) = 0;
|
||||
virtual int CompareValue(PVAL vp) = 0;
|
||||
virtual BYTE TestValue(PVAL vp);
|
||||
virtual void Divide(int cnt) {assert(false);}
|
||||
virtual void StdVar(PVAL vp, int cnt, bool b) {assert(false);}
|
||||
virtual void Add(int lv) {assert(false);}
|
||||
virtual void Add(PVAL vp) {assert(false);}
|
||||
virtual void Add(PVBLK vbp, int i) {assert(false);}
|
||||
virtual void Add(PVBLK vbp, int j, int k) {assert(false);}
|
||||
virtual void Add(PVBLK vbp, int *x, int j, int k) {assert(false);}
|
||||
virtual void AddSquare(PVAL vp) {assert(false);}
|
||||
virtual void AddSquare(PVBLK vbp, int i) {assert(false);}
|
||||
virtual void AddSquare(PVBLK vbp, int j, int k) {assert(false);}
|
||||
virtual void Times(PVAL vp) {assert(false);}
|
||||
virtual void SetMin(PVAL vp) = 0;
|
||||
virtual void SetMin(PVBLK vbp, int i) = 0;
|
||||
virtual void SetMin(PVBLK vbp, int j, int k) = 0;
|
||||
virtual void SetMin(PVBLK vbp, int *x, int j, int k) = 0;
|
||||
virtual void SetMax(PVAL vp) = 0;
|
||||
virtual void SetMax(PVBLK vbp, int i) = 0;
|
||||
virtual void SetMax(PVBLK vbp, int j, int k) = 0;
|
||||
virtual void SetMax(PVBLK vbp, int *x, int j, int k) = 0;
|
||||
virtual char *ShowValue(char *buf, int len = 0) = 0;
|
||||
virtual char *GetCharString(char *p) = 0;
|
||||
virtual char *GetShortString(char *p, int n) {return "#####";}
|
||||
virtual char *GetIntString(char *p, int n) = 0;
|
||||
virtual char *GetFloatString(char *p, int n, int prec) = 0;
|
||||
virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) = 0;
|
||||
virtual int GetTime(PGLOBAL g, PVAL *vp, int np) = 0;
|
||||
virtual bool FormatValue(PVAL vp, char *fmt) = 0;
|
||||
char *ShowTypedValue(PGLOBAL g, char *buf, int typ, int n, int p);
|
||||
protected:
|
||||
virtual bool SetConstFormat(PGLOBAL, FORMAT&) = 0;
|
||||
|
||||
// Constructor used by derived classes
|
||||
VALUE(int type) : Type(type) {}
|
||||
|
||||
// Members
|
||||
PGLOBAL Global; // To reduce arglist
|
||||
//const int Type; // The value type
|
||||
int Type; // The value type
|
||||
int Clen; // Internal value length
|
||||
}; // end of class VALUE
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class STRING: represents zero terminated strings. */
|
||||
/***********************************************************************/
|
||||
class STRING : public VALUE {
|
||||
friend class SFROW;
|
||||
public:
|
||||
// Constructors
|
||||
STRING(PSZ s);
|
||||
STRING(PGLOBAL g, PSZ s, int n, int c = 0);
|
||||
STRING(PGLOBAL g, short i);
|
||||
STRING(PGLOBAL g, int n);
|
||||
STRING(PGLOBAL g, double f);
|
||||
|
||||
// Implementation
|
||||
virtual bool IsTypeNum(void) {return false;}
|
||||
virtual bool IsZero(void) {return (Strp) ? strlen(Strp) == 0 : true;}
|
||||
virtual bool IsCi(void) {return Ci;}
|
||||
virtual void Reset(void) {*Strp = '\0';}
|
||||
virtual int GetValLen(void) {return Len;}
|
||||
virtual int GetValPrec() {return (Ci) ? 1 : 0;}
|
||||
virtual int GetLength(void) {return Len;}
|
||||
virtual int GetSize(void) {return (Strp) ? strlen(Strp) : 0;}
|
||||
virtual PSZ GetCharValue(void) {return Strp;}
|
||||
virtual short GetShortValue(void) {return (short)atoi(Strp);}
|
||||
virtual int GetIntValue(void) {return atol(Strp);}
|
||||
virtual double GetFloatValue(void) {return atof(Strp);}
|
||||
virtual void *GetTo_Val(void) {return Strp;}
|
||||
|
||||
// Methods
|
||||
virtual bool SetValue_pval(PVAL valp, bool chktype);
|
||||
virtual void SetValue_char(char *p, int n);
|
||||
virtual void SetValue_psz(PSZ s);
|
||||
virtual void SetValue_pvblk(PVBLK blk, int n);
|
||||
virtual void SetValue(short i);
|
||||
virtual void SetValue(int n);
|
||||
virtual void SetValue(double f);
|
||||
virtual void SetBinValue(void *p);
|
||||
virtual bool GetBinValue(void *buf, int buflen, bool go);
|
||||
virtual void GetBinValue(void *buf, int len);
|
||||
virtual char *ShowValue(char *buf, int);
|
||||
virtual char *GetCharString(char *p);
|
||||
virtual char *GetShortString(char *p, int n);
|
||||
virtual char *GetIntString(char *p, int n);
|
||||
virtual char *GetFloatString(char *p, int n, int prec = -1);
|
||||
virtual bool IsEqual(PVAL vp, bool chktype);
|
||||
virtual int CompareValue(PVAL vp);
|
||||
virtual BYTE TestValue(PVAL vp);
|
||||
virtual void SetMin(PVAL vp);
|
||||
virtual void SetMin(PVBLK vbp, int i);
|
||||
virtual void SetMin(PVBLK vbp, int j, int k);
|
||||
virtual void SetMin(PVBLK vbp, int *x, int j, int k);
|
||||
virtual void SetMax(PVAL vp);
|
||||
virtual void SetMax(PVBLK vbp, int i);
|
||||
virtual void SetMax(PVBLK vbp, int j, int k);
|
||||
virtual void SetMax(PVBLK vbp, int *x, int j, int k);
|
||||
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
|
||||
virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
|
||||
virtual int GetTime(PGLOBAL g, PVAL *vp, int np);
|
||||
virtual bool FormatValue(PVAL vp, char *fmt);
|
||||
virtual void Print(PGLOBAL g, FILE *, uint);
|
||||
virtual void Print(PGLOBAL g, char *, uint);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
STRING(void) : VALUE(TYPE_ERROR) {}
|
||||
|
||||
// Members
|
||||
PSZ Strp;
|
||||
int Len;
|
||||
bool Ci; // true if case insensitive
|
||||
}; // end of class STRING
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class SHVAL: represents short integer values. */
|
||||
/***********************************************************************/
|
||||
class SHVAL : public VALUE {
|
||||
public:
|
||||
// Constructors
|
||||
SHVAL(PSZ s);
|
||||
SHVAL(short n);
|
||||
SHVAL(int n);
|
||||
SHVAL(double f);
|
||||
|
||||
// Implementation
|
||||
virtual bool IsTypeNum(void) {return true;}
|
||||
virtual bool IsZero(void) {return Sval == 0;}
|
||||
virtual void Reset(void) {Sval = 0;}
|
||||
virtual int GetValLen(void);
|
||||
virtual int GetValPrec() {return 0;}
|
||||
virtual int GetSize(void) {return sizeof(short);}
|
||||
//virtual PSZ GetCharValue(void) {}
|
||||
virtual short GetShortValue(void) {return Sval;}
|
||||
virtual int GetIntValue(void) {return (int)Sval;}
|
||||
virtual double GetFloatValue(void) {return (double)Sval;}
|
||||
virtual void *GetTo_Val(void) {return &Sval;}
|
||||
|
||||
// Methods
|
||||
virtual bool SetValue_pval(PVAL valp, bool chktype);
|
||||
virtual void SetValue_char(char *p, int n);
|
||||
virtual void SetValue_psz(PSZ s);
|
||||
virtual void SetValue_bool(bool b) {Sval = (b) ? 1 : 0;}
|
||||
virtual void SetValue(short i) {Sval = i;}
|
||||
virtual void SetValue(int n) {Sval = (short)n;}
|
||||
virtual void SetValue_pvblk(PVBLK blk, int n);
|
||||
virtual void SetBinValue(void *p);
|
||||
virtual bool GetBinValue(void *buf, int buflen, bool go);
|
||||
virtual void GetBinValue(void *buf, int len);
|
||||
virtual char *ShowValue(char *buf, int);
|
||||
virtual char *GetCharString(char *p);
|
||||
virtual char *GetShortString(char *p, int n);
|
||||
virtual char *GetIntString(char *p, int n);
|
||||
virtual char *GetFloatString(char *p, int n, int prec = -1);
|
||||
virtual bool IsEqual(PVAL vp, bool chktype);
|
||||
virtual int CompareValue(PVAL vp);
|
||||
virtual void Divide(int cnt);
|
||||
virtual void StdVar(PVAL vp, int cnt, bool b);
|
||||
virtual void Add(int lv) {Sval += (short)lv;}
|
||||
virtual void Add(PVAL vp);
|
||||
virtual void Add(PVBLK vbp, int i);
|
||||
virtual void Add(PVBLK vbp, int j, int k);
|
||||
virtual void Add(PVBLK vbp, int *x, int j, int k);
|
||||
virtual void AddSquare(PVAL vp);
|
||||
virtual void AddSquare(PVBLK vbp, int i);
|
||||
virtual void AddSquare(PVBLK vbp, int j, int k);
|
||||
virtual void Times(PVAL vp);
|
||||
virtual void SetMin(PVAL vp);
|
||||
virtual void SetMin(PVBLK vbp, int i);
|
||||
virtual void SetMin(PVBLK vbp, int j, int k);
|
||||
virtual void SetMin(PVBLK vbp, int *x, int j, int k);
|
||||
virtual void SetMax(PVAL vp);
|
||||
virtual void SetMax(PVBLK vbp, int i);
|
||||
virtual void SetMax(PVBLK vbp, int j, int k);
|
||||
virtual void SetMax(PVBLK vbp, int *x, int j, int k);
|
||||
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
|
||||
virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
|
||||
virtual int GetTime(PGLOBAL g, PVAL *vp, int np) {return 0;}
|
||||
virtual bool FormatValue(PVAL vp, char *fmt);
|
||||
virtual void Print(PGLOBAL g, FILE *, uint);
|
||||
virtual void Print(PGLOBAL g, char *, uint);
|
||||
|
||||
protected:
|
||||
short SafeAdd(short n1, short n2);
|
||||
short SafeMult(short n1, short n2);
|
||||
// Default constructor not to be used
|
||||
SHVAL(void) : VALUE(TYPE_ERROR) {}
|
||||
|
||||
// Members
|
||||
short Sval;
|
||||
}; // end of class SHVAL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class INTVAL: represents int integer values. */
|
||||
/***********************************************************************/
|
||||
class DllExport INTVAL : public VALUE {
|
||||
public:
|
||||
// Constructors
|
||||
INTVAL(PSZ s);
|
||||
INTVAL(short i);
|
||||
INTVAL(int n);
|
||||
INTVAL(double f);
|
||||
|
||||
// Implementation
|
||||
virtual bool IsTypeNum(void) {return true;}
|
||||
virtual bool IsZero(void) {return Ival == 0;}
|
||||
virtual void Reset(void) {Ival = 0;}
|
||||
virtual int GetValLen(void);
|
||||
virtual int GetValPrec() {return 0;}
|
||||
virtual int GetSize(void) {return sizeof(int);}
|
||||
//virtual PSZ GetCharValue(void) {}
|
||||
virtual short GetShortValue(void) {return (short)Ival;}
|
||||
virtual int GetIntValue(void) {return Ival;}
|
||||
virtual double GetFloatValue(void) {return (double)Ival;}
|
||||
virtual void *GetTo_Val(void) {return &Ival;}
|
||||
|
||||
// Methods
|
||||
virtual bool SetValue_pval(PVAL valp, bool chktype);
|
||||
virtual void SetValue_char(char *p, int n);
|
||||
virtual void SetValue_psz(PSZ s);
|
||||
virtual void SetValue_bool(bool b) {Ival = (b) ? 1 : 0;}
|
||||
virtual void SetValue(short i) {Ival = (int)i;}
|
||||
virtual void SetValue(int n) {Ival = n;}
|
||||
virtual void SetValue(double f) {Ival = (int)f;}
|
||||
virtual void SetValue_pvblk(PVBLK blk, int n);
|
||||
virtual void SetBinValue(void *p);
|
||||
virtual bool GetBinValue(void *buf, int buflen, bool go);
|
||||
virtual void GetBinValue(void *buf, int len);
|
||||
virtual char *ShowValue(char *buf, int);
|
||||
virtual char *GetCharString(char *p);
|
||||
virtual char *GetShortString(char *p, int n);
|
||||
virtual char *GetIntString(char *p, int n);
|
||||
virtual char *GetFloatString(char *p, int n, int prec = -1);
|
||||
virtual bool IsEqual(PVAL vp, bool chktype);
|
||||
virtual int CompareValue(PVAL vp);
|
||||
virtual void Divide(int cnt);
|
||||
virtual void StdVar(PVAL vp, int cnt, bool b);
|
||||
virtual void Add(int lv) {Ival += lv;}
|
||||
virtual void Add(PVAL vp);
|
||||
virtual void Add(PVBLK vbp, int i);
|
||||
virtual void Add(PVBLK vbp, int j, int k);
|
||||
virtual void Add(PVBLK vbp, int *x, int j, int k);
|
||||
virtual void AddSquare(PVAL vp);
|
||||
virtual void AddSquare(PVBLK vbp, int i);
|
||||
virtual void AddSquare(PVBLK vbp, int j, int k);
|
||||
virtual void Times(PVAL vp);
|
||||
virtual void SetMin(PVAL vp);
|
||||
virtual void SetMin(PVBLK vbp, int i);
|
||||
virtual void SetMin(PVBLK vbp, int j, int k);
|
||||
virtual void SetMin(PVBLK vbp, int *x, int j, int k);
|
||||
virtual void SetMax(PVAL vp);
|
||||
virtual void SetMax(PVBLK vbp, int i);
|
||||
virtual void SetMax(PVBLK vbp, int j, int k);
|
||||
virtual void SetMax(PVBLK vbp, int *x, int j, int k);
|
||||
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
|
||||
virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
|
||||
virtual int GetTime(PGLOBAL g, PVAL *vp, int np);
|
||||
virtual bool FormatValue(PVAL vp, char *fmt);
|
||||
virtual void Print(PGLOBAL g, FILE *, uint);
|
||||
virtual void Print(PGLOBAL g, char *, uint);
|
||||
|
||||
protected:
|
||||
int SafeAdd(int n1, int n2);
|
||||
int SafeMult(int n1, int n2);
|
||||
// Default constructor not to be used
|
||||
INTVAL(void) : VALUE(TYPE_ERROR) {}
|
||||
|
||||
// Members
|
||||
int Ival;
|
||||
}; // end of class INTVAL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class DTVAL: represents a time stamp value. */
|
||||
/***********************************************************************/
|
||||
class DllExport DTVAL : public INTVAL {
|
||||
public:
|
||||
// Constructors
|
||||
DTVAL(PGLOBAL g, int n, int p, PSZ fmt);
|
||||
DTVAL(PGLOBAL g, PSZ s, int n);
|
||||
DTVAL(PGLOBAL g, short i);
|
||||
DTVAL(PGLOBAL g, int n);
|
||||
DTVAL(PGLOBAL g, double f);
|
||||
|
||||
// Implementation
|
||||
virtual bool SetValue_pval(PVAL valp, bool chktype);
|
||||
virtual void SetValue_char(char *p, int n);
|
||||
virtual void SetValue_psz(PSZ s);
|
||||
virtual void SetValue_pvblk(PVBLK blk, int n);
|
||||
virtual char *GetCharString(char *p);
|
||||
virtual char *ShowValue(char *buf, int);
|
||||
virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
|
||||
virtual int GetTime(PGLOBAL g, PVAL *vp, int np);
|
||||
virtual bool FormatValue(PVAL vp, char *fmt);
|
||||
bool SetFormat(PGLOBAL g, PSZ fmt, int len, int year = 0);
|
||||
bool SetFormat(PGLOBAL g, PVAL valp);
|
||||
bool IsFormatted(void) {return Pdtp != NULL;}
|
||||
bool GetTmMember(OPVAL op, int& mval);
|
||||
bool DateDiff(DTVAL *dtp, OPVAL op, int& tdif);
|
||||
bool MakeTime(struct tm *ptm);
|
||||
static void SetTimeShift(void);
|
||||
static int GetShift(void) {return Shift;}
|
||||
|
||||
// Methods
|
||||
bool MakeDate(PGLOBAL g, int *val, int nval);
|
||||
bool WeekNum(PGLOBAL g, int& nval);
|
||||
|
||||
struct tm *GetGmTime(void);
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
DTVAL(void) : INTVAL() {}
|
||||
|
||||
// Members
|
||||
static int Shift; // Time zone shift in seconds
|
||||
PDTP Pdtp; // To the DATPAR structure
|
||||
char *Sdate; // Utility char buffer
|
||||
//struct tm *DateTime; // Utility (not used yet)
|
||||
int DefYear; // Used by ExtractDate
|
||||
int Len; // Used by CHAR scalar function
|
||||
}; // end of class DTVAL
|
||||
|
||||
/***********************************************************************/
|
||||
/* Class DFVAL: represents double float values. */
|
||||
/***********************************************************************/
|
||||
class DFVAL : public VALUE {
|
||||
public:
|
||||
// Constructors
|
||||
DFVAL(PSZ s, int prec = 2);
|
||||
DFVAL(short i, int prec = 2);
|
||||
DFVAL(int n, int prec = 2);
|
||||
DFVAL(double f, int prec = 2);
|
||||
|
||||
// Implementation
|
||||
virtual bool IsTypeNum(void) {return true;}
|
||||
virtual bool IsZero(void) {return Fval == 0.0;}
|
||||
virtual void Reset(void) {Fval = 0.0;}
|
||||
virtual int GetValLen(void);
|
||||
virtual int GetValPrec() {return Prec;}
|
||||
virtual int GetSize(void) {return sizeof(double);}
|
||||
//virtual PSZ GetCharValue(void) {}
|
||||
virtual short GetShortValue(void) {return (short)Fval;}
|
||||
virtual int GetIntValue(void) {return (int)Fval;}
|
||||
virtual double GetFloatValue(void) {return Fval;}
|
||||
virtual void *GetTo_Val(void) {return &Fval;}
|
||||
void SetPrec(int prec) {Prec = prec;}
|
||||
|
||||
// Methods
|
||||
virtual bool SetValue_pval(PVAL valp, bool chktype);
|
||||
virtual void SetValue_char(char *p, int n);
|
||||
virtual void SetValue_psz(PSZ s);
|
||||
virtual void SetValue(short i) {Fval = (double)i;}
|
||||
virtual void SetValue(int n) {Fval = (double)n;}
|
||||
virtual void SetValue(double f) {Fval = f;}
|
||||
virtual void SetValue_pvblk(PVBLK blk, int n);
|
||||
virtual void SetBinValue(void *p);
|
||||
virtual bool GetBinValue(void *buf, int buflen, bool go);
|
||||
virtual void GetBinValue(void *buf, int len);
|
||||
virtual char *ShowValue(char *buf, int);
|
||||
virtual char *GetCharString(char *p);
|
||||
virtual char *GetShortString(char *p, int n);
|
||||
virtual char *GetIntString(char *p, int n);
|
||||
virtual char *GetFloatString(char *p, int n, int prec = -1);
|
||||
virtual bool IsEqual(PVAL vp, bool chktype);
|
||||
virtual int CompareValue(PVAL vp);
|
||||
virtual void Divide(int cnt);
|
||||
virtual void StdVar(PVAL vp, int cnt, bool b);
|
||||
virtual void Add(PVAL vp);
|
||||
virtual void Add(PVBLK vbp, int i);
|
||||
virtual void Add(PVBLK vbp, int j, int k);
|
||||
virtual void Add(PVBLK vbp, int *x, int j, int k);
|
||||
virtual void AddSquare(PVAL vp);
|
||||
virtual void AddSquare(PVBLK vbp, int i);
|
||||
virtual void AddSquare(PVBLK vbp, int j, int k);
|
||||
virtual void Times(PVAL vp);
|
||||
virtual void SetMin(PVAL vp);
|
||||
virtual void SetMin(PVBLK vbp, int i);
|
||||
virtual void SetMin(PVBLK vbp, int j, int k);
|
||||
virtual void SetMin(PVBLK vbp, int *x, int j, int k);
|
||||
virtual void SetMax(PVAL vp);
|
||||
virtual void SetMax(PVBLK vbp, int i);
|
||||
virtual void SetMax(PVBLK vbp, int j, int k);
|
||||
virtual void SetMax(PVBLK vbp, int *x, int j, int k);
|
||||
virtual bool SetConstFormat(PGLOBAL, FORMAT&);
|
||||
virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
|
||||
virtual int GetTime(PGLOBAL g, PVAL *vp, int np);
|
||||
virtual bool FormatValue(PVAL vp, char *fmt);
|
||||
virtual void Print(PGLOBAL g, FILE *, uint);
|
||||
virtual void Print(PGLOBAL g, char *, uint);
|
||||
|
||||
// Specific function
|
||||
void Divide(double div) {Fval /= div;}
|
||||
|
||||
protected:
|
||||
// Default constructor not to be used
|
||||
DFVAL(void) : VALUE(TYPE_ERROR) {}
|
||||
|
||||
// Members
|
||||
double Fval;
|
||||
int Prec;
|
||||
}; // end of class DFVAL
|
||||
|
||||
#endif
|
||||
3126
storage/connect/xindex.cpp
Normal file
3126
storage/connect/xindex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
487
storage/connect/xindex.h
Normal file
487
storage/connect/xindex.h
Normal file
@@ -0,0 +1,487 @@
|
||||
/*************** Xindex H Declares Source Code File (.H) ***************/
|
||||
/* Name: XINDEX.H Version 3.4 */
|
||||
/* */
|
||||
/* (C) Copyright to the author Olivier BERTRAND 2004 - 2012 */
|
||||
/* */
|
||||
/* This file contains the XINDEX class declares. */
|
||||
/***********************************************************************/
|
||||
#ifndef __XINDEX_H__
|
||||
#define __XINDEX_H__
|
||||
#include "block.h"
|
||||
#include "csort.h" /* Base class declares */
|
||||
#include "xtable.h"
|
||||
#include "valblk.h"
|
||||
|
||||
enum IDT {TYPE_IDX_ERROR = 0, /* Type not defined */
|
||||
TYPE_IDX_INDX = 4, /* Permanent standard index */
|
||||
TYPE_IDX_XROW = 5}; /* Permanent row index */
|
||||
|
||||
typedef struct mem_map *MMP;
|
||||
typedef class INDEXDEF *PIXDEF;
|
||||
typedef class KPARTDEF *PKPDEF;
|
||||
typedef class XINDEX *PXINDEX;
|
||||
typedef class XLOAD *PXLOAD;
|
||||
typedef class KXYCOL *PXCOL;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Structures used when checking for possible indexing */
|
||||
/***********************************************************************/
|
||||
typedef struct index_col *PICOL;
|
||||
typedef struct index_val *PIVAL;
|
||||
typedef struct index_def *PINDX;
|
||||
typedef struct indx_used *PXUSED;
|
||||
|
||||
typedef struct index_val : public BLOCK {
|
||||
index_val(PXOB xp) {Next = NULL; Xval = xp; Kp = NULL;}
|
||||
PIVAL Next; // Next value
|
||||
PXOB Xval; // To value or array
|
||||
int *Kp; // The coordonates in a LSTBLK
|
||||
} IVAL;
|
||||
|
||||
typedef struct index_col : public BLOCK {
|
||||
index_col(PCOL cp)
|
||||
{Next = Nxtgrp = NULL; Colp = cp; Ngrp = N = 0; Vals = NULL;}
|
||||
PICOL Next; // Next column
|
||||
PICOL Nxtgrp; // Next group
|
||||
PCOL Colp; // The column
|
||||
PIVAL Vals; // To column values
|
||||
int Ngrp; // Group number of values
|
||||
int N; // Column number of values
|
||||
} ICOL;
|
||||
|
||||
typedef struct index_def : public BLOCK {
|
||||
index_def(PIXDEF xdp)
|
||||
{Next = NULL; Pxdf = xdp; Cols = NULL; Alloc = false;}
|
||||
PINDX Next;
|
||||
PIXDEF Pxdf;
|
||||
PICOL Cols;
|
||||
bool Alloc; // Must allocate values
|
||||
} INDX;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Index definition block. */
|
||||
/***********************************************************************/
|
||||
class DllExport INDEXDEF : public BLOCK { /* Index description block */
|
||||
friend class PLUGCAT;
|
||||
friend class DOSDEF;
|
||||
friend int PlgMakeIndex(PGLOBAL g, PSZ name, PIXDEF pxdf, bool add);
|
||||
public:
|
||||
// Constructor
|
||||
INDEXDEF(char *name, bool uniq = false, int n = 0);
|
||||
|
||||
// Implementation
|
||||
PIXDEF GetNext(void) {return Next;}
|
||||
void SetNext(PIXDEF pxdf) {Next = pxdf;}
|
||||
PSZ GetName(void) {return (PSZ)Name;}
|
||||
bool IsUnique(void) {return Unique;}
|
||||
bool IsAuto(void) {return AutoInc;}
|
||||
void SetAuto(bool b) {AutoInc = b;}
|
||||
void SetInvalid(bool b) {Invalid = b;}
|
||||
int GetNparts(void) {return Nparts;}
|
||||
int GetID(void) {return ID;}
|
||||
void SetID(int n) {ID = n;}
|
||||
PKPDEF GetToKeyParts(void) {return ToKeyParts;}
|
||||
void SetToKeyParts(PKPDEF kp) {ToKeyParts = kp;}
|
||||
void SetNParts(uint np) {Nparts = (signed)np;}
|
||||
void SetMaxSame(int mxs) {MaxSame = mxs;}
|
||||
void SetMxsame(PXINDEX x);
|
||||
int GetOffset(void) {return Offset;}
|
||||
void SetOffset(int off) {Offset = off;}
|
||||
int GetOffhigh(void) {return Offhigh;}
|
||||
void SetOffhigh(int hof) {Offhigh = hof;}
|
||||
int GetSize(void) {return Size;}
|
||||
void SetSize(int size) {Size = size;}
|
||||
int GetMaxSame(void) {return MaxSame;}
|
||||
bool Define(PGLOBAL g, void *memp, PTABDEF dfp, LPCSTR p);
|
||||
PIXDEF GetIndexOf(PCOL colp, bool hd = false);
|
||||
int IsIndexOf(PCOL colp);
|
||||
PKXBASE CheckIndexing(PGLOBAL g, PTDBDOS tdbp);
|
||||
PINDX CheckAND(PGLOBAL g, PINDX pix1, PINDX pix2);
|
||||
PINDX CheckOR(PGLOBAL g, PINDX pix1, PINDX pix2);
|
||||
PINDX CheckEQ(PGLOBAL g, PTDB tdbp, PXOB *arg, int op, int *kp = NULL);
|
||||
bool TestEQ(PGLOBAL g, PTDB tdbp, PXOB *arg, int op, bool b = false);
|
||||
|
||||
protected:
|
||||
PIXDEF Next; /* To next block */
|
||||
PKPDEF ToKeyParts; /* To the key part definitions */
|
||||
char *Name; /* Index name */
|
||||
bool Unique; /* true if defined as unique */
|
||||
bool Invalid; /* true if marked as Invalid */
|
||||
bool AutoInc; /* true if unique key in auto increment */
|
||||
int Nparts; /* Number of key parts */
|
||||
int ID; /* Index ID number */
|
||||
int Offset; /* Offset in index file */
|
||||
int Offhigh; /* Offset high in big index file */
|
||||
int Size; /* Size of index file */
|
||||
int MaxSame; /* Max number of same values */
|
||||
}; // end of INDEXDEF
|
||||
|
||||
typedef struct indx_used : public BLOCK {
|
||||
indx_used(PTDB tp, PIXDEF xdp, PCOL *cp, int k)
|
||||
{Tname = (char*)tp->GetName(); Xname = xdp->GetName(); Cp = cp; K = k;}
|
||||
PXUSED Next;
|
||||
char *Tname;
|
||||
PSZ Xname;
|
||||
PCOL *Cp;
|
||||
int K;
|
||||
} XUSED;
|
||||
|
||||
/***********************************************************************/
|
||||
/* Index Key Part definition block. */
|
||||
/***********************************************************************/
|
||||
class DllExport KPARTDEF : public BLOCK { /* Index Key Part desc block */
|
||||
friend class INDEXDEF;
|
||||
friend class XINDEX;
|
||||
friend class PLUGCAT;
|
||||
friend class DOSDEF;
|
||||
friend int PlgMakeIndex(PGLOBAL g, PSZ name, PIXDEF pxdf, bool add);
|
||||
public:
|
||||
KPARTDEF(PSZ name, int n); // Constructor
|
||||
|
||||
// Implementation
|
||||
PKPDEF GetNext(void) {return Next;}
|
||||
PSZ GetName(void) {return (PSZ)Name;}
|
||||
int GetNcol(void) {return Ncol;}
|
||||
void SetNext(PKPDEF pkdf) {Next = pkdf;}
|
||||
void SetKlen(int len) {Klen = len;}
|
||||
void SetMxsame(int mxs) {Mxsame = mxs;}
|
||||
|
||||
protected:
|
||||
PKPDEF Next; /* To next block */
|
||||
PSZ Name; /* Field name */
|
||||
int Mxsame; /* Field max same values */
|
||||
int Ncol; /* Field number */
|
||||
int Klen; /* Key length */
|
||||
}; // end of KPARTDEF
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the XDB Index virtual base class declaration. */
|
||||
/***********************************************************************/
|
||||
class DllExport XXBASE : public CSORT, public BLOCK {
|
||||
friend class INDEXDEF;
|
||||
friend class KXYCOL;
|
||||
public:
|
||||
// Constructor
|
||||
XXBASE(PTDBDOS tbxp, bool b);
|
||||
|
||||
// Implementation
|
||||
virtual IDT GetType(void) = 0;
|
||||
virtual void Reset(void) = 0;
|
||||
virtual bool IsMul(void) {return false;}
|
||||
virtual bool IsRandom(void) {return true;}
|
||||
virtual bool HaveSame(void) {return false;}
|
||||
virtual int GetCurPos(void) {return Cur_K;}
|
||||
virtual void SetNval(int n) {assert(n == 1);}
|
||||
virtual void SetOp(OPVAL op) {Op = op;}
|
||||
int GetNdif(void) {return Ndif;}
|
||||
int GetNum_K(void) {return Num_K;}
|
||||
int GetCur_K(void) {return Cur_K;}
|
||||
int GetID(void) {return ID;}
|
||||
void SetID(int id) {ID = id;}
|
||||
void SetNth(int n) {Nth = n;}
|
||||
int *GetPof(void) {return Pof;}
|
||||
int *GetPex(void) {return Pex;}
|
||||
void FreeIndex(void) {PlgDBfree(Index);}
|
||||
|
||||
// Methods
|
||||
virtual void Print(PGLOBAL g, FILE *f, uint n);
|
||||
virtual void Print(PGLOBAL g, char *ps, uint z);
|
||||
virtual bool Init(PGLOBAL g) = 0;
|
||||
virtual int MaxRange(void) {return 1;}
|
||||
virtual int Fetch(PGLOBAL g) = 0;
|
||||
virtual bool NextVal(bool eq) {return true;}
|
||||
virtual int FastFind(int nk) = 0;
|
||||
virtual bool Reorder(PGLOBAL g) {return true;}
|
||||
virtual int Range(PGLOBAL g, int limit = 0, bool incl = true)
|
||||
{return -1;} // Means error
|
||||
virtual int Qcompare(int *, int *) = 0;
|
||||
virtual int GroupSize(void) {return 1;}
|
||||
virtual void Close(void) = 0;
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PTDBASE Tbxp; // Points to calling table TDB
|
||||
PXCOL To_KeyCol; // To KeyCol class list
|
||||
MBLOCK Record; // Record allocation block
|
||||
int* &To_Rec; // We are using ftell, fseek
|
||||
int Cur_K; // Index of current record
|
||||
int Old_K; // Index of last record
|
||||
int Num_K; // Size of Rec_K pointer array
|
||||
int Ndif; // Number of distinct values
|
||||
int Bot; // Bottom of research index
|
||||
int Top; // Top of research index
|
||||
int Inf, Sup; // Used for block optimization
|
||||
OPVAL Op; // Search operator
|
||||
bool Mul; // true if multiple
|
||||
bool Srtd; // true for sorted column
|
||||
int Val_K; // Index of current value
|
||||
int Nblk; // Number of blocks
|
||||
int Sblk; // Block size
|
||||
int Thresh; // Thresh for sorting join indexes
|
||||
int ID; // Index ID number
|
||||
int Nth; // Nth constant to fetch
|
||||
}; // end of class XXBASE
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the standard (multicolumn) Index class declaration. */
|
||||
/***********************************************************************/
|
||||
class DllExport XINDEX : public XXBASE {
|
||||
friend class KXYCOL;
|
||||
public:
|
||||
// Constructor
|
||||
XINDEX(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp,
|
||||
PCOL *cp, PXOB *xp = NULL, int k = 0);
|
||||
|
||||
// Implementation
|
||||
virtual IDT GetType(void) {return TYPE_IDX_INDX;}
|
||||
virtual bool IsMul(void) {return (Nval < Nk) ? true : Mul;}
|
||||
virtual bool HaveSame(void) {return Op == OP_SAME;}
|
||||
virtual int GetCurPos(void) {return (Pex) ? Pex[Cur_K] : Cur_K;}
|
||||
virtual void SetNval(int n) {Nval = n;}
|
||||
int GetMaxSame(void) {return MaxSame;}
|
||||
int GetDefoff(void) {return Defoff;}
|
||||
int GetDefhigh(void) {return Defhigh;}
|
||||
int GetSize(void) {return Size;}
|
||||
|
||||
// Methods
|
||||
virtual void Reset(void);
|
||||
virtual bool Init(PGLOBAL g);
|
||||
virtual int Qcompare(int *, int *);
|
||||
virtual int Fetch(PGLOBAL g);
|
||||
virtual int FastFind(int nk);
|
||||
virtual int GroupSize(void);
|
||||
virtual int Range(PGLOBAL g, int limit = 0, bool incl = true);
|
||||
virtual int MaxRange(void) {return MaxSame;}
|
||||
virtual int ColMaxSame(PXCOL kp);
|
||||
virtual void Close(void);
|
||||
virtual bool NextVal(bool eq);
|
||||
virtual bool Make(PGLOBAL g, PIXDEF sxp);
|
||||
virtual bool SaveIndex(PGLOBAL g, PIXDEF sxp);
|
||||
virtual bool Reorder(PGLOBAL g);
|
||||
bool GetAllSizes(PGLOBAL g, int &ndif, int &numk);
|
||||
|
||||
protected:
|
||||
bool NextValDif(void);
|
||||
|
||||
// Members
|
||||
PIXDEF Xdp; // To index definition
|
||||
PTDBDOS Tdbp; // Points to calling table TDB
|
||||
PXLOAD X; // To XLOAD class
|
||||
PXCOL To_LastCol; // To the last key part block
|
||||
PXCOL To_LastVal; // To the last used key part block
|
||||
PCOL *To_Cols; // To array of indexed columns
|
||||
PXOB *To_Vals; // To array of column values
|
||||
int Nk; // The number of indexed columns
|
||||
int Nval; // The number of used columns
|
||||
int Incr; // Increment of record position
|
||||
int Defoff; // Offset of definition in index file
|
||||
int Defhigh; // High order of offset big value
|
||||
int Size; // Size of definition in index file
|
||||
int MaxSame; // Max number of same values
|
||||
}; // end of class XINDEX
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the fast single column index class declaration. */
|
||||
/***********************************************************************/
|
||||
class DllExport XINDXS : public XINDEX {
|
||||
friend class KXYCOL;
|
||||
public:
|
||||
// Constructor
|
||||
XINDXS(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp = NULL);
|
||||
|
||||
// Implementation
|
||||
virtual void SetNval(int n) {assert(n == 1);}
|
||||
|
||||
// Methods
|
||||
virtual int Qcompare(int *, int *);
|
||||
virtual int Fetch(PGLOBAL g);
|
||||
virtual int FastFind(int nk);
|
||||
virtual bool NextVal(bool eq);
|
||||
virtual int Range(PGLOBAL g, int limit = 0, bool incl = true);
|
||||
virtual int GroupSize(void);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
}; // end of class XINDXS
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the saving/loading index utility base class. */
|
||||
/***********************************************************************/
|
||||
class DllExport XLOAD : public BLOCK {
|
||||
friend class XBIGEX;
|
||||
friend class XBIGXS;
|
||||
public:
|
||||
// Constructor
|
||||
XLOAD(void);
|
||||
|
||||
// Methods
|
||||
virtual bool Open(PGLOBAL g, char *filename, MODE mode) = 0;
|
||||
virtual bool GetOff(int& low, int& high, PIXDEF sxp) = 0;
|
||||
virtual bool Seek(PGLOBAL g, int low, int high, int origin) = 0;
|
||||
virtual bool Read(PGLOBAL g, void *buf, int n, int size) = 0;
|
||||
virtual int Write(PGLOBAL g, void *buf, int n,
|
||||
int size, bool& rc) = 0;
|
||||
virtual void Close(void);
|
||||
#if defined(XMAP)
|
||||
virtual void *FileView(PGLOBAL g, char *fn, int loff,
|
||||
int hoff, int size) = 0;
|
||||
#endif // XMAP
|
||||
|
||||
protected:
|
||||
// Members
|
||||
#if defined(WIN32)
|
||||
HANDLE Hfile; // Handle to file or map
|
||||
#if defined(XMAP)
|
||||
void *ViewBase; // Mapped view base address
|
||||
#endif // XMAP
|
||||
#else // UNIX
|
||||
int Hfile; // Descriptor to file or map
|
||||
#endif // UNIX
|
||||
}; // end of class XLOAD
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the saving/loading indexes utility class. */
|
||||
/***********************************************************************/
|
||||
class DllExport XFILE : public XLOAD {
|
||||
public:
|
||||
// Constructor
|
||||
XFILE(void);
|
||||
|
||||
// Methods
|
||||
virtual bool Open(PGLOBAL g, char *filename, MODE mode);
|
||||
virtual bool GetOff(int& low, int& high, PIXDEF sxp);
|
||||
virtual bool Seek(PGLOBAL g, int low, int high, int origin);
|
||||
virtual bool Read(PGLOBAL g, void *buf, int n, int size);
|
||||
virtual int Write(PGLOBAL g, void *buf, int n, int size, bool& rc);
|
||||
virtual void Close(void);
|
||||
#if defined(XMAP)
|
||||
virtual void *FileView(PGLOBAL g, char *fn, int loff,
|
||||
int hoff, int size);
|
||||
#endif // XMAP
|
||||
|
||||
protected:
|
||||
// Members
|
||||
FILE *Xfile; // Index stream file
|
||||
#if defined(XMAP) && !defined(WIN32)
|
||||
MMP Mmp; // To UNIX mapped index file
|
||||
#endif // XMAP
|
||||
}; // end of class XFILE
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the saving/loading huge indexes utility class. */
|
||||
/***********************************************************************/
|
||||
class DllExport XHUGE : public XLOAD {
|
||||
public:
|
||||
// Constructor
|
||||
XHUGE(void) : XLOAD() {}
|
||||
|
||||
// Methods
|
||||
virtual bool Open(PGLOBAL g, char *filename, MODE mode);
|
||||
virtual bool GetOff(int& low, int& high, PIXDEF sxp);
|
||||
virtual bool Seek(PGLOBAL g, int low, int high, int origin);
|
||||
virtual bool Read(PGLOBAL g, void *buf, int n, int size);
|
||||
virtual int Write(PGLOBAL g, void *buf, int n, int size, bool& rc);
|
||||
#if defined(XMAP)
|
||||
virtual void *FileView(PGLOBAL g, char *fn, int loff,
|
||||
int hoff, int size);
|
||||
#endif // XMAP
|
||||
|
||||
protected:
|
||||
// Members
|
||||
}; // end of class XHUGE
|
||||
|
||||
/***********************************************************************/
|
||||
/* This is the XDB index for columns containing ROWID values. */
|
||||
/***********************************************************************/
|
||||
class DllExport XXROW : public XXBASE {
|
||||
friend class KXYCOL;
|
||||
public:
|
||||
// Constructor
|
||||
XXROW(PTDBDOS tbxp);
|
||||
|
||||
// Implementation
|
||||
virtual IDT GetType(void) {return TYPE_IDX_XROW;}
|
||||
virtual void Reset(void);
|
||||
|
||||
// Methods
|
||||
virtual bool Init(PGLOBAL g);
|
||||
virtual int Fetch(PGLOBAL g);
|
||||
virtual int FastFind(int nk);
|
||||
virtual int MaxRange(void) {return 1;}
|
||||
virtual int Range(PGLOBAL g, int limit = 0, bool incl = true);
|
||||
virtual int Qcompare(int *, int *) {assert(false); return 0;}
|
||||
virtual void Close(void) {}
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PTDBDOS Tdbp; // Points to calling table TDB
|
||||
PVAL Valp; // The value to match in index
|
||||
}; // end of class XXROW
|
||||
|
||||
/***********************************************************************/
|
||||
/* Definition of class KXYCOL used to store values of indexed columns */
|
||||
/***********************************************************************/
|
||||
class KXYCOL: public BLOCK {
|
||||
friend class INDEXDEF;
|
||||
friend class XINDEX;
|
||||
friend class XINDXS;
|
||||
friend class XBIGEX;
|
||||
friend class XBIGXS;
|
||||
friend class TDBDOS;
|
||||
public:
|
||||
// Constructors
|
||||
KXYCOL(PKXBASE kp);
|
||||
|
||||
// Implementation
|
||||
int GetType(void) {return Type;}
|
||||
void SetValue(PCOL colp, int i);
|
||||
|
||||
public:
|
||||
// Methods
|
||||
virtual bool Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln);
|
||||
virtual bool InitFind(PGLOBAL g, PXOB xp);
|
||||
virtual void ReAlloc(PGLOBAL g, int n);
|
||||
virtual void FreeData(void);
|
||||
virtual void FillValue(PVAL valp);
|
||||
virtual int CompVal(int i);
|
||||
void InitBinFind(void *vp);
|
||||
bool MakeBlockArray(PGLOBAL g, int nb, int size);
|
||||
int Compare(int i1, int i2);
|
||||
int CompBval(int i);
|
||||
void Save(int i) {Valp->SetBinValue(Kblp->GetValPtr(i));}
|
||||
void Restore(int j) {Kblp->SetValue(Valp, j);}
|
||||
void Move(int j, int k) {Kblp->Move(k, j);}
|
||||
|
||||
// Specific functions
|
||||
#if defined(XMAP)
|
||||
BYTE *MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m);
|
||||
#endif // XMAP
|
||||
int *MakeOffset(PGLOBAL g, int n);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
PXCOL Next; // To next in the key part list
|
||||
PXCOL Previous; // To previous in the key part list
|
||||
PKXBASE Kxp; // To the INDEX class block
|
||||
PCOL Colp; // To matching object if a column
|
||||
bool IsSorted; // true if column is already sorted
|
||||
bool Asc; // true for ascending sort, false for Desc
|
||||
MBLOCK Keys; // Data array allocation block
|
||||
void* &To_Keys; // To data array
|
||||
PVBLK Kblp; // To Valblock of the data array
|
||||
MBLOCK Bkeys; // Block array allocation block
|
||||
void* &To_Bkeys; // To block array
|
||||
PVBLK Blkp; // To Valblock of the block array
|
||||
PVAL Valp; // Value use by Find
|
||||
int Klen; // Length of character string or num value
|
||||
int Kprec; // The Value(s) precision or CI
|
||||
int Type; // The Value(s) type
|
||||
bool Prefix; // Key on CHAR column prefix
|
||||
MBLOCK Koff; // Offset allocation block
|
||||
CPINT &Kof; // Reference to offset array
|
||||
int Val_K; // Index of current column value
|
||||
int Ndf; // Number of stored values
|
||||
int Mxs; // Max same for this column
|
||||
}; // end of class KXYCOL
|
||||
|
||||
#endif // __XINDEX_H__
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user