summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mnogosearch.org>2013-02-07 13:34:27 +0400
committerAlexander Barkov <bar@mnogosearch.org>2013-02-07 13:34:27 +0400
commit30c4b0ebc24fe0106e146b1f6577a4150e71e258 (patch)
tree592673d8c2f5b418833c3ee5fcfeb9dbf4ba1681
parent60c4cab3bd00621cc03afb1be6de01c8fab0c5f0 (diff)
downloadmariadb-git-30c4b0ebc24fe0106e146b1f6577a4150e71e258.tar.gz
- Fixing TAB to 2 spaces
- Fixing line endings from "\r\n" to "\n"
-rw-r--r--storage/connect/block.h114
-rw-r--r--storage/connect/catalog.h300
-rw-r--r--storage/connect/checklvl.h84
-rw-r--r--storage/connect/colblk.cpp758
-rw-r--r--storage/connect/colblk.h360
-rw-r--r--storage/connect/connect.cc1720
-rw-r--r--storage/connect/connect.h154
-rw-r--r--storage/connect/csort.cpp1924
-rw-r--r--storage/connect/csort.h212
-rw-r--r--storage/connect/domdoc.cpp1198
-rw-r--r--storage/connect/domdoc.h276
-rw-r--r--storage/connect/engmsg.h2026
-rw-r--r--storage/connect/filamap.cpp1376
-rw-r--r--storage/connect/filamap.h228
-rw-r--r--storage/connect/filamdbf.cpp1980
-rw-r--r--storage/connect/filamdbf.h222
-rw-r--r--storage/connect/filamfix.cpp2884
-rw-r--r--storage/connect/filamfix.h180
-rw-r--r--storage/connect/filamtxt.cpp2820
-rw-r--r--storage/connect/filamtxt.h396
-rw-r--r--storage/connect/filamvct.cpp8400
-rw-r--r--storage/connect/filamvct.h498
-rw-r--r--storage/connect/filamzip.cpp1644
-rw-r--r--storage/connect/filamzip.h348
-rw-r--r--storage/connect/fmdlex.c3050
-rw-r--r--storage/connect/frmsg1.h2026
-rw-r--r--storage/connect/frmsg2.h2026
-rw-r--r--storage/connect/global.h502
-rw-r--r--storage/connect/ha_connect.cc7554
-rw-r--r--storage/connect/ha_connect.h786
-rw-r--r--storage/connect/inihandl.c2650
-rw-r--r--storage/connect/libdoc.cpp1502
-rw-r--r--storage/connect/libdoc.h288
-rw-r--r--storage/connect/macutil.cpp636
-rw-r--r--storage/connect/macutil.h72
-rw-r--r--storage/connect/maputil.cpp344
-rw-r--r--storage/connect/maputil.h44
-rw-r--r--storage/connect/messages.h26
-rw-r--r--storage/connect/msgid.h2026
-rw-r--r--storage/connect/mycat.cc1314
-rw-r--r--storage/connect/mycat.h128
-rw-r--r--storage/connect/myconn.cpp1094
-rw-r--r--storage/connect/myconn.h182
-rw-r--r--storage/connect/myutil.cpp386
-rw-r--r--storage/connect/odbconn.cpp4078
-rw-r--r--storage/connect/odbconn.h370
-rw-r--r--storage/connect/osutil.c464
-rw-r--r--storage/connect/osutil.h206
-rw-r--r--storage/connect/plgcnx.h436
-rw-r--r--storage/connect/plgdbsem.h1046
-rw-r--r--storage/connect/plgdbutl.cpp3116
-rw-r--r--storage/connect/plgodbc.h460
-rw-r--r--storage/connect/plgxml.cpp280
-rw-r--r--storage/connect/plgxml.h354
-rw-r--r--storage/connect/plugutil.c1000
-rw-r--r--storage/connect/preparse.h122
-rw-r--r--storage/connect/rcmsg.c418
-rw-r--r--storage/connect/reldef.cpp842
-rw-r--r--storage/connect/reldef.h388
-rw-r--r--storage/connect/resource.h272
-rw-r--r--storage/connect/tabcol.cpp340
-rw-r--r--storage/connect/tabcol.h220
-rw-r--r--storage/connect/tabdos.cpp2456
-rw-r--r--storage/connect/tabdos.h492
-rw-r--r--storage/connect/tabfix.cpp984
-rw-r--r--storage/connect/tabfix.h160
-rw-r--r--storage/connect/tabfmt.cpp2782
-rw-r--r--storage/connect/tabfmt.h328
-rw-r--r--storage/connect/table.cpp854
-rw-r--r--storage/connect/tabmac.cpp916
-rw-r--r--storage/connect/tabmac.h214
-rw-r--r--storage/connect/tabmul.cpp2948
-rw-r--r--storage/connect/tabmul.h440
-rw-r--r--storage/connect/tabmysql.cpp2210
-rw-r--r--storage/connect/tabmysql.h278
-rw-r--r--storage/connect/tabodbc.cpp2158
-rw-r--r--storage/connect/tabodbc.h450
-rw-r--r--storage/connect/tabpivot.cpp2404
-rw-r--r--storage/connect/tabpivot.h482
-rw-r--r--storage/connect/tabsys.cpp1754
-rw-r--r--storage/connect/tabsys.h368
-rw-r--r--storage/connect/tabtbl.cpp1554
-rw-r--r--storage/connect/tabtbl.h324
-rw-r--r--storage/connect/tabvct.cpp1126
-rw-r--r--storage/connect/tabvct.h246
-rw-r--r--storage/connect/tabwmi.cpp2306
-rw-r--r--storage/connect/tabwmi.h382
-rw-r--r--storage/connect/tabxml.cpp3424
-rw-r--r--storage/connect/tabxml.h492
-rw-r--r--storage/connect/user_connect.cc308
-rw-r--r--storage/connect/user_connect.h160
-rw-r--r--storage/connect/valblk.cpp2826
-rw-r--r--storage/connect/valblk.h718
-rw-r--r--storage/connect/value.cpp9650
-rw-r--r--storage/connect/value.h1210
-rw-r--r--storage/connect/xindex.cpp6244
-rw-r--r--storage/connect/xindex.h974
-rw-r--r--storage/connect/xobject.cpp356
-rw-r--r--storage/connect/xobject.h272
-rw-r--r--storage/connect/xtable.h402
100 files changed, 63401 insertions, 63401 deletions
diff --git a/storage/connect/block.h b/storage/connect/block.h
index 7360e442185..963cfa42f32 100644
--- a/storage/connect/block.h
+++ b/storage/connect/block.h
@@ -1,57 +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
+/**************** 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
diff --git a/storage/connect/catalog.h b/storage/connect/catalog.h
index 94a5a124359..c2716035a2f 100644
--- a/storage/connect/catalog.h
+++ b/storage/connect/catalog.h
@@ -1,150 +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
+/*************** 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
diff --git a/storage/connect/checklvl.h b/storage/connect/checklvl.h
index 81eb9d00e7b..5505534678d 100644
--- a/storage/connect/checklvl.h
+++ b/storage/connect/checklvl.h
@@ -1,42 +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_
+/************** 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_
diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp
index c83f959bb10..ceb7dcf92a0 100644
--- a/storage/connect/colblk.cpp
+++ b/storage/connect/colblk.cpp
@@ -1,379 +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
-
+/************* 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
+
diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h
index 84dcb4284af..3e6b9f3ee05 100644
--- a/storage/connect/colblk.h
+++ b/storage/connect/colblk.h
@@ -1,180 +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
+/*************** 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
diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc
index 8395ab65f41..436969c5932 100644
--- a/storage/connect/connect.cc
+++ b/storage/connect/connect.cc
@@ -1,860 +1,860 @@
-/* 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;
-
-/***********************************************************************/
-/* 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
+/* 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;
+
+/***********************************************************************/
+/* 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
diff --git a/storage/connect/connect.h b/storage/connect/connect.h
index 8e5fdbdbe6c..f4f7b3aae33 100644
--- a/storage/connect/connect.h
+++ b/storage/connect/connect.h
@@ -1,77 +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);
+/* 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);
diff --git a/storage/connect/csort.cpp b/storage/connect/csort.cpp
index 70b00accc0b..6a2e7a33702 100644
--- a/storage/connect/csort.cpp
+++ b/storage/connect/csort.cpp
@@ -1,962 +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 --------------------------- */
+/*************** 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 --------------------------- */
diff --git a/storage/connect/csort.h b/storage/connect/csort.h
index 4fd4815277c..702152de43e 100644
--- a/storage/connect/csort.h
+++ b/storage/connect/csort.h
@@ -1,106 +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
-
+/*************** 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
+
diff --git a/storage/connect/domdoc.cpp b/storage/connect/domdoc.cpp
index 96fc5dc57e4..08092d7bca5 100644
--- a/storage/connect/domdoc.cpp
+++ b/storage/connect/domdoc.cpp
@@ -1,599 +1,599 @@
-/******************************************************************/
-/* 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 ??
-#elif defined(MSX4)
-#import "msxml4.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
-#elif defined(MSX6)
-#import "msxml6.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
-#else // MSX4
-#error MSX? is not defined
-#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
+/******************************************************************/
+/* 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 ??
+#elif defined(MSX4)
+#import "msxml4.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
+#elif defined(MSX6)
+#import "msxml6.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
+#else // MSX4
+#error MSX? is not defined
+#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
diff --git a/storage/connect/domdoc.h b/storage/connect/domdoc.h
index 64719b5f728..e025ee13fc6 100644
--- a/storage/connect/domdoc.h
+++ b/storage/connect/domdoc.h
@@ -1,138 +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
+/******************************************************************/
+/* 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
diff --git a/storage/connect/engmsg.h b/storage/connect/engmsg.h
index 0c63cf1ee4e..ccced92261e 100644
--- a/storage/connect/engmsg.h
+++ b/storage/connect/engmsg.h
@@ -1,1013 +1,1013 @@
-#define MSG_ACCESS_VIOLATN "Access violation"
-#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Activity allocation failed"
-#define MSG_ADDVAL_ERROR "Error %d in AddValue"
-#define MSG_ADD_BAD_TYPE "Array add value type mismatch (%s -> %s)"
-#define MSG_ADD_NULL_DOM "Adding string %s to a null domain"
-#define MSG_ADPOS_IN_DICTP "ADPOS to work in User_Dictp"
-#define MSG_AFTER " after: "
-#define MSG_ALG_CHOICE_AUTO "Best algorithm choice is automatic"
-#define MSG_ALG_CHOICE_BAD "Bad algorithm choice value, reset to AUTO"
-#define MSG_ALG_CHOICE_QRY "Using Query algorithm"
-#define MSG_ALG_CURLY_BRK "Algorithm choice depends on outer curly brackets"
-#define MSG_ALLOC_ERROR "Error allocating %s"
-#define MSG_ALL_DELETED "All lines deleted in %.2lf sec"
-#define MSG_ALTER_DB_ERR "Cannot find the DB to alter"
-#define MSG_AMBIG_COL_QUAL "Ambiguous qualifier %s for column %s"
-#define MSG_AMBIG_CORREL "Select %s.* refers more than one table"
-#define MSG_AMBIG_SPEC_COL "Ambiguous special column %s"
-#define MSG_ANSWER_TYPE "Answer of type"
-#define MSG_API_CONF_ERROR "SQL Error: API_CONFORMANCE"
-#define MSG_APPL_ACCESSIBLE "Application %s accessible"
-#define MSG_APPL_ACTIVE "Application %s still active"
-#define MSG_APPL_BAD_SAVE "Application %s may be incorrectly saved"
-#define MSG_APPL_CREATED "Application %s created"
-#define MSG_APPL_IS_ACTIVE "Application already active"
-#define MSG_APPL_NOT_INIT "Application not initialized"
-#define MSG_APPL_NOT_LOADED "Application not loaded"
-#define MSG_APPL_QUIT "Application %s quit"
-#define MSG_APPL_SAVED "Application %s saved"
-#define MSG_APP_STILL_ACTIV "Application of language %s still active (not freed)"
-#define MSG_AREAFILE_NOTFND "Area file not found"
-#define MSG_ARGS_SYNTAX_ERR "?SetArgs syntax error: unexpected %s after %s"
-#define MSG_ARG_ALREADY_SET "Argument %d already set"
-#define MSG_ARG_NOT_AN_ATTR "Argument is not an attribute (wrong pos-type %d)"
-#define MSG_ARG_OUT_CONTEXT "@-type argument used out of context"
-#define MSG_ARG_OUT_RANGE "Phrase argument of value %d is out of range"
-#define MSG_ARG_PTR_NOSEM "Argument of value %d points to a nonterm having no Sem"
-#define MSG_ARG_PTR_NOSEMS "Argument of value %d points to a nonterm having no semantics"
-#define MSG_ARG_REF_LOOP "?Looping argument cross references"
-#define MSG_ARG_TWO_CONST "2nd argument of %s must be a constant"
-#define MSG_ARRAY_ALLOC_ERR "Memory allocation error in ARRAY"
-#define MSG_ARRAY_BNDS_EXCD "Array bounds exceeded"
-#define MSG_ARRAY_ERROR "Error while making array k=%d n=%d"
-#define MSG_ATTRIBUTE_ERROR "Error rule %u attribute %s: "
-#define MSG_ATT_NOT_CASE "Attribute has wrong value %d (not a casevalue)"
-#define MSG_ATT_POSCODE_BIG "Attribute poscode %d is too big (max=%d)"
-#define MSG_AVGLEN_ERROR "avglen should be between %d and %d"
-#define MSG_BAD_AGGREG_FUNC "Unsupported aggregate function %d"
-#define MSG_BAD_ARGTYPES "Argument type invalid for %s"
-#define MSG_BAD_ARGUMENTS "Argument not attached for %s"
-#define MSG_BAD_ARG_NUM "Invalid number of arguments %d"
-#define MSG_BAD_ARG_TYPE "Bad argument type %d"
-#define MSG_BAD_ARRAY_OPER "Arrays must be used with the IN operator"
-#define MSG_BAD_ARRAY_TYPE "Illegal array type %d"
-#define MSG_BAD_ARRAY_VAL "Arrays must have the same number of values"
-#define MSG_BAD_BIN_FMT "Invalid format %c for the %s BIN column"
-#define MSG_BAD_BLK_ESTIM "Number of blocks exceeds estimate"
-#define MSG_BAD_BLK_SIZE "No match in block %d size"
-#define MSG_BAD_BYTE_NUM "bad number of bytes written"
-#define MSG_BAD_BYTE_READ "bad number of bytes read"
-#define MSG_BAD_CARDINALITY "Invalid Cardinality call for multiple table"
-#define MSG_BAD_CASE_SPEC "Wrong case specification %c, enter new one: "
-#define MSG_BAD_CHAR_SPEC "Invalid character specification:'%s'"
-#define MSG_BAD_CHECK_TYPE "Invalid CheckColumn subtype %d"
-#define MSG_BAD_CHECK_VAL "Bad check setting '%s'"
-#define MSG_BAD_COLCRT_ARG "Bad COLCRT argument (type=%hd, domain=%hd)"
-#define MSG_BAD_COLDEF_TYPE "Coldefs: wrong type %d"
-#define MSG_BAD_COLIST_ITEM "Incorrect colist item"
-#define MSG_BAD_COLIST_TYPE "Bad Colist type=%d"
-#define MSG_BAD_COLSIZE "Colsize %d is too small for this database"
-#define MSG_BAD_COL_ENTRY "Invalid entry for column %s"
-#define MSG_BAD_COL_FORMAT "Invalid column format type %d"
-#define MSG_BAD_COL_IN_FILT "Incorrect column in filter"
-#define MSG_BAD_COL_QUALIF "Bad qualifier %s for column %s"
-#define MSG_BAD_COL_TYPE "Invalid type %s for column %s"
-#define MSG_BAD_COL_XPATH "Invalid Xpath in column %s for HTML table %s"
-#define MSG_BAD_COMPARE_OP "Bad compare op %d"
-#define MSG_BAD_CONST_TYPE "Bad constant type=%d"
-#define MSG_BAD_CONV_TYPE "Invalid convert type %d"
-#define MSG_BAD_CORREL "Select %s.* correlation refers no tables"
-#define MSG_BAD_DATETIME "Invalid datetime value"
-#define MSG_BAD_DATE_OPER "Unexpected date operator %d"
-#define MSG_BAD_DBF_FILE "DBF file %s is corrupted"
-#define MSG_BAD_DBF_REC "DBF file %s corrupted at record %d"
-#define MSG_BAD_DBF_TYPE "Unsupported DBF type %c"
-#define MSG_BAD_DEF_ARG "Bad INDEXDEF argument (type=%hd, domain=%hd)"
-#define MSG_BAD_DEF_READ "Unexpected EOF in deferred Read"
-#define MSG_BAD_DEF_TYPE "Invalid column definition type"
-#define MSG_BAD_DIRECTORY "Bad directory %s: %s"
-#define MSG_BAD_DIST_JN_FIL "Invalid Distinct Join filter"
-#define MSG_BAD_DIST_JOIN "Invalid Distinct Join specification"
-#define MSG_BAD_DOM_COL_DEF "Invalid column definitions for a domain"
-#define MSG_BAD_DOM_VALUE "%d is not a valid domain value"
-#define MSG_BAD_EDIT_INIT "Coparm: edition %s not properly initialized"
-#define MSG_BAD_EVAL_TYPE "Bad scalar function eval type=%d"
-#define MSG_BAD_EXEC_MODE "Bad execution mode '%s'"
-#define MSG_BAD_EXP_ARGTYPE "Invalid expression argument type=%d"
-#define MSG_BAD_EXP_OPER "Bad expression operator=%d"
-#define MSG_BAD_FETCH_RC "Unexpected Fetch return code %d"
-#define MSG_BAD_FIELD_FMT "Invalid field format %c for %s"
-#define MSG_BAD_FIELD_RANK "Invalid field rank %d for column %s"
-#define MSG_BAD_FIELD_TYPE "Bad type field %s"
-#define MSG_BAD_FILE_HANDLE "Invalid File Handle: %s"
-#define MSG_BAD_FILE_LIST "Bad Filelist section"
-#define MSG_BAD_FILTER "Bad filter: Opc=%d B_T=%d %d Type=%d %d"
-#define MSG_BAD_FILTER_CONV "Bad filter conversion, B_T=%d,%d"
-#define MSG_BAD_FILTER_LINK "Bad filter link operator %d"
-#define MSG_BAD_FILTER_OP "Invalid filter operator %d"
-#define MSG_BAD_FILTEST_OP "Invalid operator %d %d for FilTest"
-#define MSG_BAD_FLD_FORMAT "Bad format for field %d of %s"
-#define MSG_BAD_FLD_LENGTH "Field %s too long (%s --> %d) line %d of %s"
-#define MSG_BAD_FLOAT_CONV "Invalid convert of float array"
-#define MSG_BAD_FPARM_NEXT "Coparm: FPARM with non-null Next"
-#define MSG_BAD_FREQ_SET "Bad frequency setting for column %s"
-#define MSG_BAD_FUNC_ARG "Funcarg of type %d not implemented"
-#define MSG_BAD_FUNC_ARGTYP "Bad Function argument type=%d"
-#define MSG_BAD_FUNC_MODE "%s: invalid mode %d"
-#define MSG_BAD_GENRE "Genre is invalid"
-#define MSG_BAD_GETVIEW_RET "GetView: invalid return type %d"
-#define MSG_BAD_HANDLE_VAL "Invalid handle value"
-#define MSG_BAD_HAV_FILTER "Having filter found in a Vanilla query"
-#define MSG_BAD_HAV_FILTYPE "Bad filter type for Having Clause"
-#define MSG_BAD_HEADER "File %s: Header corrupted"
-#define MSG_BAD_HEADER_VAL "Invalid header value %d"
-#define MSG_BAD_HEAD_END "Can't read end of header"
-#define MSG_BAD_INDEX_COL "Bad column %s for index %s"
-#define MSG_BAD_INDEX_DEF "Bad index definition for %s"
-#define MSG_BAD_INDEX_FILE "Wrong index file %s"
-#define MSG_BAD_INDEX_PART "Bad index part for %s"
-#define MSG_BAD_INPUT "Incorrect input"
-#define MSG_BAD_IN_ARGTYPE "Bad argument type for IN operator"
-#define MSG_BAD_IN_ENDING "Error: wrong end of IN string"
-#define MSG_BAD_IN_STRING "IN string begins or ends with invalid char %c ... %c"
-#define MSG_BAD_JCOL_TYPE "Logical JCT error: Unmatched column types"
-#define MSG_BAD_JOIN_EXP "Invalid expression used in join"
-#define MSG_BAD_JOIN_FILTER "Improper join filter"
-#define MSG_BAD_JOIN_OP "Bad join operator %d"
-#define MSG_BAD_LANG_SIZE "Wrong Language file size %d"
-#define MSG_BAD_LINEFLD_FMT "Bad format line %d field %d of %s"
-#define MSG_BAD_LINE_LEN "Line length not equal to Lrecl"
-#define MSG_BAD_LIST_TYPE "Invalid list type=%d"
-#define MSG_BAD_LOCALE "Invalid locale %s"
-#define MSG_BAD_LOCDFON_ARG "Bad parameter for LOCDFON"
-#define MSG_BAD_LOCNODE_USE "Unexpected use of LOCNODE"
-#define MSG_BAD_LRECL "Table/File lrecl mismatch (%d,%hd)"
-#define MSG_BAD_MAX_HAVING "MAXTMP value too small for Having"
-#define MSG_BAD_MAX_NREC "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d"
-#define MSG_BAD_MAX_PARAM "Bad parameters for setting max value"
-#define MSG_BAD_MAX_SETTING "Bad max setting '%c'"
-#define MSG_BAD_MERGE_TYPE "Type %d cannot be merged"
-#define MSG_BAD_NODE_TYPE "Bad type %d for table node"
-#define MSG_BAD_OFFSET_VAL "Invalid null offset value for a CSV table"
-#define MSG_BAD_OPEN_MODE "Invalid open mode %d"
-#define MSG_BAD_OPERATOR "Invalid operator %s"
-#define MSG_BAD_ORDER_MODE "Bad ordering mode %c"
-#define MSG_BAD_ORDER_TYPE "Type=%d invalid for order item"
-#define MSG_BAD_OUTER_JOIN "Invalid outer join on child table"
-#define MSG_BAD_PAD_ARGTYP "Bad argument type for Pad or Justify"
-#define MSG_BAD_PARAMETERS "%.8s: Bad parameters"
-#define MSG_BAD_PARAM_TYPE "%.8s: Bad parameter type=%d"
-#define MSG_BAD_PARM_COUNT "Parameter count mismatch"
-#define MSG_BAD_PHASE_NUM "Out of range phrase number %d"
-#define MSG_BAD_PHRASE_NB "out of range phrase number %d rc=%d\n"
-#define MSG_BAD_POS_CODE "Invalid POS code %d"
-#define MSG_BAD_POS_TYPE "Invalid POS code type %d"
-#define MSG_BAD_PROJNUM "Bad projnum %d for column %s"
-#define MSG_BAD_QUERY_OPEN "Query open invalid mode %d"
-#define MSG_BAD_QUERY_TYPE "Invalid query type %d for %s"
-#define MSG_BAD_QUOTE_FIELD "Missing ending quote in %s field %d line %d"
-#define MSG_BAD_READ_NUMBER "Wrong number %d of values read from %s"
-#define MSG_BAD_RECFM "Invalid recfm type %d for DOSCOL"
-#define MSG_BAD_RECFM_VAL "Bad Recfm value %d"
-#define MSG_BAD_RESULT_TYPE "Bad result type %d for %s"
-#define MSG_BAD_RETURN_TYPE "Bad returned type %d"
-#define MSG_BAD_ROW_VALIST "Invalid ROW list of values"
-#define MSG_BAD_ROW_VALNB "Number of values in list mismatch"
-#define MSG_BAD_SCF_ARGTYPE "Argument %d type=%s invalid for %s"
-#define MSG_BAD_SEM_DOMAIN "Invalid domain .%d"
-#define MSG_BAD_SETTINGS "Some settings do not match table type"
-#define MSG_BAD_SET_CASE "Cannot set sensitive an insensitive array"
-#define MSG_BAD_SET_STRING "Invalid SetValue from string"
-#define MSG_BAD_SET_TYPE "Bad set type %hd"
-#define MSG_BAD_SPECIAL_CMD "Ill formed special command"
-#define MSG_BAD_SPECIAL_COL "Bad special column %s"
-#define MSG_BAD_SPEC_COLUMN "Special column invalid for this table type"
-#define MSG_BAD_SQL_PARAM "Invalid SQL parameter for FindColblk"
-#define MSG_BAD_SUBLST_TYPE "Coparm: bad sub-list type %d"
-#define MSG_BAD_SUBSEL_IN_X "Bad sub-select in expression"
-#define MSG_BAD_SUBSEL_TYPE "Bad Sub-Select returned type %d"
-#define MSG_BAD_SUB_RESULT "Undefined Sub-Select function result"
-#define MSG_BAD_SUB_SELECT "Bad sub-select in function argument"
-#define MSG_BAD_TABLE_LINE "Illegal or truncated line '%s' in Tables section"
-#define MSG_BAD_TABLE_LIST "Table %s not found in table list"
-#define MSG_BAD_TABLE_TYPE "Bad type %s for table %s"
-#define MSG_BAD_TEST_TYPE "Array BlockTest type mismatch %s %s"
-#define MSG_BAD_TRIM_ARGTYP "Bad argument type for Trim"
-#define MSG_BAD_TYPE_FOR_IN "Arg type mismatch for IN function"
-#define MSG_BAD_TYPE_FOR_S "Incorrect type %d for %s(%d)"
-#define MSG_BAD_TYPE_LIKE "Bad operand(%d) type=%d for LIKE"
-#define MSG_BAD_UPD_COR "Qualifier %s of column %s not related to the updated table %s"
-#define MSG_BAD_USERBLK_LEN "User block write length error"
-#define MSG_BAD_USETEMP "Bad usetemp setting '%s'"
-#define MSG_BAD_USETEMP_VAL "Bad Usetemp value %d"
-#define MSG_BAD_VALBLK_INDX "Out of range valblock index value"
-#define MSG_BAD_VALBLK_TYPE "Invalid value block type %d"
-#define MSG_BAD_VALNODE "Bad type %d for column %s value node"
-#define MSG_BAD_VALUE_TYPE "Invalid value type %d"
-#define MSG_BAD_VAL_UPDATE "Don't know which %s value to update"
-#define MSG_BAD_VIEW_OPEN "View open invalid mode %d"
-#define MSG_BAD_XMODE_VAL "Bad execution mode %d"
-#define MSG_BAD_XOBJ_TYPE "Bad Xobject type %d"
-#define MSG_BAS_NS_LIST "Invalid namespaces list format"
-#define MSG_BIN_F_TOO_LONG "Value too long for field %s (%d --> %d)"
-#define MSG_BIN_MODE_FAIL "Set binary mode failed: %s"
-#define MSG_BLKTYPLEN_MISM "Non matching block types/lengths in SetValue"
-#define MSG_BLK_IS_NULL "Blk is NULL"
-#define MSG_BLOCK_NO_MATCH "Non matching block"
-#define MSG_BREAKPOINT "Breakpoint"
-#define MSG_BUFF_TOO_SMALL "GetColData: Buffer is too small"
-#define MSG_BUFSIZE_ERROR "Error getting screen buffer size"
-#define MSG_BUILDING_GROUPS "Building groups"
-#define MSG_BUILD_DIST_GRPS "Building groups distinct"
-#define MSG_BUILD_INDEX "Building index %s on %s"
-#define MSG_BXP_NULL "Bxp NULL in PUTFON"
-#define MSG_CANNOT_OPEN "Cannot open %s"
-#define MSG_CD_ONE_STEP "Count Distinct must be processed in one step"
-#define MSG_CD_ORDER_ERROR "Ordering error in Count Distinct"
-#define MSG_CHECKING_ROWS "Checking rows to update"
-#define MSG_CHECK_LEVEL "Checking level reset to %u"
-#define MSG_CHSIZE_ERROR "chsize error: %s"
-#define MSG_CLN_NOT_IN_JOIN "Column C%d not found in join"
-#define MSG_CNTDIS_COL_LOST "Count Distinct column lost"
-#define MSG_COLIST_BAD_TYPE "Invalid Colist element type=%d"
-#define MSG_COLNAM_TOO_LONG "Column name too long"
-#define MSG_COLSEC_TOO_BIG "Column section too big in table %s (%d)"
-#define MSG_COLS_REDUCED " (reduced by Maxcol)"
-#define MSG_COLUMN_ERROR "Column error"
-#define MSG_COLUMN_MISMATCH "Column %s mismatch"
-#define MSG_COLUMN_NOT_KEY "Join column R%d.%s is not a key"
-#define MSG_COL_ALLOC_ERR "Cannot allocate column node"
-#define MSG_COL_ALLOC_ERROR "Memory allocation error for column %d"
-#define MSG_COL_HAS_NO_DEF "Column %s has no definition"
-#define MSG_COL_INVAL_TABLE "Column %s.%s not found in table %s alias %s"
-#define MSG_COL_ISNOT_TABLE "Column %s is not in table %s"
-#define MSG_COL_NB_MISM "Number of columns mismatch"
-#define MSG_COL_NOTIN_GRPBY "Column %s not in Group By list"
-#define MSG_COL_NOTIN_TABLE "Column %s is not in any table"
-#define MSG_COL_NOTIN_UPDT "%s does not belong to the updated table %s"
-#define MSG_COL_NOT_CODED "Column %s is not coded"
-#define MSG_COL_NOT_EXIST "Column %s is not in table %s"
-#define MSG_COL_NOT_FOUND "Column %s does not exist in %s"
-#define MSG_COL_NOT_IN_DB "Column %s of table %s not in DB"
-#define MSG_COL_NOT_IN_JOIN "Column %s not found in join"
-#define MSG_COL_NOT_SORTED "Column %s of table %s is not sorted"
-#define MSG_COL_NUM_MISM "Number of columns mismatch"
-#define MSG_COL_USED_TWICE "Column %s linked twice ???"
-#define MSG_COMPUTE_ERROR "Error in Compute, op=%d"
-#define MSG_COMPUTE_NIY "Compute not implemented for token strings"
-#define MSG_COMPUTING "Computing"
-#define MSG_COMPUTING_DIST "Computing Distinct"
-#define MSG_COMPUTING_FUNC "Computing function(s)"
-#define MSG_COM_ERROR "Com error"
-#define MSG_CONCAT_SUBNODE "Cannot concatenate sub-nodes"
-#define MSG_CONNECTED "Connected"
-#define MSG_CONNECT_CANCEL "Connection cancelled by user"
-#define MSG_CONNECT_ERROR "Error %d connecting to %s"
-#define MSG_CONN_CLOSED "%s(%d) closed"
-#define MSG_CONN_CREATED "Connection %s created"
-#define MSG_CONN_DROPPED "Connection %s dropped"
-#define MSG_CONN_OPEN "%s(%d) open (%s)"
-#define MSG_CONN_SUC_OPEN "%s(%d) successfully open"
-#define MSG_CONTROL_C_EXIT "Control C exit"
-#define MSG_COPY_BAD_PHASE "List copy invalid in phase %d"
-#define MSG_COPY_INV_TYPE "Coparm: type not supported %d"
-#define MSG_CORREL_NO_QRY "Correlated subqueries cannot be of QRY type"
-#define MSG_CREATED_PLUGDB " Created by PlugDB %s "
-#define MSG_CURSOR_SET "Cursor set to %d"
-#define MSG_DATABASE_ACTIVE "Database %s activated"
-#define MSG_DATABASE_LOADED "Database %s loaded"
-#define MSG_DATA_IS_NULL "ExecSpecialCmd: data is NULL"
-#define MSG_DATA_MISALIGN "Datatype misalignment"
-#define MSG_DBASE_FILE "dBASE dbf file: "
-#define MSG_DB_ALREADY_DEF "Database %s already defined"
-#define MSG_DB_ALTERED "Database altered"
-#define MSG_DB_CREATED "Database %s created"
-#define MSG_DB_NOT_SPEC "Database not specified"
-#define MSG_DB_REMOVED "Database %s removed from DB list"
-#define MSG_DB_SORT_ERROR "Error in DB sort"
-#define MSG_DB_STOPPED "Database %s stopped"
-#define MSG_DEBUG_NOT_ACTIV "Debug is not active"
-#define MSG_DEBUG_SET_INV "Invalid Debug set %c"
-#define MSG_DEF_ALLOC_ERROR "Error allocating %s DEF class"
-#define MSG_DELETING_ROWS "Deleting rows"
-#define MSG_DEL_FILE_ERR "Error deleting %s"
-#define MSG_DEL_READ_ERROR "Delete: read error req=%d len=%d"
-#define MSG_DEL_WRITE_ERROR "Delete: write error: %s"
-#define MSG_DEPREC_FLAG "Deprecated option Flag, use Coltype"
-#define MSG_DICTIONARY "Dictionary "
-#define MSG_DIRECT_VARTOK "Direct access of variable token rules not implemented"
-#define MSG_DISCONNECTED "Disonnected"
-#define MSG_DISTINCT_ERROR "More than one DISTINCT functional item"
-#define MSG_DISTINCT_ROWS "Selecting distinct rows"
-#define MSG_DISTINCT_VALUES "Retrieving distinct values"
-#define MSG_DIS_NOHEAD_JOIN "Distinct join on not heading table"
-#define MSG_DLL_LOAD_ERROR "Error %d loading module %s"
-#define MSG_DOMAIN_EMPTY "Domain %s is empty"
-#define MSG_DOMAIN_ERROR "Column %s domain(%s)/value(%s) mismatch"
-#define MSG_DOMAIN_FULL "Domain %s is full (max=%d)"
-#define MSG_DOM_FILE_ERROR "Domain file %s not found"
-#define MSG_DOM_NOT_SUPP "MS-DOM not supported by this version"
-#define MSG_DOM_OPEN_ERROR "Domain open error: %s"
-#define MSG_DOM_READ_ERROR "Domain read error %d: %s"
-#define MSG_DOM_READ_ONLY "Domain table %s is read only"
-#define MSG_DOM_WRITE_ERROR "Domain write error %d: %s"
-#define MSG_DONE "Done, rc=%d"
-#define MSG_DOSALMEM_NOMEM "Memory Allocation failed, not enough memory"
-#define MSG_DROP_DB_ERR "Drop database %s failed"
-#define MSG_DSORT_LOG_ERROR "Logical error in Kindex distinct Sort"
-#define MSG_DUMMY_NO_COLS "Dummy tables must have no columns"
-#define MSG_DUPLICAT_COUNT "Count on more than one column"
-#define MSG_DUP_COL_NAME "Duplicate column name %s"
-#define MSG_DUP_PROJNUM "Duplicated projnum %d for column %s"
-#define MSG_DVAL_NOTIN_LIST "Value %s not found in distinct values list of column %s"
-#define MSG_EMPTY_DOC "Empty document"
-#define MSG_EMPTY_FILE "%s empty file %s: "
-#define MSG_ENDSTR_MISMATCH "No match between end of string and end of node"
-#define MSG_END_OF_DELETE "%d line(s) deleted in %.2lf sec"
-#define MSG_END_OF_INSERT "%d line(s) inserted in %.2lf sec"
-#define MSG_END_OF_QUERY "%d line(s) retrieved in %.2lf sec"
-#define MSG_END_OF_UPDATE "%d line(s) updated in %.2lf sec"
-#define MSG_EOF_AFTER_LINE "EOF after line %d"
-#define MSG_EOF_INDEX_FILE "EOF while reading index file"
-#define MSG_ERASED " and erased"
-#define MSG_ERASE_FAILED " (erase failed)"
-#define MSG_ERROR "Error"
-#define MSG_ERROR_IN_LSK "Error %d in lseek64"
-#define MSG_ERROR_IN_SFP "Error %d in SetFilePointer"
-#define MSG_ERROR_NO_PARM "No parameter (valid only with %.8s.1 and %.8s.5)"
-#define MSG_ERROR_OPENING "Error opening: "
-#define MSG_ERR_NUM_GT_MAX "Error: Numval (%d) greater than Maxnum (%d)"
-#define MSG_ERR_READING_REC "Error reading record %d of %s"
-#define MSG_ERR_RET_RULE "error return, rule=%u"
-#define MSG_ERR_RET_TYPE "error return, type=%d"
-#define MSG_EVAL_EXPIRED "Evaluation version expired"
-#define MSG_EVAL_ONLY "I agree to use this Dll for evaluation purpose only"
-#define MSG_EXECUTING "Executing"
-#define MSG_EXECUTION_ERROR "Execution error"
-#define MSG_EXEC_MODE_IS "Execution mode is %s"
-#define MSG_EXEC_MODE_RESET ". Mode reset to Execute"
-#define MSG_EXEC_MODE_SET "Execution mode set to %s"
-#define MSG_EXIT_EVAL_ERR "Error evaluating Exit"
-#define MSG_EXIT_FROM_LANG "Exit from language %s version %d.%d"
-#define MSG_FAIL_ADD_NODE "Failed to add %s table node"
-#define MSG_FETCHING_DATA "Fetching data"
-#define MSG_FETCHING_ROWS "Fetching rows"
-#define MSG_FETCH_NO_RES "Fetch: No Result Set"
-#define MSG_FIELD_TOO_LONG "Value too long for field %d line %d"
-#define MSG_FILELEN_ERROR "Error in %s for %s"
-#define MSG_FILE_CLOSE_ERR "Error %d occurred closing the file"
-#define MSG_FILE_IS_EMPTY "File %s is empty"
-#define MSG_FILE_MAP_ERR "File mapping error"
-#define MSG_FILE_MAP_ERROR "CreateFileMapping %s error rc=%d"
-#define MSG_FILE_NOT_FOUND "File %s cannot be found"
-#define MSG_FILE_OPEN_YET "File %s already open"
-#define MSG_FILE_UNFOUND "File %s not found"
-#define MSG_FILGRP_NO_TABLE "Missing table %d for a filter group"
-#define MSG_FILTER_ATTACH "Filter passed to Attach"
-#define MSG_FILTER_NO_TABLE "Missing first table for a filter"
-#define MSG_FIND_BAD_TYPE "Array Find type mismatch %s %s"
-#define MSG_FIX_OVFLW_ADD "Fixed Overflow on add"
-#define MSG_FIX_OVFLW_TIMES "Fixed Overflow on times"
-#define MSG_FIX_UNFLW_ADD "Fixed Underflow on add"
-#define MSG_FIX_UNFLW_TIMES "Fixed Underflow on times"
-#define MSG_FLD_TOO_LNG_FOR "Field %d too long for %s line %d of %s"
-#define MSG_FLTST_NO_CORREL "FilTest should be called only for correlated subqueries"
-#define MSG_FLT_BAD_RESULT "Float inexact result"
-#define MSG_FLT_DENORMAL_OP "Float denormal operand"
-#define MSG_FLT_INVALID_OP "Float invalid operation"
-#define MSG_FLT_OVERFLOW "Float overflow"
-#define MSG_FLT_STACK_CHECK "Float stack check"
-#define MSG_FLT_UNDERFLOW "Float underflow"
-#define MSG_FLT_ZERO_DIVIDE "Float divide by zero"
-#define MSG_FMT_WRITE_NIY "Writing %s files is not implemented yet"
-#define MSG_FNC_NOTIN_SLIST "Order aggregate function not in select list"
-#define MSG_FORMAT_ERROR "Formating error"
-#define MSG_FOXPRO_FILE "FoxPro file: "
-#define MSG_FPUTS_ERROR "fputs error: %s"
-#define MSG_FSBPARP_NULL "PUTFON: fsbparp is NULL"
-#define MSG_FSEEK_ERROR "fseek error: %s"
-#define MSG_FSETPOS_ERROR "fseek error for i=%d"
-#define MSG_FTELL_ERROR "ftell error for recd=%d: %s"
-#define MSG_FUNCTION_ERROR "%s error: %d"
-#define MSG_FUNC_ERRNO "Error %d in %s"
-#define MSG_FUNC_ERROR "Error in %s"
-#define MSG_FUNC_ERR_S "%s error: %s"
-#define MSG_FUNC_REF_DEL "Reference to a defined function (rule %d) which has been deleted"
-#define MSG_FWRITE_ERROR "fwrite error: %s"
-#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
-#define MSG_GETFILESIZE_ERR "Error %d in GetFileSize"
-#define MSG_GET_DIST_VALS "Retrieving distinct values from "
-#define MSG_GET_ERROR "Error in %s (column %d)"
-#define MSG_GET_FUNC_ERR "Error getting function %s: %s"
-#define MSG_GET_NAME_ERR "Error getting SYS table names"
-#define MSG_GLOBAL_ERROR "Cannot allocate Global (size=%d)\n"
-#define MSG_GRAM_ALLOC_ERR "Allocation error in Grammar Up"
-#define MSG_GRAM_MISMATCH "Warning: GRAMMAR version mismatch (saved under GRAMMAR v%u)"
-#define MSG_GRAM_SUBSET_ERR "Grammar dictionary Subset error"
-#define MSG_GRBY_TAB_NOTIMP "Group by filtered joined table not implemented"
-#define MSG_GROUPBY_NOT_ALL "Group By must include all non-functional select items"
-#define MSG_GROUP_ON_FUNC "Invalid group by on functional column"
-#define MSG_GRP_COL_MISM "Column mismatch in groups"
-#define MSG_GRP_LIST_MISMAT "Grouping does not match select list"
-#define MSG_GUARD_PAGE "Guard page violation"
-#define MSG_GZOPEN_ERROR "gzopen %s error %d on %s"
-#define MSG_GZPUTS_ERROR "gzputs error: %s"
-#define MSG_HANDLE_IS_NULL "%s is NULL: last error: %d"
-#define MSG_HARRY_COMP_NIY "Compute not implemented for coded strings"
-#define MSG_HAVING_FILTER "Filtering by Having"
-#define MSG_HBUF_TOO_SMALL "Buffer(%d) too small for header(%d)"
-#define MSG_HEAD_OPEN_ERROR "Error opening header file %s"
-#define MSG_HEAD_READ_ERROR "Error reading header file %s"
-#define MSG_HEAD_WRITE_ERR "Error writing header file %s"
-#define MSG_HI_OFFSET_ERR "High offet is not 0"
-#define MSG_HUGE_DEFAULT "Huge defaults to %d"
-#define MSG_HUGE_WARNING_1 "Huge memory not 16-bit compatible for %d\n"
-#define MSG_HUGE_WARNING_2 "Unpredictable results may occur\n"
-#define MSG_IDLE "Idle"
-#define MSG_ILLEGAL_INSTR "Illegal instruction"
-#define MSG_ILL_FILTER_CONV "Filtering implies an illegal conversion"
-#define MSG_INDEX_CREATED "Index %s created on %s"
-#define MSG_INDEX_DEF_ERR "Error storing index definition for %s"
-#define MSG_INDEX_DROPPED "Index %s dropped from %s"
-#define MSG_INDEX_INIT_ERR "Cannot initialize index %s"
-#define MSG_INDEX_NOT_DEF "Index %s has no definition"
-#define MSG_INDEX_NOT_UNIQ "Index is not unique"
-#define MSG_INDEX_ONE_SAVE "Indexes are saved in one unique file"
-#define MSG_INDEX_SEP_SAVE "Indexes are saved in separate files"
-#define MSG_INDEX_YET_ON "Index %s already exists on %s"
-#define MSG_INDX_ALL_DROP "All indexes dropped from %s"
-#define MSG_INDX_COL_NOTIN "Index column %s is not in table %s"
-#define MSG_INDX_EXIST_YET "Index entry already exists"
-#define MSG_INIT_ERROR "Error initializing %s"
-#define MSG_INIT_FAILED "Failed to initialize %s processing"
-#define MSG_INPUT "Input: "
-#define MSG_INPUT_KEYBD_YET "Input already from keyboard"
-#define MSG_INSERTING "Inserting: "
-#define MSG_INSERT_ERROR "Insert error: file %s in use"
-#define MSG_INSERT_MISMATCH "Column/Value list mismatch"
-#define MSG_INTERNAL "internal"
-#define MSG_INT_COL_ERROR "Internal error for index column %s"
-#define MSG_INT_OVERFLOW "Integer overflow"
-#define MSG_INT_ZERO_DIVIDE "Integer divide by zero"
-#define MSG_INVALID_BIP "Invalid Bip .%d"
-#define MSG_INVALID_DISP "Invalid disposition"
-#define MSG_INVALID_FTYPE "SBV: invalid Ftype %d"
-#define MSG_INVALID_HANDLE "Invalid handle"
-#define MSG_INVALID_OPER "Invalid operator %d for %s"
-#define MSG_INVALID_OPTION "Invalid option %s"
-#define MSG_INV_COLUMN_TYPE "Invalid type %d for column %s"
-#define MSG_INV_COL_DATATYP "Invalid Data Type %d for column %d"
-#define MSG_INV_COL_NUM "Invalid column %d"
-#define MSG_INV_COL_TYPE "Invalid column type %s"
-#define MSG_INV_CONC_BIP "Invalid bip (only valid are : %.8s.0 .1 and .5)"
-#define MSG_INV_DATA_PATH "Invalid database path %s"
-#define MSG_INV_DEF_READ "Invalid deferred Read rc=%d"
-#define MSG_INV_DIRCOL_OFST "Invalid DIRCOL offset %d"
-#define MSG_INV_DOMAIN_TYPE "Invalid type %d"
-#define MSG_INV_FILTER "Filter met in %s"
-#define MSG_INV_FNC_BUFTYPE "FNC: invalid argument type %d for %s"
-#define MSG_INV_INFO_TYPE "Invalid catalog info type %d"
-#define MSG_INV_INIPATH "Invalid inipath "
-#define MSG_INV_MAP_POS "Invalid map position"
-#define MSG_INV_OPERATOR "invalid operator %d\n"
-#define MSG_INV_PARAMETER "Invalid parameter %s"
-#define MSG_INV_PARM_TYPE "Invalid parameter type"
-#define MSG_INV_QUALIFIER "Invalid qualifier '%s'"
-#define MSG_INV_QUERY_TYPE "Invalid query type %d"
-#define MSG_INV_RAND_ACC "Invalid random access to non optimized table"
-#define MSG_INV_REC_POS "Invalid record position"
-#define MSG_INV_RESULT_TYPE "Invalid result type %s"
-#define MSG_INV_SET_SUBTYPE "Invalid SetFormat subtype %d"
-#define MSG_INV_SPECIAL_CMD "%s: Invalid special command"
-#define MSG_INV_SUBTYPE "Invalid subtype %s"
-#define MSG_INV_TOK_DOMAIN "Invalid token domain %s"
-#define MSG_INV_TOPSEM_CMD "Invalid TopSem command %c"
-#define MSG_INV_TRANSF_USE "Invalid use in transformation rule"
-#define MSG_INV_TYPE_SPEC "Invalid type specification (%.8s.%d)"
-#define MSG_INV_UPDT_TABLE "Table %s invalid for update"
-#define MSG_INV_VALUE_LIST "Invalid Insert value list"
-#define MSG_INV_WHERE_JOIN "Invalid where clause in join query"
-#define MSG_INV_WORK_PATH "Invalid work path %s"
-#define MSG_IN_ARGTYPE_MISM "Argument type mismatch for IN expression"
-#define MSG_IN_USE " and in use"
-#define MSG_IN_WITHOUT_SUB "IN or EXISTS without array or subquery"
-#define MSG_IS_NOT_CONN "%s is not a connection definition"
-#define MSG_JCT_MISS_COLS "Missing columns for a JCT table"
-#define MSG_JCT_MISS_TABLE "Missing joined table for JCT"
-#define MSG_JCT_NO_FILTER "Virtual JCT tables cannot be filtered"
-#define MSG_JCT_NO_KEY "Logical JCT error: no key"
-#define MSG_JOIN_KEY_NO_COL "Join key is not a column"
-#define MSG_KEY_ALLOC_ERR "Error allocating Key offset block"
-#define MSG_KEY_ALLOC_ERROR "Memory allocation error, Klen=%d n=%d"
-#define MSG_LANGUAGE_QUIT "%s quit"
-#define MSG_LANG_ACTIVE "Language %s active"
-#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Lang block allocation failed"
-#define MSG_LANG_ALREADY_UP "Edited language is already there"
-#define MSG_LANG_BAD_SAVE "Language %s may be incorrectly saved"
-#define MSG_LANG_NOT_FREED "Language %s cannot be freed (not in main chain)"
-#define MSG_LANG_SAVED "Language %s saved"
-#define MSG_LANG_WR_LEN_ERR "Lang block write length error"
-#define MSG_LDF_ALLOC_ERROR "LdfBlock allocation error"
-#define MSG_LDF_RN_MISMATCH "LDF rule number mismatch"
-#define MSG_LDF_WLEN_ERROR "LdfData write length error"
-#define MSG_LDF_W_LEN_ERROR "LdfData write length error"
-#define MSG_LIC_NO_MYSQL "Your current license does not enable using the MySQL table type"
-#define MSG_LINEAR_ERROR "Linearization error"
-#define MSG_LINE_LENGTH "Output line length reset to %d"
-#define MSG_LINE_MAXLIN "Max number of work lines reset to %d"
-#define MSG_LINE_MAXRES "Max number of output lines reset to %d"
-#define MSG_LINE_MAXTMP "Max number of intermediate lines reset to %d"
-#define MSG_LINE_TOO_LONG "New line is too long"
-#define MSG_LINJOINDB_ERROR "System error: incorrect call to LinJoinDB"
-#define MSG_LIST "--List--"
-#define MSG_LNG_NOT_IN_LIST "Language %s not found in attached list"
-#define MSG_LOADING_DB "Loading DB Description"
-#define MSG_LOADING_FAILED "Loading of %s failed"
-#define MSG_LOAD_CDLL_ERROR "Error loading ConnDll: rc=%d"
-#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n too big ? (%d)\n"
-#define MSG_LOGICAL_ERROR "%s: Logical error"
-#define MSG_LRECL_TOO_SMALL "Lrecl too small (headlen = %d)"
-#define MSG_MAC_NO_DELETE "Delete not enabled for MAC tables"
-#define MSG_MAC_NO_INDEX "No direct access to MAC tables"
-#define MSG_MAC_READ_ONLY "MAC tables are read only"
-#define MSG_MAC_WIN_ONLY "MAC tables are Windows only"
-#define MSG_MAKE_EMPTY_FILE "Making empty file %s: %s"
-#define MSG_MAKING "Making"
-#define MSG_MAKING_DISTINCT "Making distinct groups"
-#define MSG_MALLOC_ERROR "Memory allocation failed: %s returned Null"
-#define MSG_MALLOC_NULL "malloc returned Null"
-#define MSG_MAP_NO_MORE "Type %s no more supported"
-#define MSG_MAP_OBJ_ERR "Error %d occurred closing the mapping object"
-#define MSG_MAP_VEC_ONLY "MAP Insert is for VEC Estimate tables only"
-#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s error rc=%d"
-#define MSG_MAXSIZE_ERROR "Cannot calculate max size on open table"
-#define MSG_MAXTMP_TRUNCATE "Intermediate results truncated by maxtmp=%d"
-#define MSG_MAX_BITMAP "Max opt bitmap size reset to %d"
-#define MSG_MEMSIZE_TOO_BIG "Error: memsize (%d) too big for length (%d)"
-#define MSG_MEM_ALLOC_ERR "Memory allocation error, %s size=%d"
-#define MSG_MEM_ALLOC_ERROR "Memory allocation error"
-#define MSG_MEM_ALLOC_YET "Memory already allocated"
-#define MSG_METAFILE_NOTFND "Grammar Meta file not found"
-#define MSG_MISPLACED_QUOTE "Misplaced quote in line %d"
-#define MSG_MISSING "Missing: Value=%p Argval=%p Builtin=%d"
-#define MSG_MISSING_ARG "Missing argument for operator %d"
-#define MSG_MISSING_COL_DEF "Missing column definition"
-#define MSG_MISSING_CONNECT "Missing connect string"
-#define MSG_MISSING_EOL "Missing endline character in %s"
-#define MSG_MISSING_FIELD "Missing field %d in %s line %d"
-#define MSG_MISSING_FNAME "Missing file name"
-#define MSG_MISSING_NODE "Missing %s node in %s"
-#define MSG_MISSING_POS "Missing POS code"
-#define MSG_MISSING_ROWNODE "Can't find RowNode for row %d"
-#define MSG_MISSING_SERV_DB "Missing server and/or database string"
-#define MSG_MISS_LEAD_COL "Missing leading index column %s"
-#define MSG_MISS_NAME_LRECL "Missing file name and/or lrecl"
-#define MSG_MISS_TABLE_LIST "Missing table list"
-#define MSG_MISS_VCT_ELMT "Missing VCT block size (Elements)"
-#define MSG_MIS_TAG_LIST "Missing column tag list"
-#define MSG_MKEMPTY_NIY "MakeEmptyFile: not yet implemented for Huge and Unix"
-#define MSG_MOVE_INV_TYPE "MOVPARM: Invalid parameter type %d"
-#define MSG_MULT_DISTINCT "Distinct is specified more than once"
-#define MSG_MULT_KEY_ERROR "Multiple key error k=%d n=%d"
-#define MSG_MUL_MAKECOL_ERR "Tabmul MakeCol logical error"
-#define MSG_MYSQL_CNC_OFF "MySQL connection is closed"
-#define MSG_MYSQL_CNC_ON "MySQL connection is established"
-#define MSG_MYSQL_NOT_SUP "MySQL not supported by this version"
-#define MSG_MY_CNC_ALREADY "MySQL connection already active"
-#define MSG_NAME_CONV_ERR "Error converting node name"
-#define MSG_NAME_IS_USED "Name %s already in use"
-#define MSG_NCOL_GT_MAXCOL "Too many columns (%d > %d max)"
-#define MSG_NEW_CHAR_NULL "new char(%d) returned Null"
-#define MSG_NEW_DOC_FAILED "Cannot create new document"
-#define MSG_NEW_RETURN_NULL "New returned Null in PlugEvalLike"
-#define MSG_NEW_TABLE_ERR "Unable to retrieve new table %s"
-#define MSG_NEXT_FILE_ERROR "Couldn't find next file. rc=%d"
-#define MSG_NODEF_FROM_VIEW "Cannot define a table from a view"
-#define MSG_NODE_FOR_CHAR "Node %s found when looking for character"
-#define MSG_NODE_SUBSET_ERR "Node %d Subset error"
-#define MSG_NONCONT_EXCEPT "Noncontinuable exception"
-#define MSG_NON_DUP_HAVING "Having clause in non/dup functional query"
-#define MSG_NON_EVAL_SEM "Sem not evaluated: p_no=%d"
-#define MSG_NOP_ZLIB_INDEX "Cannot do indexing on non optimized zlib table"
-#define MSG_NOT_A_DBF_FILE "Not a dBASE dbf file "
-#define MSG_NOT_ENOUGH_COLS "Not enough columns in %s"
-#define MSG_NOT_ENOUGH_MEM "Not enough memory to perform this operation"
-#define MSG_NOT_FIXED_LEN "File %s is not fixed length, len=%d lrecl=%d"
-#define MSG_NOT_IMPLEMENTED "Not implemented: %.8s"
-#define MSG_NOT_IMPL_JOIN "Not implemented for Join"
-#define MSG_NOT_IMPL_SET "Not implemented for set operators"
-#define MSG_NOT_IMPL_YET "Not implemented yet"
-#define MSG_NOT_LINEARIZED "Table tree was not linearized"
-#define MSG_NOT_MODIFIABLE " (not modifiable)"
-#define MSG_NO_0DH_HEAD "No 0Dh at end of header (dbc=%d)"
-#define MSG_NO_ACTIVE_APPL "No active application"
-#define MSG_NO_ACTIVE_DB "No active database"
-#define MSG_NO_ACTIVE_UDIC "No active user dictionary"
-#define MSG_NO_AGGR_FUNC "Aggregated function %d not allowed here"
-#define MSG_NO_AREA_FILE "Area file not found"
-#define MSG_NO_AVAIL_RESULT "No result available"
-#define MSG_NO_BIG_DELETE "Partial delete not yet implemented for Huge files"
-#define MSG_NO_CHAR_FROM "Cannot return char value from type %d"
-#define MSG_NO_CLUSTER_COL "No clustered columns"
-#define MSG_NO_COL_ADDING "Cannot add new column(s) to old definition"
-#define MSG_NO_COL_DEF_AS "Column definitions cannot be used with AS Select"
-#define MSG_NO_COL_FOUND "No column found in section %s"
-#define MSG_NO_COL_IN_TABLE "Column %d not in table %s"
-#define MSG_NO_COL_SECTION "Missing column section for table %s"
-#define MSG_NO_CONNECT_ADDR "No connexion address provided"
-#define MSG_NO_CONST_FILTER "Constant filters not implemented"
-#define MSG_NO_CURLY_BRKT "No closing curly bracket"
-#define MSG_NO_DATABASE "Database %s not found"
-#define MSG_NO_DATE_FMT "No date format for valblock of type %d"
-#define MSG_NO_DBF_INSERT "Insert not supported yet for GDF files"
-#define MSG_NO_DEF_FNCCOL "Cannot find default function column"
-#define MSG_NO_DEF_PIVOTCOL "Cannot find default pivot column"
-#define MSG_NO_DIR_INDX_RD "No direct access of %s tables"
-#define MSG_NO_DMY_DIR_ACC "No direct access of virtual DUMMY tables"
-#define MSG_NO_DOM_DELETE "Partial delete not yet implemented for domains"
-#define MSG_NO_DOM_MATCH "Unmatched string %.8s... in domain %s"
-#define MSG_NO_EDITED_LANG "Coparm: No active edited language"
-#define MSG_NO_EXP_LINK "Cannot use expression to link a JCT table"
-#define MSG_NO_EXT_FILTER "Filtering cannot refer to another table"
-#define MSG_NO_EXT_UPDATE "Cannot update with reference to another table"
-#define MSG_NO_FEAT_SUPPORT "No %s support in this version"
-#define MSG_NO_FILE_LIST "Table %s has no file list"
-#define MSG_NO_FLD_FORMAT "Missing format for field %d of %s"
-#define MSG_NO_FORMAT_COL "Cannot format the type COLUMN"
-#define MSG_NO_FORMAT_TYPE "Cannot set format from type %d"
-#define MSG_NO_FULL_JOIN "Only Equi-join on key(s) is allowed by check setting"
-#define MSG_NO_FUL_OUT_JOIN "Full outer joins are not supported"
-#define MSG_NO_FUNC_ORDER "Unsupported ordering on functional item"
-#define MSG_NO_HEAD_JOIN "Join on not heading table"
-#define MSG_NO_HQL_CONV "Conversion to HQL not available"
-#define MSG_NO_INDEX "No indexes on table %s"
-#define MSG_NO_INDEX_GBX "No or improper index for SQLGBX"
-#define MSG_NO_INDEX_IN "No indexes found in %s"
-#define MSG_NO_INDEX_READ "No indexed read for multiple tables"
-#define MSG_NO_INIT_LANG "No initial language"
-#define MSG_NO_JOIN_TO_EXP "No join to expressions"
-#define MSG_NO_JOIN_UPDEL "Update/Delete on MySQL table cannot be joined"
-#define MSG_NO_KEY_COL "No key columns found"
-#define MSG_NO_KEY_UPDATE "Cannot update key names"
-#define MSG_NO_LANGUAGE "No language in operation\n"
-#define MSG_NO_LANG_TO_QUIT "No next language to quit"
-#define MSG_NO_LISTVAL_HERE "LSTBLK: List of values used out of context"
-#define MSG_NO_MAP_INSERT "MAP incompatible with Insert"
-#define MSG_NO_MATCHING_COL "No matching column %s in %s"
-#define MSG_NO_MATCH_COL "Cannot find matching column"
-#define MSG_NO_MEMORY "No memory"
-#define MSG_NO_MEM_CORR_SUB "In memory correlated subquery not implemented yet"
-#define MSG_NO_MODE_PADDED "Mode not supported for padded files"
-#define MSG_NO_MORE_COL "Column %s no more in pivot table"
-#define MSG_NO_MORE_LANG "No more language, exit from %s\n"
-#define MSG_NO_MORE_VAR "VAR files no more supported"
-#define MSG_NO_MULCOL_JOIN "No join yet on muticolumn index"
-#define MSG_NO_MULT_HAVING "Multiple having clauses not implemented"
-#define MSG_NO_MUL_DIR_ACC "Direct access of multiple tables not implemented yet"
-#define MSG_NO_MUL_VCT "VCT tables cannot be multiple"
-#define MSG_NO_MYSQL_CONN "No open MySQL connection"
-#define MSG_NO_MYSQL_DELETE "Delete should not be called for MySQL tables"
-#define MSG_NO_NBCOL "No NBcol"
-#define MSG_NO_NBLIN "No NBlin, MaxSize or Continued"
-#define MSG_NO_NBLIN_CONT "Fetch: No NBlin or Continued"
-#define MSG_NO_NULL_CONST "Cannot handle <null> constant"
-#define MSG_NO_ODBC_COL "Automatic ODBC columns not supported in this version"
-#define MSG_NO_ODBC_DELETE "Delete should not be called for ODBC tables"
-#define MSG_NO_ODBC_DIRECT "Direct access of ODBC tables not implemented yet"
-#define MSG_NO_ODBC_MUL "Multiple(2) not supported for ODBC tables"
-#define MSG_NO_ODBC_SPECOL "No ODBC special columns"
-#define MSG_NO_OPT_COLUMN "Not optimizable or no optimized columns"
-#define MSG_NO_OP_MODIF "Modificators do not apply to %s"
-#define MSG_NO_PARAMETER "No parameter"
-#define MSG_NO_PART_DEL "No partial delete of %s files"
-#define MSG_NO_PART_MAP "Partial mapping not implemented for this OS"
-#define MSG_NO_PAR_BLK_INS "Cannot insert partial block yet"
-#define MSG_NO_PIV_DIR_ACC "No direct access to PIVOT tables"
-#define MSG_NO_POS_ADDED "No Pos_code added"
-#define MSG_NO_PROMPTING "Cannot handle prompting for distributed tables"
-#define MSG_NO_QRY_DELETE "Delete cannot be used for QRY views"
-#define MSG_NO_QUERY_ARRAY "Array from QUERY not implemented yet"
-#define MSG_NO_RCUR_DSK_YET "Recursive use of DISK not implemented yet"
-#define MSG_NO_READ_32 "Can't read 32 bytes"
-#define MSG_NO_RECOV_SPACE "Cannot recover space in index file"
-#define MSG_NO_REF_DELETE "Cannot delete with reference to another table"
-#define MSG_NO_REF_UPDATE "Cannot update with reference to another table"
-#define MSG_NO_REMOTE_FNC "Cannot process some functions remotely"
-#define MSG_NO_ROWID_FOR_AM "Can't get RowID in direct access for tables of type %s"
-#define MSG_NO_ROW_NODE "Row node name is not defined"
-#define MSG_NO_SECTION_NAME "Missing section name"
-#define MSG_NO_SEC_UPDATE "Cannot update section names"
-#define MSG_NO_SELECTED_DB "No selected database"
-#define MSG_NO_SELF_PIVOT "Cannot pivot oneself!"
-#define MSG_NO_SERVER_FOUND "No server found"
-#define MSG_NO_SETPOS_YET "%s SetPos not implemented yet"
-#define MSG_NO_SFEXIT_UNIX "Function %s not available on Unix"
-#define MSG_NO_SOURCE " (no source)"
-#define MSG_NO_SPEC_COL "No MySQL special columns"
-#define MSG_NO_SQL_DELETE "Delete cannot be currently used for SQL views"
-#define MSG_NO_SUB_VAL "No sub value for array of type %d"
-#define MSG_NO_SUCH_INDEX "No indexes %s on table %s"
-#define MSG_NO_SUCH_SERVER "cannot find the server %s"
-#define MSG_NO_SUCH_TABLE "Table %s not in DB"
-#define MSG_NO_TABCOL_DATA "No data found for table %s column %s"
-#define MSG_NO_TABLE_COL "No columns found for %s"
-#define MSG_NO_TABLE_DEL "Delete not enabled for %s tables "
-#define MSG_NO_TABLE_DESC "No Table Description Block"
-#define MSG_NO_TABLE_INDEX "Table %s has no index"
-#define MSG_NO_TABLE_LIST "No table list"
-#define MSG_NO_TAB_DATA "No data found for table %s"
-#define MSG_NO_TERM_IN_TOK "Non terminal cannot be used in token rules"
-#define MSG_NO_TOKEN_DB "Cannot find DB for Token column %s"
-#define MSG_NO_UNIX_CATINFO "No catalog info under Unix"
-#define MSG_NO_UPDEL_JOIN "Update/Delete on ODBC table cannot be joined"
-#define MSG_NO_VCT_DELETE "Partial delete not yet implemented for VCT files"
-#define MSG_NO_VIEW_COLDEF "No coldefs available for views"
-#define MSG_NO_VIEW_SORT "Cannot sort/join SQL functional view %s"
-#define MSG_NO_ZIP_DELETE "Delete Zip files not implemented yet"
-#define MSG_NO_ZIP_DIR_ACC "Direct access of ZDOS tables not implemented yet"
-#define MSG_NULL_COL_VALUE "Column Value block is NULL"
-#define MSG_NULL_ENTRY "InitLang, null entry %d %s"
-#define MSG_NULL_QUERY "Null query"
-#define MSG_NUMVAL_NOMATCH "Numval mismatch for %s"
-#define MSG_N_FULL_PARSES "%d full parses"
-#define MSG_ODBC_READ_ONLY "ODBC is currently read only"
-#define MSG_OFFSET_NOT_SUPP "Offset not implemented for this type of sub query"
-#define MSG_ONE_LANG_YET "Already one language in edition"
-#define MSG_ONE_PARAM_ONLY "Only one parameter allowed"
-#define MSG_ONLY_LOG10_IMPL "Only Log10 is implemented"
-#define MSG_ON_LANGUAGE "Language %.8s version %d.%d loaded for editing"
-#define MSG_OPENING "Opening"
-#define MSG_OPENING_QUERY "Opening query"
-#define MSG_OPEN_EMPTY_FILE "Opening empty file %s: %s"
-#define MSG_OPEN_ERROR "Open error %d in mode %d on %s: "
-#define MSG_OPEN_ERROR_IS "Open error on %s: %s"
-#define MSG_OPEN_ERROR_ON "Open error on %s"
-#define MSG_OPEN_MODE_ERROR "Open(%s) error %d on %s"
-#define MSG_OPEN_SORT_ERROR "Logical sort error in QUERY Open"
-#define MSG_OPEN_STRERROR "open error: %s"
-#define MSG_OPEN_W_ERROR "Couldn't open %s for writing"
-#define MSG_OPTBLK_RD_ERR "Error reading opt block values: %s"
-#define MSG_OPTBLK_WR_ERR "Error writing opt block values: %s"
-#define MSG_OPTIMIZING "Optimizing "
-#define MSG_OPT_BMAP_RD_ERR "Error reading opt bitmaps: %s"
-#define MSG_OPT_BMAP_WR_ERR "Error writing opt bitmaps: %s"
-#define MSG_OPT_CANCELLED "Optimize cancelled by User"
-#define MSG_OPT_DVAL_RD_ERR "Error reading distinct values: %s"
-#define MSG_OPT_DVAL_WR_ERR "Error writing distinct values: %s"
-#define MSG_OPT_HEAD_RD_ERR "Error reading opt file header: %s"
-#define MSG_OPT_HEAD_WR_ERR "Error writing opt file header: %s"
-#define MSG_OPT_INIT "Optimization initialized"
-#define MSG_OPT_LOGIC_ERR "Logical error in SetBitmap, i=%d"
-#define MSG_OPT_MAX_RD_ERR "Error reading opt max values: %s"
-#define MSG_OPT_MAX_WR_ERR "Error writing opt max values: %s"
-#define MSG_OPT_MIN_RD_ERR "Error reading opt min values: %s"
-#define MSG_OPT_MIN_WR_ERR "Error writing opt min values: %s"
-#define MSG_OPT_NOT_MATCH "Non-matching opt file %s"
-#define MSG_OP_RES_TOO_LONG "Result too long for operator=%d"
-#define MSG_ORDER_OUT_RANGE "Order %d out of range"
-#define MSG_ORDER_TWICE "Ordering twice the same select item"
-#define MSG_PAGE_ERROR "In page error"
-#define MSG_PARM_CNT_MISS "Parameter count mismatch"
-#define MSG_PARSE_NULL_SEM "Parse with null semantics"
-#define MSG_PARSING_QUERY "Parsing query"
-#define MSG_PIX_ERROR "Pix %s error Rule_no=%u\n"
-#define MSG_PIX_TEST_ERROR "Rule=%u: pix-TEST not in first node\n"
-#define MSG_PLG_READ_ONLY "PLG is currently Read Only"
-#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp is NULL"
-#define MSG_PLUG_NOT_INIT "Plug was not initialized\n"
-#define MSG_PLUG_NOT_RUN "Plug is not running"
-#define MSG_PNODE_RULE "(P_node %d rule %d) "
-#define MSG_POS_TOO_LONG "%s too long (>%d)"
-#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp is NULL"
-#define MSG_PRIV_INSTR "Privileged instruction"
-#define MSG_PROCADD_ERROR "Error %d getting address of %s"
-#define MSG_PROCESS_SUBQRY "Processing Sub-Query"
-#define MSG_PROC_WOULD_LOOP "Process would loop (maxres=%d maxlin=%d)"
-#define MSG_PROGRESS_INFO "Progress Information"
-#define MSG_PROMPT_CANCEL "Prompt was cancelled"
-#define MSG_PROMPT_NIY "Prompt not implemented for this configuration"
-#define MSG_PTR_NOT_FOUND "Pointer not found Num=%d ti1=%d"
-#define MSG_PXDEF_IS_NULL "Pxdef is NULL"
-#define MSG_QRY_READ_ONLY "QRY views are read only"
-#define MSG_QUERY_CANCELLED "Query Cancelled by User"
-#define MSG_QUERY_NOT_EXEC "Query not executed"
-#define MSG_QUERY_SAVED "Query %s saved"
-#define MSG_QUOTE_IN_QUOTE "Quote char inside quoted field in line %d"
-#define MSG_RANGE_NIY "Range NIY for %s"
-#define MSG_RANGE_NO_JOIN "Range is not meant for join index"
-#define MSG_RC_READING "rc=%d reading table %s"
-#define MSG_READB_BAD_INIT "%s ReadDB called with Init=0"
-#define MSG_READCOL_ERROR "SQLCOL ReadColumn error"
-#define MSG_READING "Reading"
-#define MSG_READING_FROM "Reading from %s"
-#define MSG_READING_RECORD "Error reading record %d of %s"
-#define MSG_READY "Ready"
-#define MSG_READ_ERROR "Error reading %s: %s"
-#define MSG_READ_ERROR_RC "Read error, rc=%d"
-#define MSG_READ_MEM_ERROR "Reading memory %d: size=%d"
-#define MSG_READ_ONLY "Cannot modify this read/only protected table"
-#define MSG_READ_SEEK_ERROR "Read seek error: %s"
-#define MSG_READ_SEG_ERROR "Reading segment %d: size=%d"
-#define MSG_RECEIVED "Received %c\n"
-#define MSG_RECORD_ERROR "Error reading record %d of %s"
-#define MSG_RECORD_NO_SEP "Record with no separator"
-#define MSG_REC_SKIPPED " (%d bad records skipped by MaxErr setting)"
-#define MSG_REDUCE_INDEX "Reducing index"
-#define MSG_REGISTER_ERR "Unable to register NS with prefix='%s' and href='%s'"
-#define MSG_REMOTE_CONN_ERR "Remote connection failed"
-#define MSG_REMOVE_ERROR "Error removing %s: %s"
-#define MSG_REMOVE_NOT_IMPL "Remove not implemented for non-table TDB"
-#define MSG_RENAME_ERROR "Error renaming %s to %s: %s"
-#define MSG_RENUM_RULES "Renumber rules and enter ADD again (rule saved in buffer)"
-#define MSG_REORDER_INDEX "Reordering index"
-#define MSG_REQU_ARG_NUM "Function %s requires %d arguments"
-#define MSG_RESET_TO "%s reset to %d"
-#define MSG_RES_NOT_UNIQUE "Result is not a unique value"
-#define MSG_RET_FROM_LANG "Return to language %s version %d.%d from language %s version %d.%d"
-#define MSG_ROWID_NOT_IMPL "RowNumber not implemented for tables of type %s"
-#define MSG_ROWS_SELECTED "%d rows selected in %.2lf sec"
-#define MSG_ROWS_TRUNCATED " (truncated by MAXRES, LIMIT, FREQ or AreaSize setting)"
-#define MSG_ROW_ARGNB_ERR "ROW arg number mismatch (%d,%d)"
-#define MSG_RPC_SERVER_ERR "RPC error, server not responding"
-#define MSG_RSC_ALLOC_ERROR "Memory allocation error in Rescol %s"
-#define MSG_RULE_ENTERED "Rule %d entered"
-#define MSG_RULE_SUBSET_ERR "Rules Subset error"
-#define MSG_SAVING_INDEX "Saving index file"
-#define MSG_SCAN_NOT_IMP "Scan not implemented"
-#define MSG_SEC_KEY_FIRST "Section and key names must come first on Insert"
-#define MSG_SEC_NAME_FIRST "Section name must come first on Insert"
-#define MSG_SEC_NOT_FOUND "Section %s not found in %s"
-#define MSG_SEEK_ERROR "Seek error in CopyHeader"
-#define MSG_SEMANTIC_TREE "Semantic Tree"
-#define MSG_SEM_BAD_REF "Sem name @%d refers to an argument of type not 0 or 1"
-#define MSG_SEM_UNKNOWN "unknown, rc=%d"
-#define MSG_SEP_IN_FIELD "Field %d contains the separator character"
-#define MSG_SEQUENCE_ERROR "Sequence error on statement allocation"
-#define MSG_SETEOF_ERROR "Error %d in SetEndOfFile"
-#define MSG_SETRECPOS_NIY "SetRecpos not implemented for this table type"
-#define MSG_SET_LOCALE "Locale set to %s"
-#define MSG_SET_NULL_DOM "Setting value %d to a null domain"
-#define MSG_SET_OP_NOT_IMPL "sorry - set operators not implemented"
-#define MSG_SET_STR_TRUNC "SetValue: String would be truncated"
-#define MSG_SEVERAL_TREES "Some tables are not properly joined"
-#define MSG_SFP_ERROR "SetFilePointer error: %s"
-#define MSG_SFUNC_NOT_IMPL "Scalar Function %s not implemented"
-#define MSG_SHARED_LIB_ERR "Error loading shared library %s: %s"
-#define MSG_SINGLE_STEP "Single step"
-#define MSG_SLEEP "I slept %d milliseconds"
-#define MSG_SMART_SORTING "Retrieving sorted rows (pass %d of %d)"
-#define MSG_SMART_SORT_ERR "Logical Smart Sort Error 1"
-#define MSG_SORTING "Sorting"
-#define MSG_SORTING_INDEX "Sorting index"
-#define MSG_SORTING_VAL "Sorting %d values"
-#define MSG_SORT_JOIN_INDEX "Sorting join index"
-#define MSG_SPCOL_READONLY "Special column %s is Read Only"
-#define MSG_SPEC_CMD_SEP "Special commands must be executed separately"
-#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d not supported"
-#define MSG_SQL_BLOCK_MISM "CheckColumn: SQL current blocks mismatch"
-#define MSG_SQL_CONF_ERROR "SQL Error: SQL_CONFORMANCE"
-#define MSG_SQL_READ_ONLY "SQL views are currently read only"
-#define MSG_SRCH_CLOSE_ERR "Couldn't close search handle"
-#define MSG_SRC_TABLE_UNDEF "Source table is not defined"
-#define MSG_STACK_ERROR "stack error, i=%d\n"
-#define MSG_STACK_OVERFLOW "Parser: Stack overflow\n"
-#define MSG_STRG_NOT_FOUND "String not found"
-#define MSG_STRING_INV_LIST "List invalid for SemString"
-#define MSG_STRING_TOO_BIG "String too big for domain %s"
-#define MSG_SUBALLOC_ERROR "Not enough memory in area %p for request of %d (used=%d free=%d)"
-#define MSG_SUBAL_HUGE_ERR "Not enough memory in huge %p for request of %d"
-#define MSG_SUBARG_NOSEM "@ or sub-phrase arg of level %d points to a meaningless argument"
-#define MSG_SUBARG_OUTRANGE "Out of range @ or sub-phrase argument of level %d"
-#define MSG_SUBQRY_ONEITEM "Sub-Query must have exactly one select item"
-#define MSG_SUBSET_ERROR "SubSet error in LoadDB"
-#define MSG_SUB_OPEN_YET "Subquery already open"
-#define MSG_SUB_RES_TOO_LNG "Result too long for SUBSTR"
-#define MSG_SYNTAX_ERROR "Syntax error"
-#define MSG_SYSTEM_ERROR "System error %d"
-#define MSG_S_ACCESS_DENIED "%s: access denied"
-#define MSG_S_ERROR "%s error"
-#define MSG_S_ERROR_NUM "%s: error=%d"
-#define MSG_S_INTRUPT_ERROR "%s: interrupt error"
-#define MSG_S_INVALID_PARM "%s: invalid parameter"
-#define MSG_S_INV_ADDRESS "%s: invalid address"
-#define MSG_S_UNKNOWN_ERROR "%s: unknown error code %u"
-#define MSG_TABDIR_READONLY "DIR tables are read/only"
-#define MSG_TABLE_ALREADY "Table %s already exists"
-#define MSG_TABLE_ALTERED "%s table %s altered"
-#define MSG_TABLE_CREATED "%s table %s created"
-#define MSG_TABLE_DROPPED "Table %s dropped"
-#define MSG_TABLE_MULT_JOIN "Table %s used more than once for join"
-#define MSG_TABLE_NOT_IN_DB "Table %s does not exist in %s"
-#define MSG_TABLE_NOT_OPT "Not an optimizable table"
-#define MSG_TABLE_NO_INDEX "Table %s cannot be indexed"
-#define MSG_TABLE_NO_OPT "Table %s does not exist or type is not optimizable"
-#define MSG_TABLE_READ_ONLY "%s tables are read only "
-#define MSG_TABMUL_READONLY "Multiple tables are read/only"
-#define MSG_TAB_NOT_LOADED " (some tables could not be loaded)"
-#define MSG_TAB_NOT_SPEC "No table specified"
-#define MSG_TB_VW_NOTIN_DB "Table or view %s not in DB"
-#define MSG_TDB_NXT_NOT_NUL "Tdb.Next not NULL"
-#define MSG_TDB_USE_ERROR "Error, Tdbp->Use=%d"
-#define MSG_TOO_MANY_COLS "Too many columns"
-#define MSG_TOO_MANY_COLTAB "Too many columns in %s (%d)"
-#define MSG_TOO_MANY_FIELDS "Too many fields line %d of %s"
-#define MSG_TOO_MANY_JUMPS "Too many jump levels"
-#define MSG_TOO_MANY_KEYS "Too many keys (%d)"
-#define MSG_TOO_MANY_POS "Too many pos_codes"
-#define MSG_TOO_MANY_TABLES "Too many tables (%d)"
-#define MSG_TOPSEM_ERROR "Unknown error in TopSem"
-#define MSG_TO_BLK_IS_NULL "To Blk is NULL"
-#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr is not null"
-#define MSG_TO_PIX_NOT_NULL "Set.To_Pix is not null"
-#define MSG_TO_SEM_NOT_NULL "Set.To_Sem is not null"
-#define MSG_TRUNCATE_ERROR "truncate error: %s"
-#define MSG_TRUNC_BY_ESTIM "truncated by Estimate"
-#define MSG_TYPES_ERROR "Error on Types(%d)"
-#define MSG_TYPE_CONV_ERROR "Type cannot be converted in expression"
-#define MSG_TYPE_DEF_MISM "type and definition do not match"
-#define MSG_TYPE_MISMATCH "Key and source are not of the same type"
-#define MSG_TYPE_RECFM_MISM "Type and Recfm mismatch"
-#define MSG_TYPE_TO_VERIFY "Type to verify: %d"
-#define MSG_TYPE_VALUE_ERR "Column %s type(%s)/value(%s) mismatch"
-#define MSG_UNBALANCE_QUOTE "Unbalanced quote in line %d"
-#define MSG_UNDEFINED_AM "COLBLK %s: undefined Access Method"
-#define MSG_UNDEFINED_PATH "Undefined Plgcnx.ini path"
-#define MSG_UNDEF_COL_COUNT "Count on undefined column"
-#define MSG_UNKNOWN_DOMAIN "Unknown domain %s"
-#define MSG_UNKNOWN_ERROR "Unknown error"
-#define MSG_UNKNOWN_EXCPT "Unknown exception"
-#define MSG_UNKNOWN_NAME "Unknown name: %.8s"
-#define MSG_UNKNOWN_PATH "Unknown Plgcnx.ini path"
-#define MSG_UNKNOWN_POS "Unknown pos name: %s"
-#define MSG_UNKNOWN_SEM "Unknown Sem %.8s, rc=%d"
-#define MSG_UNKNOWN_SYNONYM "Unknown synonym"
-#define MSG_UNKNW_QRY_TYPE "ReadDB: unknown query type"
-#define MSG_UNKN_ERR_CODE "Unknown error code %d"
-#define MSG_UNLOADABLE " unloadable: "
-#define MSG_UNLOADABLE_PRM "%s unloadable: %s"
-#define MSG_UNMATCH_FIL_ARG "Unmatched filter argument"
-#define MSG_UNQ_COL_SEV_TAB "Unqualified column %s is in several tables"
-#define MSG_UNRESOLVED_ARG "?Unresolved argument %s at %d line %d"
-#define MSG_UPDATE_ERROR "Error updating %s"
-#define MSG_UPDATING_ROWS "Updating rows"
-#define MSG_UPD_ZIP_NOT_IMP "Updating ZDOS tables not implemented yet"
-#define MSG_UP_LANGUAGE "Block language %.8s version %d level %d loaded"
-#define MSG_USED_FREE_MEM "%d used in sarea, %d free"
-#define MSG_USETEMP_IS "UseTemp is %s"
-#define MSG_USETEMP_RESET ". Usetemp reset to Auto"
-#define MSG_USETEMP_SET "UseTemp set to %s"
-#define MSG_USE_NO_MATCH "Use do not match : Use=%d, ti2=%d, ti3=%d"
-#define MSG_USING_INDEX " (Using index"
-#define MSG_VALIST_MISMATCH "List of values mismatch"
-#define MSG_VALSTR_TOO_LONG "Value %s too long for string of length %d"
-#define MSG_VALTYPE_NOMATCH "Non matching Value types"
-#define MSG_VALUE_ERROR "Column %s: value is null"
-#define MSG_VALUE_NOT_ALLOC "Value not allocated for column R%d %s"
-#define MSG_VALUE_TOO_BIG "Value %lld too big for column %s"
-#define MSG_VALUE_TOO_LONG "Value %s too long for column %s of length %d"
-#define MSG_VAL_ALLOC_ERR "Cannot allocate value node"
-#define MSG_VAL_TOO_LONG "Value field %s too long for %s"
-#define MSG_VIEW_ALREADY "View %s already exists"
-#define MSG_VIEW_CREATED "%s view %s created"
-#define MSG_VIEW_DROPPED "View %s dropped"
-#define MSG_VIEW_NOT_IN_DB "View %s does not exist in %s"
-#define MSG_VIR_NO_DELETE "Delete not allowed for %s tables"
-#define MSG_VIR_READ_ONLY "Virtual %s tables are read only"
-#define MSG_VM_LANG "Language has VM format, not supported"
-#define MSG_VOID_FIRST_ARG "First argument should not be void"
-#define MSG_VOID_IN_STRING "Error: void IN string"
-#define MSG_VOID_ORDER_LIST "Null ordering list, system error ?"
-#define MSG_VOID_POS_DICT "Void Pos dictionary"
-#define MSG_VOID_QUERY "Void query %s"
-#define MSG_WORK_AREA "Work area: %s"
-#define MSG_WORK_TOO_SMALL "Work area too small, increase AreaSize"
-#define MSG_WRITE_ERROR "Error writing to %s"
-#define MSG_WRITE_SEEK_ERR "Write seek error: %s"
-#define MSG_WRITE_STRERROR "Error writing %s: %s"
-#define MSG_WRITING "Writing"
-#define MSG_WRITING_ERROR "Error writing to %s: %s"
-#define MSG_WRITING_QUERY "Writing query: "
-#define MSG_WRONG_ARG_NUM "Function %s does not take %d arguments"
-#define MSG_WRONG_COL_NUM "Column number %d out of range in %s"
-#define MSG_WRONG_DB_LIST "Wrong or nul database list"
-#define MSG_WRONG_FUNCTION "Wrong function %d"
-#define MSG_WRONG_OP_PARM "Wrong operator or parameters for %s"
-#define MSG_WRONG_PARMS "Wrong parameters for %s"
-#define MSG_WRONG_PASSWORD "Illegal password for %s"
-#define MSG_WRONG_TYPE "unsupported type"
-#define MSG_WRONG_USERFILE "Wrong Userfile size=%d"
-#define MSG_WS_CONV_ERR "Error converting %s to WS"
-#define MSG_XCOL_MISMATCH "Column %s mismatch in index"
-#define MSG_XDB_DEL_ERROR "Error while deleting entries from XDB file"
-#define MSG_XFILE_READERR "Error %d reading index file"
-#define MSG_XFILE_TOO_SMALL "Index file is smaller than index length"
-#define MSG_XFILE_WRITERR "Error writing index file: %s"
-#define MSG_XMLTAB_INIT_ERR "Error initializing XML table"
-#define MSG_XML_INIT_ERROR "Error initializing new XML file"
-#define MSG_XPATH_CNTX_ERR "Unable to create new XPath context"
-#define MSG_XPATH_EVAL_ERR "Unable to evaluate xpath location '%s'"
-#define MSG_XPATH_NOT_SUPP "Unsupported Xpath for column %s"
-#define MSG_X_ARG_ADDED "%d arguments have been added"
-#define MSG_X_ARG_SET "%d arguments have been set"
-#define MSG_X_ON_TAB " %s on %s("
-#define MSG_ZERO_DIVIDE "Zero divide in expression"
+#define MSG_ACCESS_VIOLATN "Access violation"
+#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Activity allocation failed"
+#define MSG_ADDVAL_ERROR "Error %d in AddValue"
+#define MSG_ADD_BAD_TYPE "Array add value type mismatch (%s -> %s)"
+#define MSG_ADD_NULL_DOM "Adding string %s to a null domain"
+#define MSG_ADPOS_IN_DICTP "ADPOS to work in User_Dictp"
+#define MSG_AFTER " after: "
+#define MSG_ALG_CHOICE_AUTO "Best algorithm choice is automatic"
+#define MSG_ALG_CHOICE_BAD "Bad algorithm choice value, reset to AUTO"
+#define MSG_ALG_CHOICE_QRY "Using Query algorithm"
+#define MSG_ALG_CURLY_BRK "Algorithm choice depends on outer curly brackets"
+#define MSG_ALLOC_ERROR "Error allocating %s"
+#define MSG_ALL_DELETED "All lines deleted in %.2lf sec"
+#define MSG_ALTER_DB_ERR "Cannot find the DB to alter"
+#define MSG_AMBIG_COL_QUAL "Ambiguous qualifier %s for column %s"
+#define MSG_AMBIG_CORREL "Select %s.* refers more than one table"
+#define MSG_AMBIG_SPEC_COL "Ambiguous special column %s"
+#define MSG_ANSWER_TYPE "Answer of type"
+#define MSG_API_CONF_ERROR "SQL Error: API_CONFORMANCE"
+#define MSG_APPL_ACCESSIBLE "Application %s accessible"
+#define MSG_APPL_ACTIVE "Application %s still active"
+#define MSG_APPL_BAD_SAVE "Application %s may be incorrectly saved"
+#define MSG_APPL_CREATED "Application %s created"
+#define MSG_APPL_IS_ACTIVE "Application already active"
+#define MSG_APPL_NOT_INIT "Application not initialized"
+#define MSG_APPL_NOT_LOADED "Application not loaded"
+#define MSG_APPL_QUIT "Application %s quit"
+#define MSG_APPL_SAVED "Application %s saved"
+#define MSG_APP_STILL_ACTIV "Application of language %s still active (not freed)"
+#define MSG_AREAFILE_NOTFND "Area file not found"
+#define MSG_ARGS_SYNTAX_ERR "?SetArgs syntax error: unexpected %s after %s"
+#define MSG_ARG_ALREADY_SET "Argument %d already set"
+#define MSG_ARG_NOT_AN_ATTR "Argument is not an attribute (wrong pos-type %d)"
+#define MSG_ARG_OUT_CONTEXT "@-type argument used out of context"
+#define MSG_ARG_OUT_RANGE "Phrase argument of value %d is out of range"
+#define MSG_ARG_PTR_NOSEM "Argument of value %d points to a nonterm having no Sem"
+#define MSG_ARG_PTR_NOSEMS "Argument of value %d points to a nonterm having no semantics"
+#define MSG_ARG_REF_LOOP "?Looping argument cross references"
+#define MSG_ARG_TWO_CONST "2nd argument of %s must be a constant"
+#define MSG_ARRAY_ALLOC_ERR "Memory allocation error in ARRAY"
+#define MSG_ARRAY_BNDS_EXCD "Array bounds exceeded"
+#define MSG_ARRAY_ERROR "Error while making array k=%d n=%d"
+#define MSG_ATTRIBUTE_ERROR "Error rule %u attribute %s: "
+#define MSG_ATT_NOT_CASE "Attribute has wrong value %d (not a casevalue)"
+#define MSG_ATT_POSCODE_BIG "Attribute poscode %d is too big (max=%d)"
+#define MSG_AVGLEN_ERROR "avglen should be between %d and %d"
+#define MSG_BAD_AGGREG_FUNC "Unsupported aggregate function %d"
+#define MSG_BAD_ARGTYPES "Argument type invalid for %s"
+#define MSG_BAD_ARGUMENTS "Argument not attached for %s"
+#define MSG_BAD_ARG_NUM "Invalid number of arguments %d"
+#define MSG_BAD_ARG_TYPE "Bad argument type %d"
+#define MSG_BAD_ARRAY_OPER "Arrays must be used with the IN operator"
+#define MSG_BAD_ARRAY_TYPE "Illegal array type %d"
+#define MSG_BAD_ARRAY_VAL "Arrays must have the same number of values"
+#define MSG_BAD_BIN_FMT "Invalid format %c for the %s BIN column"
+#define MSG_BAD_BLK_ESTIM "Number of blocks exceeds estimate"
+#define MSG_BAD_BLK_SIZE "No match in block %d size"
+#define MSG_BAD_BYTE_NUM "bad number of bytes written"
+#define MSG_BAD_BYTE_READ "bad number of bytes read"
+#define MSG_BAD_CARDINALITY "Invalid Cardinality call for multiple table"
+#define MSG_BAD_CASE_SPEC "Wrong case specification %c, enter new one: "
+#define MSG_BAD_CHAR_SPEC "Invalid character specification:'%s'"
+#define MSG_BAD_CHECK_TYPE "Invalid CheckColumn subtype %d"
+#define MSG_BAD_CHECK_VAL "Bad check setting '%s'"
+#define MSG_BAD_COLCRT_ARG "Bad COLCRT argument (type=%hd, domain=%hd)"
+#define MSG_BAD_COLDEF_TYPE "Coldefs: wrong type %d"
+#define MSG_BAD_COLIST_ITEM "Incorrect colist item"
+#define MSG_BAD_COLIST_TYPE "Bad Colist type=%d"
+#define MSG_BAD_COLSIZE "Colsize %d is too small for this database"
+#define MSG_BAD_COL_ENTRY "Invalid entry for column %s"
+#define MSG_BAD_COL_FORMAT "Invalid column format type %d"
+#define MSG_BAD_COL_IN_FILT "Incorrect column in filter"
+#define MSG_BAD_COL_QUALIF "Bad qualifier %s for column %s"
+#define MSG_BAD_COL_TYPE "Invalid type %s for column %s"
+#define MSG_BAD_COL_XPATH "Invalid Xpath in column %s for HTML table %s"
+#define MSG_BAD_COMPARE_OP "Bad compare op %d"
+#define MSG_BAD_CONST_TYPE "Bad constant type=%d"
+#define MSG_BAD_CONV_TYPE "Invalid convert type %d"
+#define MSG_BAD_CORREL "Select %s.* correlation refers no tables"
+#define MSG_BAD_DATETIME "Invalid datetime value"
+#define MSG_BAD_DATE_OPER "Unexpected date operator %d"
+#define MSG_BAD_DBF_FILE "DBF file %s is corrupted"
+#define MSG_BAD_DBF_REC "DBF file %s corrupted at record %d"
+#define MSG_BAD_DBF_TYPE "Unsupported DBF type %c"
+#define MSG_BAD_DEF_ARG "Bad INDEXDEF argument (type=%hd, domain=%hd)"
+#define MSG_BAD_DEF_READ "Unexpected EOF in deferred Read"
+#define MSG_BAD_DEF_TYPE "Invalid column definition type"
+#define MSG_BAD_DIRECTORY "Bad directory %s: %s"
+#define MSG_BAD_DIST_JN_FIL "Invalid Distinct Join filter"
+#define MSG_BAD_DIST_JOIN "Invalid Distinct Join specification"
+#define MSG_BAD_DOM_COL_DEF "Invalid column definitions for a domain"
+#define MSG_BAD_DOM_VALUE "%d is not a valid domain value"
+#define MSG_BAD_EDIT_INIT "Coparm: edition %s not properly initialized"
+#define MSG_BAD_EVAL_TYPE "Bad scalar function eval type=%d"
+#define MSG_BAD_EXEC_MODE "Bad execution mode '%s'"
+#define MSG_BAD_EXP_ARGTYPE "Invalid expression argument type=%d"
+#define MSG_BAD_EXP_OPER "Bad expression operator=%d"
+#define MSG_BAD_FETCH_RC "Unexpected Fetch return code %d"
+#define MSG_BAD_FIELD_FMT "Invalid field format %c for %s"
+#define MSG_BAD_FIELD_RANK "Invalid field rank %d for column %s"
+#define MSG_BAD_FIELD_TYPE "Bad type field %s"
+#define MSG_BAD_FILE_HANDLE "Invalid File Handle: %s"
+#define MSG_BAD_FILE_LIST "Bad Filelist section"
+#define MSG_BAD_FILTER "Bad filter: Opc=%d B_T=%d %d Type=%d %d"
+#define MSG_BAD_FILTER_CONV "Bad filter conversion, B_T=%d,%d"
+#define MSG_BAD_FILTER_LINK "Bad filter link operator %d"
+#define MSG_BAD_FILTER_OP "Invalid filter operator %d"
+#define MSG_BAD_FILTEST_OP "Invalid operator %d %d for FilTest"
+#define MSG_BAD_FLD_FORMAT "Bad format for field %d of %s"
+#define MSG_BAD_FLD_LENGTH "Field %s too long (%s --> %d) line %d of %s"
+#define MSG_BAD_FLOAT_CONV "Invalid convert of float array"
+#define MSG_BAD_FPARM_NEXT "Coparm: FPARM with non-null Next"
+#define MSG_BAD_FREQ_SET "Bad frequency setting for column %s"
+#define MSG_BAD_FUNC_ARG "Funcarg of type %d not implemented"
+#define MSG_BAD_FUNC_ARGTYP "Bad Function argument type=%d"
+#define MSG_BAD_FUNC_MODE "%s: invalid mode %d"
+#define MSG_BAD_GENRE "Genre is invalid"
+#define MSG_BAD_GETVIEW_RET "GetView: invalid return type %d"
+#define MSG_BAD_HANDLE_VAL "Invalid handle value"
+#define MSG_BAD_HAV_FILTER "Having filter found in a Vanilla query"
+#define MSG_BAD_HAV_FILTYPE "Bad filter type for Having Clause"
+#define MSG_BAD_HEADER "File %s: Header corrupted"
+#define MSG_BAD_HEADER_VAL "Invalid header value %d"
+#define MSG_BAD_HEAD_END "Can't read end of header"
+#define MSG_BAD_INDEX_COL "Bad column %s for index %s"
+#define MSG_BAD_INDEX_DEF "Bad index definition for %s"
+#define MSG_BAD_INDEX_FILE "Wrong index file %s"
+#define MSG_BAD_INDEX_PART "Bad index part for %s"
+#define MSG_BAD_INPUT "Incorrect input"
+#define MSG_BAD_IN_ARGTYPE "Bad argument type for IN operator"
+#define MSG_BAD_IN_ENDING "Error: wrong end of IN string"
+#define MSG_BAD_IN_STRING "IN string begins or ends with invalid char %c ... %c"
+#define MSG_BAD_JCOL_TYPE "Logical JCT error: Unmatched column types"
+#define MSG_BAD_JOIN_EXP "Invalid expression used in join"
+#define MSG_BAD_JOIN_FILTER "Improper join filter"
+#define MSG_BAD_JOIN_OP "Bad join operator %d"
+#define MSG_BAD_LANG_SIZE "Wrong Language file size %d"
+#define MSG_BAD_LINEFLD_FMT "Bad format line %d field %d of %s"
+#define MSG_BAD_LINE_LEN "Line length not equal to Lrecl"
+#define MSG_BAD_LIST_TYPE "Invalid list type=%d"
+#define MSG_BAD_LOCALE "Invalid locale %s"
+#define MSG_BAD_LOCDFON_ARG "Bad parameter for LOCDFON"
+#define MSG_BAD_LOCNODE_USE "Unexpected use of LOCNODE"
+#define MSG_BAD_LRECL "Table/File lrecl mismatch (%d,%hd)"
+#define MSG_BAD_MAX_HAVING "MAXTMP value too small for Having"
+#define MSG_BAD_MAX_NREC "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d"
+#define MSG_BAD_MAX_PARAM "Bad parameters for setting max value"
+#define MSG_BAD_MAX_SETTING "Bad max setting '%c'"
+#define MSG_BAD_MERGE_TYPE "Type %d cannot be merged"
+#define MSG_BAD_NODE_TYPE "Bad type %d for table node"
+#define MSG_BAD_OFFSET_VAL "Invalid null offset value for a CSV table"
+#define MSG_BAD_OPEN_MODE "Invalid open mode %d"
+#define MSG_BAD_OPERATOR "Invalid operator %s"
+#define MSG_BAD_ORDER_MODE "Bad ordering mode %c"
+#define MSG_BAD_ORDER_TYPE "Type=%d invalid for order item"
+#define MSG_BAD_OUTER_JOIN "Invalid outer join on child table"
+#define MSG_BAD_PAD_ARGTYP "Bad argument type for Pad or Justify"
+#define MSG_BAD_PARAMETERS "%.8s: Bad parameters"
+#define MSG_BAD_PARAM_TYPE "%.8s: Bad parameter type=%d"
+#define MSG_BAD_PARM_COUNT "Parameter count mismatch"
+#define MSG_BAD_PHASE_NUM "Out of range phrase number %d"
+#define MSG_BAD_PHRASE_NB "out of range phrase number %d rc=%d\n"
+#define MSG_BAD_POS_CODE "Invalid POS code %d"
+#define MSG_BAD_POS_TYPE "Invalid POS code type %d"
+#define MSG_BAD_PROJNUM "Bad projnum %d for column %s"
+#define MSG_BAD_QUERY_OPEN "Query open invalid mode %d"
+#define MSG_BAD_QUERY_TYPE "Invalid query type %d for %s"
+#define MSG_BAD_QUOTE_FIELD "Missing ending quote in %s field %d line %d"
+#define MSG_BAD_READ_NUMBER "Wrong number %d of values read from %s"
+#define MSG_BAD_RECFM "Invalid recfm type %d for DOSCOL"
+#define MSG_BAD_RECFM_VAL "Bad Recfm value %d"
+#define MSG_BAD_RESULT_TYPE "Bad result type %d for %s"
+#define MSG_BAD_RETURN_TYPE "Bad returned type %d"
+#define MSG_BAD_ROW_VALIST "Invalid ROW list of values"
+#define MSG_BAD_ROW_VALNB "Number of values in list mismatch"
+#define MSG_BAD_SCF_ARGTYPE "Argument %d type=%s invalid for %s"
+#define MSG_BAD_SEM_DOMAIN "Invalid domain .%d"
+#define MSG_BAD_SETTINGS "Some settings do not match table type"
+#define MSG_BAD_SET_CASE "Cannot set sensitive an insensitive array"
+#define MSG_BAD_SET_STRING "Invalid SetValue from string"
+#define MSG_BAD_SET_TYPE "Bad set type %hd"
+#define MSG_BAD_SPECIAL_CMD "Ill formed special command"
+#define MSG_BAD_SPECIAL_COL "Bad special column %s"
+#define MSG_BAD_SPEC_COLUMN "Special column invalid for this table type"
+#define MSG_BAD_SQL_PARAM "Invalid SQL parameter for FindColblk"
+#define MSG_BAD_SUBLST_TYPE "Coparm: bad sub-list type %d"
+#define MSG_BAD_SUBSEL_IN_X "Bad sub-select in expression"
+#define MSG_BAD_SUBSEL_TYPE "Bad Sub-Select returned type %d"
+#define MSG_BAD_SUB_RESULT "Undefined Sub-Select function result"
+#define MSG_BAD_SUB_SELECT "Bad sub-select in function argument"
+#define MSG_BAD_TABLE_LINE "Illegal or truncated line '%s' in Tables section"
+#define MSG_BAD_TABLE_LIST "Table %s not found in table list"
+#define MSG_BAD_TABLE_TYPE "Bad type %s for table %s"
+#define MSG_BAD_TEST_TYPE "Array BlockTest type mismatch %s %s"
+#define MSG_BAD_TRIM_ARGTYP "Bad argument type for Trim"
+#define MSG_BAD_TYPE_FOR_IN "Arg type mismatch for IN function"
+#define MSG_BAD_TYPE_FOR_S "Incorrect type %d for %s(%d)"
+#define MSG_BAD_TYPE_LIKE "Bad operand(%d) type=%d for LIKE"
+#define MSG_BAD_UPD_COR "Qualifier %s of column %s not related to the updated table %s"
+#define MSG_BAD_USERBLK_LEN "User block write length error"
+#define MSG_BAD_USETEMP "Bad usetemp setting '%s'"
+#define MSG_BAD_USETEMP_VAL "Bad Usetemp value %d"
+#define MSG_BAD_VALBLK_INDX "Out of range valblock index value"
+#define MSG_BAD_VALBLK_TYPE "Invalid value block type %d"
+#define MSG_BAD_VALNODE "Bad type %d for column %s value node"
+#define MSG_BAD_VALUE_TYPE "Invalid value type %d"
+#define MSG_BAD_VAL_UPDATE "Don't know which %s value to update"
+#define MSG_BAD_VIEW_OPEN "View open invalid mode %d"
+#define MSG_BAD_XMODE_VAL "Bad execution mode %d"
+#define MSG_BAD_XOBJ_TYPE "Bad Xobject type %d"
+#define MSG_BAS_NS_LIST "Invalid namespaces list format"
+#define MSG_BIN_F_TOO_LONG "Value too long for field %s (%d --> %d)"
+#define MSG_BIN_MODE_FAIL "Set binary mode failed: %s"
+#define MSG_BLKTYPLEN_MISM "Non matching block types/lengths in SetValue"
+#define MSG_BLK_IS_NULL "Blk is NULL"
+#define MSG_BLOCK_NO_MATCH "Non matching block"
+#define MSG_BREAKPOINT "Breakpoint"
+#define MSG_BUFF_TOO_SMALL "GetColData: Buffer is too small"
+#define MSG_BUFSIZE_ERROR "Error getting screen buffer size"
+#define MSG_BUILDING_GROUPS "Building groups"
+#define MSG_BUILD_DIST_GRPS "Building groups distinct"
+#define MSG_BUILD_INDEX "Building index %s on %s"
+#define MSG_BXP_NULL "Bxp NULL in PUTFON"
+#define MSG_CANNOT_OPEN "Cannot open %s"
+#define MSG_CD_ONE_STEP "Count Distinct must be processed in one step"
+#define MSG_CD_ORDER_ERROR "Ordering error in Count Distinct"
+#define MSG_CHECKING_ROWS "Checking rows to update"
+#define MSG_CHECK_LEVEL "Checking level reset to %u"
+#define MSG_CHSIZE_ERROR "chsize error: %s"
+#define MSG_CLN_NOT_IN_JOIN "Column C%d not found in join"
+#define MSG_CNTDIS_COL_LOST "Count Distinct column lost"
+#define MSG_COLIST_BAD_TYPE "Invalid Colist element type=%d"
+#define MSG_COLNAM_TOO_LONG "Column name too long"
+#define MSG_COLSEC_TOO_BIG "Column section too big in table %s (%d)"
+#define MSG_COLS_REDUCED " (reduced by Maxcol)"
+#define MSG_COLUMN_ERROR "Column error"
+#define MSG_COLUMN_MISMATCH "Column %s mismatch"
+#define MSG_COLUMN_NOT_KEY "Join column R%d.%s is not a key"
+#define MSG_COL_ALLOC_ERR "Cannot allocate column node"
+#define MSG_COL_ALLOC_ERROR "Memory allocation error for column %d"
+#define MSG_COL_HAS_NO_DEF "Column %s has no definition"
+#define MSG_COL_INVAL_TABLE "Column %s.%s not found in table %s alias %s"
+#define MSG_COL_ISNOT_TABLE "Column %s is not in table %s"
+#define MSG_COL_NB_MISM "Number of columns mismatch"
+#define MSG_COL_NOTIN_GRPBY "Column %s not in Group By list"
+#define MSG_COL_NOTIN_TABLE "Column %s is not in any table"
+#define MSG_COL_NOTIN_UPDT "%s does not belong to the updated table %s"
+#define MSG_COL_NOT_CODED "Column %s is not coded"
+#define MSG_COL_NOT_EXIST "Column %s is not in table %s"
+#define MSG_COL_NOT_FOUND "Column %s does not exist in %s"
+#define MSG_COL_NOT_IN_DB "Column %s of table %s not in DB"
+#define MSG_COL_NOT_IN_JOIN "Column %s not found in join"
+#define MSG_COL_NOT_SORTED "Column %s of table %s is not sorted"
+#define MSG_COL_NUM_MISM "Number of columns mismatch"
+#define MSG_COL_USED_TWICE "Column %s linked twice ???"
+#define MSG_COMPUTE_ERROR "Error in Compute, op=%d"
+#define MSG_COMPUTE_NIY "Compute not implemented for token strings"
+#define MSG_COMPUTING "Computing"
+#define MSG_COMPUTING_DIST "Computing Distinct"
+#define MSG_COMPUTING_FUNC "Computing function(s)"
+#define MSG_COM_ERROR "Com error"
+#define MSG_CONCAT_SUBNODE "Cannot concatenate sub-nodes"
+#define MSG_CONNECTED "Connected"
+#define MSG_CONNECT_CANCEL "Connection cancelled by user"
+#define MSG_CONNECT_ERROR "Error %d connecting to %s"
+#define MSG_CONN_CLOSED "%s(%d) closed"
+#define MSG_CONN_CREATED "Connection %s created"
+#define MSG_CONN_DROPPED "Connection %s dropped"
+#define MSG_CONN_OPEN "%s(%d) open (%s)"
+#define MSG_CONN_SUC_OPEN "%s(%d) successfully open"
+#define MSG_CONTROL_C_EXIT "Control C exit"
+#define MSG_COPY_BAD_PHASE "List copy invalid in phase %d"
+#define MSG_COPY_INV_TYPE "Coparm: type not supported %d"
+#define MSG_CORREL_NO_QRY "Correlated subqueries cannot be of QRY type"
+#define MSG_CREATED_PLUGDB " Created by PlugDB %s "
+#define MSG_CURSOR_SET "Cursor set to %d"
+#define MSG_DATABASE_ACTIVE "Database %s activated"
+#define MSG_DATABASE_LOADED "Database %s loaded"
+#define MSG_DATA_IS_NULL "ExecSpecialCmd: data is NULL"
+#define MSG_DATA_MISALIGN "Datatype misalignment"
+#define MSG_DBASE_FILE "dBASE dbf file: "
+#define MSG_DB_ALREADY_DEF "Database %s already defined"
+#define MSG_DB_ALTERED "Database altered"
+#define MSG_DB_CREATED "Database %s created"
+#define MSG_DB_NOT_SPEC "Database not specified"
+#define MSG_DB_REMOVED "Database %s removed from DB list"
+#define MSG_DB_SORT_ERROR "Error in DB sort"
+#define MSG_DB_STOPPED "Database %s stopped"
+#define MSG_DEBUG_NOT_ACTIV "Debug is not active"
+#define MSG_DEBUG_SET_INV "Invalid Debug set %c"
+#define MSG_DEF_ALLOC_ERROR "Error allocating %s DEF class"
+#define MSG_DELETING_ROWS "Deleting rows"
+#define MSG_DEL_FILE_ERR "Error deleting %s"
+#define MSG_DEL_READ_ERROR "Delete: read error req=%d len=%d"
+#define MSG_DEL_WRITE_ERROR "Delete: write error: %s"
+#define MSG_DEPREC_FLAG "Deprecated option Flag, use Coltype"
+#define MSG_DICTIONARY "Dictionary "
+#define MSG_DIRECT_VARTOK "Direct access of variable token rules not implemented"
+#define MSG_DISCONNECTED "Disonnected"
+#define MSG_DISTINCT_ERROR "More than one DISTINCT functional item"
+#define MSG_DISTINCT_ROWS "Selecting distinct rows"
+#define MSG_DISTINCT_VALUES "Retrieving distinct values"
+#define MSG_DIS_NOHEAD_JOIN "Distinct join on not heading table"
+#define MSG_DLL_LOAD_ERROR "Error %d loading module %s"
+#define MSG_DOMAIN_EMPTY "Domain %s is empty"
+#define MSG_DOMAIN_ERROR "Column %s domain(%s)/value(%s) mismatch"
+#define MSG_DOMAIN_FULL "Domain %s is full (max=%d)"
+#define MSG_DOM_FILE_ERROR "Domain file %s not found"
+#define MSG_DOM_NOT_SUPP "MS-DOM not supported by this version"
+#define MSG_DOM_OPEN_ERROR "Domain open error: %s"
+#define MSG_DOM_READ_ERROR "Domain read error %d: %s"
+#define MSG_DOM_READ_ONLY "Domain table %s is read only"
+#define MSG_DOM_WRITE_ERROR "Domain write error %d: %s"
+#define MSG_DONE "Done, rc=%d"
+#define MSG_DOSALMEM_NOMEM "Memory Allocation failed, not enough memory"
+#define MSG_DROP_DB_ERR "Drop database %s failed"
+#define MSG_DSORT_LOG_ERROR "Logical error in Kindex distinct Sort"
+#define MSG_DUMMY_NO_COLS "Dummy tables must have no columns"
+#define MSG_DUPLICAT_COUNT "Count on more than one column"
+#define MSG_DUP_COL_NAME "Duplicate column name %s"
+#define MSG_DUP_PROJNUM "Duplicated projnum %d for column %s"
+#define MSG_DVAL_NOTIN_LIST "Value %s not found in distinct values list of column %s"
+#define MSG_EMPTY_DOC "Empty document"
+#define MSG_EMPTY_FILE "%s empty file %s: "
+#define MSG_ENDSTR_MISMATCH "No match between end of string and end of node"
+#define MSG_END_OF_DELETE "%d line(s) deleted in %.2lf sec"
+#define MSG_END_OF_INSERT "%d line(s) inserted in %.2lf sec"
+#define MSG_END_OF_QUERY "%d line(s) retrieved in %.2lf sec"
+#define MSG_END_OF_UPDATE "%d line(s) updated in %.2lf sec"
+#define MSG_EOF_AFTER_LINE "EOF after line %d"
+#define MSG_EOF_INDEX_FILE "EOF while reading index file"
+#define MSG_ERASED " and erased"
+#define MSG_ERASE_FAILED " (erase failed)"
+#define MSG_ERROR "Error"
+#define MSG_ERROR_IN_LSK "Error %d in lseek64"
+#define MSG_ERROR_IN_SFP "Error %d in SetFilePointer"
+#define MSG_ERROR_NO_PARM "No parameter (valid only with %.8s.1 and %.8s.5)"
+#define MSG_ERROR_OPENING "Error opening: "
+#define MSG_ERR_NUM_GT_MAX "Error: Numval (%d) greater than Maxnum (%d)"
+#define MSG_ERR_READING_REC "Error reading record %d of %s"
+#define MSG_ERR_RET_RULE "error return, rule=%u"
+#define MSG_ERR_RET_TYPE "error return, type=%d"
+#define MSG_EVAL_EXPIRED "Evaluation version expired"
+#define MSG_EVAL_ONLY "I agree to use this Dll for evaluation purpose only"
+#define MSG_EXECUTING "Executing"
+#define MSG_EXECUTION_ERROR "Execution error"
+#define MSG_EXEC_MODE_IS "Execution mode is %s"
+#define MSG_EXEC_MODE_RESET ". Mode reset to Execute"
+#define MSG_EXEC_MODE_SET "Execution mode set to %s"
+#define MSG_EXIT_EVAL_ERR "Error evaluating Exit"
+#define MSG_EXIT_FROM_LANG "Exit from language %s version %d.%d"
+#define MSG_FAIL_ADD_NODE "Failed to add %s table node"
+#define MSG_FETCHING_DATA "Fetching data"
+#define MSG_FETCHING_ROWS "Fetching rows"
+#define MSG_FETCH_NO_RES "Fetch: No Result Set"
+#define MSG_FIELD_TOO_LONG "Value too long for field %d line %d"
+#define MSG_FILELEN_ERROR "Error in %s for %s"
+#define MSG_FILE_CLOSE_ERR "Error %d occurred closing the file"
+#define MSG_FILE_IS_EMPTY "File %s is empty"
+#define MSG_FILE_MAP_ERR "File mapping error"
+#define MSG_FILE_MAP_ERROR "CreateFileMapping %s error rc=%d"
+#define MSG_FILE_NOT_FOUND "File %s cannot be found"
+#define MSG_FILE_OPEN_YET "File %s already open"
+#define MSG_FILE_UNFOUND "File %s not found"
+#define MSG_FILGRP_NO_TABLE "Missing table %d for a filter group"
+#define MSG_FILTER_ATTACH "Filter passed to Attach"
+#define MSG_FILTER_NO_TABLE "Missing first table for a filter"
+#define MSG_FIND_BAD_TYPE "Array Find type mismatch %s %s"
+#define MSG_FIX_OVFLW_ADD "Fixed Overflow on add"
+#define MSG_FIX_OVFLW_TIMES "Fixed Overflow on times"
+#define MSG_FIX_UNFLW_ADD "Fixed Underflow on add"
+#define MSG_FIX_UNFLW_TIMES "Fixed Underflow on times"
+#define MSG_FLD_TOO_LNG_FOR "Field %d too long for %s line %d of %s"
+#define MSG_FLTST_NO_CORREL "FilTest should be called only for correlated subqueries"
+#define MSG_FLT_BAD_RESULT "Float inexact result"
+#define MSG_FLT_DENORMAL_OP "Float denormal operand"
+#define MSG_FLT_INVALID_OP "Float invalid operation"
+#define MSG_FLT_OVERFLOW "Float overflow"
+#define MSG_FLT_STACK_CHECK "Float stack check"
+#define MSG_FLT_UNDERFLOW "Float underflow"
+#define MSG_FLT_ZERO_DIVIDE "Float divide by zero"
+#define MSG_FMT_WRITE_NIY "Writing %s files is not implemented yet"
+#define MSG_FNC_NOTIN_SLIST "Order aggregate function not in select list"
+#define MSG_FORMAT_ERROR "Formating error"
+#define MSG_FOXPRO_FILE "FoxPro file: "
+#define MSG_FPUTS_ERROR "fputs error: %s"
+#define MSG_FSBPARP_NULL "PUTFON: fsbparp is NULL"
+#define MSG_FSEEK_ERROR "fseek error: %s"
+#define MSG_FSETPOS_ERROR "fseek error for i=%d"
+#define MSG_FTELL_ERROR "ftell error for recd=%d: %s"
+#define MSG_FUNCTION_ERROR "%s error: %d"
+#define MSG_FUNC_ERRNO "Error %d in %s"
+#define MSG_FUNC_ERROR "Error in %s"
+#define MSG_FUNC_ERR_S "%s error: %s"
+#define MSG_FUNC_REF_DEL "Reference to a defined function (rule %d) which has been deleted"
+#define MSG_FWRITE_ERROR "fwrite error: %s"
+#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
+#define MSG_GETFILESIZE_ERR "Error %d in GetFileSize"
+#define MSG_GET_DIST_VALS "Retrieving distinct values from "
+#define MSG_GET_ERROR "Error in %s (column %d)"
+#define MSG_GET_FUNC_ERR "Error getting function %s: %s"
+#define MSG_GET_NAME_ERR "Error getting SYS table names"
+#define MSG_GLOBAL_ERROR "Cannot allocate Global (size=%d)\n"
+#define MSG_GRAM_ALLOC_ERR "Allocation error in Grammar Up"
+#define MSG_GRAM_MISMATCH "Warning: GRAMMAR version mismatch (saved under GRAMMAR v%u)"
+#define MSG_GRAM_SUBSET_ERR "Grammar dictionary Subset error"
+#define MSG_GRBY_TAB_NOTIMP "Group by filtered joined table not implemented"
+#define MSG_GROUPBY_NOT_ALL "Group By must include all non-functional select items"
+#define MSG_GROUP_ON_FUNC "Invalid group by on functional column"
+#define MSG_GRP_COL_MISM "Column mismatch in groups"
+#define MSG_GRP_LIST_MISMAT "Grouping does not match select list"
+#define MSG_GUARD_PAGE "Guard page violation"
+#define MSG_GZOPEN_ERROR "gzopen %s error %d on %s"
+#define MSG_GZPUTS_ERROR "gzputs error: %s"
+#define MSG_HANDLE_IS_NULL "%s is NULL: last error: %d"
+#define MSG_HARRY_COMP_NIY "Compute not implemented for coded strings"
+#define MSG_HAVING_FILTER "Filtering by Having"
+#define MSG_HBUF_TOO_SMALL "Buffer(%d) too small for header(%d)"
+#define MSG_HEAD_OPEN_ERROR "Error opening header file %s"
+#define MSG_HEAD_READ_ERROR "Error reading header file %s"
+#define MSG_HEAD_WRITE_ERR "Error writing header file %s"
+#define MSG_HI_OFFSET_ERR "High offet is not 0"
+#define MSG_HUGE_DEFAULT "Huge defaults to %d"
+#define MSG_HUGE_WARNING_1 "Huge memory not 16-bit compatible for %d\n"
+#define MSG_HUGE_WARNING_2 "Unpredictable results may occur\n"
+#define MSG_IDLE "Idle"
+#define MSG_ILLEGAL_INSTR "Illegal instruction"
+#define MSG_ILL_FILTER_CONV "Filtering implies an illegal conversion"
+#define MSG_INDEX_CREATED "Index %s created on %s"
+#define MSG_INDEX_DEF_ERR "Error storing index definition for %s"
+#define MSG_INDEX_DROPPED "Index %s dropped from %s"
+#define MSG_INDEX_INIT_ERR "Cannot initialize index %s"
+#define MSG_INDEX_NOT_DEF "Index %s has no definition"
+#define MSG_INDEX_NOT_UNIQ "Index is not unique"
+#define MSG_INDEX_ONE_SAVE "Indexes are saved in one unique file"
+#define MSG_INDEX_SEP_SAVE "Indexes are saved in separate files"
+#define MSG_INDEX_YET_ON "Index %s already exists on %s"
+#define MSG_INDX_ALL_DROP "All indexes dropped from %s"
+#define MSG_INDX_COL_NOTIN "Index column %s is not in table %s"
+#define MSG_INDX_EXIST_YET "Index entry already exists"
+#define MSG_INIT_ERROR "Error initializing %s"
+#define MSG_INIT_FAILED "Failed to initialize %s processing"
+#define MSG_INPUT "Input: "
+#define MSG_INPUT_KEYBD_YET "Input already from keyboard"
+#define MSG_INSERTING "Inserting: "
+#define MSG_INSERT_ERROR "Insert error: file %s in use"
+#define MSG_INSERT_MISMATCH "Column/Value list mismatch"
+#define MSG_INTERNAL "internal"
+#define MSG_INT_COL_ERROR "Internal error for index column %s"
+#define MSG_INT_OVERFLOW "Integer overflow"
+#define MSG_INT_ZERO_DIVIDE "Integer divide by zero"
+#define MSG_INVALID_BIP "Invalid Bip .%d"
+#define MSG_INVALID_DISP "Invalid disposition"
+#define MSG_INVALID_FTYPE "SBV: invalid Ftype %d"
+#define MSG_INVALID_HANDLE "Invalid handle"
+#define MSG_INVALID_OPER "Invalid operator %d for %s"
+#define MSG_INVALID_OPTION "Invalid option %s"
+#define MSG_INV_COLUMN_TYPE "Invalid type %d for column %s"
+#define MSG_INV_COL_DATATYP "Invalid Data Type %d for column %d"
+#define MSG_INV_COL_NUM "Invalid column %d"
+#define MSG_INV_COL_TYPE "Invalid column type %s"
+#define MSG_INV_CONC_BIP "Invalid bip (only valid are : %.8s.0 .1 and .5)"
+#define MSG_INV_DATA_PATH "Invalid database path %s"
+#define MSG_INV_DEF_READ "Invalid deferred Read rc=%d"
+#define MSG_INV_DIRCOL_OFST "Invalid DIRCOL offset %d"
+#define MSG_INV_DOMAIN_TYPE "Invalid type %d"
+#define MSG_INV_FILTER "Filter met in %s"
+#define MSG_INV_FNC_BUFTYPE "FNC: invalid argument type %d for %s"
+#define MSG_INV_INFO_TYPE "Invalid catalog info type %d"
+#define MSG_INV_INIPATH "Invalid inipath "
+#define MSG_INV_MAP_POS "Invalid map position"
+#define MSG_INV_OPERATOR "invalid operator %d\n"
+#define MSG_INV_PARAMETER "Invalid parameter %s"
+#define MSG_INV_PARM_TYPE "Invalid parameter type"
+#define MSG_INV_QUALIFIER "Invalid qualifier '%s'"
+#define MSG_INV_QUERY_TYPE "Invalid query type %d"
+#define MSG_INV_RAND_ACC "Invalid random access to non optimized table"
+#define MSG_INV_REC_POS "Invalid record position"
+#define MSG_INV_RESULT_TYPE "Invalid result type %s"
+#define MSG_INV_SET_SUBTYPE "Invalid SetFormat subtype %d"
+#define MSG_INV_SPECIAL_CMD "%s: Invalid special command"
+#define MSG_INV_SUBTYPE "Invalid subtype %s"
+#define MSG_INV_TOK_DOMAIN "Invalid token domain %s"
+#define MSG_INV_TOPSEM_CMD "Invalid TopSem command %c"
+#define MSG_INV_TRANSF_USE "Invalid use in transformation rule"
+#define MSG_INV_TYPE_SPEC "Invalid type specification (%.8s.%d)"
+#define MSG_INV_UPDT_TABLE "Table %s invalid for update"
+#define MSG_INV_VALUE_LIST "Invalid Insert value list"
+#define MSG_INV_WHERE_JOIN "Invalid where clause in join query"
+#define MSG_INV_WORK_PATH "Invalid work path %s"
+#define MSG_IN_ARGTYPE_MISM "Argument type mismatch for IN expression"
+#define MSG_IN_USE " and in use"
+#define MSG_IN_WITHOUT_SUB "IN or EXISTS without array or subquery"
+#define MSG_IS_NOT_CONN "%s is not a connection definition"
+#define MSG_JCT_MISS_COLS "Missing columns for a JCT table"
+#define MSG_JCT_MISS_TABLE "Missing joined table for JCT"
+#define MSG_JCT_NO_FILTER "Virtual JCT tables cannot be filtered"
+#define MSG_JCT_NO_KEY "Logical JCT error: no key"
+#define MSG_JOIN_KEY_NO_COL "Join key is not a column"
+#define MSG_KEY_ALLOC_ERR "Error allocating Key offset block"
+#define MSG_KEY_ALLOC_ERROR "Memory allocation error, Klen=%d n=%d"
+#define MSG_LANGUAGE_QUIT "%s quit"
+#define MSG_LANG_ACTIVE "Language %s active"
+#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Lang block allocation failed"
+#define MSG_LANG_ALREADY_UP "Edited language is already there"
+#define MSG_LANG_BAD_SAVE "Language %s may be incorrectly saved"
+#define MSG_LANG_NOT_FREED "Language %s cannot be freed (not in main chain)"
+#define MSG_LANG_SAVED "Language %s saved"
+#define MSG_LANG_WR_LEN_ERR "Lang block write length error"
+#define MSG_LDF_ALLOC_ERROR "LdfBlock allocation error"
+#define MSG_LDF_RN_MISMATCH "LDF rule number mismatch"
+#define MSG_LDF_WLEN_ERROR "LdfData write length error"
+#define MSG_LDF_W_LEN_ERROR "LdfData write length error"
+#define MSG_LIC_NO_MYSQL "Your current license does not enable using the MySQL table type"
+#define MSG_LINEAR_ERROR "Linearization error"
+#define MSG_LINE_LENGTH "Output line length reset to %d"
+#define MSG_LINE_MAXLIN "Max number of work lines reset to %d"
+#define MSG_LINE_MAXRES "Max number of output lines reset to %d"
+#define MSG_LINE_MAXTMP "Max number of intermediate lines reset to %d"
+#define MSG_LINE_TOO_LONG "New line is too long"
+#define MSG_LINJOINDB_ERROR "System error: incorrect call to LinJoinDB"
+#define MSG_LIST "--List--"
+#define MSG_LNG_NOT_IN_LIST "Language %s not found in attached list"
+#define MSG_LOADING_DB "Loading DB Description"
+#define MSG_LOADING_FAILED "Loading of %s failed"
+#define MSG_LOAD_CDLL_ERROR "Error loading ConnDll: rc=%d"
+#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n too big ? (%d)\n"
+#define MSG_LOGICAL_ERROR "%s: Logical error"
+#define MSG_LRECL_TOO_SMALL "Lrecl too small (headlen = %d)"
+#define MSG_MAC_NO_DELETE "Delete not enabled for MAC tables"
+#define MSG_MAC_NO_INDEX "No direct access to MAC tables"
+#define MSG_MAC_READ_ONLY "MAC tables are read only"
+#define MSG_MAC_WIN_ONLY "MAC tables are Windows only"
+#define MSG_MAKE_EMPTY_FILE "Making empty file %s: %s"
+#define MSG_MAKING "Making"
+#define MSG_MAKING_DISTINCT "Making distinct groups"
+#define MSG_MALLOC_ERROR "Memory allocation failed: %s returned Null"
+#define MSG_MALLOC_NULL "malloc returned Null"
+#define MSG_MAP_NO_MORE "Type %s no more supported"
+#define MSG_MAP_OBJ_ERR "Error %d occurred closing the mapping object"
+#define MSG_MAP_VEC_ONLY "MAP Insert is for VEC Estimate tables only"
+#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s error rc=%d"
+#define MSG_MAXSIZE_ERROR "Cannot calculate max size on open table"
+#define MSG_MAXTMP_TRUNCATE "Intermediate results truncated by maxtmp=%d"
+#define MSG_MAX_BITMAP "Max opt bitmap size reset to %d"
+#define MSG_MEMSIZE_TOO_BIG "Error: memsize (%d) too big for length (%d)"
+#define MSG_MEM_ALLOC_ERR "Memory allocation error, %s size=%d"
+#define MSG_MEM_ALLOC_ERROR "Memory allocation error"
+#define MSG_MEM_ALLOC_YET "Memory already allocated"
+#define MSG_METAFILE_NOTFND "Grammar Meta file not found"
+#define MSG_MISPLACED_QUOTE "Misplaced quote in line %d"
+#define MSG_MISSING "Missing: Value=%p Argval=%p Builtin=%d"
+#define MSG_MISSING_ARG "Missing argument for operator %d"
+#define MSG_MISSING_COL_DEF "Missing column definition"
+#define MSG_MISSING_CONNECT "Missing connect string"
+#define MSG_MISSING_EOL "Missing endline character in %s"
+#define MSG_MISSING_FIELD "Missing field %d in %s line %d"
+#define MSG_MISSING_FNAME "Missing file name"
+#define MSG_MISSING_NODE "Missing %s node in %s"
+#define MSG_MISSING_POS "Missing POS code"
+#define MSG_MISSING_ROWNODE "Can't find RowNode for row %d"
+#define MSG_MISSING_SERV_DB "Missing server and/or database string"
+#define MSG_MISS_LEAD_COL "Missing leading index column %s"
+#define MSG_MISS_NAME_LRECL "Missing file name and/or lrecl"
+#define MSG_MISS_TABLE_LIST "Missing table list"
+#define MSG_MISS_VCT_ELMT "Missing VCT block size (Elements)"
+#define MSG_MIS_TAG_LIST "Missing column tag list"
+#define MSG_MKEMPTY_NIY "MakeEmptyFile: not yet implemented for Huge and Unix"
+#define MSG_MOVE_INV_TYPE "MOVPARM: Invalid parameter type %d"
+#define MSG_MULT_DISTINCT "Distinct is specified more than once"
+#define MSG_MULT_KEY_ERROR "Multiple key error k=%d n=%d"
+#define MSG_MUL_MAKECOL_ERR "Tabmul MakeCol logical error"
+#define MSG_MYSQL_CNC_OFF "MySQL connection is closed"
+#define MSG_MYSQL_CNC_ON "MySQL connection is established"
+#define MSG_MYSQL_NOT_SUP "MySQL not supported by this version"
+#define MSG_MY_CNC_ALREADY "MySQL connection already active"
+#define MSG_NAME_CONV_ERR "Error converting node name"
+#define MSG_NAME_IS_USED "Name %s already in use"
+#define MSG_NCOL_GT_MAXCOL "Too many columns (%d > %d max)"
+#define MSG_NEW_CHAR_NULL "new char(%d) returned Null"
+#define MSG_NEW_DOC_FAILED "Cannot create new document"
+#define MSG_NEW_RETURN_NULL "New returned Null in PlugEvalLike"
+#define MSG_NEW_TABLE_ERR "Unable to retrieve new table %s"
+#define MSG_NEXT_FILE_ERROR "Couldn't find next file. rc=%d"
+#define MSG_NODEF_FROM_VIEW "Cannot define a table from a view"
+#define MSG_NODE_FOR_CHAR "Node %s found when looking for character"
+#define MSG_NODE_SUBSET_ERR "Node %d Subset error"
+#define MSG_NONCONT_EXCEPT "Noncontinuable exception"
+#define MSG_NON_DUP_HAVING "Having clause in non/dup functional query"
+#define MSG_NON_EVAL_SEM "Sem not evaluated: p_no=%d"
+#define MSG_NOP_ZLIB_INDEX "Cannot do indexing on non optimized zlib table"
+#define MSG_NOT_A_DBF_FILE "Not a dBASE dbf file "
+#define MSG_NOT_ENOUGH_COLS "Not enough columns in %s"
+#define MSG_NOT_ENOUGH_MEM "Not enough memory to perform this operation"
+#define MSG_NOT_FIXED_LEN "File %s is not fixed length, len=%d lrecl=%d"
+#define MSG_NOT_IMPLEMENTED "Not implemented: %.8s"
+#define MSG_NOT_IMPL_JOIN "Not implemented for Join"
+#define MSG_NOT_IMPL_SET "Not implemented for set operators"
+#define MSG_NOT_IMPL_YET "Not implemented yet"
+#define MSG_NOT_LINEARIZED "Table tree was not linearized"
+#define MSG_NOT_MODIFIABLE " (not modifiable)"
+#define MSG_NO_0DH_HEAD "No 0Dh at end of header (dbc=%d)"
+#define MSG_NO_ACTIVE_APPL "No active application"
+#define MSG_NO_ACTIVE_DB "No active database"
+#define MSG_NO_ACTIVE_UDIC "No active user dictionary"
+#define MSG_NO_AGGR_FUNC "Aggregated function %d not allowed here"
+#define MSG_NO_AREA_FILE "Area file not found"
+#define MSG_NO_AVAIL_RESULT "No result available"
+#define MSG_NO_BIG_DELETE "Partial delete not yet implemented for Huge files"
+#define MSG_NO_CHAR_FROM "Cannot return char value from type %d"
+#define MSG_NO_CLUSTER_COL "No clustered columns"
+#define MSG_NO_COL_ADDING "Cannot add new column(s) to old definition"
+#define MSG_NO_COL_DEF_AS "Column definitions cannot be used with AS Select"
+#define MSG_NO_COL_FOUND "No column found in section %s"
+#define MSG_NO_COL_IN_TABLE "Column %d not in table %s"
+#define MSG_NO_COL_SECTION "Missing column section for table %s"
+#define MSG_NO_CONNECT_ADDR "No connexion address provided"
+#define MSG_NO_CONST_FILTER "Constant filters not implemented"
+#define MSG_NO_CURLY_BRKT "No closing curly bracket"
+#define MSG_NO_DATABASE "Database %s not found"
+#define MSG_NO_DATE_FMT "No date format for valblock of type %d"
+#define MSG_NO_DBF_INSERT "Insert not supported yet for GDF files"
+#define MSG_NO_DEF_FNCCOL "Cannot find default function column"
+#define MSG_NO_DEF_PIVOTCOL "Cannot find default pivot column"
+#define MSG_NO_DIR_INDX_RD "No direct access of %s tables"
+#define MSG_NO_DMY_DIR_ACC "No direct access of virtual DUMMY tables"
+#define MSG_NO_DOM_DELETE "Partial delete not yet implemented for domains"
+#define MSG_NO_DOM_MATCH "Unmatched string %.8s... in domain %s"
+#define MSG_NO_EDITED_LANG "Coparm: No active edited language"
+#define MSG_NO_EXP_LINK "Cannot use expression to link a JCT table"
+#define MSG_NO_EXT_FILTER "Filtering cannot refer to another table"
+#define MSG_NO_EXT_UPDATE "Cannot update with reference to another table"
+#define MSG_NO_FEAT_SUPPORT "No %s support in this version"
+#define MSG_NO_FILE_LIST "Table %s has no file list"
+#define MSG_NO_FLD_FORMAT "Missing format for field %d of %s"
+#define MSG_NO_FORMAT_COL "Cannot format the type COLUMN"
+#define MSG_NO_FORMAT_TYPE "Cannot set format from type %d"
+#define MSG_NO_FULL_JOIN "Only Equi-join on key(s) is allowed by check setting"
+#define MSG_NO_FUL_OUT_JOIN "Full outer joins are not supported"
+#define MSG_NO_FUNC_ORDER "Unsupported ordering on functional item"
+#define MSG_NO_HEAD_JOIN "Join on not heading table"
+#define MSG_NO_HQL_CONV "Conversion to HQL not available"
+#define MSG_NO_INDEX "No indexes on table %s"
+#define MSG_NO_INDEX_GBX "No or improper index for SQLGBX"
+#define MSG_NO_INDEX_IN "No indexes found in %s"
+#define MSG_NO_INDEX_READ "No indexed read for multiple tables"
+#define MSG_NO_INIT_LANG "No initial language"
+#define MSG_NO_JOIN_TO_EXP "No join to expressions"
+#define MSG_NO_JOIN_UPDEL "Update/Delete on MySQL table cannot be joined"
+#define MSG_NO_KEY_COL "No key columns found"
+#define MSG_NO_KEY_UPDATE "Cannot update key names"
+#define MSG_NO_LANGUAGE "No language in operation\n"
+#define MSG_NO_LANG_TO_QUIT "No next language to quit"
+#define MSG_NO_LISTVAL_HERE "LSTBLK: List of values used out of context"
+#define MSG_NO_MAP_INSERT "MAP incompatible with Insert"
+#define MSG_NO_MATCHING_COL "No matching column %s in %s"
+#define MSG_NO_MATCH_COL "Cannot find matching column"
+#define MSG_NO_MEMORY "No memory"
+#define MSG_NO_MEM_CORR_SUB "In memory correlated subquery not implemented yet"
+#define MSG_NO_MODE_PADDED "Mode not supported for padded files"
+#define MSG_NO_MORE_COL "Column %s no more in pivot table"
+#define MSG_NO_MORE_LANG "No more language, exit from %s\n"
+#define MSG_NO_MORE_VAR "VAR files no more supported"
+#define MSG_NO_MULCOL_JOIN "No join yet on muticolumn index"
+#define MSG_NO_MULT_HAVING "Multiple having clauses not implemented"
+#define MSG_NO_MUL_DIR_ACC "Direct access of multiple tables not implemented yet"
+#define MSG_NO_MUL_VCT "VCT tables cannot be multiple"
+#define MSG_NO_MYSQL_CONN "No open MySQL connection"
+#define MSG_NO_MYSQL_DELETE "Delete should not be called for MySQL tables"
+#define MSG_NO_NBCOL "No NBcol"
+#define MSG_NO_NBLIN "No NBlin, MaxSize or Continued"
+#define MSG_NO_NBLIN_CONT "Fetch: No NBlin or Continued"
+#define MSG_NO_NULL_CONST "Cannot handle <null> constant"
+#define MSG_NO_ODBC_COL "Automatic ODBC columns not supported in this version"
+#define MSG_NO_ODBC_DELETE "Delete should not be called for ODBC tables"
+#define MSG_NO_ODBC_DIRECT "Direct access of ODBC tables not implemented yet"
+#define MSG_NO_ODBC_MUL "Multiple(2) not supported for ODBC tables"
+#define MSG_NO_ODBC_SPECOL "No ODBC special columns"
+#define MSG_NO_OPT_COLUMN "Not optimizable or no optimized columns"
+#define MSG_NO_OP_MODIF "Modificators do not apply to %s"
+#define MSG_NO_PARAMETER "No parameter"
+#define MSG_NO_PART_DEL "No partial delete of %s files"
+#define MSG_NO_PART_MAP "Partial mapping not implemented for this OS"
+#define MSG_NO_PAR_BLK_INS "Cannot insert partial block yet"
+#define MSG_NO_PIV_DIR_ACC "No direct access to PIVOT tables"
+#define MSG_NO_POS_ADDED "No Pos_code added"
+#define MSG_NO_PROMPTING "Cannot handle prompting for distributed tables"
+#define MSG_NO_QRY_DELETE "Delete cannot be used for QRY views"
+#define MSG_NO_QUERY_ARRAY "Array from QUERY not implemented yet"
+#define MSG_NO_RCUR_DSK_YET "Recursive use of DISK not implemented yet"
+#define MSG_NO_READ_32 "Can't read 32 bytes"
+#define MSG_NO_RECOV_SPACE "Cannot recover space in index file"
+#define MSG_NO_REF_DELETE "Cannot delete with reference to another table"
+#define MSG_NO_REF_UPDATE "Cannot update with reference to another table"
+#define MSG_NO_REMOTE_FNC "Cannot process some functions remotely"
+#define MSG_NO_ROWID_FOR_AM "Can't get RowID in direct access for tables of type %s"
+#define MSG_NO_ROW_NODE "Row node name is not defined"
+#define MSG_NO_SECTION_NAME "Missing section name"
+#define MSG_NO_SEC_UPDATE "Cannot update section names"
+#define MSG_NO_SELECTED_DB "No selected database"
+#define MSG_NO_SELF_PIVOT "Cannot pivot oneself!"
+#define MSG_NO_SERVER_FOUND "No server found"
+#define MSG_NO_SETPOS_YET "%s SetPos not implemented yet"
+#define MSG_NO_SFEXIT_UNIX "Function %s not available on Unix"
+#define MSG_NO_SOURCE " (no source)"
+#define MSG_NO_SPEC_COL "No MySQL special columns"
+#define MSG_NO_SQL_DELETE "Delete cannot be currently used for SQL views"
+#define MSG_NO_SUB_VAL "No sub value for array of type %d"
+#define MSG_NO_SUCH_INDEX "No indexes %s on table %s"
+#define MSG_NO_SUCH_SERVER "cannot find the server %s"
+#define MSG_NO_SUCH_TABLE "Table %s not in DB"
+#define MSG_NO_TABCOL_DATA "No data found for table %s column %s"
+#define MSG_NO_TABLE_COL "No columns found for %s"
+#define MSG_NO_TABLE_DEL "Delete not enabled for %s tables "
+#define MSG_NO_TABLE_DESC "No Table Description Block"
+#define MSG_NO_TABLE_INDEX "Table %s has no index"
+#define MSG_NO_TABLE_LIST "No table list"
+#define MSG_NO_TAB_DATA "No data found for table %s"
+#define MSG_NO_TERM_IN_TOK "Non terminal cannot be used in token rules"
+#define MSG_NO_TOKEN_DB "Cannot find DB for Token column %s"
+#define MSG_NO_UNIX_CATINFO "No catalog info under Unix"
+#define MSG_NO_UPDEL_JOIN "Update/Delete on ODBC table cannot be joined"
+#define MSG_NO_VCT_DELETE "Partial delete not yet implemented for VCT files"
+#define MSG_NO_VIEW_COLDEF "No coldefs available for views"
+#define MSG_NO_VIEW_SORT "Cannot sort/join SQL functional view %s"
+#define MSG_NO_ZIP_DELETE "Delete Zip files not implemented yet"
+#define MSG_NO_ZIP_DIR_ACC "Direct access of ZDOS tables not implemented yet"
+#define MSG_NULL_COL_VALUE "Column Value block is NULL"
+#define MSG_NULL_ENTRY "InitLang, null entry %d %s"
+#define MSG_NULL_QUERY "Null query"
+#define MSG_NUMVAL_NOMATCH "Numval mismatch for %s"
+#define MSG_N_FULL_PARSES "%d full parses"
+#define MSG_ODBC_READ_ONLY "ODBC is currently read only"
+#define MSG_OFFSET_NOT_SUPP "Offset not implemented for this type of sub query"
+#define MSG_ONE_LANG_YET "Already one language in edition"
+#define MSG_ONE_PARAM_ONLY "Only one parameter allowed"
+#define MSG_ONLY_LOG10_IMPL "Only Log10 is implemented"
+#define MSG_ON_LANGUAGE "Language %.8s version %d.%d loaded for editing"
+#define MSG_OPENING "Opening"
+#define MSG_OPENING_QUERY "Opening query"
+#define MSG_OPEN_EMPTY_FILE "Opening empty file %s: %s"
+#define MSG_OPEN_ERROR "Open error %d in mode %d on %s: "
+#define MSG_OPEN_ERROR_IS "Open error on %s: %s"
+#define MSG_OPEN_ERROR_ON "Open error on %s"
+#define MSG_OPEN_MODE_ERROR "Open(%s) error %d on %s"
+#define MSG_OPEN_SORT_ERROR "Logical sort error in QUERY Open"
+#define MSG_OPEN_STRERROR "open error: %s"
+#define MSG_OPEN_W_ERROR "Couldn't open %s for writing"
+#define MSG_OPTBLK_RD_ERR "Error reading opt block values: %s"
+#define MSG_OPTBLK_WR_ERR "Error writing opt block values: %s"
+#define MSG_OPTIMIZING "Optimizing "
+#define MSG_OPT_BMAP_RD_ERR "Error reading opt bitmaps: %s"
+#define MSG_OPT_BMAP_WR_ERR "Error writing opt bitmaps: %s"
+#define MSG_OPT_CANCELLED "Optimize cancelled by User"
+#define MSG_OPT_DVAL_RD_ERR "Error reading distinct values: %s"
+#define MSG_OPT_DVAL_WR_ERR "Error writing distinct values: %s"
+#define MSG_OPT_HEAD_RD_ERR "Error reading opt file header: %s"
+#define MSG_OPT_HEAD_WR_ERR "Error writing opt file header: %s"
+#define MSG_OPT_INIT "Optimization initialized"
+#define MSG_OPT_LOGIC_ERR "Logical error in SetBitmap, i=%d"
+#define MSG_OPT_MAX_RD_ERR "Error reading opt max values: %s"
+#define MSG_OPT_MAX_WR_ERR "Error writing opt max values: %s"
+#define MSG_OPT_MIN_RD_ERR "Error reading opt min values: %s"
+#define MSG_OPT_MIN_WR_ERR "Error writing opt min values: %s"
+#define MSG_OPT_NOT_MATCH "Non-matching opt file %s"
+#define MSG_OP_RES_TOO_LONG "Result too long for operator=%d"
+#define MSG_ORDER_OUT_RANGE "Order %d out of range"
+#define MSG_ORDER_TWICE "Ordering twice the same select item"
+#define MSG_PAGE_ERROR "In page error"
+#define MSG_PARM_CNT_MISS "Parameter count mismatch"
+#define MSG_PARSE_NULL_SEM "Parse with null semantics"
+#define MSG_PARSING_QUERY "Parsing query"
+#define MSG_PIX_ERROR "Pix %s error Rule_no=%u\n"
+#define MSG_PIX_TEST_ERROR "Rule=%u: pix-TEST not in first node\n"
+#define MSG_PLG_READ_ONLY "PLG is currently Read Only"
+#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp is NULL"
+#define MSG_PLUG_NOT_INIT "Plug was not initialized\n"
+#define MSG_PLUG_NOT_RUN "Plug is not running"
+#define MSG_PNODE_RULE "(P_node %d rule %d) "
+#define MSG_POS_TOO_LONG "%s too long (>%d)"
+#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp is NULL"
+#define MSG_PRIV_INSTR "Privileged instruction"
+#define MSG_PROCADD_ERROR "Error %d getting address of %s"
+#define MSG_PROCESS_SUBQRY "Processing Sub-Query"
+#define MSG_PROC_WOULD_LOOP "Process would loop (maxres=%d maxlin=%d)"
+#define MSG_PROGRESS_INFO "Progress Information"
+#define MSG_PROMPT_CANCEL "Prompt was cancelled"
+#define MSG_PROMPT_NIY "Prompt not implemented for this configuration"
+#define MSG_PTR_NOT_FOUND "Pointer not found Num=%d ti1=%d"
+#define MSG_PXDEF_IS_NULL "Pxdef is NULL"
+#define MSG_QRY_READ_ONLY "QRY views are read only"
+#define MSG_QUERY_CANCELLED "Query Cancelled by User"
+#define MSG_QUERY_NOT_EXEC "Query not executed"
+#define MSG_QUERY_SAVED "Query %s saved"
+#define MSG_QUOTE_IN_QUOTE "Quote char inside quoted field in line %d"
+#define MSG_RANGE_NIY "Range NIY for %s"
+#define MSG_RANGE_NO_JOIN "Range is not meant for join index"
+#define MSG_RC_READING "rc=%d reading table %s"
+#define MSG_READB_BAD_INIT "%s ReadDB called with Init=0"
+#define MSG_READCOL_ERROR "SQLCOL ReadColumn error"
+#define MSG_READING "Reading"
+#define MSG_READING_FROM "Reading from %s"
+#define MSG_READING_RECORD "Error reading record %d of %s"
+#define MSG_READY "Ready"
+#define MSG_READ_ERROR "Error reading %s: %s"
+#define MSG_READ_ERROR_RC "Read error, rc=%d"
+#define MSG_READ_MEM_ERROR "Reading memory %d: size=%d"
+#define MSG_READ_ONLY "Cannot modify this read/only protected table"
+#define MSG_READ_SEEK_ERROR "Read seek error: %s"
+#define MSG_READ_SEG_ERROR "Reading segment %d: size=%d"
+#define MSG_RECEIVED "Received %c\n"
+#define MSG_RECORD_ERROR "Error reading record %d of %s"
+#define MSG_RECORD_NO_SEP "Record with no separator"
+#define MSG_REC_SKIPPED " (%d bad records skipped by MaxErr setting)"
+#define MSG_REDUCE_INDEX "Reducing index"
+#define MSG_REGISTER_ERR "Unable to register NS with prefix='%s' and href='%s'"
+#define MSG_REMOTE_CONN_ERR "Remote connection failed"
+#define MSG_REMOVE_ERROR "Error removing %s: %s"
+#define MSG_REMOVE_NOT_IMPL "Remove not implemented for non-table TDB"
+#define MSG_RENAME_ERROR "Error renaming %s to %s: %s"
+#define MSG_RENUM_RULES "Renumber rules and enter ADD again (rule saved in buffer)"
+#define MSG_REORDER_INDEX "Reordering index"
+#define MSG_REQU_ARG_NUM "Function %s requires %d arguments"
+#define MSG_RESET_TO "%s reset to %d"
+#define MSG_RES_NOT_UNIQUE "Result is not a unique value"
+#define MSG_RET_FROM_LANG "Return to language %s version %d.%d from language %s version %d.%d"
+#define MSG_ROWID_NOT_IMPL "RowNumber not implemented for tables of type %s"
+#define MSG_ROWS_SELECTED "%d rows selected in %.2lf sec"
+#define MSG_ROWS_TRUNCATED " (truncated by MAXRES, LIMIT, FREQ or AreaSize setting)"
+#define MSG_ROW_ARGNB_ERR "ROW arg number mismatch (%d,%d)"
+#define MSG_RPC_SERVER_ERR "RPC error, server not responding"
+#define MSG_RSC_ALLOC_ERROR "Memory allocation error in Rescol %s"
+#define MSG_RULE_ENTERED "Rule %d entered"
+#define MSG_RULE_SUBSET_ERR "Rules Subset error"
+#define MSG_SAVING_INDEX "Saving index file"
+#define MSG_SCAN_NOT_IMP "Scan not implemented"
+#define MSG_SEC_KEY_FIRST "Section and key names must come first on Insert"
+#define MSG_SEC_NAME_FIRST "Section name must come first on Insert"
+#define MSG_SEC_NOT_FOUND "Section %s not found in %s"
+#define MSG_SEEK_ERROR "Seek error in CopyHeader"
+#define MSG_SEMANTIC_TREE "Semantic Tree"
+#define MSG_SEM_BAD_REF "Sem name @%d refers to an argument of type not 0 or 1"
+#define MSG_SEM_UNKNOWN "unknown, rc=%d"
+#define MSG_SEP_IN_FIELD "Field %d contains the separator character"
+#define MSG_SEQUENCE_ERROR "Sequence error on statement allocation"
+#define MSG_SETEOF_ERROR "Error %d in SetEndOfFile"
+#define MSG_SETRECPOS_NIY "SetRecpos not implemented for this table type"
+#define MSG_SET_LOCALE "Locale set to %s"
+#define MSG_SET_NULL_DOM "Setting value %d to a null domain"
+#define MSG_SET_OP_NOT_IMPL "sorry - set operators not implemented"
+#define MSG_SET_STR_TRUNC "SetValue: String would be truncated"
+#define MSG_SEVERAL_TREES "Some tables are not properly joined"
+#define MSG_SFP_ERROR "SetFilePointer error: %s"
+#define MSG_SFUNC_NOT_IMPL "Scalar Function %s not implemented"
+#define MSG_SHARED_LIB_ERR "Error loading shared library %s: %s"
+#define MSG_SINGLE_STEP "Single step"
+#define MSG_SLEEP "I slept %d milliseconds"
+#define MSG_SMART_SORTING "Retrieving sorted rows (pass %d of %d)"
+#define MSG_SMART_SORT_ERR "Logical Smart Sort Error 1"
+#define MSG_SORTING "Sorting"
+#define MSG_SORTING_INDEX "Sorting index"
+#define MSG_SORTING_VAL "Sorting %d values"
+#define MSG_SORT_JOIN_INDEX "Sorting join index"
+#define MSG_SPCOL_READONLY "Special column %s is Read Only"
+#define MSG_SPEC_CMD_SEP "Special commands must be executed separately"
+#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d not supported"
+#define MSG_SQL_BLOCK_MISM "CheckColumn: SQL current blocks mismatch"
+#define MSG_SQL_CONF_ERROR "SQL Error: SQL_CONFORMANCE"
+#define MSG_SQL_READ_ONLY "SQL views are currently read only"
+#define MSG_SRCH_CLOSE_ERR "Couldn't close search handle"
+#define MSG_SRC_TABLE_UNDEF "Source table is not defined"
+#define MSG_STACK_ERROR "stack error, i=%d\n"
+#define MSG_STACK_OVERFLOW "Parser: Stack overflow\n"
+#define MSG_STRG_NOT_FOUND "String not found"
+#define MSG_STRING_INV_LIST "List invalid for SemString"
+#define MSG_STRING_TOO_BIG "String too big for domain %s"
+#define MSG_SUBALLOC_ERROR "Not enough memory in area %p for request of %d (used=%d free=%d)"
+#define MSG_SUBAL_HUGE_ERR "Not enough memory in huge %p for request of %d"
+#define MSG_SUBARG_NOSEM "@ or sub-phrase arg of level %d points to a meaningless argument"
+#define MSG_SUBARG_OUTRANGE "Out of range @ or sub-phrase argument of level %d"
+#define MSG_SUBQRY_ONEITEM "Sub-Query must have exactly one select item"
+#define MSG_SUBSET_ERROR "SubSet error in LoadDB"
+#define MSG_SUB_OPEN_YET "Subquery already open"
+#define MSG_SUB_RES_TOO_LNG "Result too long for SUBSTR"
+#define MSG_SYNTAX_ERROR "Syntax error"
+#define MSG_SYSTEM_ERROR "System error %d"
+#define MSG_S_ACCESS_DENIED "%s: access denied"
+#define MSG_S_ERROR "%s error"
+#define MSG_S_ERROR_NUM "%s: error=%d"
+#define MSG_S_INTRUPT_ERROR "%s: interrupt error"
+#define MSG_S_INVALID_PARM "%s: invalid parameter"
+#define MSG_S_INV_ADDRESS "%s: invalid address"
+#define MSG_S_UNKNOWN_ERROR "%s: unknown error code %u"
+#define MSG_TABDIR_READONLY "DIR tables are read/only"
+#define MSG_TABLE_ALREADY "Table %s already exists"
+#define MSG_TABLE_ALTERED "%s table %s altered"
+#define MSG_TABLE_CREATED "%s table %s created"
+#define MSG_TABLE_DROPPED "Table %s dropped"
+#define MSG_TABLE_MULT_JOIN "Table %s used more than once for join"
+#define MSG_TABLE_NOT_IN_DB "Table %s does not exist in %s"
+#define MSG_TABLE_NOT_OPT "Not an optimizable table"
+#define MSG_TABLE_NO_INDEX "Table %s cannot be indexed"
+#define MSG_TABLE_NO_OPT "Table %s does not exist or type is not optimizable"
+#define MSG_TABLE_READ_ONLY "%s tables are read only "
+#define MSG_TABMUL_READONLY "Multiple tables are read/only"
+#define MSG_TAB_NOT_LOADED " (some tables could not be loaded)"
+#define MSG_TAB_NOT_SPEC "No table specified"
+#define MSG_TB_VW_NOTIN_DB "Table or view %s not in DB"
+#define MSG_TDB_NXT_NOT_NUL "Tdb.Next not NULL"
+#define MSG_TDB_USE_ERROR "Error, Tdbp->Use=%d"
+#define MSG_TOO_MANY_COLS "Too many columns"
+#define MSG_TOO_MANY_COLTAB "Too many columns in %s (%d)"
+#define MSG_TOO_MANY_FIELDS "Too many fields line %d of %s"
+#define MSG_TOO_MANY_JUMPS "Too many jump levels"
+#define MSG_TOO_MANY_KEYS "Too many keys (%d)"
+#define MSG_TOO_MANY_POS "Too many pos_codes"
+#define MSG_TOO_MANY_TABLES "Too many tables (%d)"
+#define MSG_TOPSEM_ERROR "Unknown error in TopSem"
+#define MSG_TO_BLK_IS_NULL "To Blk is NULL"
+#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr is not null"
+#define MSG_TO_PIX_NOT_NULL "Set.To_Pix is not null"
+#define MSG_TO_SEM_NOT_NULL "Set.To_Sem is not null"
+#define MSG_TRUNCATE_ERROR "truncate error: %s"
+#define MSG_TRUNC_BY_ESTIM "truncated by Estimate"
+#define MSG_TYPES_ERROR "Error on Types(%d)"
+#define MSG_TYPE_CONV_ERROR "Type cannot be converted in expression"
+#define MSG_TYPE_DEF_MISM "type and definition do not match"
+#define MSG_TYPE_MISMATCH "Key and source are not of the same type"
+#define MSG_TYPE_RECFM_MISM "Type and Recfm mismatch"
+#define MSG_TYPE_TO_VERIFY "Type to verify: %d"
+#define MSG_TYPE_VALUE_ERR "Column %s type(%s)/value(%s) mismatch"
+#define MSG_UNBALANCE_QUOTE "Unbalanced quote in line %d"
+#define MSG_UNDEFINED_AM "COLBLK %s: undefined Access Method"
+#define MSG_UNDEFINED_PATH "Undefined Plgcnx.ini path"
+#define MSG_UNDEF_COL_COUNT "Count on undefined column"
+#define MSG_UNKNOWN_DOMAIN "Unknown domain %s"
+#define MSG_UNKNOWN_ERROR "Unknown error"
+#define MSG_UNKNOWN_EXCPT "Unknown exception"
+#define MSG_UNKNOWN_NAME "Unknown name: %.8s"
+#define MSG_UNKNOWN_PATH "Unknown Plgcnx.ini path"
+#define MSG_UNKNOWN_POS "Unknown pos name: %s"
+#define MSG_UNKNOWN_SEM "Unknown Sem %.8s, rc=%d"
+#define MSG_UNKNOWN_SYNONYM "Unknown synonym"
+#define MSG_UNKNW_QRY_TYPE "ReadDB: unknown query type"
+#define MSG_UNKN_ERR_CODE "Unknown error code %d"
+#define MSG_UNLOADABLE " unloadable: "
+#define MSG_UNLOADABLE_PRM "%s unloadable: %s"
+#define MSG_UNMATCH_FIL_ARG "Unmatched filter argument"
+#define MSG_UNQ_COL_SEV_TAB "Unqualified column %s is in several tables"
+#define MSG_UNRESOLVED_ARG "?Unresolved argument %s at %d line %d"
+#define MSG_UPDATE_ERROR "Error updating %s"
+#define MSG_UPDATING_ROWS "Updating rows"
+#define MSG_UPD_ZIP_NOT_IMP "Updating ZDOS tables not implemented yet"
+#define MSG_UP_LANGUAGE "Block language %.8s version %d level %d loaded"
+#define MSG_USED_FREE_MEM "%d used in sarea, %d free"
+#define MSG_USETEMP_IS "UseTemp is %s"
+#define MSG_USETEMP_RESET ". Usetemp reset to Auto"
+#define MSG_USETEMP_SET "UseTemp set to %s"
+#define MSG_USE_NO_MATCH "Use do not match : Use=%d, ti2=%d, ti3=%d"
+#define MSG_USING_INDEX " (Using index"
+#define MSG_VALIST_MISMATCH "List of values mismatch"
+#define MSG_VALSTR_TOO_LONG "Value %s too long for string of length %d"
+#define MSG_VALTYPE_NOMATCH "Non matching Value types"
+#define MSG_VALUE_ERROR "Column %s: value is null"
+#define MSG_VALUE_NOT_ALLOC "Value not allocated for column R%d %s"
+#define MSG_VALUE_TOO_BIG "Value %lld too big for column %s"
+#define MSG_VALUE_TOO_LONG "Value %s too long for column %s of length %d"
+#define MSG_VAL_ALLOC_ERR "Cannot allocate value node"
+#define MSG_VAL_TOO_LONG "Value field %s too long for %s"
+#define MSG_VIEW_ALREADY "View %s already exists"
+#define MSG_VIEW_CREATED "%s view %s created"
+#define MSG_VIEW_DROPPED "View %s dropped"
+#define MSG_VIEW_NOT_IN_DB "View %s does not exist in %s"
+#define MSG_VIR_NO_DELETE "Delete not allowed for %s tables"
+#define MSG_VIR_READ_ONLY "Virtual %s tables are read only"
+#define MSG_VM_LANG "Language has VM format, not supported"
+#define MSG_VOID_FIRST_ARG "First argument should not be void"
+#define MSG_VOID_IN_STRING "Error: void IN string"
+#define MSG_VOID_ORDER_LIST "Null ordering list, system error ?"
+#define MSG_VOID_POS_DICT "Void Pos dictionary"
+#define MSG_VOID_QUERY "Void query %s"
+#define MSG_WORK_AREA "Work area: %s"
+#define MSG_WORK_TOO_SMALL "Work area too small, increase AreaSize"
+#define MSG_WRITE_ERROR "Error writing to %s"
+#define MSG_WRITE_SEEK_ERR "Write seek error: %s"
+#define MSG_WRITE_STRERROR "Error writing %s: %s"
+#define MSG_WRITING "Writing"
+#define MSG_WRITING_ERROR "Error writing to %s: %s"
+#define MSG_WRITING_QUERY "Writing query: "
+#define MSG_WRONG_ARG_NUM "Function %s does not take %d arguments"
+#define MSG_WRONG_COL_NUM "Column number %d out of range in %s"
+#define MSG_WRONG_DB_LIST "Wrong or nul database list"
+#define MSG_WRONG_FUNCTION "Wrong function %d"
+#define MSG_WRONG_OP_PARM "Wrong operator or parameters for %s"
+#define MSG_WRONG_PARMS "Wrong parameters for %s"
+#define MSG_WRONG_PASSWORD "Illegal password for %s"
+#define MSG_WRONG_TYPE "unsupported type"
+#define MSG_WRONG_USERFILE "Wrong Userfile size=%d"
+#define MSG_WS_CONV_ERR "Error converting %s to WS"
+#define MSG_XCOL_MISMATCH "Column %s mismatch in index"
+#define MSG_XDB_DEL_ERROR "Error while deleting entries from XDB file"
+#define MSG_XFILE_READERR "Error %d reading index file"
+#define MSG_XFILE_TOO_SMALL "Index file is smaller than index length"
+#define MSG_XFILE_WRITERR "Error writing index file: %s"
+#define MSG_XMLTAB_INIT_ERR "Error initializing XML table"
+#define MSG_XML_INIT_ERROR "Error initializing new XML file"
+#define MSG_XPATH_CNTX_ERR "Unable to create new XPath context"
+#define MSG_XPATH_EVAL_ERR "Unable to evaluate xpath location '%s'"
+#define MSG_XPATH_NOT_SUPP "Unsupported Xpath for column %s"
+#define MSG_X_ARG_ADDED "%d arguments have been added"
+#define MSG_X_ARG_SET "%d arguments have been set"
+#define MSG_X_ON_TAB " %s on %s("
+#define MSG_ZERO_DIVIDE "Zero divide in expression"
diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp
index 7fc06c36e0a..e4bd2b59ec2 100644
--- a/storage/connect/filamap.cpp
+++ b/storage/connect/filamap.cpp
@@ -1,688 +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
-
+/*********** 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
+
diff --git a/storage/connect/filamap.h b/storage/connect/filamap.h
index 3e9949e88dc..d3503bb0c1d 100644
--- a/storage/connect/filamap.h
+++ b/storage/connect/filamap.h
@@ -1,114 +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
+/*************** 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
diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp
index 4299622a4b4..268de657ed9 100644
--- a/storage/connect/filamdbf.cpp
+++ b/storage/connect/filamdbf.cpp
@@ -1,990 +1,990 @@
-/*********** 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, len, 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= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb")))
- return NULL;
-
- /**************************************************************************/
- /* 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;
- } else
- len = thisfield.Length;
-
- if (trace)
- htrc("%-11s %c %6ld %3d %2d %3d %3d\n",
- thisfield.Name, thisfield.Type, thisfield.Offset, len,
- 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
- : (len > 10) ? TYPE_BIGINT : 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= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb")))
- return 0; // Assume file does not exist
-
- /************************************************************************/
- /* 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))) {
-#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)
- {
- char c;
- 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;
-
- // Currently only standard Xbase types are supported
- for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) {
- descp++;
-
- switch ((c = *GetFormatType(cdp->GetType()))) {
- case 'S': // Short integer
- case 'L': // Large (big) integer
- c = 'N'; // Numeric
- case 'N': // Numeric (integer)
- case 'F': // Float (double)
- descp->Decimals = (uchar)cdp->F.Prec;
- case 'C': // Char
- case 'D': // Date
- break;
- default: // Should never happen
- sprintf(g->Message, "Unsupported DBF type %c for column %s",
- c, cdp->GetName());
- return true;
- } // endswitch c
-
- strncpy(descp->Name, cdp->GetName(), 11);
- descp->Type = c;
- descp->Length = (uchar)cdp->GetLong();
- } // 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());
- if ((Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, 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 ---------------------------------- */
+/*********** 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, len, 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= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb")))
+ return NULL;
+
+ /**************************************************************************/
+ /* 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;
+ } else
+ len = thisfield.Length;
+
+ if (trace)
+ htrc("%-11s %c %6ld %3d %2d %3d %3d\n",
+ thisfield.Name, thisfield.Type, thisfield.Offset, len,
+ 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
+ : (len > 10) ? TYPE_BIGINT : 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= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb")))
+ return 0; // Assume file does not exist
+
+ /************************************************************************/
+ /* 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))) {
+#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)
+ {
+ char c;
+ 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;
+
+ // Currently only standard Xbase types are supported
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) {
+ descp++;
+
+ switch ((c = *GetFormatType(cdp->GetType()))) {
+ case 'S': // Short integer
+ case 'L': // Large (big) integer
+ c = 'N'; // Numeric
+ case 'N': // Numeric (integer)
+ case 'F': // Float (double)
+ descp->Decimals = (uchar)cdp->F.Prec;
+ case 'C': // Char
+ case 'D': // Date
+ break;
+ default: // Should never happen
+ sprintf(g->Message, "Unsupported DBF type %c for column %s",
+ c, cdp->GetName());
+ return true;
+ } // endswitch c
+
+ strncpy(descp->Name, cdp->GetName(), 11);
+ descp->Type = c;
+ descp->Length = (uchar)cdp->GetLong();
+ } // 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());
+ if ((Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, 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 ---------------------------------- */
diff --git a/storage/connect/filamdbf.h b/storage/connect/filamdbf.h
index f5dc2590dfc..5325f4f9deb 100644
--- a/storage/connect/filamdbf.h
+++ b/storage/connect/filamdbf.h
@@ -1,111 +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
+/***************** 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
diff --git a/storage/connect/filamfix.cpp b/storage/connect/filamfix.cpp
index 37c84677e74..e86da680969 100644
--- a/storage/connect/filamfix.cpp
+++ b/storage/connect/filamfix.cpp
@@ -1,1442 +1,1442 @@
-/*********** File AM Fix C++ Program Source Code File (.CPP) ***********/
-/* PROGRAM NAME: FILAMFIX */
-/* ------------- */
-/* Version 1.4 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the FIX/BIN file access method classes. */
-/* */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant sections of the System 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 <errno.h>
-#include <unistd.h>
-#else // !UNIX
-#include <io.h>
-#endif // !UNIX
-#include <sys/stat.h>
-#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. */
-/* filamfix.h is header containing the file AM classes declarations. */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "filamfix.h"
-#include "tabdos.h"
-
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
-#endif
-
-extern int num_read, num_there, num_eq[2]; // Statistics
-bool PushWarning(PGLOBAL g, PTDBASE tdbp);
-
-/* --------------------------- Class FIXFAM -------------------------- */
-
-/***********************************************************************/
-/* Constructors. */
-/***********************************************************************/
-FIXFAM::FIXFAM(PDOSDEF tdp) : BLKFAM(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
-
- } // end of FIXFAM standard constructor
-
-FIXFAM::FIXFAM(PFIXFAM txfp) : BLKFAM(txfp)
- {
- } // end of FIXFAM copy constructor
-
-/***********************************************************************/
-/* Allocate the block buffer for the table. */
-/***********************************************************************/
-bool FIXFAM::AllocateBuffer(PGLOBAL g)
- {
- Buflen = Blksize;
- To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
-
- if (UseTemp || Tdbp->GetMode() == MODE_DELETE) {
- if (Padded) {
- strcpy(g->Message, MSG(NO_MODE_PADDED));
- return true;
- } // endif Padded
-
- // Allocate a separate buffer so block reading can be kept
- Dbflen = Nrec;
- DelBuf = PlugSubAlloc(g, NULL, Blksize);
- } else if (Tdbp->GetMode() == MODE_INSERT) {
- /*******************************************************************/
- /* For Insert the buffer must be prepared. */
- /*******************************************************************/
- memset(To_Buf, ' ', Buflen);
-
- if (/*Tdbp->GetFtype() < 2 &&*/ !Padded)
- // If not binary, the file is physically a text file.
- // We do it also for binary table because the lrecl can have been
- // specified with additional space to include line ending.
- 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
-
- Rbuf = Nrec; // To be used by WriteDB
- } // endif Insert
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* Reset buffer access according to indexing and to mode. */
-/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
-/***********************************************************************/
-void FIXFAM::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->GetMode() == MODE_READ && ReadBlks != 1 && !Padded &&
- Tdbp->GetKindex() /*&& Tdbp->GetKindex()->IsRandom()*/) {
- 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 FIX file. */
-/***********************************************************************/
-int FIXFAM::ReadBuffer(PGLOBAL g)
- {
- int n, rc = RC_OK;
-
- if (!Closing) {
- /*******************************************************************/
- /* Sequential reading when Placed is not true. */
- /*******************************************************************/
- if (Placed) {
- Tdbp->SetLine(To_Buf + CurNum * Lrecl);
- Placed = false;
- } else if (++CurNum < Rbuf) {
- Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
- return RC_OK;
- } else if (Rbuf < Nrec && CurBlk != -1) {
- return RC_EF;
- } else {
- /*****************************************************************/
- /* New block. */
- /*****************************************************************/
- CurNum = 0;
- Tdbp->SetLine(To_Buf);
-
- if (++CurBlk >= Block)
- return RC_EF;
-
- } // endif's
-
- if (OldBlk == CurBlk) {
- IsRead = true; // Was read indeed
- return RC_OK; // Block is already there
- } // endif OldBlk
-
- } // endif !Closing
-
- if (Modif) {
- /*******************************************************************/
- /* The old block was modified in Update mode. */
- /* In Update mode we simply rewrite the old block on itself. */
- /*******************************************************************/
- bool moved = false;
-
- if (UseTemp) // Copy any intermediate lines.
- if (MoveIntermediateLines(g, &moved))
- rc = RC_FX;
-
- if (rc == RC_OK) {
- // Fpos is last position, Headlen is DBF file header length
- if (!moved && fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
- sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
- rc = RC_FX;
- } else if (fwrite(To_Buf, Lrecl, Rbuf, T_Stream) != (size_t)Rbuf) {
- sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
- rc = RC_FX;
- } // endif fwrite
-
- Spos = Fpos + Nrec; // + Rbuf ???
- } // endif rc
-
- if (Closing || rc != RC_OK) { // Error or called from CloseDB
- Closing = true; // To tell CloseDB about error
- return rc;
- } // endif Closing
-
- // NOTE: Next line was added to avoid a very strange fread bug.
- // When the fseek is not executed (even the file has the good
- // pointer position) the next read can happen anywhere in the file.
- OldBlk = CurBlk; // This will force fseek to be executed
- Modif = 0;
-// Spos = Fpos + Nrec; done above
- } // endif Mode
-
- // This could be done only for new block. However note that FPOS
- // is used as block position when updating and as line position
- // when deleting so this has to be carefully checked.
- Fpos = CurBlk * Nrec; // Fpos is new line position
-
- // fseek is required only in non sequential reading
- if (CurBlk != OldBlk + 1)
- // Note: Headlen is for DBF tables
- if (fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
- sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
- return RC_FX;
- } // endif fseek
-
-#ifdef DEBTRACE
- htrc("File position is now %d\n", ftell(Stream));
-#endif
-
-//long tell = ftell(Stream); not used
-
- if (Padded)
- n = fread(To_Buf, (size_t)Blksize, 1, Stream);
- else
- n = fread(To_Buf, (size_t)Lrecl, (size_t)Nrec, Stream);
-
- if (n) {
- rc = RC_OK;
- Rbuf = (Padded) ? n * Nrec : n;
- ReadBlks++;
- num_read++;
- } else if (feof(Stream)) {
- rc = RC_EF;
- } else {
-#if defined(UNIX)
- sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
-#else
- sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
-#endif
-
-#ifdef DEBTRACE
- htrc("%s\n", g->Message);
-#endif
- return RC_FX;
- } // endelse
-
- OldBlk = CurBlk; // Last block actually read
- IsRead = true; // Is read indeed
- return rc;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* WriteBuffer: File write routine for FIX access method. */
-/* Updates are written into the (Temp) file in ReadBuffer. */
-/***********************************************************************/
-int FIXFAM::WriteBuffer(PGLOBAL g)
- {
-#ifdef DEBTRACE
- fprintf(debug,
- "FIX WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
- Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
-#endif
-
- if (Tdbp->GetMode() == MODE_INSERT) {
- /*******************************************************************/
- /* In Insert mode, blocs are added sequentialy to the file end. */
- /*******************************************************************/
- if (++CurNum != Rbuf) {
- Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
- return RC_OK; // We write only full blocks
- } // endif CurNum
-
-#ifdef DEBTRACE
- htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
-#endif
-
- // Now start the writing process.
- if (fwrite(To_Buf, Lrecl, Rbuf, Stream) != (size_t)Rbuf) {
- sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
- Closing = true; // To tell CloseDB about a Write error
- return RC_FX;
- } // endif size
-
- CurBlk++;
- CurNum = 0;
- Tdbp->SetLine(To_Buf);
-
-#ifdef DEBTRACE
- htrc("write done\n");
-#endif
-
- } else { // Mode == MODE_UPDATE
- // T_Stream is the temporary stream or the table file stream itself
- if (!T_Stream)
- if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
- if (OpenTempFile(g))
- return RC_FX;
-
- if (CopyHeader(g)) // For DBF tables
- return RC_FX;
-
- } else
- T_Stream = Stream;
-
- Modif++; // Modified line in Update mode
- } // endif Mode
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for FIXFAM access method. */
-/***********************************************************************/
-int FIXFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- bool moved;
-
- /*********************************************************************/
- /* There is an alternative here: */
- /* 1 - use a temporary file in which are copied all not deleted */
- /* lines, at the end the original file will be deleted and */
- /* the temporary file renamed to the original file name. */
- /* 2 - directly move the not deleted lines inside the original */
- /* file, and at the end erase all trailing records. */
- /* This will be experimented. */
- /*********************************************************************/
-#ifdef DEBTRACE
- fprintf(debug,
- "DOS DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
- irc, UseTemp, Fpos, Tpos, Spos);
-#endif
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the end-of-file position. */
- /*******************************************************************/
- Fpos = Tdbp->Cardinality(g);
-#ifdef DEBTRACE
- htrc("Fpos placed at file end=%d\n", Fpos);
-#endif
- } else // Fpos is the deleted line position
- Fpos = CurBlk * Nrec + CurNum;
-
- if (Tpos == Spos) {
- /*******************************************************************/
- /* First line to delete. */
- /*******************************************************************/
- if (UseTemp) {
- /*****************************************************************/
- /* Open temporary file, lines before this will be moved. */
- /*****************************************************************/
- if (OpenTempFile(g))
- return RC_FX;
-
- } else {
- /*****************************************************************/
- /* Move of eventual preceeding lines is not required here. */
- /* Set the target file as being the source file itself. */
- /* Set the future Tpos, and give Spos a value to block moving. */
- /*****************************************************************/
- T_Stream = Stream;
- Spos = Tpos = Fpos;
- } // endif UseTemp
-
- } // endif Tpos == Spos
-
- /*********************************************************************/
- /* Move any intermediate lines. */
- /*********************************************************************/
- if (MoveIntermediateLines(g, &moved))
- return RC_FX;
-
- if (irc == RC_OK) {
- /*******************************************************************/
- /* Reposition the file pointer and set Spos. */
- /*******************************************************************/
- Spos = Fpos + 1; // New start position is on next line
-
- if (moved) {
- if (fseek(Stream, Spos * Lrecl, SEEK_SET)) {
- sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
- return RC_FX;
- } // endif fseek
-
- OldBlk = -2; // To force fseek to be executed on next block
- } // endif moved
-
-#ifdef DEBTRACE
- htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- } else {
- /*******************************************************************/
- /* Last call after EOF has been reached. */
- /*******************************************************************/
- if (UseTemp) {
- /*****************************************************************/
- /* Ok, now delete old file and rename new temp file. */
- /*****************************************************************/
- if (RenameTempFile(g))
- return RC_FX;
-
- } else {
- /*****************************************************************/
- /* Because the chsize functionality is only accessible with a */
- /* system call we must close the file and reopen it with the */
- /* open function (_fopen for MS ??) this is still to be checked */
- /* for compatibility with Text files and other OS's. */
- /*****************************************************************/
- char filename[_MAX_PATH];
- int rc, h;
-
- rc = PlugCloseFile(g, To_Fb);
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
- return RC_FX;
-
- /*****************************************************************/
- /* Remove extra records. */
- /*****************************************************************/
-#if defined(UNIX)
- if (ftruncate(h, (off_t)(Tpos * Lrecl))) {
- sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#else
- if (chsize(h, Tpos * Lrecl)) {
- sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#endif
-
- close(h);
-
-#ifdef DEBTRACE
- htrc("done, h=%d irc=%d\n", h, irc);
-#endif
- } // endif UseTemp
-
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Move intermediate deleted or updated lines. */
-/* This works only for file open in binary mode. */
-/***********************************************************************/
-bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
- {
- int n;
- size_t req, len;
-
- for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
- /*******************************************************************/
- /* Non consecutive line to delete. Move intermediate lines. */
- /*******************************************************************/
- if (!UseTemp || !*b)
- if (fseek(Stream, Headlen + Spos * Lrecl, SEEK_SET)) {
- sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- req = (size_t)min(n, Dbflen);
- len = fread(DelBuf, Lrecl, req, Stream);
-
-#ifdef DEBTRACE
- htrc("after read req=%d len=%d\n", req, len);
-#endif
-
- if (len != req) {
- sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
- return true;
- } // endif len
-
- if (!UseTemp) // Delete mode, cannot be a DBF file
- if (fseek(T_Stream, Tpos * Lrecl, SEEK_SET)) {
- sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
- return true;
- } // endif
-
- if ((len = fwrite(DelBuf, Lrecl, req, T_Stream)) != req) {
- sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
- return true;
- } // endif
-
-#ifdef DEBTRACE
- htrc("after write pos=%d\n", ftell(Stream));
-#endif
-
- Tpos += (int)req;
- Spos += (int)req;
-
-#ifdef DEBTRACE
- htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- *b = true;
- } // endfor n
-
- return false;
- } // end of MoveIntermediate Lines
-
-/***********************************************************************/
-/* Table file close routine for FIX access method. */
-/***********************************************************************/
-void FIXFAM::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) {
- 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
-
- // Finally close the file
- rc = PlugCloseFile(g, To_Fb);
-
- fin:
-#ifdef DEBTRACE
- htrc("FIX 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 BGXFAM ---------------------------- */
-
-/***********************************************************************/
-/* Implementation of the BGXFAM class. */
-/* This is the FAM class for FIX tables of more than 2 gigabytes. */
-/***********************************************************************/
-BGXFAM::BGXFAM(PDOSDEF tdp) : FIXFAM(tdp)
- {
- Hfile = INVALID_HANDLE_VALUE;
- Tfile = INVALID_HANDLE_VALUE;
- } // end of BGXFAM constructor
-
-BGXFAM::BGXFAM(PBGXFAM txfp) : FIXFAM(txfp)
- {
- Hfile = txfp->Hfile;
- Tfile = txfp->Tfile;
- } // end of BGXFAM copy constructor
-
-/***********************************************************************/
-/* Set current position in a big file. */
-/***********************************************************************/
-bool BGXFAM::BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, int org)
- {
-#if defined(WIN32)
- char buf[256];
- DWORD drc;
- LARGE_INTEGER of;
-
- of.QuadPart = pos;
- of.LowPart = SetFilePointer(h, of.LowPart, &of.HighPart, org);
-
- if (of.LowPart == INVALID_SET_FILE_POINTER &&
- (drc = GetLastError()) != NO_ERROR) {
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- sprintf(g->Message, MSG(SFP_ERROR), buf);
- return true;
- } // endif
-#else // !WIN32
- if (lseek64(h, pos, org) < 0) {
- sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
- return true;
- } // endif
-#endif // !WIN32
-
- return false;
- } // end of BigSeek
-
-/***********************************************************************/
-/* Read from a big file. */
-/***********************************************************************/
-int BGXFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req)
- {
- int rc;
-
-#if defined(WIN32)
- DWORD nbr, drc, len = (DWORD)req;
- bool brc = ReadFile(h, inbuf, len, &nbr, NULL);
-
-#ifdef DEBTRACE
- htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr);
-#endif
-
- if (!brc) {
- char buf[256]; // , *fn = (h == Hfile) ? To_File : "Tempfile";
-
- drc = GetLastError();
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- sprintf(g->Message, MSG(READ_ERROR), To_File, buf);
-#ifdef DEBTRACE
- htrc("BIGREAD: %s\n", g->Message);
-#endif
- rc = -1;
- } else
- rc = (int)nbr;
-#else // !WIN32
- size_t len = (size_t)req;
- ssize_t nbr = read(h, inbuf, len);
-
- rc = (int)nbr;
-#endif // !WIN32
-
- return rc;
- } // end of BigRead
-
-/***********************************************************************/
-/* Write into a big file. */
-/***********************************************************************/
-bool BGXFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req)
- {
- bool rc = false;
-
-#if defined(WIN32)
- DWORD nbw, drc, len = (DWORD)req;
- bool brc = WriteFile(h, inbuf, len, &nbw, NULL);
-
-#ifdef DEBTRACE
- htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw);
-#endif
-
- if (!brc || nbw != len) {
- char buf[256], *fn = (h == Hfile) ? To_File : "Tempfile";
-
- if (brc)
- strcpy(buf, MSG(BAD_BYTE_NUM));
- else {
- drc = GetLastError();
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- } // endelse brc
-
- sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf);
-
-#ifdef DEBTRACE
- htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
- nbw, len, drc, g->Message);
-#endif
- rc = true;
- } // endif brc || nbw
-#else // !WIN32
- size_t len = (size_t)req;
- ssize_t nbw = write(h, inbuf, len);
-
- if (nbw != (ssize_t)len) {
- const char *fn = (h == Hfile) ? To_File : "Tempfile";
-
- sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
-#ifdef DEBTRACE
- htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
- nbw, len, errno, g->Message);
-#endif
- rc = true;
- } // endif nbr
-#endif // !WIN32
-
- return rc;
- } // end of BigWrite
-
-#if 0
-/***********************************************************************/
-/* Reset: reset position values at the beginning of file. */
-/***********************************************************************/
-void BGXFAM::Reset(void)
- {
- FIXFAM::Reset();
- Xpos = 0;
- } // end of Reset
-#endif // 0
-
-/***********************************************************************/
-/* OpenTableFile: opens a huge file using Windows/Unix API's. */
-/***********************************************************************/
-bool BGXFAM::OpenTableFile(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- MODE mode = Tdbp->GetMode();
- PDBUSER dbuserp = PlgGetUser(g);
-
- if ((To_Fb && To_Fb->Count) || Hfile != INVALID_HANDLE_VALUE) {
- sprintf(g->Message, MSG(FILE_OPEN_YET), To_File);
- return true;
- } // endif
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
-#ifdef DEBTRACE
- htrc("OpenTableFile: filename=%s mode=%d\n", filename, mode);
-#endif
-
-#if defined(WIN32)
- DWORD rc, access, creation, share = 0;
-
- /*********************************************************************/
- /* Create the file object according to access mode */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- access = GENERIC_READ;
- share = FILE_SHARE_READ;
- creation = OPEN_EXISTING;
- break;
- case MODE_DELETE:
- if (!Tdbp->GetNext()) {
- // Store the number of deleted rows
- DelRows = Cardinality(g);
-
- // This will delete the whole file and provoque ReadDB to
- // return immediately.
- access = GENERIC_READ | GENERIC_WRITE;
- creation = TRUNCATE_EXISTING;
- Tdbp->ResetSize();
- Headlen = 0;
- break;
- } // endif
-
- // Selective delete, pass thru
- case MODE_UPDATE:
- if ((UseTemp = Tdbp->IsUsingTemp(g)))
- access = GENERIC_READ;
- else
- access = GENERIC_READ | GENERIC_WRITE;
-
- creation = OPEN_EXISTING;
- break;
- case MODE_INSERT:
- access = GENERIC_WRITE;
- creation = OPEN_ALWAYS;
- break;
- default:
- sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
- return true;
- } // endswitch
-
- Hfile = CreateFile(filename, access, share, NULL, creation,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- rc = GetLastError();
- sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)filename, sizeof(filename), NULL);
- strcat(g->Message, filename);
- } else
- rc = 0;
-
-#ifdef DEBTRACE
- fprintf(debug,
- " rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n",
- rc, access, share, creation, Hfile, filename);
-#endif
-
- if (mode == MODE_INSERT)
- /*******************************************************************/
- /* In Insert mode we must position the cursor at end of file. */
- /*******************************************************************/
- if (BigSeek(g, Hfile, (BIGINT)0, FILE_END))
- return true;
-
-#else // UNIX
- int rc = 0;
- int oflag = O_LARGEFILE; // Enable file size > 2G
- mode_t tmode = 0;
-
- /*********************************************************************/
- /* Create the file object according to access mode */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- oflag |= O_RDONLY;
- break;
- case MODE_DELETE:
- if (!Tdbp->GetNext()) {
- // This will delete the whole file and provoque ReadDB to
- // return immediately.
- oflag |= (O_RDWR | O_TRUNC);
- Tdbp->ResetSize();
- break;
- } // endif
-
- // Selective delete, pass thru
- case MODE_UPDATE:
- UseTemp = Tdbp->IsUsingTemp(g);
- oflag |= (UseTemp) ? O_RDONLY : O_RDWR;
- break;
- case MODE_INSERT:
- oflag |= (O_WRONLY | O_CREAT | O_APPEND);
- tmode = S_IREAD | S_IWRITE;
- break;
- default:
- sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
- return true;
- } // endswitch
-
- Hfile= global_open(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, oflag, tmode);
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- rc = errno;
- } else
- rc = 0;
-
-#ifdef DEBTRACE
- htrc(" rc=%d oflag=%p tmode=%p handle=%p fn=%s\n",
- rc, oflag, tmode, Hfile, filename);
-#endif
-
-#endif // UNIX
-
- if (!rc) {
- if (!To_Fb) {
- To_Fb = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
- To_Fb->Fname = To_File;
- To_Fb->Type = TYPE_FB_HANDLE;
- To_Fb->Memory = NULL;
- To_Fb->Length = 0;
- To_Fb->Mode = mode;
- To_Fb->File = NULL;
- To_Fb->Next = dbuserp->Openlist;
- dbuserp->Openlist = To_Fb;
- } // endif To_Fb
-
- To_Fb->Count = 1;
- To_Fb->Mode = mode;
- To_Fb->Handle = Hfile;
-
- /*******************************************************************/
- /* Allocate the block buffer. */
- /*******************************************************************/
- return AllocateBuffer(g);
- } else
- return (mode == MODE_READ && rc == ENOENT)
- ? PushWarning(g, Tdbp) : true;
-
- } // end of OpenTableFile
-
-/***********************************************************************/
-/* BIGFIX 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 BGXFAM::Cardinality(PGLOBAL g)
- {
- if (g) {
- char filename[_MAX_PATH];
- int card = -1;
- BIGINT fsize;
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
-#if defined(WIN32) // OB
- LARGE_INTEGER len;
- DWORD rc = 0;
-
- len.QuadPart = -1;
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- HANDLE h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (h == INVALID_HANDLE_VALUE)
- if ((rc = GetLastError()) != ERROR_FILE_NOT_FOUND) {
- sprintf(g->Message, MSG(OPEN_ERROR), rc, 10, filename);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)filename, sizeof(filename), NULL);
- strcat(g->Message, filename);
- return -1;
- } else
- return 0; // File does not exist
-
- // Get the size of the file (can be greater than 4 GB)
- len.LowPart = GetFileSize(h, (LPDWORD)&len.HighPart);
- CloseHandle(h);
- } else
- len.LowPart = GetFileSize(Hfile, (LPDWORD)&len.HighPart);
-
- if (len.LowPart == 0xFFFFFFFF && (rc = GetLastError()) != NO_ERROR) {
- sprintf(g->Message, MSG(FILELEN_ERROR), "GetFileSize", filename);
- return -2;
- } else
- fsize = len.QuadPart;
-
-#else // UNIX
- if (Hfile == INVALID_HANDLE_VALUE) {
- int h = open64(filename, O_RDONLY, 0);
-
-#ifdef DEBTRACE
- htrc(" h=%d\n", h);
-#endif
-
- if (h == INVALID_HANDLE_VALUE) {
-#ifdef DEBTRACE
- htrc(" errno=%d ENOENT=%d\n", errno, ENOENT);
-#endif
- if (errno != ENOENT) {
- sprintf(g->Message, MSG(OPEN_ERROR_IS),
- filename, strerror(errno));
- return -1;
- } else
- return 0; // File does not exist
-
- } // endif h
-
- // Get the size of the file (can be greater than 4 GB)
- fsize = lseek64(h, 0, SEEK_END);
- close(h);
- } else {
- BIGINT curpos = lseek64(Hfile, 0, SEEK_CUR);
-
- fsize = lseek64(Hfile, 0, SEEK_END);
- lseek64(Hfile, curpos, SEEK_SET);
- } // endif Hfile
-
- if (fsize < 0) {
- sprintf(g->Message, MSG(FILELEN_ERROR), "lseek64", filename);
- return -2;
- } // endif fsize
-
-#endif // UNIX
-
- // Check the real size of the file
- if (Padded && Blksize) {
- if (fsize % (BIGINT)Blksize) {
- sprintf(g->Message, MSG(NOT_FIXED_LEN),
- filename, (int)fsize, Lrecl);
- return -3;
- } else
- card = (int)(fsize / (BIGINT)Blksize) * Nrec;
-
- } else if (fsize % (BIGINT)Lrecl) {
- sprintf(g->Message, MSG(NOT_FIXED_LEN), filename, (int)fsize, Lrecl);
- return -3;
- } else
- card = (int)(fsize / (BIGINT)Lrecl); // Fixed length file
-
-#ifdef DEBTRACE
- htrc(" Computed max_K=%d fsize=%lf lrecl=%d\n",
- card, (double)fsize, Lrecl);
-#endif
-
- // Set number of blocks for later use
- Block = (card + Nrec - 1) / Nrec;
- return card;
- } else
- return -1;
-
- } // end of Cardinality
-
-/***********************************************************************/
-/* ReadBuffer: Read Nrec lines for a big fixed/binary file. */
-/***********************************************************************/
-int BGXFAM::ReadBuffer(PGLOBAL g)
- {
- int nbr, rc = RC_OK;
-
- if (!Closing) {
- /*******************************************************************/
- /* Sequential reading when Placed is not true. */
- /*******************************************************************/
- if (Placed) {
- Tdbp->SetLine(To_Buf + CurNum * Lrecl);
- Placed = false;
- } else if (++CurNum < Rbuf) {
- Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
- return RC_OK;
- } else if (Rbuf < Nrec && CurBlk != -1) {
- return RC_EF;
- } else {
- /*****************************************************************/
- /* New block. */
- /*****************************************************************/
- CurNum = 0;
- Tdbp->SetLine(To_Buf);
-
- if (++CurBlk >= Block)
- return RC_EF;
-
- } // endif's
-
- if (OldBlk == CurBlk) {
- IsRead = true; // Was read indeed
- return RC_OK; // Block is already there
- } // endif OldBlk
-
- } // endif !Closing
-
- if (Modif) {
- /*******************************************************************/
- /* The old block was modified in Update mode. */
- /* In Update mode we simply rewrite the old block on itself. */
- /*******************************************************************/
- bool moved = false;
-
- if (UseTemp) // Copy any intermediate lines.
- if (MoveIntermediateLines(g, &moved))
- rc = RC_FX;
-
- if (rc == RC_OK) {
- // Set file position to OldBlk position (Fpos)
- if (!moved && BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
- rc = RC_FX;
- else if (BigWrite(g, Tfile, To_Buf, Lrecl * Rbuf))
- rc = RC_FX;
-
- Spos = Fpos + Nrec; // + Rbuf ???
- } // endif rc
-
- if (Closing || rc != RC_OK) // Error or called from CloseDB
- return rc;
-
- // NOTE: Next line was added to avoid a very strange fread bug.
- // When the fseek is not executed (even the file has the good
- // pointer position) the next read can happen anywhere in the file.
- OldBlk = CurBlk; // This will force fseek to be executed
- Modif = 0;
- } // endif Mode
-
- Fpos = CurBlk * Nrec;
-
- // Setting file pointer is required only in non sequential reading
- if (CurBlk != OldBlk + 1)
- if (BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
- return RC_FX;
-
-#ifdef DEBTRACE
- htrc("File position is now %d\n", Fpos);
-#endif
-
- nbr = BigRead(g, Hfile, To_Buf, (Padded) ? Blksize : Lrecl * Nrec);
-
- if (nbr > 0) {
- Rbuf = (Padded) ? Nrec : nbr / Lrecl;
- rc = RC_OK;
- ReadBlks++;
- num_read++;
- } else
- rc = (nbr == 0) ? RC_EF : RC_FX;
-
- OldBlk = CurBlk; // Last block actually read
- IsRead = true; // Is read indeed
- return rc;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* WriteBuffer: File write routine for BGXFAM access method. */
-/* Updates are written into the (Temp) file in ReadBuffer. */
-/***********************************************************************/
-int BGXFAM::WriteBuffer(PGLOBAL g)
- {
-#ifdef DEBTRACE
- fprintf(debug,
- "BIG WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
- Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
-#endif
-
- if (Tdbp->GetMode() == MODE_INSERT) {
- /*******************************************************************/
- /* In Insert mode, blocks are added sequentialy to the file end. */
- /*******************************************************************/
- if (++CurNum != Rbuf) {
- Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
- return RC_OK; // We write only full blocks
- } // endif CurNum
-
-#ifdef DEBTRACE
- htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
-#endif
-
- // Now start the writing process.
- if (BigWrite(g, Hfile, To_Buf, Lrecl * Rbuf))
- return RC_FX;
-
- CurBlk++;
- CurNum = 0;
- Tdbp->SetLine(To_Buf);
-
-#ifdef DEBTRACE
- htrc("write done\n");
-#endif
-
- } else { // Mode == MODE_UPDATE
- // Tfile is the temporary file or the table file handle itself
- if (Tfile == INVALID_HANDLE_VALUE)
- if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
- if (OpenTempFile(g))
- return RC_FX;
-
- } else
- Tfile = Hfile;
-
- Modif++; // Modified line in Update mode
- } // endif Mode
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for BGXFAM access method. */
-/***********************************************************************/
-int BGXFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- bool moved;
-
- /*********************************************************************/
- /* There is an alternative here: */
- /* 1 - use a temporary file in which are copied all not deleted */
- /* lines, at the end the original file will be deleted and */
- /* the temporary file renamed to the original file name. */
- /* 2 - directly move the not deleted lines inside the original */
- /* file, and at the end erase all trailing records. */
- /* This will be experimented. */
- /*********************************************************************/
-#ifdef DEBTRACE
- fprintf(debug,
- "BGX DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
- irc, UseTemp, Fpos, Tpos, Spos);
-#endif
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the end-of-file position. */
- /*******************************************************************/
- Fpos = Tdbp->Cardinality(g);
-#ifdef DEBTRACE
- htrc("Fpos placed at file end=%d\n", Fpos);
-#endif
- } else // Fpos is the deleted line position
- Fpos = CurBlk * Nrec + CurNum;
-
- if (Tpos == Spos) {
- /*******************************************************************/
- /* First line to delete. Move of eventual preceeding lines is */
- /* not required here if a temporary file is not used, just the */
- /* setting of future Spos and Tpos. */
- /*******************************************************************/
- if (UseTemp) {
- /*****************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*****************************************************************/
- if (OpenTempFile(g))
- return RC_FX;
-
- } else {
- /*****************************************************************/
- /* Move of eventual preceeding lines is not required here. */
- /* Set the target file as being the source file itself. */
- /* Set the future Tpos, and give Spos a value to block copying. */
- /*****************************************************************/
- Tfile = Hfile;
- Spos = Tpos = Fpos;
- } // endif UseTemp
-
- } // endif Tpos == Spos
-
- /*********************************************************************/
- /* Move any intermediate lines. */
- /*********************************************************************/
- if (MoveIntermediateLines(g, &moved))
- return RC_FX;
-
- if (irc == RC_OK) {
-#ifdef DEBTRACE
- assert(Spos == Fpos);
-#endif
- Spos++; // New start position is on next line
-
- if (moved) {
- if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
- return RC_FX;
-
- OldBlk = -2; // To force fseek to be executed on next block
- } // endif moved
-
-#ifdef DEBTRACE
- htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- } else {
- /*******************************************************************/
- /* Last call after EOF has been reached. */
- /*******************************************************************/
- char filename[_MAX_PATH];
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (UseTemp) {
- /*****************************************************************/
- /* Ok, now delete old file and rename new temp file. */
- /*****************************************************************/
- if (RenameTempFile(g))
- return RC_FX;
-
- } else {
- /*****************************************************************/
- /* Remove extra records. */
- /*****************************************************************/
-#if defined(WIN32)
- if (BigSeek(g, Hfile, (BIGINT)Tpos * (BIGINT)Lrecl))
- return RC_FX;
-
- if (!SetEndOfFile(Hfile)) {
- DWORD drc = GetLastError();
-
- sprintf(g->Message, MSG(SETEOF_ERROR), drc);
- return RC_FX;
- } // endif error
-#else // !WIN32
- if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) {
- sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
- return RC_FX;
- } // endif
-#endif // !WIN32
-
- } // endif UseTemp
-
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Open a temporary file used while updating or deleting. */
-/***********************************************************************/
-bool BGXFAM::OpenTempFile(PGLOBAL g)
- {
- char *tempname;
- PDBUSER dup = PlgGetUser(g);
-
- /*********************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*********************************************************************/
- tempname = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
- PlugSetPath(tempname, To_File, Tdbp->GetPath());
- strcat(PlugRemoveType(tempname, tempname), ".t");
- remove(tempname); // Be sure it does not exist yet
-
-#if defined(WIN32)
- Tfile = CreateFile(tempname, GENERIC_WRITE, 0, NULL,
- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (Tfile == INVALID_HANDLE_VALUE) {
- DWORD rc = GetLastError();
- sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)tempname, _MAX_PATH, NULL);
- strcat(g->Message, tempname);
- return true;
- } // endif Tfile
-#else // UNIX
- Tfile = open64(tempname, O_WRONLY | O_TRUNC, S_IWRITE);
-
- if (Tfile == INVALID_HANDLE_VALUE) {
- int rc = errno;
- sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
- strcat(g->Message, strerror(errno));
- return true;
- } //endif Tfile
-#endif // UNIX
-
- To_Fbt = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
- To_Fbt->Fname = tempname;
- To_Fbt->Type = TYPE_FB_HANDLE;
- To_Fbt->Memory = NULL;
- To_Fbt->Length = 0;
- To_Fbt->File = NULL;
- To_Fbt->Next = dup->Openlist;
- To_Fbt->Count = 1;
- To_Fbt->Mode = MODE_INSERT;
- To_Fbt->Handle = Tfile;
- dup->Openlist = To_Fbt;
- return false;
- } // end of OpenTempFile
-
-/***********************************************************************/
-/* Move intermediate deleted or updated lines. */
-/***********************************************************************/
-bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
- {
- int n, req, nbr;
-
- for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
- /*******************************************************************/
- /* Non consecutive line to delete. Move intermediate lines. */
- /*******************************************************************/
- if (!UseTemp || !*b)
- if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
- return true;
-
- req = min(n, Dbflen) * Lrecl;
-
- if ((nbr = BigRead(g, Hfile, DelBuf, req)) != req) {
- sprintf(g->Message, MSG(DEL_READ_ERROR), req, nbr);
- return true;
- } // endif nbr
-
- if (!UseTemp)
- if (BigSeek(g, Tfile, (BIGINT)Tpos * (BIGINT)Lrecl))
- return true;
-
- if (BigWrite(g, Tfile, DelBuf, req))
- return true;
-
- req /= Lrecl;
- Tpos += (int)req;
- Spos += (int)req;
-
-#ifdef DEBTRACE
- htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- *b = true;
- } // endfor n
-
- return false;
- } // end of MoveIntermediateLines
-
-/***********************************************************************/
-/* Data Base close routine for BIGFIX access method. */
-/***********************************************************************/
-void BGXFAM::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--;
- wrc = WriteBuffer(g);
- } else if (mode == MODE_UPDATE) {
- if (Modif && !Closing) {
- // Last updated block remains to be written
- Closing = true;
- wrc = ReadBuffer(g);
- } // endif Modif
-
- if (UseTemp && Tfile && 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
-
- // Finally close the file
- rc = PlugCloseFile(g, To_Fb);
-
- fin:
-#ifdef DEBTRACE
- htrc("BGX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
- To_File, mode, wrc, rc);
-#endif
- Hfile = INVALID_HANDLE_VALUE; // So we can know whether table is open
- } // end of CloseTableFile
-
-/***********************************************************************/
-/* Rewind routine for huge FIX access method. */
-/* Note: commenting out OldBlk = -1 has two advantages: */
-/* 1 - It forces fseek on first block, thus suppressing the need to */
-/* rewind the file, anyway unuseful when second pass if indexed. */
-/* 2 - It permit to avoid re-reading small tables having only 1 block.*/
-/* (even very unlikely for huge files!) */
-/***********************************************************************/
-void BGXFAM::Rewind(void)
- {
-#if 0 // This is probably unuseful because file is accessed directly
-#if defined(WIN32) //OB
- SetFilePointer(Hfile, 0, NULL, FILE_BEGIN);
-#else // UNIX
- lseek64(Hfile, 0, SEEK_SET);
-#endif // UNIX
-#endif // 0
- CurBlk = -1;
- CurNum = Rbuf;
-//OldBlk = -1;
-//Rbuf = 0; commented out in case we reuse last read block
- Fpos = 0;
- } // end of Rewind
+/*********** File AM Fix C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMFIX */
+/* ------------- */
+/* Version 1.4 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the FIX/BIN file access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System 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 <errno.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <sys/stat.h>
+#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. */
+/* filamfix.h is header containing the file AM classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "filamfix.h"
+#include "tabdos.h"
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+#endif
+
+extern int num_read, num_there, num_eq[2]; // Statistics
+bool PushWarning(PGLOBAL g, PTDBASE tdbp);
+
+/* --------------------------- Class FIXFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+FIXFAM::FIXFAM(PDOSDEF tdp) : BLKFAM(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
+
+ } // end of FIXFAM standard constructor
+
+FIXFAM::FIXFAM(PFIXFAM txfp) : BLKFAM(txfp)
+ {
+ } // end of FIXFAM copy constructor
+
+/***********************************************************************/
+/* Allocate the block buffer for the table. */
+/***********************************************************************/
+bool FIXFAM::AllocateBuffer(PGLOBAL g)
+ {
+ Buflen = Blksize;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (UseTemp || Tdbp->GetMode() == MODE_DELETE) {
+ if (Padded) {
+ strcpy(g->Message, MSG(NO_MODE_PADDED));
+ return true;
+ } // endif Padded
+
+ // Allocate a separate buffer so block reading can be kept
+ Dbflen = Nrec;
+ DelBuf = PlugSubAlloc(g, NULL, Blksize);
+ } else if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* For Insert the buffer must be prepared. */
+ /*******************************************************************/
+ memset(To_Buf, ' ', Buflen);
+
+ if (/*Tdbp->GetFtype() < 2 &&*/ !Padded)
+ // If not binary, the file is physically a text file.
+ // We do it also for binary table because the lrecl can have been
+ // specified with additional space to include line ending.
+ 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
+
+ Rbuf = Nrec; // To be used by WriteDB
+ } // endif Insert
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Reset buffer access according to indexing and to mode. */
+/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
+/***********************************************************************/
+void FIXFAM::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->GetMode() == MODE_READ && ReadBlks != 1 && !Padded &&
+ Tdbp->GetKindex() /*&& Tdbp->GetKindex()->IsRandom()*/) {
+ 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 FIX file. */
+/***********************************************************************/
+int FIXFAM::ReadBuffer(PGLOBAL g)
+ {
+ int n, rc = RC_OK;
+
+ if (!Closing) {
+ /*******************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*******************************************************************/
+ if (Placed) {
+ Tdbp->SetLine(To_Buf + CurNum * Lrecl);
+ Placed = false;
+ } else if (++CurNum < Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK;
+ } else if (Rbuf < Nrec && CurBlk != -1) {
+ return RC_EF;
+ } else {
+ /*****************************************************************/
+ /* New block. */
+ /*****************************************************************/
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ } // endif's
+
+ if (OldBlk == CurBlk) {
+ IsRead = true; // Was read indeed
+ return RC_OK; // Block is already there
+ } // endif OldBlk
+
+ } // endif !Closing
+
+ if (Modif) {
+ /*******************************************************************/
+ /* The old block was modified in Update mode. */
+ /* In Update mode we simply rewrite the old block on itself. */
+ /*******************************************************************/
+ bool moved = false;
+
+ if (UseTemp) // Copy any intermediate lines.
+ if (MoveIntermediateLines(g, &moved))
+ rc = RC_FX;
+
+ if (rc == RC_OK) {
+ // Fpos is last position, Headlen is DBF file header length
+ if (!moved && fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ rc = RC_FX;
+ } else if (fwrite(To_Buf, Lrecl, Rbuf, T_Stream) != (size_t)Rbuf) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ rc = RC_FX;
+ } // endif fwrite
+
+ Spos = Fpos + Nrec; // + Rbuf ???
+ } // endif rc
+
+ if (Closing || rc != RC_OK) { // Error or called from CloseDB
+ Closing = true; // To tell CloseDB about error
+ return rc;
+ } // endif Closing
+
+ // NOTE: Next line was added to avoid a very strange fread bug.
+ // When the fseek is not executed (even the file has the good
+ // pointer position) the next read can happen anywhere in the file.
+ OldBlk = CurBlk; // This will force fseek to be executed
+ Modif = 0;
+// Spos = Fpos + Nrec; done above
+ } // endif Mode
+
+ // This could be done only for new block. However note that FPOS
+ // is used as block position when updating and as line position
+ // when deleting so this has to be carefully checked.
+ Fpos = CurBlk * Nrec; // Fpos is new line position
+
+ // fseek is required only in non sequential reading
+ if (CurBlk != OldBlk + 1)
+ // Note: Headlen is for DBF tables
+ if (fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return RC_FX;
+ } // endif fseek
+
+#ifdef DEBTRACE
+ htrc("File position is now %d\n", ftell(Stream));
+#endif
+
+//long tell = ftell(Stream); not used
+
+ if (Padded)
+ n = fread(To_Buf, (size_t)Blksize, 1, Stream);
+ else
+ n = fread(To_Buf, (size_t)Lrecl, (size_t)Nrec, Stream);
+
+ if (n) {
+ rc = RC_OK;
+ Rbuf = (Padded) ? n * Nrec : n;
+ ReadBlks++;
+ num_read++;
+ } else if (feof(Stream)) {
+ rc = RC_EF;
+ } else {
+#if defined(UNIX)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#endif
+
+#ifdef DEBTRACE
+ htrc("%s\n", g->Message);
+#endif
+ return RC_FX;
+ } // endelse
+
+ OldBlk = CurBlk; // Last block actually read
+ IsRead = true; // Is read indeed
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for FIX access method. */
+/* Updates are written into the (Temp) file in ReadBuffer. */
+/***********************************************************************/
+int FIXFAM::WriteBuffer(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ fprintf(debug,
+ "FIX WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
+ Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
+#endif
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode, blocs are added sequentialy to the file end. */
+ /*******************************************************************/
+ if (++CurNum != Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK; // We write only full blocks
+ } // endif CurNum
+
+#ifdef DEBTRACE
+ htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
+#endif
+
+ // Now start the writing process.
+ if (fwrite(To_Buf, Lrecl, Rbuf, Stream) != (size_t)Rbuf) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ Closing = true; // To tell CloseDB about a Write error
+ return RC_FX;
+ } // endif size
+
+ CurBlk++;
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+#ifdef DEBTRACE
+ htrc("write done\n");
+#endif
+
+ } else { // Mode == MODE_UPDATE
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream)
+ if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ if (CopyHeader(g)) // For DBF tables
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ Modif++; // Modified line in Update mode
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for FIXFAM access method. */
+/***********************************************************************/
+int FIXFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool moved;
+
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This will be experimented. */
+ /*********************************************************************/
+#ifdef DEBTRACE
+ fprintf(debug,
+ "DOS DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+#endif
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = Tdbp->Cardinality(g);
+#ifdef DEBTRACE
+ htrc("Fpos placed at file end=%d\n", Fpos);
+#endif
+ } else // Fpos is the deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. */
+ /*******************************************************************/
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open temporary file, lines before this will be moved. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceeding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block moving. */
+ /*****************************************************************/
+ T_Stream = Stream;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ /*******************************************************************/
+ /* Reposition the file pointer and set Spos. */
+ /*******************************************************************/
+ Spos = Fpos + 1; // New start position is on next line
+
+ if (moved) {
+ if (fseek(Stream, Spos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif fseek
+
+ OldBlk = -2; // To force fseek to be executed on next block
+ } // endif moved
+
+#ifdef DEBTRACE
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Ok, now delete old file and rename new temp file. */
+ /*****************************************************************/
+ if (RenameTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS ??) this is still to be checked */
+ /* for compatibility with Text files and other OS's. */
+ /*****************************************************************/
+ char filename[_MAX_PATH];
+ int rc, h;
+
+ rc = PlugCloseFile(g, To_Fb);
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+#if defined(UNIX)
+ if (ftruncate(h, (off_t)(Tpos * Lrecl))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (chsize(h, Tpos * Lrecl)) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+#ifdef DEBTRACE
+ htrc("done, h=%d irc=%d\n", h, irc);
+#endif
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/* This works only for file open in binary mode. */
+/***********************************************************************/
+bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int n;
+ size_t req, len;
+
+ for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!UseTemp || !*b)
+ if (fseek(Stream, Headlen + Spos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ req = (size_t)min(n, Dbflen);
+ len = fread(DelBuf, Lrecl, req, Stream);
+
+#ifdef DEBTRACE
+ htrc("after read req=%d len=%d\n", req, len);
+#endif
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
+ return true;
+ } // endif len
+
+ if (!UseTemp) // Delete mode, cannot be a DBF file
+ if (fseek(T_Stream, Tpos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(DelBuf, Lrecl, req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+#ifdef DEBTRACE
+ htrc("after write pos=%d\n", ftell(Stream));
+#endif
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+#ifdef DEBTRACE
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ *b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediate Lines
+
+/***********************************************************************/
+/* Table file close routine for FIX access method. */
+/***********************************************************************/
+void FIXFAM::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) {
+ 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
+
+ // Finally close the file
+ rc = PlugCloseFile(g, To_Fb);
+
+ fin:
+#ifdef DEBTRACE
+ htrc("FIX 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 BGXFAM ---------------------------- */
+
+/***********************************************************************/
+/* Implementation of the BGXFAM class. */
+/* This is the FAM class for FIX tables of more than 2 gigabytes. */
+/***********************************************************************/
+BGXFAM::BGXFAM(PDOSDEF tdp) : FIXFAM(tdp)
+ {
+ Hfile = INVALID_HANDLE_VALUE;
+ Tfile = INVALID_HANDLE_VALUE;
+ } // end of BGXFAM constructor
+
+BGXFAM::BGXFAM(PBGXFAM txfp) : FIXFAM(txfp)
+ {
+ Hfile = txfp->Hfile;
+ Tfile = txfp->Tfile;
+ } // end of BGXFAM copy constructor
+
+/***********************************************************************/
+/* Set current position in a big file. */
+/***********************************************************************/
+bool BGXFAM::BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, int org)
+ {
+#if defined(WIN32)
+ char buf[256];
+ DWORD drc;
+ LARGE_INTEGER of;
+
+ of.QuadPart = pos;
+ of.LowPart = SetFilePointer(h, of.LowPart, &of.HighPart, org);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ (drc = GetLastError()) != NO_ERROR) {
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(SFP_ERROR), buf);
+ return true;
+ } // endif
+#else // !WIN32
+ if (lseek64(h, pos, org) < 0) {
+ sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
+ return true;
+ } // endif
+#endif // !WIN32
+
+ return false;
+ } // end of BigSeek
+
+/***********************************************************************/
+/* Read from a big file. */
+/***********************************************************************/
+int BGXFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req)
+ {
+ int rc;
+
+#if defined(WIN32)
+ DWORD nbr, drc, len = (DWORD)req;
+ bool brc = ReadFile(h, inbuf, len, &nbr, NULL);
+
+#ifdef DEBTRACE
+ htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr);
+#endif
+
+ if (!brc) {
+ char buf[256]; // , *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(READ_ERROR), To_File, buf);
+#ifdef DEBTRACE
+ htrc("BIGREAD: %s\n", g->Message);
+#endif
+ rc = -1;
+ } else
+ rc = (int)nbr;
+#else // !WIN32
+ size_t len = (size_t)req;
+ ssize_t nbr = read(h, inbuf, len);
+
+ rc = (int)nbr;
+#endif // !WIN32
+
+ return rc;
+ } // end of BigRead
+
+/***********************************************************************/
+/* Write into a big file. */
+/***********************************************************************/
+bool BGXFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req)
+ {
+ bool rc = false;
+
+#if defined(WIN32)
+ DWORD nbw, drc, len = (DWORD)req;
+ bool brc = WriteFile(h, inbuf, len, &nbw, NULL);
+
+#ifdef DEBTRACE
+ htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw);
+#endif
+
+ if (!brc || nbw != len) {
+ char buf[256], *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ if (brc)
+ strcpy(buf, MSG(BAD_BYTE_NUM));
+ else {
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ } // endelse brc
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf);
+
+#ifdef DEBTRACE
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, drc, g->Message);
+#endif
+ rc = true;
+ } // endif brc || nbw
+#else // !WIN32
+ size_t len = (size_t)req;
+ ssize_t nbw = write(h, inbuf, len);
+
+ if (nbw != (ssize_t)len) {
+ const char *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
+#ifdef DEBTRACE
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, errno, g->Message);
+#endif
+ rc = true;
+ } // endif nbr
+#endif // !WIN32
+
+ return rc;
+ } // end of BigWrite
+
+#if 0
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void BGXFAM::Reset(void)
+ {
+ FIXFAM::Reset();
+ Xpos = 0;
+ } // end of Reset
+#endif // 0
+
+/***********************************************************************/
+/* OpenTableFile: opens a huge file using Windows/Unix API's. */
+/***********************************************************************/
+bool BGXFAM::OpenTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ if ((To_Fb && To_Fb->Count) || Hfile != INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, MSG(FILE_OPEN_YET), To_File);
+ return true;
+ } // endif
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+#ifdef DEBTRACE
+ htrc("OpenTableFile: filename=%s mode=%d\n", filename, mode);
+#endif
+
+#if defined(WIN32)
+ DWORD rc, access, creation, share = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ access = GENERIC_READ;
+ share = FILE_SHARE_READ;
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted rows
+ DelRows = Cardinality(g);
+
+ // This will delete the whole file and provoque ReadDB to
+ // return immediately.
+ access = GENERIC_READ | GENERIC_WRITE;
+ creation = TRUNCATE_EXISTING;
+ Tdbp->ResetSize();
+ Headlen = 0;
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ if ((UseTemp = Tdbp->IsUsingTemp(g)))
+ access = GENERIC_READ;
+ else
+ access = GENERIC_READ | GENERIC_WRITE;
+
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_INSERT:
+ access = GENERIC_WRITE;
+ creation = OPEN_ALWAYS;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ Hfile = CreateFile(filename, access, share, NULL, creation,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ } else
+ rc = 0;
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ " rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n",
+ rc, access, share, creation, Hfile, filename);
+#endif
+
+ if (mode == MODE_INSERT)
+ /*******************************************************************/
+ /* In Insert mode we must position the cursor at end of file. */
+ /*******************************************************************/
+ if (BigSeek(g, Hfile, (BIGINT)0, FILE_END))
+ return true;
+
+#else // UNIX
+ int rc = 0;
+ int oflag = O_LARGEFILE; // Enable file size > 2G
+ mode_t tmode = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ oflag |= O_RDONLY;
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // This will delete the whole file and provoque ReadDB to
+ // return immediately.
+ oflag |= (O_RDWR | O_TRUNC);
+ Tdbp->ResetSize();
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ oflag |= (UseTemp) ? O_RDONLY : O_RDWR;
+ break;
+ case MODE_INSERT:
+ oflag |= (O_WRONLY | O_CREAT | O_APPEND);
+ tmode = S_IREAD | S_IWRITE;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ Hfile= global_open(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, oflag, tmode);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = errno;
+ } else
+ rc = 0;
+
+#ifdef DEBTRACE
+ htrc(" rc=%d oflag=%p tmode=%p handle=%p fn=%s\n",
+ rc, oflag, tmode, Hfile, filename);
+#endif
+
+#endif // UNIX
+
+ if (!rc) {
+ if (!To_Fb) {
+ To_Fb = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fb->Fname = To_File;
+ To_Fb->Type = TYPE_FB_HANDLE;
+ To_Fb->Memory = NULL;
+ To_Fb->Length = 0;
+ To_Fb->Mode = mode;
+ To_Fb->File = NULL;
+ To_Fb->Next = dbuserp->Openlist;
+ dbuserp->Openlist = To_Fb;
+ } // endif To_Fb
+
+ To_Fb->Count = 1;
+ To_Fb->Mode = mode;
+ To_Fb->Handle = Hfile;
+
+ /*******************************************************************/
+ /* Allocate the block buffer. */
+ /*******************************************************************/
+ return AllocateBuffer(g);
+ } else
+ return (mode == MODE_READ && rc == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* BIGFIX 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 BGXFAM::Cardinality(PGLOBAL g)
+ {
+ if (g) {
+ char filename[_MAX_PATH];
+ int card = -1;
+ BIGINT fsize;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+#if defined(WIN32) // OB
+ LARGE_INTEGER len;
+ DWORD rc = 0;
+
+ len.QuadPart = -1;
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ HANDLE h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h == INVALID_HANDLE_VALUE)
+ if ((rc = GetLastError()) != ERROR_FILE_NOT_FOUND) {
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, 10, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ return -1;
+ } else
+ return 0; // File does not exist
+
+ // Get the size of the file (can be greater than 4 GB)
+ len.LowPart = GetFileSize(h, (LPDWORD)&len.HighPart);
+ CloseHandle(h);
+ } else
+ len.LowPart = GetFileSize(Hfile, (LPDWORD)&len.HighPart);
+
+ if (len.LowPart == 0xFFFFFFFF && (rc = GetLastError()) != NO_ERROR) {
+ sprintf(g->Message, MSG(FILELEN_ERROR), "GetFileSize", filename);
+ return -2;
+ } else
+ fsize = len.QuadPart;
+
+#else // UNIX
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ int h = open64(filename, O_RDONLY, 0);
+
+#ifdef DEBTRACE
+ htrc(" h=%d\n", h);
+#endif
+
+ if (h == INVALID_HANDLE_VALUE) {
+#ifdef DEBTRACE
+ htrc(" errno=%d ENOENT=%d\n", errno, ENOENT);
+#endif
+ if (errno != ENOENT) {
+ sprintf(g->Message, MSG(OPEN_ERROR_IS),
+ filename, strerror(errno));
+ return -1;
+ } else
+ return 0; // File does not exist
+
+ } // endif h
+
+ // Get the size of the file (can be greater than 4 GB)
+ fsize = lseek64(h, 0, SEEK_END);
+ close(h);
+ } else {
+ BIGINT curpos = lseek64(Hfile, 0, SEEK_CUR);
+
+ fsize = lseek64(Hfile, 0, SEEK_END);
+ lseek64(Hfile, curpos, SEEK_SET);
+ } // endif Hfile
+
+ if (fsize < 0) {
+ sprintf(g->Message, MSG(FILELEN_ERROR), "lseek64", filename);
+ return -2;
+ } // endif fsize
+
+#endif // UNIX
+
+ // Check the real size of the file
+ if (Padded && Blksize) {
+ if (fsize % (BIGINT)Blksize) {
+ sprintf(g->Message, MSG(NOT_FIXED_LEN),
+ filename, (int)fsize, Lrecl);
+ return -3;
+ } else
+ card = (int)(fsize / (BIGINT)Blksize) * Nrec;
+
+ } else if (fsize % (BIGINT)Lrecl) {
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), filename, (int)fsize, Lrecl);
+ return -3;
+ } else
+ card = (int)(fsize / (BIGINT)Lrecl); // Fixed length file
+
+#ifdef DEBTRACE
+ htrc(" Computed max_K=%d fsize=%lf lrecl=%d\n",
+ card, (double)fsize, Lrecl);
+#endif
+
+ // Set number of blocks for later use
+ Block = (card + Nrec - 1) / Nrec;
+ return card;
+ } else
+ return -1;
+
+ } // end of Cardinality
+
+/***********************************************************************/
+/* ReadBuffer: Read Nrec lines for a big fixed/binary file. */
+/***********************************************************************/
+int BGXFAM::ReadBuffer(PGLOBAL g)
+ {
+ int nbr, rc = RC_OK;
+
+ if (!Closing) {
+ /*******************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*******************************************************************/
+ if (Placed) {
+ Tdbp->SetLine(To_Buf + CurNum * Lrecl);
+ Placed = false;
+ } else if (++CurNum < Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK;
+ } else if (Rbuf < Nrec && CurBlk != -1) {
+ return RC_EF;
+ } else {
+ /*****************************************************************/
+ /* New block. */
+ /*****************************************************************/
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ } // endif's
+
+ if (OldBlk == CurBlk) {
+ IsRead = true; // Was read indeed
+ return RC_OK; // Block is already there
+ } // endif OldBlk
+
+ } // endif !Closing
+
+ if (Modif) {
+ /*******************************************************************/
+ /* The old block was modified in Update mode. */
+ /* In Update mode we simply rewrite the old block on itself. */
+ /*******************************************************************/
+ bool moved = false;
+
+ if (UseTemp) // Copy any intermediate lines.
+ if (MoveIntermediateLines(g, &moved))
+ rc = RC_FX;
+
+ if (rc == RC_OK) {
+ // Set file position to OldBlk position (Fpos)
+ if (!moved && BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
+ rc = RC_FX;
+ else if (BigWrite(g, Tfile, To_Buf, Lrecl * Rbuf))
+ rc = RC_FX;
+
+ Spos = Fpos + Nrec; // + Rbuf ???
+ } // endif rc
+
+ if (Closing || rc != RC_OK) // Error or called from CloseDB
+ return rc;
+
+ // NOTE: Next line was added to avoid a very strange fread bug.
+ // When the fseek is not executed (even the file has the good
+ // pointer position) the next read can happen anywhere in the file.
+ OldBlk = CurBlk; // This will force fseek to be executed
+ Modif = 0;
+ } // endif Mode
+
+ Fpos = CurBlk * Nrec;
+
+ // Setting file pointer is required only in non sequential reading
+ if (CurBlk != OldBlk + 1)
+ if (BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
+ return RC_FX;
+
+#ifdef DEBTRACE
+ htrc("File position is now %d\n", Fpos);
+#endif
+
+ nbr = BigRead(g, Hfile, To_Buf, (Padded) ? Blksize : Lrecl * Nrec);
+
+ if (nbr > 0) {
+ Rbuf = (Padded) ? Nrec : nbr / Lrecl;
+ rc = RC_OK;
+ ReadBlks++;
+ num_read++;
+ } else
+ rc = (nbr == 0) ? RC_EF : RC_FX;
+
+ OldBlk = CurBlk; // Last block actually read
+ IsRead = true; // Is read indeed
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for BGXFAM access method. */
+/* Updates are written into the (Temp) file in ReadBuffer. */
+/***********************************************************************/
+int BGXFAM::WriteBuffer(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ fprintf(debug,
+ "BIG WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
+ Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
+#endif
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode, blocks are added sequentialy to the file end. */
+ /*******************************************************************/
+ if (++CurNum != Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK; // We write only full blocks
+ } // endif CurNum
+
+#ifdef DEBTRACE
+ htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
+#endif
+
+ // Now start the writing process.
+ if (BigWrite(g, Hfile, To_Buf, Lrecl * Rbuf))
+ return RC_FX;
+
+ CurBlk++;
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+#ifdef DEBTRACE
+ htrc("write done\n");
+#endif
+
+ } else { // Mode == MODE_UPDATE
+ // Tfile is the temporary file or the table file handle itself
+ if (Tfile == INVALID_HANDLE_VALUE)
+ if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ Tfile = Hfile;
+
+ Modif++; // Modified line in Update mode
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for BGXFAM access method. */
+/***********************************************************************/
+int BGXFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool moved;
+
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This will be experimented. */
+ /*********************************************************************/
+#ifdef DEBTRACE
+ fprintf(debug,
+ "BGX DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+#endif
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = Tdbp->Cardinality(g);
+#ifdef DEBTRACE
+ htrc("Fpos placed at file end=%d\n", Fpos);
+#endif
+ } else // Fpos is the deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. Move of eventual preceeding lines is */
+ /* not required here if a temporary file is not used, just the */
+ /* setting of future Spos and Tpos. */
+ /*******************************************************************/
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceeding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ Tfile = Hfile;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+#ifdef DEBTRACE
+ assert(Spos == Fpos);
+#endif
+ Spos++; // New start position is on next line
+
+ if (moved) {
+ if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
+ return RC_FX;
+
+ OldBlk = -2; // To force fseek to be executed on next block
+ } // endif moved
+
+#ifdef DEBTRACE
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ char filename[_MAX_PATH];
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Ok, now delete old file and rename new temp file. */
+ /*****************************************************************/
+ if (RenameTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+#if defined(WIN32)
+ if (BigSeek(g, Hfile, (BIGINT)Tpos * (BIGINT)Lrecl))
+ return RC_FX;
+
+ if (!SetEndOfFile(Hfile)) {
+ DWORD drc = GetLastError();
+
+ sprintf(g->Message, MSG(SETEOF_ERROR), drc);
+ return RC_FX;
+ } // endif error
+#else // !WIN32
+ if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+#endif // !WIN32
+
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool BGXFAM::OpenTempFile(PGLOBAL g)
+ {
+ char *tempname;
+ PDBUSER dup = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ tempname = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+ remove(tempname); // Be sure it does not exist yet
+
+#if defined(WIN32)
+ Tfile = CreateFile(tempname, GENERIC_WRITE, 0, NULL,
+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)tempname, _MAX_PATH, NULL);
+ strcat(g->Message, tempname);
+ return true;
+ } // endif Tfile
+#else // UNIX
+ Tfile = open64(tempname, O_WRONLY | O_TRUNC, S_IWRITE);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ int rc = errno;
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
+ strcat(g->Message, strerror(errno));
+ return true;
+ } //endif Tfile
+#endif // UNIX
+
+ To_Fbt = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fbt->Fname = tempname;
+ To_Fbt->Type = TYPE_FB_HANDLE;
+ To_Fbt->Memory = NULL;
+ To_Fbt->Length = 0;
+ To_Fbt->File = NULL;
+ To_Fbt->Next = dup->Openlist;
+ To_Fbt->Count = 1;
+ To_Fbt->Mode = MODE_INSERT;
+ To_Fbt->Handle = Tfile;
+ dup->Openlist = To_Fbt;
+ return false;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int n, req, nbr;
+
+ for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!UseTemp || !*b)
+ if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
+ return true;
+
+ req = min(n, Dbflen) * Lrecl;
+
+ if ((nbr = BigRead(g, Hfile, DelBuf, req)) != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), req, nbr);
+ return true;
+ } // endif nbr
+
+ if (!UseTemp)
+ if (BigSeek(g, Tfile, (BIGINT)Tpos * (BIGINT)Lrecl))
+ return true;
+
+ if (BigWrite(g, Tfile, DelBuf, req))
+ return true;
+
+ req /= Lrecl;
+ Tpos += (int)req;
+ Spos += (int)req;
+
+#ifdef DEBTRACE
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ *b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediateLines
+
+/***********************************************************************/
+/* Data Base close routine for BIGFIX access method. */
+/***********************************************************************/
+void BGXFAM::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--;
+ wrc = WriteBuffer(g);
+ } else if (mode == MODE_UPDATE) {
+ if (Modif && !Closing) {
+ // Last updated block remains to be written
+ Closing = true;
+ wrc = ReadBuffer(g);
+ } // endif Modif
+
+ if (UseTemp && Tfile && 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
+
+ // Finally close the file
+ rc = PlugCloseFile(g, To_Fb);
+
+ fin:
+#ifdef DEBTRACE
+ htrc("BGX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
+ To_File, mode, wrc, rc);
+#endif
+ Hfile = INVALID_HANDLE_VALUE; // So we can know whether table is open
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for huge FIX access method. */
+/* Note: commenting out OldBlk = -1 has two advantages: */
+/* 1 - It forces fseek on first block, thus suppressing the need to */
+/* rewind the file, anyway unuseful when second pass if indexed. */
+/* 2 - It permit to avoid re-reading small tables having only 1 block.*/
+/* (even very unlikely for huge files!) */
+/***********************************************************************/
+void BGXFAM::Rewind(void)
+ {
+#if 0 // This is probably unuseful because file is accessed directly
+#if defined(WIN32) //OB
+ SetFilePointer(Hfile, 0, NULL, FILE_BEGIN);
+#else // UNIX
+ lseek64(Hfile, 0, SEEK_SET);
+#endif // UNIX
+#endif // 0
+ CurBlk = -1;
+ CurNum = Rbuf;
+//OldBlk = -1;
+//Rbuf = 0; commented out in case we reuse last read block
+ Fpos = 0;
+ } // end of Rewind
diff --git a/storage/connect/filamfix.h b/storage/connect/filamfix.h
index 8c781bdd65c..758d891bf2c 100644
--- a/storage/connect/filamfix.h
+++ b/storage/connect/filamfix.h
@@ -1,90 +1,90 @@
-/************** 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
-
-
-/***********************************************************************/
-/* 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
+/************** 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
+
+
+/***********************************************************************/
+/* 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
diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp
index 5fb87991b85..5e4c8575814 100644
--- a/storage/connect/filamtxt.cpp
+++ b/storage/connect/filamtxt.cpp
@@ -1,1410 +1,1410 @@
-/*********** File AM Txt C++ Program Source Code File (.CPP) ***********/
-/* PROGRAM NAME: FILAMTXT */
-/* ------------- */
-/* Version 1.4 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the Text file access method classes. */
-/* */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant sections of the System 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) || defined(UNIV_LINUX)
-#include <errno.h>
-#include <unistd.h>
-//#if !defined(sun) // Sun has the ftruncate fnc.
-//#define USETEMP // Force copy mode for DELETE
-//#endif // !sun
-#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. */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "filamtxt.h"
-#include "tabdos.h"
-
-#if defined(UNIX) || defined(UNIV_LINUX)
-#include "osutil.h"
-#define _fileno fileno
-#define _O_RDONLY O_RDONLY
-#endif
-
-extern int num_read, num_there, num_eq[2]; // Statistics
-extern "C" int trace;
-
-bool PushWarning(PGLOBAL g, PTDBASE tdbp);
-
-/* --------------------------- Class TXTFAM -------------------------- */
-
-/***********************************************************************/
-/* Constructors. */
-/***********************************************************************/
-TXTFAM::TXTFAM(PDOSDEF tdp)
- {
- Tdbp = NULL;
- To_Fb = NULL;
- To_File = tdp->Fn;
- Lrecl = tdp->Lrecl;
- Placed = false;
- IsRead = true;
- Blocked = false;
- To_Buf = NULL;
- DelBuf = NULL;
- BlkPos = NULL;
- BlkLen = 0;
- Buflen = 0;
- Dbflen = 0;
- Rows = 0;
- DelRows = 0;
- Headlen = 0;
- Block = 0;
- Last = 0;
- Nrec = 1;
- OldBlk = -1;
- CurBlk = -1;
- ReadBlks = 0;
- CurNum = 0;
- Rbuf = 0;
- Modif = 0;
- Blksize = 0;
- Padded = false;
- Eof = tdp->Eof;
- Ending = tdp->Ending;
- CrLf = (char*)(Ending == 2 ? "\r\n" : "\n");
- } // end of TXTFAM standard constructor
-
-TXTFAM::TXTFAM(PTXF txfp)
- {
- Tdbp = txfp->Tdbp;
- To_Fb = txfp->To_Fb;
- To_File = txfp->To_File;
- Lrecl = txfp->Lrecl;
- Placed = txfp->Placed;
- IsRead = txfp->IsRead;
- Blocked = txfp->Blocked;
- To_Buf = txfp->To_Buf;
- DelBuf = txfp->DelBuf;
- BlkPos = txfp->BlkPos;
- BlkLen = txfp->BlkLen;
- Buflen = txfp->Buflen;
- Dbflen = txfp->Dbflen;
- Rows = txfp->Rows;
- DelRows = txfp->DelRows;
- Headlen = txfp->Headlen;
- Block = txfp->Block;
- Last = txfp->Last;
- Nrec = txfp->Nrec;
- OldBlk = txfp->OldBlk;
- CurBlk = txfp->CurBlk;
- ReadBlks = txfp->ReadBlks;
- CurNum = txfp->CurNum;
- Rbuf = txfp->Rbuf;
- Modif = txfp->Modif;
- Blksize = txfp->Blksize;
- Padded = txfp->Padded;
- Eof = txfp->Eof;
- Ending = txfp->Ending;
- } // end of TXTFAM copy constructor
-
-/***********************************************************************/
-/* Reset: reset position values at the beginning of file. */
-/***********************************************************************/
-void TXTFAM::Reset(void)
- {
- Rows = 0;
- DelRows = 0;
- OldBlk = -1;
- CurBlk = -1;
- ReadBlks = 0;
- CurNum = 0;
- Rbuf = 0;
- Modif = 0;
- Placed = false;
- } // end of Reset
-
-/***********************************************************************/
-/* TXT GetFileLength: returns file size in number of bytes. */
-/***********************************************************************/
-int TXTFAM::GetFileLength(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- int h;
- int len;
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
- h= global_open(g, MSGID_OPEN_MODE_STRERROR, filename, _O_RDONLY);
-
- if (trace)
- htrc("GetFileLength: fn=%s h=%d\n", filename, h);
-
- if (h == -1) {
- if (errno != ENOENT) {
- if (trace)
- htrc("%s\n", g->Message);
- len = -1;
- }
- else
- {
- len = 0; // File does not exist yet
- g->Message[0]= '\0';
- }
- } else {
- if ((len = _filelength(h)) < 0)
- sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", filename);
-
- if (Eof && len)
- len--; // Do not count the EOF character
-
- close(h);
- } // endif h
-
- return len;
- } // end of GetFileLength
-
-/***********************************************************************/
-/* 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). */
-/* Note: This function is meant only for fixed length files but is */
-/* placed here to be available to FIXFAM and MPXFAM classes. */
-/***********************************************************************/
-int TXTFAM::Cardinality(PGLOBAL g)
- {
- if (g) {
- int card = -1;
- int len = GetFileLength(g);
-
- if (len >= 0) {
- if (Padded && Blksize) {
- if (!(len % Blksize))
- card = (len / Blksize) * Nrec;
- else
- sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, Lrecl);
-
- } else {
- if (!(len % Lrecl))
- card = len / (int)Lrecl; // Fixed length file
- else
- sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, Lrecl);
-
- } // endif Padded
-
- if (trace)
- htrc(" Computed max_K=%d Filen=%d lrecl=%d\n",
- card, len, Lrecl);
-
- } else
- card = 0;
-
- // Set number of blocks for later use
- Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
- return card;
- } else
- return 1;
-
- } // end of Cardinality
-
-/***********************************************************************/
-/* Use BlockTest to reduce the table estimated size. */
-/* Note: This function is meant only for fixed length files but is */
-/* placed here to be available to FIXFAM and MPXFAM classes. */
-/***********************************************************************/
-int TXTFAM::MaxBlkSize(PGLOBAL g, int s)
- {
- int savcur = CurBlk, blm1 = Block - 1;
- int size, last = s - blm1 * Nrec;
-
- // 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 == blm1) ? last : Nrec;
-
- CurBlk = savcur;
- return size;
- } // end of MaxBlkSize
-
-/* --------------------------- Class DOSFAM -------------------------- */
-
-/***********************************************************************/
-/* Constructors. */
-/***********************************************************************/
-DOSFAM::DOSFAM(PDOSDEF tdp) : TXTFAM(tdp)
- {
- To_Fbt = NULL;
- Stream = NULL;
- T_Stream = NULL;
- Fpos = Spos = Tpos = 0;
- UseTemp = false;
- Bin = false;
- } // end of DOSFAM standard constructor
-
-DOSFAM::DOSFAM(PDOSFAM tdfp) : TXTFAM(tdfp)
- {
- To_Fbt = tdfp->To_Fbt;
- Stream = tdfp->Stream;
- T_Stream = tdfp->T_Stream;
- Fpos = tdfp->Fpos;
- Spos = tdfp->Spos;
- Tpos = tdfp->Tpos;
- UseTemp = tdfp->UseTemp;
- Bin = tdfp->Bin;
- } // end of DOSFAM copy constructor
-
-/***********************************************************************/
-/* Reset: reset position values at the beginning of file. */
-/***********************************************************************/
-void DOSFAM::Reset(void)
- {
- TXTFAM::Reset();
- Bin = false;
- Fpos = Tpos = Spos = 0;
- } // end of Reset
-
-/***********************************************************************/
-/* DOS GetFileLength: returns file size in number of bytes. */
-/***********************************************************************/
-int DOSFAM::GetFileLength(PGLOBAL g)
- {
- int len;
-
- if (!Stream)
- len = TXTFAM::GetFileLength(g);
- else
- if ((len = _filelength(_fileno(Stream))) < 0)
- sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", To_File);
-
- if (trace)
- htrc("File length=%d\n", len);
-
- return len;
- } // end of GetFileLength
-
-/***********************************************************************/
-/* 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 DOSFAM::Cardinality(PGLOBAL g)
- {
- return (g) ? -1 : 0;
- } // end of Cardinality
-
-/***********************************************************************/
-/* Use BlockTest to reduce the table estimated size. */
-/* Note: This function is not really implemented yet. */
-/***********************************************************************/
-int DOSFAM::MaxBlkSize(PGLOBAL g, int s)
- {
- return s;
- } // end of MaxBlkSize
-
-/***********************************************************************/
-/* OpenTableFile: Open a DOS/UNIX table file using C standard I/Os. */
-/***********************************************************************/
-bool DOSFAM::OpenTableFile(PGLOBAL g)
- {
- char opmode[4], filename[_MAX_PATH];
-//int ftype = Tdbp->GetFtype();
- MODE mode = Tdbp->Mode;
- PDBUSER dbuserp = PlgGetUser(g);
-
- // This is required when using Unix files under Windows
- Bin = (Ending == 1);
-
- switch (mode) {
- case MODE_READ:
- strcpy(opmode, "r");
- break;
- case MODE_DELETE:
- if (!Tdbp->Next) {
- // Store the number of deleted lines
- DelRows = Cardinality(g);
-
- if (Blocked) {
- // Cardinality must return 0
- Block = 0;
- Last = Nrec;
- } // endif blocked
-
- // This will erase the entire file
- strcpy(opmode, "w");
- Tdbp->ResetSize();
- break;
- } // endif
-
- // Selective delete, pass thru
- Bin = true;
- case MODE_UPDATE:
- if ((UseTemp = Tdbp->IsUsingTemp(g))) {
- strcpy(opmode, "r");
- Bin = true;
- } else
- strcpy(opmode, "r+");
-
- break;
- case MODE_INSERT:
- strcpy(opmode, "a+");
- break;
- default:
- sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
- return true;
- } // endswitch Mode
-
- // For blocked I/O or for moving lines, open the table in binary
- strcat(opmode, (Blocked || Bin) ? "b" : "t");
-
- // Now open the file stream
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (!(Stream = PlugOpenFile(g, filename, opmode))) {
- if (trace)
- htrc("%s\n", g->Message);
-
- return (mode == MODE_READ && errno == ENOENT)
- ? PushWarning(g, Tdbp) : true;
- } // endif Stream
-
- if (trace)
- htrc("File %s open Stream=%p mode=%s\n", filename, Stream, opmode);
-
- 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 line buffer. For mode Delete a bigger buffer has to */
-/* be allocated because is it also used to move lines into the file. */
-/***********************************************************************/
-bool DOSFAM::AllocateBuffer(PGLOBAL g)
- {
- MODE mode = Tdbp->Mode;
-
- // Lrecl does not include line ending
- Buflen = Lrecl + Ending + ((Bin) ? 1 : 0);
-
- if (trace)
- htrc("SubAllocating a buffer of %d bytes\n", Buflen);
-
- To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
-
- if (UseTemp || mode == MODE_DELETE) {
- // Have a big buffer to move lines
- Dbflen = Buflen * DOS_BUFF_LEN;
- DelBuf = PlugSubAlloc(g, NULL, Dbflen);
- } else if (mode == MODE_INSERT) {
- /*******************************************************************/
- /* Prepare the buffer so eventual gaps are filled with blanks. */
- /*******************************************************************/
- memset(To_Buf, ' ', Buflen);
- To_Buf[Buflen - 2] = '\n';
- To_Buf[Buflen - 1] = '\0';
- } // endif's mode
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* GetRowID: return the RowID of last read record. */
-/***********************************************************************/
-int DOSFAM::GetRowID(void)
- {
- return Rows;
- } // end of GetRowID
-
-/***********************************************************************/
-/* GetPos: return the position of last read record. */
-/***********************************************************************/
-int DOSFAM::GetPos(void)
- {
- return Fpos;
- } // end of GetPos
-
-/***********************************************************************/
-/* GetNextPos: return the position of next record. */
-/***********************************************************************/
-int DOSFAM::GetNextPos(void)
- {
- return ftell(Stream);
- } // end of GetNextPos
-
-/***********************************************************************/
-/* SetPos: Replace the table at the specified position. */
-/***********************************************************************/
-bool DOSFAM::SetPos(PGLOBAL g, int pos)
- {
- Fpos = pos;
-
- if (fseek(Stream, Fpos, SEEK_SET)) {
- sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
- return true;
- } // endif
-
- Placed = true;
- return false;
- } // end of SetPos
-
-/***********************************************************************/
-/* Record file position in case of UPDATE or DELETE. */
-/***********************************************************************/
-bool DOSFAM::RecordPos(PGLOBAL g)
- {
- if ((Fpos = ftell(Stream)) < 0) {
- sprintf(g->Message, MSG(FTELL_ERROR), 0, strerror(errno));
- return true;
- } // endif Fpos
-
- return false;
- } // end of RecordPos
-
-/***********************************************************************/
-/* Skip one record in file. */
-/***********************************************************************/
-int DOSFAM::SkipRecord(PGLOBAL g, bool header)
- {
- PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- // Skip this record
- if (!fgets(To_Buf, Buflen, Stream)) {
- if (feof(Stream))
- return RC_EF;
-
-#if defined(UNIX) || defined(UNIV_LINUX)
- sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0));
-#else
- sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
-#endif
- return RC_FX;
- } // endif fgets
-
- // Update progress information
- dup->ProgCur = GetPos();
-
- if (header) {
- // For Delete
- Fpos = ftell(Stream);
-
- if (!UseTemp)
- Tpos = Spos = Fpos; // No need to move header
-
- } // endif header
-
-#if defined(THREAD)
- return RC_NF; // To have progress info
-#else
- return RC_OK; // To loop locally
-#endif
- } // end of SkipRecord
-
-/***********************************************************************/
-/* ReadBuffer: Read one line for a text file. */
-/***********************************************************************/
-int DOSFAM::ReadBuffer(PGLOBAL g)
- {
- char *p;
- int rc;
-
- if (!Stream)
- return RC_EF;
-
- if (trace)
- htrc("ReadBuffer: Tdbp=%p To_Line=%p Placed=%d\n",
- Tdbp, Tdbp->To_Line, Placed);
-
- if (!Placed) {
- /*******************************************************************/
- /* Record file position in case of UPDATE or DELETE. */
- /*******************************************************************/
- if (RecordPos(g))
- return RC_FX;
-
- CurBlk = (int)Rows++;
-
- if (trace)
- htrc("ReadBuffer: CurBlk=%d\n", CurBlk);
-
- } else
- Placed = false;
-
- if (trace)
- htrc(" About to read: stream=%p To_Buf=%p Buflen=%d\n",
- Stream, To_Buf, Buflen);
-
- if (fgets(To_Buf, Buflen, Stream)) {
- p = To_Buf + strlen(To_Buf) - 1;
-
- if (trace)
- htrc(" Read: To_Buf=%p p=%c\n", To_Buf, To_Buf, p);
-
-#if defined(UNIX)
- if (true) {
- // Data files can be imported from Windows (having CRLF)
-#else
- if (Bin) {
- // Data file is read in binary so CRLF remains
-#endif
- if (*p == '\n' || *p == '\r') {
- // is this enough for Unix ???
- *p = '\0'; // Eliminate ending CR or LF character
-
- if (p > To_Buf) {
- // is this enough for Unix ???
- p--;
-
- if (*p == '\n' || *p == '\r')
- *p = '\0'; // Eliminate ending CR or LF character
-
- } // endif To_Buf
-
- } // endif p
-
- } else if (*p == '\n')
- *p = '\0'; // Eliminate ending new-line character
-
- if (trace)
- htrc(" To_Buf='%s'\n", To_Buf);
-
- strcpy(Tdbp->To_Line, To_Buf);
- num_read++;
- rc = RC_OK;
- } else if (feof(Stream)) {
- rc = RC_EF;
- } else {
-#if defined(UNIX)
- sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0));
-#else
- sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
-#endif
-
- if (trace)
- htrc("%s\n", g->Message);
-
- rc = RC_FX;
- } // endif's fgets
-
- if (trace)
- htrc("ReadBuffer: rc=%d\n", rc);
-
- IsRead = true;
- return rc;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* WriteBuffer: File write routine for DOS access method. */
-/***********************************************************************/
-int DOSFAM::WriteBuffer(PGLOBAL g)
- {
- char *crlf = "\n";
- int curpos = 0;
- bool moved = true;
-
- // T_Stream is the temporary stream or the table file stream itself
- if (!T_Stream)
- if (UseTemp && Tdbp->Mode == MODE_UPDATE) {
- if (OpenTempFile(g))
- return RC_FX;
-
- } else
- T_Stream = Stream;
-
- if (Tdbp->Mode == MODE_UPDATE) {
- /*******************************************************************/
- /* Here we simply rewrite a record on itself. There are two cases */
- /* were another method should be used, a/ when Update apply to */
- /* the whole file, b/ when updating the last field of a variable */
- /* length file. The method could be to rewrite a new file, then */
- /* to erase the old one and rename the new updated file. */
- /*******************************************************************/
- curpos = ftell(Stream);
-
- if (trace)
- htrc("Last : %d cur: %d\n", Fpos, curpos);
-
- if (UseTemp) {
- /*****************************************************************/
- /* We are using a temporary file. Before writing the updated */
- /* record, we must eventually copy all the intermediate records */
- /* that have not been updated. */
- /*****************************************************************/
- if (MoveIntermediateLines(g, &moved))
- return RC_FX;
-
- Spos = curpos; // New start position
- } else
- // Update is directly written back into the file,
- // with this (fast) method, record size cannot change.
- if (fseek(Stream, Fpos, SEEK_SET)) {
- sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
- return RC_FX;
- } // endif
-
- } // endif mode
-
- /*********************************************************************/
- /* Prepare the write buffer. */
- /*********************************************************************/
-#if defined(WIN32)
- if (Bin)
- crlf = "\r\n";
-#endif // WIN32
- strcat(strcpy(To_Buf, Tdbp->To_Line), crlf);
-
- /*********************************************************************/
- /* Now start the writing process. */
- /*********************************************************************/
- if ((fputs(To_Buf, T_Stream)) == EOF) {
- sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno));
- return RC_FX;
- } // endif EOF
-
- if (Tdbp->Mode == MODE_UPDATE && moved)
- if (fseek(Stream, curpos, SEEK_SET)) {
- sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
- return RC_FX;
- } // endif
-
- if (trace)
- htrc("write done\n");
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for DOS and BLK access methods. */
-/***********************************************************************/
-int DOSFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- bool moved;
- int curpos = ftell(Stream);
-
- /*********************************************************************/
- /* There is an alternative here: */
- /* 1 - use a temporary file in which are copied all not deleted */
- /* lines, at the end the original file will be deleted and */
- /* the temporary file renamed to the original file name. */
- /* 2 - directly move the not deleted lines inside the original */
- /* file, and at the end erase all trailing records. */
- /* This will be experimented, but method 1 must be used for Unix as */
- /* the function needed to erase trailing records is not available. */
- /*********************************************************************/
- if (trace)
- htrc(
- "DOS DeleteDB: rc=%d UseTemp=%d curpos=%d Fpos=%d Tpos=%d Spos=%d\n",
- irc, UseTemp, curpos, Fpos, Tpos, Spos);
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the end-of-file position. */
- /*******************************************************************/
- fseek(Stream, 0, SEEK_END);
- Fpos = ftell(Stream);
-
- if (trace)
- htrc("Fpos placed at file end=%d\n", Fpos);
-
- } // endif irc
-
- if (Tpos == Spos) {
- /*******************************************************************/
- /* First line to delete, Open temporary file. */
- /*******************************************************************/
- if (UseTemp) {
- if (OpenTempFile(g))
- return RC_FX;
-
- } else {
- /*****************************************************************/
- /* Move of eventual preceeding lines is not required here. */
- /* Set the target file as being the source file itself. */
- /* Set the future Tpos, and give Spos a value to block copying. */
- /*****************************************************************/
- T_Stream = Stream;
- Spos = Tpos = Fpos;
- } // endif UseTemp
-
- } // endif Tpos == Spos
-
- /*********************************************************************/
- /* Move any intermediate lines. */
- /*********************************************************************/
- if (MoveIntermediateLines(g, &moved))
- return RC_FX;
-
- if (irc == RC_OK) {
- /*******************************************************************/
- /* Reposition the file pointer and set Spos. */
- /*******************************************************************/
- if (!UseTemp || moved)
- if (fseek(Stream, curpos, SEEK_SET)) {
- sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
- return RC_FX;
- } // endif
-
- Spos = GetNextPos(); // New start position
-
- if (trace)
- htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
-
- } else {
- /*******************************************************************/
- /* Last call after EOF has been reached. */
- /* The UseTemp case is treated in CloseTableFile. */
- /*******************************************************************/
- if (!UseTemp) {
- /*****************************************************************/
- /* Because the chsize functionality is only accessible with a */
- /* system call we must close the file and reopen it with the */
- /* open function (_fopen for MS ??) this is still to be checked */
- /* for compatibility with Text files and other OS's. */
- /*****************************************************************/
- char filename[_MAX_PATH];
- int h, rc; // File handle, return code
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
- rc = PlugCloseFile(g, To_Fb);
-
- if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
- return RC_FX;
-
- /*****************************************************************/
- /* Remove extra records. */
- /*****************************************************************/
-#if defined(UNIX)
- if (ftruncate(h, (off_t)Tpos)) {
- sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#else
- if (chsize(h, Tpos)) {
- sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#endif
-
- close(h);
-
- if (trace)
- htrc("done, h=%d irc=%d\n", h, irc);
-
- } // endif !UseTemp
-
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Open a temporary file used while updating or deleting. */
-/***********************************************************************/
-bool DOSFAM::OpenTempFile(PGLOBAL g)
- {
- char tempname[_MAX_PATH];
- bool rc = false;
-
- /*********************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*********************************************************************/
- PlugSetPath(tempname, To_File, Tdbp->GetPath());
- strcat(PlugRemoveType(tempname, tempname), ".t");
-
- if (!(T_Stream = PlugOpenFile(g, tempname, "wb"))) {
- if (trace)
- htrc("%s\n", g->Message);
-
- rc = true;
- } else
- To_Fbt = PlgGetUser(g)->Openlist;
-
- return rc;
- } // end of OpenTempFile
-
-/***********************************************************************/
-/* Move intermediate deleted or updated lines. */
-/* This works only for file open in binary mode. */
-/***********************************************************************/
-bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
- {
- int n;
- size_t req, len;
-
- for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
- if (!UseTemp || !*b)
- if (fseek(Stream, Spos, SEEK_SET)) {
- sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- req = (size_t)min(n, Dbflen);
- len = fread(DelBuf, 1, req, Stream);
-
- if (trace)
- htrc("after read req=%d len=%d\n", req, len);
-
- if (len != req) {
- sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
- return true;
- } // endif len
-
- if (!UseTemp)
- if (fseek(T_Stream, Tpos, SEEK_SET)) {
- sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
- return true;
- } // endif
-
- if ((len = fwrite(DelBuf, 1, req, T_Stream)) != req) {
- sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
- return true;
- } // endif
-
- if (trace)
- htrc("after write pos=%d\n", ftell(Stream));
-
- Tpos += (int)req;
- Spos += (int)req;
-
- if (trace)
- htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
-
- *b = true;
- } // endfor n
-
- return false;
- } // end of MoveIntermediate Lines
-
-/***********************************************************************/
-/* Delete the old file and rename the new temp file. */
-/***********************************************************************/
-int DOSFAM::RenameTempFile(PGLOBAL g)
- {
- char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH];
- int rc;
-
- if (!To_Fbt)
- return RC_INFO; // Nothing to do ???
-
- // This loop is necessary because, in case of join,
- // To_File can have been open several times.
- for (PFBLOCK fb = PlgGetUser(g)->Openlist; fb; fb = fb->Next)
- rc = PlugCloseFile(g, fb);
-
- tempname = (char*)To_Fbt->Fname;
- PlugSetPath(filename, To_File, Tdbp->GetPath());
- strcat(PlugRemoveType(filetemp, filename), ".ttt");
- remove(filetemp); // May still be there from previous error
-
- if (rename(filename, filetemp)) { // Save file for security
- sprintf(g->Message, MSG(RENAME_ERROR),
- filename, filetemp, strerror(errno));
- rc = RC_FX;
- } else if (rename(tempname, filename)) {
- sprintf(g->Message, MSG(RENAME_ERROR),
- tempname, filename, strerror(errno));
- rc = rename(filetemp, filename); // Restore saved file
- rc = RC_FX;
- } else if (remove(filetemp)) {
- sprintf(g->Message, MSG(REMOVE_ERROR),
- filetemp, strerror(errno));
- rc = RC_INFO; // Acceptable
- } else
- rc = RC_OK;
-
- return rc;
- } // end of RenameTempFile
-
-/***********************************************************************/
-/* Table file close routine for DOS access method. */
-/***********************************************************************/
-void DOSFAM::CloseTableFile(PGLOBAL g)
- {
- int rc;
-
- if (UseTemp && T_Stream) {
- if (Tdbp->Mode == MODE_UPDATE) {
- // Copy eventually remaining lines
- bool b;
-
- fseek(Stream, 0, SEEK_END);
- Fpos = ftell(Stream);
- rc = MoveIntermediateLines(g, &b);
- } // endif Mode
-
- // Delete the old file and rename the new temp file.
- RenameTempFile(g); // Also close all files
- } else {
- rc = PlugCloseFile(g, To_Fb);
-
- if (trace)
- htrc("DOS Close: closing %s rc=%d\n", To_File, rc);
-
- } // endif UseTemp
-
- Stream = NULL; // So we can know whether table is open
- } // end of CloseTableFile
-
-/***********************************************************************/
-/* Rewind routine for DOS access method. */
-/***********************************************************************/
-void DOSFAM::Rewind(void)
- {
- rewind(Stream);
- Rows = 0;
- OldBlk = CurBlk = -1;
- } // end of Rewind
-
-/* --------------------------- Class BLKFAM -------------------------- */
-
-/***********************************************************************/
-/* Constructors. */
-/***********************************************************************/
-BLKFAM::BLKFAM(PDOSDEF tdp) : DOSFAM(tdp)
- {
- Blocked = true;
- Block = tdp->GetBlock();
- Last = tdp->GetLast();
- Nrec = tdp->GetElemt();
- Closing = false;
- BlkPos = tdp->GetTo_Pos();
- CurLine = NULL;
- NxtLine = NULL;
- OutBuf = NULL;
- } // end of BLKFAM standard constructor
-
-BLKFAM::BLKFAM(PBLKFAM txfp) : DOSFAM(txfp)
- {
- Closing = txfp->Closing;
- CurLine = txfp->CurLine;
- NxtLine = txfp->NxtLine;
- OutBuf = txfp->OutBuf;
- } // end of BLKFAM copy constructor
-
-/***********************************************************************/
-/* Reset: reset position values at the beginning of file. */
-/***********************************************************************/
-void BLKFAM::Reset(void)
- {
- DOSFAM::Reset();
- Closing = false;
- } // 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 BLKFAM::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
-
-/***********************************************************************/
-/* Use BlockTest to reduce the table estimated size. */
-/***********************************************************************/
-int BLKFAM::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
-
-/***********************************************************************/
-/* Allocate the line buffer. For mode Delete or when a temp file is */
-/* used another big buffer has to be allocated because is it used */
-/* to move or update the lines into the (temp) file. */
-/***********************************************************************/
-bool BLKFAM::AllocateBuffer(PGLOBAL g)
- {
- int len;
- MODE mode = Tdbp->GetMode();
-
- // For variable length files, Lrecl does not include CRLF
- len = Lrecl + ((Tdbp->GetFtype()) ? 0 : Ending);
- Buflen = len * Nrec;
- CurLine = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
-
- if (UseTemp || mode == MODE_DELETE) {
- if (mode == MODE_UPDATE)
- OutBuf = (char*)PlugSubAlloc(g, NULL, len + 1);
-
- Dbflen = Buflen;
- DelBuf = PlugSubAlloc(g, NULL, Dbflen);
- } else if (mode == MODE_INSERT)
- Rbuf = Nrec; // To be used by WriteDB
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* GetRowID: return the RowID of last read record. */
-/***********************************************************************/
-int BLKFAM::GetRowID(void)
- {
- return CurNum + Nrec * CurBlk + 1;
- } // end of GetRowID
-
-/***********************************************************************/
-/* GetPos: return the position of last read record. */
-/***********************************************************************/
-int BLKFAM::GetPos(void)
- {
- return (CurNum + Nrec * CurBlk); // Computed file index
- } // end of GetPos
-
-/***********************************************************************/
-/* GetNextPos: called by DeleteRecords. */
-/***********************************************************************/
-int BLKFAM::GetNextPos(void)
- {
- return Fpos + NxtLine - CurLine;
- } // end of GetNextPos
-
-/***********************************************************************/
-/* SetPos: Replace the table at the specified position. */
-/***********************************************************************/
-bool BLKFAM::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;
-#if defined(_DEBUG)
- num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
-#endif
-
- // Indicate the table position was externally set
- Placed = true;
- return false;
- } // end of SetPos
-
-/***********************************************************************/
-/* Record file position in case of UPDATE or DELETE. */
-/* Not used yet for blocked tables. */
-/***********************************************************************/
-bool BLKFAM::RecordPos(PGLOBAL g)
- {
- Fpos = (CurNum + Nrec * CurBlk); // Computed file index
- return false;
- } // end of RecordPos
-
-/***********************************************************************/
-/* Skip one record in file. */
-/***********************************************************************/
-int BLKFAM::SkipRecord(PGLOBAL g, bool header)
- {
- if (header) {
- // For Delete
- Fpos = BlkPos[0]; // First block starts after the header
-
- if (!UseTemp)
- Tpos = Spos = Fpos; // No need to move header
-
- } // endif header
-
- OldBlk = -2; // To force fseek on first block
- return RC_OK;
- } // end of SkipRecord
-
-/***********************************************************************/
-/* ReadBuffer: Read one line for a text file. */
-/***********************************************************************/
-int BLKFAM::ReadBuffer(PGLOBAL g)
- {
- int i, n, rc = RC_OK;
-
- /*********************************************************************/
- /* Sequential reading when Placed is not true. */
- /*********************************************************************/
- if (Placed) {
- Placed = false;
- } else 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';
- goto fin;
- } else if (Rbuf < Nrec && CurBlk != -1) {
- return RC_EF;
- } else {
- /*******************************************************************/
- /* New block. */
- /*******************************************************************/
- CurNum = 0;
-
- if (++CurBlk >= Block)
- return RC_EF;
-
- } // endif's
-
- if (OldBlk == CurBlk)
- goto ok; // Block is already there
-
- // fseek is required only in non sequential reading
- if (CurBlk != OldBlk + 1)
- if (fseek(Stream, BlkPos[CurBlk], SEEK_SET)) {
- sprintf(g->Message, MSG(FSETPOS_ERROR), BlkPos[CurBlk]);
- return RC_FX;
- } // endif fseek
-
- // Calculate the length of block to read
- BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk];
-
- if (trace)
- htrc("File position is now %d\n", ftell(Stream));
-
- // Read the entire next block
- n = fread(To_Buf, 1, (size_t)BlkLen, Stream);
-
- if (n == BlkLen) {
-// ReadBlks++;
- num_read++;
- Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
-
- ok:
- rc = RC_OK;
-
- // Get the position of the current line
- for (i = 0, CurLine = To_Buf; i < CurNum; i++)
- while (*CurLine++ != '\n') ; // What about Unix ???
-
- // 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';
- } else if (feof(Stream)) {
- rc = RC_EF;
- } else {
-#if defined(UNIX)
- sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
-#else
- sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
-#endif
-
- if (trace)
- htrc("%s\n", g->Message);
-
- return RC_FX;
- } // endelse
-
- OldBlk = CurBlk; // Last block actually read
- IsRead = true; // Is read indeed
-
- fin:
- // Store the current record file position for Delete and Update
- Fpos = BlkPos[CurBlk] + CurLine - To_Buf;
- return rc;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* WriteBuffer: File write routine for the blocked DOS access method. */
-/* Update is directly written back into the file, */
-/* with this (fast) method, record size cannot change. */
-/***********************************************************************/
-int BLKFAM::WriteBuffer(PGLOBAL g)
- {
- if (Tdbp->GetMode() == MODE_INSERT) {
- /*******************************************************************/
- /* In Insert mode, blocks are added sequentially to the file end. */
- /*******************************************************************/
- if (!Closing) { // Add line to the write buffer
- strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
-
- if (++CurNum != Rbuf) {
- CurLine += strlen(CurLine);
- return RC_OK; // We write only full blocks
- } // endif CurNum
-
- } // endif Closing
-
- // Now start the writing process.
- NxtLine = CurLine + strlen(CurLine);
- BlkLen = NxtLine - To_Buf;
-
- if (fwrite(To_Buf, 1, BlkLen, Stream) != (size_t)BlkLen) {
- sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
- Closing = true; // To tell CloseDB about a Write error
- return RC_FX;
- } // endif size
-
- CurBlk++;
- CurNum = 0;
- CurLine = To_Buf;
- } else {
- /*******************************************************************/
- /* Mode == MODE_UPDATE. */
- /*******************************************************************/
- char *crlf;
- size_t len;
- int curpos = ftell(Stream);
- bool moved = true;
-
- // T_Stream is the temporary stream or the table file stream itself
- if (!T_Stream)
- if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
- if (OpenTempFile(g))
- return RC_FX;
-
- } else
- T_Stream = Stream;
-
- if (UseTemp) {
- /*****************************************************************/
- /* We are using a temporary file. Before writing the updated */
- /* record, we must eventually copy all the intermediate records */
- /* that have not been updated. */
- /*****************************************************************/
- if (MoveIntermediateLines(g, &moved))
- return RC_FX;
-
- Spos = GetNextPos(); // New start position
-
- // Prepare the output buffer
-#if defined(WIN32)
- crlf = "\r\n";
-#else
- crlf = "\n";
-#endif // WIN32
- strcat(strcpy(OutBuf, Tdbp->GetLine()), crlf);
- len = strlen(OutBuf);
- } else {
- if (fseek(Stream, Fpos, SEEK_SET)) { // Fpos is last position
- sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
- return RC_FX;
- } // endif fseek
-
- // Replace the line inside read buffer (length has not changed)
- memcpy(CurLine, Tdbp->GetLine(), strlen(Tdbp->GetLine()));
- OutBuf = CurLine;
- len = (size_t)(NxtLine - CurLine);
- } // endif UseTemp
-
- if (fwrite(OutBuf, 1, len, T_Stream) != (size_t)len) {
- sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
- return RC_FX;
- } // endif fwrite
-
- if (moved)
- if (fseek(Stream, curpos, SEEK_SET)) {
- sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
- return RC_FX;
- } // endif
-
- } // endif Mode
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Table file close routine for DOS access method. */
-/***********************************************************************/
-void BLKFAM::CloseTableFile(PGLOBAL g)
- {
- int rc, wrc = RC_OK;
-
- if (UseTemp && T_Stream) {
- if (Tdbp->GetMode() == MODE_UPDATE) {
- // Copy eventually remaining lines
- bool b;
-
- fseek(Stream, 0, SEEK_END);
- Fpos = ftell(Stream);
- rc = MoveIntermediateLines(g, &b);
- } else
- rc = RC_OK;
-
- if (rc == RC_OK)
- // Delete the old file and rename the new temp file.
- rc = RenameTempFile(g); // Also close all files
- else
- rc = PlugCloseFile(g, To_Fb);
-
- } else {
- // Closing is True if last Write was in error
- if (Tdbp->GetMode() == MODE_INSERT && CurNum && !Closing) {
- // Some more inserted lines remain to be written
- Rbuf = CurNum--;
- Closing = true;
- wrc = WriteBuffer(g);
- } else if (Modif && !Closing) {
- // Last updated block remains to be written
- Closing = true;
- wrc = ReadBuffer(g);
- } // endif's
-
- rc = PlugCloseFile(g, To_Fb);
-
- if (trace)
- htrc("BLK CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
- To_File, Tdbp->GetMode(), wrc, rc);
-
- } // endif UseTemp
-
- Stream = NULL; // So we can know whether table is open
- } // end of CloseTableFile
-
-/***********************************************************************/
-/* Rewind routine for DOS access method. */
-/* Note: commenting out OldBlk = -1 has two advantages: */
-/* 1 - It forces fseek on first block, thus suppressing the need to */
-/* rewind the file, anyway unuseful when second pass if indexed. */
-/* 2 - It permit to avoid re-reading small tables having only 1 block.*/
-/***********************************************************************/
-void BLKFAM::Rewind(void)
- {
-//rewind(Stream); will be placed by fseek
- CurBlk = -1;
- CurNum = Rbuf;
-//OldBlk = -1; commented out in case we reuse last read block
-//Rbuf = 0; commented out in case we reuse last read block
- } // end of Rewind
-
+/*********** File AM Txt C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMTXT */
+/* ------------- */
+/* Version 1.4 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the Text file access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System 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) || defined(UNIV_LINUX)
+#include <errno.h>
+#include <unistd.h>
+//#if !defined(sun) // Sun has the ftruncate fnc.
+//#define USETEMP // Force copy mode for DELETE
+//#endif // !sun
+#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. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include "osutil.h"
+#define _fileno fileno
+#define _O_RDONLY O_RDONLY
+#endif
+
+extern int num_read, num_there, num_eq[2]; // Statistics
+extern "C" int trace;
+
+bool PushWarning(PGLOBAL g, PTDBASE tdbp);
+
+/* --------------------------- Class TXTFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+TXTFAM::TXTFAM(PDOSDEF tdp)
+ {
+ Tdbp = NULL;
+ To_Fb = NULL;
+ To_File = tdp->Fn;
+ Lrecl = tdp->Lrecl;
+ Placed = false;
+ IsRead = true;
+ Blocked = false;
+ To_Buf = NULL;
+ DelBuf = NULL;
+ BlkPos = NULL;
+ BlkLen = 0;
+ Buflen = 0;
+ Dbflen = 0;
+ Rows = 0;
+ DelRows = 0;
+ Headlen = 0;
+ Block = 0;
+ Last = 0;
+ Nrec = 1;
+ OldBlk = -1;
+ CurBlk = -1;
+ ReadBlks = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ Modif = 0;
+ Blksize = 0;
+ Padded = false;
+ Eof = tdp->Eof;
+ Ending = tdp->Ending;
+ CrLf = (char*)(Ending == 2 ? "\r\n" : "\n");
+ } // end of TXTFAM standard constructor
+
+TXTFAM::TXTFAM(PTXF txfp)
+ {
+ Tdbp = txfp->Tdbp;
+ To_Fb = txfp->To_Fb;
+ To_File = txfp->To_File;
+ Lrecl = txfp->Lrecl;
+ Placed = txfp->Placed;
+ IsRead = txfp->IsRead;
+ Blocked = txfp->Blocked;
+ To_Buf = txfp->To_Buf;
+ DelBuf = txfp->DelBuf;
+ BlkPos = txfp->BlkPos;
+ BlkLen = txfp->BlkLen;
+ Buflen = txfp->Buflen;
+ Dbflen = txfp->Dbflen;
+ Rows = txfp->Rows;
+ DelRows = txfp->DelRows;
+ Headlen = txfp->Headlen;
+ Block = txfp->Block;
+ Last = txfp->Last;
+ Nrec = txfp->Nrec;
+ OldBlk = txfp->OldBlk;
+ CurBlk = txfp->CurBlk;
+ ReadBlks = txfp->ReadBlks;
+ CurNum = txfp->CurNum;
+ Rbuf = txfp->Rbuf;
+ Modif = txfp->Modif;
+ Blksize = txfp->Blksize;
+ Padded = txfp->Padded;
+ Eof = txfp->Eof;
+ Ending = txfp->Ending;
+ } // end of TXTFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void TXTFAM::Reset(void)
+ {
+ Rows = 0;
+ DelRows = 0;
+ OldBlk = -1;
+ CurBlk = -1;
+ ReadBlks = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ Modif = 0;
+ Placed = false;
+ } // end of Reset
+
+/***********************************************************************/
+/* TXT GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int TXTFAM::GetFileLength(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int h;
+ int len;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ h= global_open(g, MSGID_OPEN_MODE_STRERROR, filename, _O_RDONLY);
+
+ if (trace)
+ htrc("GetFileLength: fn=%s h=%d\n", filename, h);
+
+ if (h == -1) {
+ if (errno != ENOENT) {
+ if (trace)
+ htrc("%s\n", g->Message);
+ len = -1;
+ }
+ else
+ {
+ len = 0; // File does not exist yet
+ g->Message[0]= '\0';
+ }
+ } else {
+ if ((len = _filelength(h)) < 0)
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", filename);
+
+ if (Eof && len)
+ len--; // Do not count the EOF character
+
+ close(h);
+ } // endif h
+
+ return len;
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* 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). */
+/* Note: This function is meant only for fixed length files but is */
+/* placed here to be available to FIXFAM and MPXFAM classes. */
+/***********************************************************************/
+int TXTFAM::Cardinality(PGLOBAL g)
+ {
+ if (g) {
+ int card = -1;
+ int len = GetFileLength(g);
+
+ if (len >= 0) {
+ if (Padded && Blksize) {
+ if (!(len % Blksize))
+ card = (len / Blksize) * Nrec;
+ else
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, Lrecl);
+
+ } else {
+ if (!(len % Lrecl))
+ card = len / (int)Lrecl; // Fixed length file
+ else
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, Lrecl);
+
+ } // endif Padded
+
+ if (trace)
+ htrc(" Computed max_K=%d Filen=%d lrecl=%d\n",
+ card, len, Lrecl);
+
+ } else
+ card = 0;
+
+ // Set number of blocks for later use
+ Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
+ return card;
+ } else
+ return 1;
+
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/* Note: This function is meant only for fixed length files but is */
+/* placed here to be available to FIXFAM and MPXFAM classes. */
+/***********************************************************************/
+int TXTFAM::MaxBlkSize(PGLOBAL g, int s)
+ {
+ int savcur = CurBlk, blm1 = Block - 1;
+ int size, last = s - blm1 * Nrec;
+
+ // 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 == blm1) ? last : Nrec;
+
+ CurBlk = savcur;
+ return size;
+ } // end of MaxBlkSize
+
+/* --------------------------- Class DOSFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+DOSFAM::DOSFAM(PDOSDEF tdp) : TXTFAM(tdp)
+ {
+ To_Fbt = NULL;
+ Stream = NULL;
+ T_Stream = NULL;
+ Fpos = Spos = Tpos = 0;
+ UseTemp = false;
+ Bin = false;
+ } // end of DOSFAM standard constructor
+
+DOSFAM::DOSFAM(PDOSFAM tdfp) : TXTFAM(tdfp)
+ {
+ To_Fbt = tdfp->To_Fbt;
+ Stream = tdfp->Stream;
+ T_Stream = tdfp->T_Stream;
+ Fpos = tdfp->Fpos;
+ Spos = tdfp->Spos;
+ Tpos = tdfp->Tpos;
+ UseTemp = tdfp->UseTemp;
+ Bin = tdfp->Bin;
+ } // end of DOSFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void DOSFAM::Reset(void)
+ {
+ TXTFAM::Reset();
+ Bin = false;
+ Fpos = Tpos = Spos = 0;
+ } // end of Reset
+
+/***********************************************************************/
+/* DOS GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int DOSFAM::GetFileLength(PGLOBAL g)
+ {
+ int len;
+
+ if (!Stream)
+ len = TXTFAM::GetFileLength(g);
+ else
+ if ((len = _filelength(_fileno(Stream))) < 0)
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", To_File);
+
+ if (trace)
+ htrc("File length=%d\n", len);
+
+ return len;
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* 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 DOSFAM::Cardinality(PGLOBAL g)
+ {
+ return (g) ? -1 : 0;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/* Note: This function is not really implemented yet. */
+/***********************************************************************/
+int DOSFAM::MaxBlkSize(PGLOBAL g, int s)
+ {
+ return s;
+ } // end of MaxBlkSize
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file using C standard I/Os. */
+/***********************************************************************/
+bool DOSFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4], filename[_MAX_PATH];
+//int ftype = Tdbp->GetFtype();
+ MODE mode = Tdbp->Mode;
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ // This is required when using Unix files under Windows
+ Bin = (Ending == 1);
+
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "r");
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->Next) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ if (Blocked) {
+ // Cardinality must return 0
+ Block = 0;
+ Last = Nrec;
+ } // endif blocked
+
+ // This will erase the entire file
+ strcpy(opmode, "w");
+ Tdbp->ResetSize();
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ Bin = true;
+ case MODE_UPDATE:
+ if ((UseTemp = Tdbp->IsUsingTemp(g))) {
+ strcpy(opmode, "r");
+ Bin = true;
+ } else
+ strcpy(opmode, "r+");
+
+ break;
+ case MODE_INSERT:
+ strcpy(opmode, "a+");
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ // For blocked I/O or for moving lines, open the table in binary
+ strcat(opmode, (Blocked || Bin) ? "b" : "t");
+
+ // Now open the file stream
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream = PlugOpenFile(g, filename, opmode))) {
+ if (trace)
+ htrc("%s\n", g->Message);
+
+ return (mode == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Stream
+
+ if (trace)
+ htrc("File %s open Stream=%p mode=%s\n", filename, Stream, opmode);
+
+ 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 line buffer. For mode Delete a bigger buffer has to */
+/* be allocated because is it also used to move lines into the file. */
+/***********************************************************************/
+bool DOSFAM::AllocateBuffer(PGLOBAL g)
+ {
+ MODE mode = Tdbp->Mode;
+
+ // Lrecl does not include line ending
+ Buflen = Lrecl + Ending + ((Bin) ? 1 : 0);
+
+ if (trace)
+ htrc("SubAllocating a buffer of %d bytes\n", Buflen);
+
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (UseTemp || mode == MODE_DELETE) {
+ // Have a big buffer to move lines
+ Dbflen = Buflen * DOS_BUFF_LEN;
+ DelBuf = PlugSubAlloc(g, NULL, Dbflen);
+ } else if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* Prepare the buffer so eventual gaps are filled with blanks. */
+ /*******************************************************************/
+ memset(To_Buf, ' ', Buflen);
+ To_Buf[Buflen - 2] = '\n';
+ To_Buf[Buflen - 1] = '\0';
+ } // endif's mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int DOSFAM::GetRowID(void)
+ {
+ return Rows;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int DOSFAM::GetPos(void)
+ {
+ return Fpos;
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int DOSFAM::GetNextPos(void)
+ {
+ return ftell(Stream);
+ } // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool DOSFAM::SetPos(PGLOBAL g, int pos)
+ {
+ Fpos = pos;
+
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return true;
+ } // endif
+
+ Placed = true;
+ return false;
+ } // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/***********************************************************************/
+bool DOSFAM::RecordPos(PGLOBAL g)
+ {
+ if ((Fpos = ftell(Stream)) < 0) {
+ sprintf(g->Message, MSG(FTELL_ERROR), 0, strerror(errno));
+ return true;
+ } // endif Fpos
+
+ return false;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int DOSFAM::SkipRecord(PGLOBAL g, bool header)
+ {
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ // Skip this record
+ if (!fgets(To_Buf, Buflen, Stream)) {
+ if (feof(Stream))
+ return RC_EF;
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#endif
+ return RC_FX;
+ } // endif fgets
+
+ // Update progress information
+ dup->ProgCur = GetPos();
+
+ if (header) {
+ // For Delete
+ Fpos = ftell(Stream);
+
+ if (!UseTemp)
+ Tpos = Spos = Fpos; // No need to move header
+
+ } // endif header
+
+#if defined(THREAD)
+ return RC_NF; // To have progress info
+#else
+ return RC_OK; // To loop locally
+#endif
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a text file. */
+/***********************************************************************/
+int DOSFAM::ReadBuffer(PGLOBAL g)
+ {
+ char *p;
+ int rc;
+
+ if (!Stream)
+ return RC_EF;
+
+ if (trace)
+ htrc("ReadBuffer: Tdbp=%p To_Line=%p Placed=%d\n",
+ Tdbp, Tdbp->To_Line, Placed);
+
+ if (!Placed) {
+ /*******************************************************************/
+ /* Record file position in case of UPDATE or DELETE. */
+ /*******************************************************************/
+ if (RecordPos(g))
+ return RC_FX;
+
+ CurBlk = (int)Rows++;
+
+ if (trace)
+ htrc("ReadBuffer: CurBlk=%d\n", CurBlk);
+
+ } else
+ Placed = false;
+
+ if (trace)
+ htrc(" About to read: stream=%p To_Buf=%p Buflen=%d\n",
+ Stream, To_Buf, Buflen);
+
+ if (fgets(To_Buf, Buflen, Stream)) {
+ p = To_Buf + strlen(To_Buf) - 1;
+
+ if (trace)
+ htrc(" Read: To_Buf=%p p=%c\n", To_Buf, To_Buf, p);
+
+#if defined(UNIX)
+ if (true) {
+ // Data files can be imported from Windows (having CRLF)
+#else
+ if (Bin) {
+ // Data file is read in binary so CRLF remains
+#endif
+ if (*p == '\n' || *p == '\r') {
+ // is this enough for Unix ???
+ *p = '\0'; // Eliminate ending CR or LF character
+
+ if (p > To_Buf) {
+ // is this enough for Unix ???
+ p--;
+
+ if (*p == '\n' || *p == '\r')
+ *p = '\0'; // Eliminate ending CR or LF character
+
+ } // endif To_Buf
+
+ } // endif p
+
+ } else if (*p == '\n')
+ *p = '\0'; // Eliminate ending new-line character
+
+ if (trace)
+ htrc(" To_Buf='%s'\n", To_Buf);
+
+ strcpy(Tdbp->To_Line, To_Buf);
+ num_read++;
+ rc = RC_OK;
+ } else if (feof(Stream)) {
+ rc = RC_EF;
+ } else {
+#if defined(UNIX)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#endif
+
+ if (trace)
+ htrc("%s\n", g->Message);
+
+ rc = RC_FX;
+ } // endif's fgets
+
+ if (trace)
+ htrc("ReadBuffer: rc=%d\n", rc);
+
+ IsRead = true;
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for DOS access method. */
+/***********************************************************************/
+int DOSFAM::WriteBuffer(PGLOBAL g)
+ {
+ char *crlf = "\n";
+ int curpos = 0;
+ bool moved = true;
+
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream)
+ if (UseTemp && Tdbp->Mode == MODE_UPDATE) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ if (Tdbp->Mode == MODE_UPDATE) {
+ /*******************************************************************/
+ /* Here we simply rewrite a record on itself. There are two cases */
+ /* were another method should be used, a/ when Update apply to */
+ /* the whole file, b/ when updating the last field of a variable */
+ /* length file. The method could be to rewrite a new file, then */
+ /* to erase the old one and rename the new updated file. */
+ /*******************************************************************/
+ curpos = ftell(Stream);
+
+ if (trace)
+ htrc("Last : %d cur: %d\n", Fpos, curpos);
+
+ if (UseTemp) {
+ /*****************************************************************/
+ /* We are using a temporary file. Before writing the updated */
+ /* record, we must eventually copy all the intermediate records */
+ /* that have not been updated. */
+ /*****************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ Spos = curpos; // New start position
+ } else
+ // Update is directly written back into the file,
+ // with this (fast) method, record size cannot change.
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif
+
+ } // endif mode
+
+ /*********************************************************************/
+ /* Prepare the write buffer. */
+ /*********************************************************************/
+#if defined(WIN32)
+ if (Bin)
+ crlf = "\r\n";
+#endif // WIN32
+ strcat(strcpy(To_Buf, Tdbp->To_Line), crlf);
+
+ /*********************************************************************/
+ /* Now start the writing process. */
+ /*********************************************************************/
+ if ((fputs(To_Buf, T_Stream)) == EOF) {
+ sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif EOF
+
+ if (Tdbp->Mode == MODE_UPDATE && moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+
+ if (trace)
+ htrc("write done\n");
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for DOS and BLK access methods. */
+/***********************************************************************/
+int DOSFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool moved;
+ int curpos = ftell(Stream);
+
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This will be experimented, but method 1 must be used for Unix as */
+ /* the function needed to erase trailing records is not available. */
+ /*********************************************************************/
+ if (trace)
+ htrc(
+ "DOS DeleteDB: rc=%d UseTemp=%d curpos=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, curpos, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ fseek(Stream, 0, SEEK_END);
+ Fpos = ftell(Stream);
+
+ if (trace)
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ } // endif irc
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete, Open temporary file. */
+ /*******************************************************************/
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceeding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ T_Stream = Stream;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ /*******************************************************************/
+ /* Reposition the file pointer and set Spos. */
+ /*******************************************************************/
+ if (!UseTemp || moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif
+
+ Spos = GetNextPos(); // New start position
+
+ if (trace)
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /* The UseTemp case is treated in CloseTableFile. */
+ /*******************************************************************/
+ if (!UseTemp) {
+ /*****************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS ??) this is still to be checked */
+ /* for compatibility with Text files and other OS's. */
+ /*****************************************************************/
+ char filename[_MAX_PATH];
+ int h, rc; // File handle, return code
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ rc = PlugCloseFile(g, To_Fb);
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+#if defined(UNIX)
+ if (ftruncate(h, (off_t)Tpos)) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (chsize(h, Tpos)) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+ if (trace)
+ htrc("done, h=%d irc=%d\n", h, irc);
+
+ } // endif !UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool DOSFAM::OpenTempFile(PGLOBAL g)
+ {
+ char tempname[_MAX_PATH];
+ bool rc = false;
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+
+ if (!(T_Stream = PlugOpenFile(g, tempname, "wb"))) {
+ if (trace)
+ htrc("%s\n", g->Message);
+
+ rc = true;
+ } else
+ To_Fbt = PlgGetUser(g)->Openlist;
+
+ return rc;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/* This works only for file open in binary mode. */
+/***********************************************************************/
+bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int n;
+ size_t req, len;
+
+ for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
+ if (!UseTemp || !*b)
+ if (fseek(Stream, Spos, SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ req = (size_t)min(n, Dbflen);
+ len = fread(DelBuf, 1, req, Stream);
+
+ if (trace)
+ htrc("after read req=%d len=%d\n", req, len);
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
+ return true;
+ } // endif len
+
+ if (!UseTemp)
+ if (fseek(T_Stream, Tpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(DelBuf, 1, req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ if (trace)
+ htrc("after write pos=%d\n", ftell(Stream));
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (trace)
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ *b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediate Lines
+
+/***********************************************************************/
+/* Delete the old file and rename the new temp file. */
+/***********************************************************************/
+int DOSFAM::RenameTempFile(PGLOBAL g)
+ {
+ char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH];
+ int rc;
+
+ if (!To_Fbt)
+ return RC_INFO; // Nothing to do ???
+
+ // This loop is necessary because, in case of join,
+ // To_File can have been open several times.
+ for (PFBLOCK fb = PlgGetUser(g)->Openlist; fb; fb = fb->Next)
+ rc = PlugCloseFile(g, fb);
+
+ tempname = (char*)To_Fbt->Fname;
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(filetemp, filename), ".ttt");
+ remove(filetemp); // May still be there from previous error
+
+ if (rename(filename, filetemp)) { // Save file for security
+ sprintf(g->Message, MSG(RENAME_ERROR),
+ filename, filetemp, strerror(errno));
+ rc = RC_FX;
+ } else if (rename(tempname, filename)) {
+ sprintf(g->Message, MSG(RENAME_ERROR),
+ tempname, filename, strerror(errno));
+ rc = rename(filetemp, filename); // Restore saved file
+ rc = RC_FX;
+ } else if (remove(filetemp)) {
+ sprintf(g->Message, MSG(REMOVE_ERROR),
+ filetemp, strerror(errno));
+ rc = RC_INFO; // Acceptable
+ } else
+ rc = RC_OK;
+
+ return rc;
+ } // end of RenameTempFile
+
+/***********************************************************************/
+/* Table file close routine for DOS access method. */
+/***********************************************************************/
+void DOSFAM::CloseTableFile(PGLOBAL g)
+ {
+ int rc;
+
+ if (UseTemp && T_Stream) {
+ if (Tdbp->Mode == MODE_UPDATE) {
+ // Copy eventually remaining lines
+ bool b;
+
+ fseek(Stream, 0, SEEK_END);
+ Fpos = ftell(Stream);
+ rc = MoveIntermediateLines(g, &b);
+ } // endif Mode
+
+ // Delete the old file and rename the new temp file.
+ RenameTempFile(g); // Also close all files
+ } else {
+ rc = PlugCloseFile(g, To_Fb);
+
+ if (trace)
+ htrc("DOS Close: closing %s rc=%d\n", To_File, rc);
+
+ } // endif UseTemp
+
+ Stream = NULL; // So we can know whether table is open
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for DOS access method. */
+/***********************************************************************/
+void DOSFAM::Rewind(void)
+ {
+ rewind(Stream);
+ Rows = 0;
+ OldBlk = CurBlk = -1;
+ } // end of Rewind
+
+/* --------------------------- Class BLKFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+BLKFAM::BLKFAM(PDOSDEF tdp) : DOSFAM(tdp)
+ {
+ Blocked = true;
+ Block = tdp->GetBlock();
+ Last = tdp->GetLast();
+ Nrec = tdp->GetElemt();
+ Closing = false;
+ BlkPos = tdp->GetTo_Pos();
+ CurLine = NULL;
+ NxtLine = NULL;
+ OutBuf = NULL;
+ } // end of BLKFAM standard constructor
+
+BLKFAM::BLKFAM(PBLKFAM txfp) : DOSFAM(txfp)
+ {
+ Closing = txfp->Closing;
+ CurLine = txfp->CurLine;
+ NxtLine = txfp->NxtLine;
+ OutBuf = txfp->OutBuf;
+ } // end of BLKFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void BLKFAM::Reset(void)
+ {
+ DOSFAM::Reset();
+ Closing = false;
+ } // 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 BLKFAM::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
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/***********************************************************************/
+int BLKFAM::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
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete or when a temp file is */
+/* used another big buffer has to be allocated because is it used */
+/* to move or update the lines into the (temp) file. */
+/***********************************************************************/
+bool BLKFAM::AllocateBuffer(PGLOBAL g)
+ {
+ int len;
+ MODE mode = Tdbp->GetMode();
+
+ // For variable length files, Lrecl does not include CRLF
+ len = Lrecl + ((Tdbp->GetFtype()) ? 0 : Ending);
+ Buflen = len * Nrec;
+ CurLine = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (UseTemp || mode == MODE_DELETE) {
+ if (mode == MODE_UPDATE)
+ OutBuf = (char*)PlugSubAlloc(g, NULL, len + 1);
+
+ Dbflen = Buflen;
+ DelBuf = PlugSubAlloc(g, NULL, Dbflen);
+ } else if (mode == MODE_INSERT)
+ Rbuf = Nrec; // To be used by WriteDB
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int BLKFAM::GetRowID(void)
+ {
+ return CurNum + Nrec * CurBlk + 1;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int BLKFAM::GetPos(void)
+ {
+ return (CurNum + Nrec * CurBlk); // Computed file index
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: called by DeleteRecords. */
+/***********************************************************************/
+int BLKFAM::GetNextPos(void)
+ {
+ return Fpos + NxtLine - CurLine;
+ } // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool BLKFAM::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;
+#if defined(_DEBUG)
+ num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
+#endif
+
+ // Indicate the table position was externally set
+ Placed = true;
+ return false;
+ } // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/* Not used yet for blocked tables. */
+/***********************************************************************/
+bool BLKFAM::RecordPos(PGLOBAL g)
+ {
+ Fpos = (CurNum + Nrec * CurBlk); // Computed file index
+ return false;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int BLKFAM::SkipRecord(PGLOBAL g, bool header)
+ {
+ if (header) {
+ // For Delete
+ Fpos = BlkPos[0]; // First block starts after the header
+
+ if (!UseTemp)
+ Tpos = Spos = Fpos; // No need to move header
+
+ } // endif header
+
+ OldBlk = -2; // To force fseek on first block
+ return RC_OK;
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a text file. */
+/***********************************************************************/
+int BLKFAM::ReadBuffer(PGLOBAL g)
+ {
+ int i, n, rc = RC_OK;
+
+ /*********************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Placed = false;
+ } else 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';
+ goto fin;
+ } else if (Rbuf < Nrec && CurBlk != -1) {
+ return RC_EF;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ } // endif's
+
+ if (OldBlk == CurBlk)
+ goto ok; // Block is already there
+
+ // fseek is required only in non sequential reading
+ if (CurBlk != OldBlk + 1)
+ if (fseek(Stream, BlkPos[CurBlk], SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), BlkPos[CurBlk]);
+ return RC_FX;
+ } // endif fseek
+
+ // Calculate the length of block to read
+ BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk];
+
+ if (trace)
+ htrc("File position is now %d\n", ftell(Stream));
+
+ // Read the entire next block
+ n = fread(To_Buf, 1, (size_t)BlkLen, Stream);
+
+ if (n == BlkLen) {
+// ReadBlks++;
+ num_read++;
+ Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
+
+ ok:
+ rc = RC_OK;
+
+ // Get the position of the current line
+ for (i = 0, CurLine = To_Buf; i < CurNum; i++)
+ while (*CurLine++ != '\n') ; // What about Unix ???
+
+ // 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';
+ } else if (feof(Stream)) {
+ rc = RC_EF;
+ } else {
+#if defined(UNIX)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#endif
+
+ if (trace)
+ htrc("%s\n", g->Message);
+
+ return RC_FX;
+ } // endelse
+
+ OldBlk = CurBlk; // Last block actually read
+ IsRead = true; // Is read indeed
+
+ fin:
+ // Store the current record file position for Delete and Update
+ Fpos = BlkPos[CurBlk] + CurLine - To_Buf;
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for the blocked DOS access method. */
+/* Update is directly written back into the file, */
+/* with this (fast) method, record size cannot change. */
+/***********************************************************************/
+int BLKFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode, blocks are added sequentially to the file end. */
+ /*******************************************************************/
+ if (!Closing) { // Add line to the write buffer
+ strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
+
+ if (++CurNum != Rbuf) {
+ CurLine += strlen(CurLine);
+ return RC_OK; // We write only full blocks
+ } // endif CurNum
+
+ } // endif Closing
+
+ // Now start the writing process.
+ NxtLine = CurLine + strlen(CurLine);
+ BlkLen = NxtLine - To_Buf;
+
+ if (fwrite(To_Buf, 1, BlkLen, Stream) != (size_t)BlkLen) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ Closing = true; // To tell CloseDB about a Write error
+ return RC_FX;
+ } // endif size
+
+ CurBlk++;
+ CurNum = 0;
+ CurLine = To_Buf;
+ } else {
+ /*******************************************************************/
+ /* Mode == MODE_UPDATE. */
+ /*******************************************************************/
+ char *crlf;
+ size_t len;
+ int curpos = ftell(Stream);
+ bool moved = true;
+
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream)
+ if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ if (UseTemp) {
+ /*****************************************************************/
+ /* We are using a temporary file. Before writing the updated */
+ /* record, we must eventually copy all the intermediate records */
+ /* that have not been updated. */
+ /*****************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ Spos = GetNextPos(); // New start position
+
+ // Prepare the output buffer
+#if defined(WIN32)
+ crlf = "\r\n";
+#else
+ crlf = "\n";
+#endif // WIN32
+ strcat(strcpy(OutBuf, Tdbp->GetLine()), crlf);
+ len = strlen(OutBuf);
+ } else {
+ if (fseek(Stream, Fpos, SEEK_SET)) { // Fpos is last position
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif fseek
+
+ // Replace the line inside read buffer (length has not changed)
+ memcpy(CurLine, Tdbp->GetLine(), strlen(Tdbp->GetLine()));
+ OutBuf = CurLine;
+ len = (size_t)(NxtLine - CurLine);
+ } // endif UseTemp
+
+ if (fwrite(OutBuf, 1, len, T_Stream) != (size_t)len) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif fwrite
+
+ if (moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Table file close routine for DOS access method. */
+/***********************************************************************/
+void BLKFAM::CloseTableFile(PGLOBAL g)
+ {
+ int rc, wrc = RC_OK;
+
+ if (UseTemp && T_Stream) {
+ if (Tdbp->GetMode() == MODE_UPDATE) {
+ // Copy eventually remaining lines
+ bool b;
+
+ fseek(Stream, 0, SEEK_END);
+ Fpos = ftell(Stream);
+ rc = MoveIntermediateLines(g, &b);
+ } else
+ rc = RC_OK;
+
+ if (rc == RC_OK)
+ // Delete the old file and rename the new temp file.
+ rc = RenameTempFile(g); // Also close all files
+ else
+ rc = PlugCloseFile(g, To_Fb);
+
+ } else {
+ // Closing is True if last Write was in error
+ if (Tdbp->GetMode() == MODE_INSERT && CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Rbuf = CurNum--;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else if (Modif && !Closing) {
+ // Last updated block remains to be written
+ Closing = true;
+ wrc = ReadBuffer(g);
+ } // endif's
+
+ rc = PlugCloseFile(g, To_Fb);
+
+ if (trace)
+ htrc("BLK CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
+ To_File, Tdbp->GetMode(), wrc, rc);
+
+ } // endif UseTemp
+
+ Stream = NULL; // So we can know whether table is open
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for DOS access method. */
+/* Note: commenting out OldBlk = -1 has two advantages: */
+/* 1 - It forces fseek on first block, thus suppressing the need to */
+/* rewind the file, anyway unuseful when second pass if indexed. */
+/* 2 - It permit to avoid re-reading small tables having only 1 block.*/
+/***********************************************************************/
+void BLKFAM::Rewind(void)
+ {
+//rewind(Stream); will be placed by fseek
+ CurBlk = -1;
+ CurNum = Rbuf;
+//OldBlk = -1; commented out in case we reuse last read block
+//Rbuf = 0; commented out in case we reuse last read block
+ } // end of Rewind
+
diff --git a/storage/connect/filamtxt.h b/storage/connect/filamtxt.h
index 7caf481c93c..6a1093eaa06 100644
--- a/storage/connect/filamtxt.h
+++ b/storage/connect/filamtxt.h
@@ -1,198 +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
+/************** 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
diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp
index 7342ef45a2f..31f2496b390 100644
--- a/storage/connect/filamvct.cpp
+++ b/storage/connect/filamvct.cpp
@@ -1,4200 +1,4200 @@
-/*********** File AM Vct C++ Program Source Code File (.CPP) ***********/
-/* PROGRAM NAME: FILAMVCT */
-/* ------------- */
-/* Version 2.4 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the VCT file access method classes. */
-/* Added in version 2: */
-/* - Split Vec format. */
-/* - Partial delete. */
-/* - Use of tempfile for update. */
-/* */
-/***********************************************************************/
-
-/***********************************************************************/
-/* 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 // __BORLAND__
-//#include <windows.h>
-#include <sys/stat.h>
-#else // !WIN32
-#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 // !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 "osutil.h" // Unuseful for WIN32
-#include "plgdbsem.h"
-#include "valblk.h"
-#include "filamfix.h"
-#include "tabdos.h"
-#include "tabvct.h"
-#include "maputil.h"
-#include "filamvct.h"
-
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
-
-extern int num_read, num_there; // Statistics
-static int num_write;
-
-#if defined(UNIX)
-// Add dummy strerror (NGC)
-char *strerror(int num);
-#endif // UNIX
-
-/***********************************************************************/
-/* Header containing block info for not split VEC tables. */
-/* Block and last values can be calculated from NumRec and Nrec. */
-/* This is better than directly storing Block and Last because it */
-/* make possible to use the same file with tables having a different */
-/* block size value (Element -> Nrec) */
-/* Note: can be in a separate file if header=1 or a true header (2) */
-/***********************************************************************/
-typedef struct _vecheader {
-//int Block; /* The number of used blocks */
-//int Last; /* The number of used records in last block */
- int MaxRec; /* Max number of records (True vector format)*/
- int NumRec; /* Number of valid records in the table */
- } VECHEADER;
-
-/***********************************************************************/
-/* 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);
-bool PushWarning(PGLOBAL, PTDBASE);
-
-/* -------------------------- Class VCTFAM --------------------------- */
-
-/***********************************************************************/
-/* Implementation of the VCTFAM class. */
-/***********************************************************************/
-VCTFAM::VCTFAM(PVCTDEF tdp) : FIXFAM((PDOSDEF)tdp)
- {
- Last = tdp->GetLast();
- MaxBlk = (tdp->GetEstimate() > 0) ?
- ((tdp->GetEstimate() - 1) / Nrec + 1) : 0;
- NewBlock = NULL;
- AddBlock = false;
- Split = false;
-
- if ((Header = (MaxBlk) ? tdp->Header : 0))
- Block = Last = -1;
-
- Bsize = Nrec;
- CurNum = Nrec - 1;
- Colfn = NULL;
- Tempat = NULL;
- Clens = NULL;
- Deplac = NULL;
- Isnum = NULL;
- Ncol = 0;
- } // end of VCTFAM standard constructor
-
-VCTFAM::VCTFAM(PVCTFAM txfp) : FIXFAM(txfp)
- {
- MaxBlk = txfp->MaxBlk;
- NewBlock = NULL;
- AddBlock = false;
- Split = txfp->Split;
- Header = txfp->Header;
- Bsize = txfp->Bsize;
- Colfn = txfp->Colfn;
- Tempat = txfp->Tempat;
- Clens = txfp->Clens;
- Deplac = txfp->Deplac;
- Isnum = txfp->Isnum;
- Ncol = txfp->Ncol;
- } // end of VCTFAM copy constructor
-
-/***********************************************************************/
-/* Reset read/write position values. */
-/***********************************************************************/
-void VCTFAM::Reset(void)
- {
- FIXFAM::Reset();
- NewBlock = NULL;
- AddBlock = false;
- CurNum = Nrec - 1;
- } // end of Reset
-
-/***********************************************************************/
-/* Get the Headlen, Block and Last info from the file header. */
-/***********************************************************************/
-int VCTFAM::GetBlockInfo(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- int k, n;
- VECHEADER vh;
- FILE *s;
-
- if (Header < 1 || Header > 3 || !MaxBlk) {
- sprintf(g->Message, "Invalid header value %d", Header);
- return -1;
- } else
- n = (Header == 1) ? (int)sizeof(VECHEADER) : 0;
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (Header == 2)
- strcat(PlugRemoveType(filename, filename), ".blk");
-
- if (!(s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb"))) {
- // Consider this is a void table
- Last = Nrec;
- Block = 0;
- return n;
- } else if (Header == 3)
- k = fseek(s, -(int)sizeof(VECHEADER), SEEK_END);
-
- if (fread(&vh, sizeof(vh), 1, s) != 1) {
- sprintf(g->Message, "Error reading header file %s", filename);
- n = -1;
- } else if (MaxBlk * Nrec != vh.MaxRec) {
- sprintf(g->Message, "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d",
- vh.MaxRec, MaxBlk, Nrec);
- n = -1;
- } else {
- Block = (vh.NumRec > 0) ? (vh.NumRec + Nrec - 1) / Nrec : 0;
- Last = (vh.NumRec + Nrec - 1) % Nrec + 1;
- } // endif s
-
- fclose(s);
- return n;
- } // end of GetBlockInfo
-
-/***********************************************************************/
-/* Get the Headlen, Block and Last info from the file header. */
-/***********************************************************************/
-bool VCTFAM::SetBlockInfo(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- bool rc = false;
- int k;
- size_t n;
- VECHEADER vh;
- FILE *s;
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (Header != 2) {
- if (Stream) {
- s = Stream;
-
- if (Header == 1)
- k = fseek(s, 0, SEEK_SET);
-
- } else
- s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r+b");
-
- } else { // Header == 2
- strcat(PlugRemoveType(filename, filename), ".blk");
- s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "wb");
- } // endif Header
-
- if (!s) {
- sprintf(g->Message, "Error opening header file %s", filename);
- return true;
- } else if (Header == 3)
- k = fseek(s, -(int)sizeof(VECHEADER), SEEK_END);
-
- vh.MaxRec = MaxBlk * Bsize;
- vh.NumRec = (Block - 1) * Nrec + Last;
-
- if ((n = fwrite(&vh, sizeof(vh), 1, s)) != 1) {
- sprintf(g->Message, "Error writing header file %s", filename);
- rc = true;
- } // endif fread
-
- if (Header == 2 || !Stream)
- fclose(s);
-
- return rc;
- } // end of SetBlockInfo
-
-/***********************************************************************/
-/* Use BlockTest to reduce the table estimated size. */
-/***********************************************************************/
-int VCTFAM::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
-
-/***********************************************************************/
-/* VCT 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 VCTFAM::Cardinality(PGLOBAL g)
- {
- if (!g)
- return 1;
-
- if (Block < 0)
- if (Split) {
- // Separate column files and no pre setting of Block and Last
- // This allows to see a table modified externally, but Block
- // and Last must be set from the file cardinality.
- // Only happens when called by sub classes.
- char filename[_MAX_PATH];
- PSZ savfn = To_File;
- int len, clen, card = -1;
- PCOLDEF cdp = Tdbp->GetDef()->GetCols();
-
- if (!Colfn) {
- // Prepare the column file name pattern
- Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
- Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
- } // endif Colfn
-
- // Use the first column file to calculate the cardinality
- clen = cdp->GetClen();
- sprintf(filename, Colfn, 1);
- To_File = filename;
- len = GetFileLength(g);
- To_File = savfn;
-
- if (len >= 0) {
- if (!(len % clen))
- card = len / clen; // Fixed length file
- else
- sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, clen);
-
-#ifdef DEBTRACE
- htrc(" Computed max_K=%d Filen=%d Clen=%d\n",
- card, len, clen);
-#endif
- } else
- card = 0;
-
- // Set number of blocks for later use
- Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
- Last = (card + Nrec - 1) % Nrec + 1;
- return card;
- } else {
- // Vector table having Block and Last info in a Header (file)
- if ((Headlen = GetBlockInfo(g)) < 0)
- return -1; // Error
-
- } // endif split
-
- return (int)((Block - 1) * Nrec + Last);
- } // end of Cardinality
-
-/***********************************************************************/
-/* GetRowID: return the RowID of last read record. */
-/***********************************************************************/
-int VCTFAM::GetRowID(void)
- {
- return 1 + ((CurBlk < Block) ? CurNum + Nrec * CurBlk
- : (Block - 1) * Nrec + Last);
- } // end of GetRowID
-
-/***********************************************************************/
-/* VCT Create an empty file for Vector formatted tables. */
-/***********************************************************************/
-bool VCTFAM::MakeEmptyFile(PGLOBAL g, char *fn)
- {
- // Vector formatted file: this will create an empty file of the
- // required length if it does not exists yet.
- char filename[_MAX_PATH], c = 0;
- int h, n;
-
- PlugSetPath(filename, fn, Tdbp->GetPath());
-#if defined(WIN32)
- h= global_open(g, MSGID_OPEN_EMPTY_FILE, filename, _O_CREAT | _O_WRONLY, S_IREAD | S_IWRITE);
-#else // !WIN32
- h= global_open(g, MSGID_OPEN_EMPTY_FILE, filename, O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
-#endif // !WIN32
-
- if (h == -1)
- return true;
-
- n = (Header == 1 || Header == 3) ? sizeof(VECHEADER) : 0;
-
- if (lseek(h, n + MaxBlk * Nrec * Lrecl - 1, SEEK_SET) == -1) {
- sprintf(g->Message, MSG(MAKE_EMPTY_FILE), To_File, strerror(errno));
- close(h);
- return true;
- } // endif h
-
- write(h, &c, 1); // This actually fills the empty file
- close(h);
- return false;
- } // end of MakeEmptyFile
-
-/***********************************************************************/
-/* 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 VCTFAM::OpenTableFile(PGLOBAL g)
- {
- char opmode[4], filename[_MAX_PATH];
- MODE mode = Tdbp->GetMode();
- PDBUSER dbuserp = PlgGetUser(g);
-
- /*********************************************************************/
- /* Update block info if necessary. */
- /*********************************************************************/
- if (Block < 0)
- if ((Headlen = GetBlockInfo(g)) < 0)
- return true;
-
- /*********************************************************************/
- /* Open according to input/output mode required. */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- strcpy(opmode, "rb");
- break;
- case MODE_DELETE:
- if (!Tdbp->GetNext()) {
- // Store the number of deleted lines
- DelRows = Cardinality(g);
-
- // This will delete the whole file
- strcpy(opmode, "wb");
- break;
- } // endif
-
- // Selective delete, pass thru
- case MODE_UPDATE:
- UseTemp = Tdbp->IsUsingTemp(g);
- strcpy(opmode, (UseTemp) ? "rb" : "r+b");
- break;
- case MODE_INSERT:
- if (MaxBlk) {
- if (!Block)
- if (MakeEmptyFile(g, To_File))
- return true;
-
- strcpy(opmode, "r+b"); // Required to update empty blocks
- } else if (Last == Nrec)
- strcpy(opmode, "ab");
- else
- strcpy(opmode, "r+b"); // Required to update the last block
-
- break;
- default:
- sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
- return true;
- } // endswitch Mode
-
- /*********************************************************************/
- /* Use conventionnal input/output functions. */
- /*********************************************************************/
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (!(Stream = PlugOpenFile(g, filename, opmode))) {
-#ifdef DEBTRACE
- htrc("%s\n", g->Message);
-#endif
- return (mode == MODE_READ && 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
-
- if (!strcmp(opmode, "wb"))
- // This will stop the process by
- // causing GetProgMax to return 0.
- return ResetTableSize(g, 0, Nrec);
-
- num_read = num_there = num_write = 0;
-
- // Allocate the table and column block buffer
- return AllocateBuffer(g);
- } // end of OpenTableFile
-
-/***********************************************************************/
-/* Allocate the block buffers for columns used in the query. */
-/***********************************************************************/
-bool VCTFAM::AllocateBuffer(PGLOBAL g)
- {
- MODE mode = Tdbp->GetMode();
- PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
- PCOLDEF cdp;
- PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
-
- if (mode == MODE_INSERT) {
- bool chk = PlgGetUser(g)->Check & CHK_TYPE;
-
- NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
-
- for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
- memset(NewBlock + Nrec * cdp->GetPoff(),
- (IsTypeNum(cdp->GetType()) ? 0 : ' '),
- Nrec * cdp->GetClen());
-
- for (; cp; cp = (PVCTCOL)cp->Next)
- cp->Blk = AllocValBlock(g, NewBlock + Nrec * cp->Deplac,
- cp->Buf_Type, Nrec, cp->Format.Length,
- cp->Format.Prec, chk);
-
- return InitInsert(g); // Initialize inserting
- } else {
- if (UseTemp || mode == MODE_DELETE) {
- // Allocate all that is needed to move lines
- int i = 0, n = (MaxBlk) ? MaxBlk : 1;
-
- if (!Ncol)
- for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
- Ncol++;
-
- Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
- Deplac = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
- Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
-
- for (cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext()) {
- Clens[i] = cdp->GetClen();
- Deplac[i] = Headlen + cdp->GetPoff() * n * Nrec;
- Isnum[i] = IsTypeNum(cdp->GetType());
- Buflen = max(Buflen, cdp->GetClen());
- } // endfor cdp
-
- if (!UseTemp || MaxBlk) {
- Buflen *= Nrec;
- To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
- } else
- NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
-
- } // endif mode
-
- for (; cp; cp = (PVCTCOL)cp->Next)
- if (!cp->IsSpecial()) // Not a pseudo column
- cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
- cp->Format.Length, cp->Format.Prec);
-
- } //endif mode
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* Do initial action when inserting. */
-/***********************************************************************/
-bool VCTFAM::InitInsert(PGLOBAL g)
- {
- // We come here in MODE_INSERT only
- if (Last == Nrec) {
- CurBlk = Block;
- CurNum = 0;
- AddBlock = !MaxBlk;
- } else {
- int rc;
- PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
-
- // The starting point must be at the end of file as for append.
- CurBlk = Block - 1;
- CurNum = Last;
-
- // Prepare error return
- if (g->jump_level == MAX_JUMP) {
- strcpy(g->Message, MSG(TOO_MANY_JUMPS));
- return true;
- } // endif
-
- if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) {
- g->jump_level--;
- return true;
- } // endif
-
- // Last block must be updated by new values
- for (; cp; cp = (PVCTCOL)cp->Next)
- cp->ReadBlock(g);
-
- g->jump_level--;
- } // endif Last
-
- // We are not currently using a temporary file for Insert
- T_Stream = Stream;
- return false;
- } // end of InitInsert
-
-/***********************************************************************/
-/* ReadBuffer: Read one line for a VCT file. */
-/***********************************************************************/
-int VCTFAM::ReadBuffer(PGLOBAL g)
- {
- int rc = RC_OK;
- MODE mode = Tdbp->GetMode();
-
- if (Placed)
- Placed = false;
- else if ((++CurNum) >= ((CurBlk < Block - 1) ? Nrec : Last)) {
- /*******************************************************************/
- /* New block. */
- /*******************************************************************/
- CurNum = 0;
-
- if (++CurBlk == Block)
- return RC_EF; // End of file
-
- num_there++;
- } // endif CurNum
-
- if (OldBlk != CurBlk) {
- if (mode == MODE_UPDATE) {
- /*****************************************************************/
- /* Flush the eventually modified column buffers in old blocks */
- /* and read the blocks to modify attached to Set columns. */
- /*****************************************************************/
- if (MoveLines(g)) // For VECFAM
- return RC_FX;
-
- for (PVCTCOL colp = (PVCTCOL)Tdbp->GetSetCols();
- colp; colp = (PVCTCOL)colp->Next) {
- colp->WriteBlock(g);
- colp->ReadBlock(g);
- } // endfor colp
-
- } // endif mode
-
- OldBlk = CurBlk; // Last block actually read
- } // endif oldblk
-
-#ifdef DEBTRACE
- htrc(" Read: CurNum=%d CurBlk=%d rc=%d\n",
- CurNum, CurBlk, RC_OK);
-#endif
- return rc;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* Data Base write routine for VCT access method. */
-/***********************************************************************/
-int VCTFAM::WriteBuffer(PGLOBAL g)
- {
-#ifdef DEBTRACE
- htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
- Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
-#endif
-
- if (Tdbp->GetMode() == MODE_UPDATE) {
- // Mode Update is done in ReadDB, we just initialize it here
- if (!T_Stream) {
- if (UseTemp) {
- if (OpenTempFile(g))
- return RC_FX;
-
- // Most of the time, not all table columns are updated.
- // This why we must completely pre-fill the temporary file.
- Fpos = (MaxBlk) ? (Block - 1) * Nrec + Last
- : Block * Nrec; // To write last lock
-
- if (MoveIntermediateLines(g))
- return RC_FX;
-
- } else
- T_Stream = Stream;
-
- } // endif T_Stream
-
- } else {
- // Mode Insert
- if (MaxBlk && CurBlk == MaxBlk) {
- strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
- return RC_EF; // Too many lines for vector formatted table
- } // endif MaxBlk
-
- if (Closing || ++CurNum == Nrec) {
- PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
-
- if (!AddBlock) {
- // Write back the updated last block values
- for (; cp; cp = (PVCTCOL)cp->Next)
- cp->WriteBlock(g);
-
- if (!Closing && !MaxBlk) {
- // For VCT tables, future blocks must be added
- char filename[_MAX_PATH];
-
- // Close the file and reopen it in mode Insert
- fclose(Stream);
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (!(Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "ab"))) {
- Closing = true; // Tell CloseDB of error
- return RC_FX;
- } // endif Stream
-
- AddBlock = true;
- } // endif Closing
-
- } else {
- // Here we must add a new block to the file
- if (Closing)
- // Reset the overwritten columns for last block extra records
- for (; cp; cp = (PVCTCOL)cp->Next)
- memset(NewBlock + Nrec * cp->Deplac + Last * cp->Clen,
- (cp->Buf_Type == TYPE_STRING) ? ' ' : '\0',
- (Nrec - Last) * cp->Clen);
-
- if ((size_t)Nrec !=
- fwrite(NewBlock, (size_t)Lrecl, (size_t)Nrec, Stream)) {
- sprintf(g->Message, MSG(WRITE_STRERROR), To_File, strerror(errno));
- return RC_FX;
- } // endif
-
- } // endif AddBlock
-
- if (!Closing) {
- CurBlk++;
- CurNum = 0;
- } // endif Closing
-
- } // endif Closing || CurNum
-
- } // endif Mode
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for VCT access method. */
-/* Note: lines are moved directly in the files (ooops...) */
-/* Using temp file depends on the Check setting, false by default. */
-/***********************************************************************/
-int VCTFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- bool eof = false;
-#ifdef DEBTRACE
- fprintf(debug,
- "VCT DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
- irc, UseTemp, Fpos, Tpos, Spos);
-#endif
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the end-of-file position. */
- /*******************************************************************/
- Fpos = (Block - 1) * Nrec + Last;
-#ifdef DEBTRACE
- htrc("Fpos placed at file end=%d\n", Fpos);
-#endif
- eof = UseTemp && !MaxBlk;
- } else // Fpos is the Deleted line position
- Fpos = CurBlk * Nrec + CurNum;
-
- if (Tpos == Spos) {
- if (UseTemp) {
- /*****************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*****************************************************************/
- if (OpenTempFile(g))
- return RC_FX;
-
- } else {
- /*****************************************************************/
- /* First line to delete. Move of eventual preceeding lines is */
- /* not required here, just the setting of future Spos and Tpos. */
- /*****************************************************************/
- T_Stream = Stream;
- Spos = Tpos = Fpos;
- } // endif UseTemp
-
- } // endif Tpos == Spos
-
- /*********************************************************************/
- /* Move any intermediate lines. */
- /*********************************************************************/
- if (MoveIntermediateLines(g, &eof))
- return RC_FX;
-
- if (irc == RC_OK) {
- /*******************************************************************/
- /* Reposition the file pointer and set Spos. */
- /*******************************************************************/
-#ifdef DEBTRACE
- assert(Spos == Fpos);
-#endif
- Spos++; // New start position is on next line
-
-#ifdef DEBTRACE
- htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- } else {
- /*******************************************************************/
- /* Last call after EOF has been reached. */
- /* Update the Block and Last values. */
- /*******************************************************************/
- Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
- Last = (Tpos + Nrec - 1) % Nrec + 1;
-
- if (!UseTemp) { // The UseTemp case is treated in CloseTableFile
- if (!MaxBlk) {
- /***************************************************************/
- /* Because the chsize functionality is only accessible with a */
- /* system call we must close the file and reopen it with the */
- /* open function (_fopen for MS ??) this is still to be */
- /* checked for compatibility with Text files and other OS's. */
- /***************************************************************/
- char filename[_MAX_PATH];
- int rc, h;
-
- rc = CleanUnusedSpace(g); // Clean last block
- rc = PlugCloseFile(g, To_Fb);
- Stream = NULL; // For SetBlockInfo
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
- return RC_FX;
-
- /***************************************************************/
- /* Remove extra blocks. */
- /***************************************************************/
-#if defined(UNIX)
- if (ftruncate(h, (off_t)(Headlen + Block * Blksize))) {
- sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#else
- if (chsize(h, Headlen + Block * Blksize)) {
- sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#endif
-
- close(h);
-
-#ifdef DEBTRACE
- htrc("done, h=%d irc=%d\n", h, irc);
-#endif
- } else
- // Clean the unused space in the file, this is required when
- // inserting again with a partial column list.
- if (CleanUnusedSpace(g))
- return RC_FX;
-
- if (ResetTableSize(g, Block, Last))
- return RC_FX;
-
- } // endif UseTemp
-
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Open a temporary file used while updating or deleting. */
-/***********************************************************************/
-bool VCTFAM::OpenTempFile(PGLOBAL g)
- {
- char *opmode, tempname[_MAX_PATH];
- bool rc = false;
-
- /*********************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*********************************************************************/
- PlugSetPath(tempname, To_File, Tdbp->GetPath());
- strcat(PlugRemoveType(tempname, tempname), ".t");
-
- if (MaxBlk) {
- if (MakeEmptyFile(g, tempname))
- return true;
-
- opmode = "r+b";
- } else
- opmode = "wb";
-
- if (!(T_Stream = PlugOpenFile(g, tempname, opmode))) {
-#ifdef DEBTRACE
- htrc("%s\n", g->Message);
-#endif
- rc = true;
- } else
- To_Fbt = PlgGetUser(g)->Openlist;
-
- return rc;
- } // end of OpenTempFile
-
-/***********************************************************************/
-/* Move intermediate deleted or updated lines. */
-/***********************************************************************/
-bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
- {
- int i, dep, off;
- int n;
- bool eof = (b) ? *b : false;
- size_t req, len;
-
- for (n = Fpos - Spos; n > 0 || eof; n -= req) {
- /*******************************************************************/
- /* Non consecutive line to delete. Move intermediate lines. */
- /*******************************************************************/
- if (!MaxBlk)
- req = (size_t)min(n, Nrec - max(Spos % Nrec, Tpos % Nrec));
- else
- req = (size_t)min(n, Nrec);
-
- if (req) for (i = 0; i < Ncol; i++) {
- if (MaxBlk) {
- dep = Deplac[i];
- off = Spos * Clens[i];
- } else {
- if (UseTemp)
- To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
-
- dep = Deplac[i] + (Spos / Nrec) * Blksize;
- off = (Spos % Nrec) * Clens[i];
- } // endif MaxBlk
-
- if (fseek(Stream, dep + off, SEEK_SET)) {
- sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- len = fread(To_Buf, Clens[i], req, Stream);
-
-#ifdef DEBTRACE
- htrc("after read req=%d len=%d\n", req, len);
-#endif
-
- if (len != req) {
- sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
- return true;
- } // endif len
-
- if (!UseTemp || MaxBlk) {
- if (MaxBlk) {
- dep = Deplac[i];
- off = Tpos * Clens[i];
- } else {
- dep = Deplac[i] + (Tpos / Nrec) * Blksize;
- off = (Tpos % Nrec) * Clens[i];
- } // endif MaxBlk
-
- if (fseek(T_Stream, dep + off, SEEK_SET)) {
- sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
- return true;
- } // endif
-
- if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) {
- sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
- return true;
- } // endif
-
- } // endif UseTemp
-
-#ifdef DEBTRACE
- htrc("after write pos=%d\n", ftell(Stream));
-#endif
- } // endfor i
-
- Tpos += (int)req;
- Spos += (int)req;
-
- if (UseTemp && !MaxBlk && (Tpos % Nrec == 0 || (eof && Spos == Fpos))) {
- // Write the full or last block to the temporary file
- if ((dep = Nrec - (Tpos % Nrec)) < Nrec)
- // Clean the last block in case of future insert,
- // must be done here because T_Stream was open in write only.
- for (i = 0; i < Ncol; i++) {
- To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
- memset(To_Buf, (Isnum[i]) ? 0 : ' ', dep * Clens[i]);
- } // endfor i
-
- // Write a new block in the temporary file
- len = (size_t)Blksize;
-
- if (fwrite(NewBlock, 1, len, T_Stream) != len) {
- sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
- return true;
- } // endif
-
- if (Spos == Fpos)
- eof = false;
-
- } // endif UseTemp
-
-#ifdef DEBTRACE
- htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
- } // endfor n
-
- return false;
- } // end of MoveIntermediateLines
-
-/***********************************************************************/
-/* Clean deleted space in a VCT or Vec table file. */
-/***********************************************************************/
-bool VCTFAM::CleanUnusedSpace(PGLOBAL g)
- {
- int i, dep;
- int n;
- size_t req, len;
-
- if (!MaxBlk) {
- /*******************************************************************/
- /* Clean last block of the VCT table file. */
- /*******************************************************************/
- assert(!UseTemp);
-
- if (!(n = Nrec - Last))
- return false;
-
- dep = (Block - 1) * Blksize;
- req = (size_t)n;
-
- for (i = 0; i < Ncol; i++) {
- memset(To_Buf, (Isnum[i]) ? 0 : ' ', n * Clens[i]);
-
- if (fseek(Stream, dep + Deplac[i] + Last * Clens[i], SEEK_SET)) {
- sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
- return true;
- } // endif
-
- if ((len = fwrite(To_Buf, Clens[i], req, Stream)) != req) {
- sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
- return true;
- } // endif
-
- } // endfor i
-
- } else for (n = Fpos - Tpos; n > 0; n -= req) {
- /*******************************************************************/
- /* Fill VEC file remaining lines with 0's. */
- /* Note: this seems to work even column blocks have been made */
- /* with Blanks = true. Perhaps should it be set to false for VEC. */
- /*******************************************************************/
- req = (size_t)min(n, Nrec);
- memset(To_Buf, 0, Buflen);
-
- for (i = 0; i < Ncol; i++) {
- if (fseek(T_Stream, Deplac[i] + Tpos * Clens[i], SEEK_SET)) {
- sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
- return true;
- } // endif
-
- if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) {
- sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
- return true;
- } // endif
-
- } // endfor i
-
- Tpos += (int)req;
- } // endfor n
-
- return false;
- } // end of CleanUnusedSpace
-
-/***********************************************************************/
-/* Data Base close routine for VCT access method. */
-/***********************************************************************/
-void VCTFAM::CloseTableFile(PGLOBAL g)
- {
- int rc, wrc = RC_OK;
- MODE mode = Tdbp->GetMode();
-
- if (mode == MODE_INSERT) {
- if (Closing)
- wrc = RC_FX; // Last write was in error
- else
- if (CurNum) {
- // Some more inserted lines remain to be written
- Last = CurNum;
- Block = CurBlk + 1;
- Closing = true;
- wrc = WriteBuffer(g);
- } else {
- Last = Nrec;
- Block = CurBlk;
- wrc = RC_OK;
- } // endif CurNum
-
- if (wrc != RC_FX) {
- rc = ResetTableSize(g, Block, Last);
- } else if (AddBlock) {
- // Last block was not written
- rc = ResetTableSize(g, CurBlk, Nrec);
- longjmp(g->jumper[g->jump_level], 44);
- } // endif
-
- } else if (mode == MODE_UPDATE) {
- // Write back to file any pending modifications
- for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols;
- colp; colp = (PVCTCOL)colp->Next)
- colp->WriteBlock(g);
-
- if (UseTemp && T_Stream) {
- rc = RenameTempFile(g);
-
- if (Header) {
- // Header must be set because it was not set in temp file
- Stream = T_Stream = NULL; // For SetBlockInfo
- rc = SetBlockInfo(g);
- } // endif Header
-
- } // endif UseTemp
-
- } else if (mode == MODE_DELETE && UseTemp && T_Stream) {
- if (MaxBlk)
- rc = CleanUnusedSpace(g);
-
- if ((rc = RenameTempFile(g)) != RC_FX) {
- Stream = T_Stream = NULL; // For SetBlockInfo
- rc = ResetTableSize(g, Block, Last);
- } // endif rc
-
- } // endif's mode
-
- if (!(UseTemp && T_Stream))
- rc = PlugCloseFile(g, To_Fb);
-
-#ifdef DEBTRACE
- htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n",
- To_File, wrc, rc);
-#endif
- Stream = NULL;
- } // end of CloseTableFile
-
-/***********************************************************************/
-/* Data Base close routine for VCT access method. */
-/***********************************************************************/
-bool VCTFAM::ResetTableSize(PGLOBAL g, int block, int last)
- {
- bool rc = false;
-
- // Set Block and Last values for TDBVCT::MakeBlockValues
- Block = block;
- Last = last;
-
- if (!Split) {
- if (!Header) {
- // Update catalog values for Block and Last
- PVCTDEF defp = (PVCTDEF)Tdbp->GetDef();
- LPCSTR name = Tdbp->GetName();
- PCATLG cat = PlgGetCatalog(g);
-
- defp->SetBlock(Block);
- defp->SetLast(Last);
-
- if (!cat->SetIntCatInfo(name, "Blocks", Block) ||
- !cat->SetIntCatInfo(name, "Last", Last)) {
- sprintf(g->Message, MSG(UPDATE_ERROR), "Header");
- rc = true;
- } // endif
-
- } else
- rc = SetBlockInfo(g);
-
- } // endif Split
-
- Tdbp->ResetSize();
- return rc;
- } // end of ResetTableSize
-
-/***********************************************************************/
-/* Rewind routine for VCT access method. */
-/***********************************************************************/
-void VCTFAM::Rewind(void)
- {
- // In mode update we need to read Set Column blocks
- if (Tdbp->GetMode() == MODE_UPDATE)
- OldBlk = -1;
-
- // Initialize so block optimization is called for 1st block
- CurBlk = -1;
- CurNum = Nrec - 1;
-//rewind(Stream); will be placed by fseek
- } // end of Rewind
-
-/***********************************************************************/
-/* ReadBlock: Read column values from current block. */
-/***********************************************************************/
-bool VCTFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
- {
- int len;
- size_t n;
-
- /*********************************************************************/
- /* Calculate the offset and size of the block to read. */
- /*********************************************************************/
- if (MaxBlk) // True vector format
- len = Headlen + Nrec * (colp->Deplac * MaxBlk + colp->Clen * CurBlk);
- else // Blocked vector format
- len = Nrec * (colp->Deplac + Lrecl * CurBlk);
-
-#ifdef DEBTRACE
- htrc("len=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d maxblk=%d\n",
- len, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk);
-#endif
-
- if (fseek(Stream, len, SEEK_SET)) {
- sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- n = fread(colp->Blk->GetValPointer(), (size_t)colp->Clen,
- (size_t)Nrec, Stream);
-
- if (n != (size_t)Nrec) {
- if (errno == NO_ERROR)
- sprintf(g->Message, MSG(BAD_READ_NUMBER), n, To_File);
- else
- sprintf(g->Message, MSG(READ_ERROR),
- To_File, strerror(errno));
-
-#ifdef DEBTRACE
- htrc(" Read error: %s\n", g->Message);
-#endif
- return true;
- } // endif
-
-#ifdef DEBTRACE
- num_read++;
-#endif
- return false;
- } // 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. */
-/***********************************************************************/
-bool VCTFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
- {
- int len;
- size_t n;
-
- /*********************************************************************/
- /* Calculate the offset and size of the block to write. */
- /*********************************************************************/
- if (MaxBlk) // File has Vector format
- len = Headlen
- + Nrec * (colp->Deplac * MaxBlk + colp->Clen * colp->ColBlk);
- else // Old VCT format
- len = Nrec * (colp->Deplac + Lrecl * colp->ColBlk);
-
-#ifdef DEBTRACE
- htrc("modif=%d len=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n",
- Modif, len, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
-#endif
-
- if (fseek(T_Stream, len, SEEK_SET)) {
- sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- // Here Nrec was changed to CurNum in mode Insert,
- // this is the true number of records to write,
- // this also avoid writing garbage in the file for true vector tables.
- n = (Tdbp->GetMode() == MODE_INSERT) ? CurNum : Nrec;
-
- if (n != fwrite(colp->Blk->GetValPointer(),
- (size_t)colp->Clen, n, T_Stream)) {
- sprintf(g->Message, MSG(WRITE_STRERROR),
- (UseTemp) ? To_Fbt->Fname : To_File, strerror(errno));
-#ifdef DEBTRACE
- htrc("Write error: %s\n", strerror(errno));
-#endif
- return true;
- } // endif
-
-#if defined(UNIX)
- fflush(T_Stream); //NGC
-#endif
-
-#ifdef _DEBUG
- num_write++;
-#endif
-
- return false;
- } // end of WriteBlock
-
-/* -------------------------- Class VCMFAM --------------------------- */
-
-/***********************************************************************/
-/* Implementation of the VCMFAM class. */
-/***********************************************************************/
-VCMFAM::VCMFAM(PVCTDEF tdp) : VCTFAM((PVCTDEF)tdp)
- {
- Memory = NULL;
- Memcol = NULL;
- } // end of VCMFAM standard constructor
-
-VCMFAM::VCMFAM(PVCMFAM txfp) : VCTFAM(txfp)
- {
- Memory = txfp->Memory;
- Memcol = txfp->Memcol;
- } // end of VCMFAM copy constructor
-
-/***********************************************************************/
-/* Mapped 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 VCMFAM::OpenTableFile(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- int len;
- MODE mode = Tdbp->GetMode();
- PFBLOCK fp = NULL;
- PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
-
- /*********************************************************************/
- /* Update block info if necessary. */
- /*********************************************************************/
- if (Block < 0)
- if ((Headlen = GetBlockInfo(g)) < 0)
- return true;
-
- /*********************************************************************/
- /* We used the file name relative to recorded datapath. */
- /*********************************************************************/
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- /*********************************************************************/
- /* 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 VCM file, fp=%p cnt=%d\n", fp, fp->Count);
-#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;
- MODE mapmode = mode;
-
- if (mode == MODE_INSERT) {
- if (MaxBlk) {
- if (!Block)
- if (MakeEmptyFile(g, To_File))
- return true;
-
- // Inserting will be like updating the file
- mapmode = MODE_UPDATE;
- } else {
- strcpy(g->Message, "MAP Insert is for VEC Estimate tables only");
- return true;
- } // endif MaxBlk
-
- } // endif mode
-
- del = mode == MODE_DELETE && !Tdbp->GetNext();
-
- if (del) {
- DelRows = Cardinality(g);
-
- // This will stop the process by causing GetProgMax to return 0.
-// ResetTableSize(g, 0, Nrec); must be done later
- } // endif del
-
- /*******************************************************************/
- /* Create the mapping file object. */
- /*******************************************************************/
- hFile = CreateFileMap(g, filename, &mm, mapmode, 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);
- return ResetTableSize(g, 0, Nrec);
- } // 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
-
-#ifdef DEBTRACE
- htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n",
- fp, fp->Count, Memory, len);
-#endif
-
- return AllocateBuffer(g);
- } // end of OpenTableFile
-
-/***********************************************************************/
-/* Allocate the block buffers for columns used in the query. */
-/* Give a dummy value (1) to prevent allocating the value block. */
-/* It will be set pointing into the memory map of the file. */
-/* Note: Memcol must be set for all columns because it can be used */
-/* for set columns in Update. Clens values are used only in Delete. */
-/***********************************************************************/
-bool VCMFAM::AllocateBuffer(PGLOBAL g)
- {
- int m, i = 0;
- bool b = Tdbp->GetMode() == MODE_DELETE;
- PVCTCOL cp;
- PCOLDEF cdp;
- PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
-
- // Calculate the number of columns
- if (!Ncol)
- for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
- Ncol++;
-
- // To store the start position of each column
- Memcol = (char**)PlugSubAlloc(g, NULL, Ncol * sizeof(char*));
- m = (MaxBlk) ? MaxBlk : 1;
-
- // We will need all column sizes and type for Delete
- if (b) {
- Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
- Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
- } // endif b
-
- for (cdp = defp->GetCols(); i < Ncol; i++, cdp = cdp->GetNext()) {
- if (b) {
- Clens[i] = cdp->GetClen();
- Isnum[i] = IsTypeNum(cdp->GetType());
- } // endif b
-
- Memcol[i] = Memory + Headlen + cdp->GetPoff() * m * Nrec;
- } // endfor cdp
-
- for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
- if (!cp->IsSpecial()) { // Not a pseudo column
- cp->Blk = AllocValBlock(g, (void*)1, cp->Buf_Type, Nrec,
- cp->Format.Length, cp->Format.Prec);
- cp->AddStatus(BUF_MAPPED);
- } // endif IsSpecial
-
- if (Tdbp->GetMode() == MODE_INSERT)
- return InitInsert(g);
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* Do initial action when inserting. */
-/***********************************************************************/
-bool VCMFAM::InitInsert(PGLOBAL g)
- {
- int rc;
- PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
-
- // We come here in MODE_INSERT only
- if (Last == Nrec) {
- CurBlk = Block;
- CurNum = 0;
- AddBlock = !MaxBlk;
- } else {
- // The starting point must be at the end of file as for append.
- CurBlk = Block - 1;
- CurNum = Last;
- } // endif Last
-
- // Prepare error return
- if (g->jump_level == MAX_JUMP) {
- strcpy(g->Message, MSG(TOO_MANY_JUMPS));
- return true;
- } // endif
-
- if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) {
- g->jump_level--;
- return true;
- } // endif
-
- // Initialize the column block pointer
- for (; cp; cp = (PVCTCOL)cp->Next)
- cp->ReadBlock(g);
-
- g->jump_level--;
- return false;
- } // end of InitInsert
-
-/***********************************************************************/
-/* Data Base write routine for VMP access method. */
-/***********************************************************************/
-int VCMFAM::WriteBuffer(PGLOBAL g)
- {
-#ifdef DEBTRACE
- htrc("VCM WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
- Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
-#endif
-
- // Mode Update being done in ReadDB we process here Insert mode only.
- if (Tdbp->GetMode() == MODE_INSERT) {
- if (CurBlk == MaxBlk) {
- strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
- return RC_EF; // Too many lines for vector formatted table
- } // endif MaxBlk
-
- if (Closing || ++CurNum == Nrec) {
- PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
-
- // Write back the updated last block values
- for (; cp; cp = (PVCTCOL)cp->Next)
- cp->WriteBlock(g);
-
- if (!Closing) {
- CurBlk++;
- CurNum = 0;
-
- // Re-initialize the column block pointer
- for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
- cp->ReadBlock(g);
-
- } // endif Closing
-
- } // endif Closing || CurNum
-
- } // endif Mode
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for VMP access method. */
-/* Lines between deleted lines are moved in the mapfile view. */
-/***********************************************************************/
-int VCMFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- int i;
- int m, n;
-
-#ifdef DEBTRACE
- fprintf(debug,
- "VCM DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n",
- irc, To_Buf, Tpos, Spos);
-#endif
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the top of map position. */
- /*******************************************************************/
- Fpos = (Block - 1) * Nrec + Last;
-#ifdef DEBTRACE
- htrc("Fpos placed at file top=%p\n", Fpos);
-#endif
- } else // Fpos is the Deleted line position
- Fpos = CurBlk * Nrec + CurNum;
-
- 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 (Fpos > Spos) {
- /*******************************************************************/
- /* Non consecutive line to delete. Move intermediate lines. */
- /*******************************************************************/
- if (!MaxBlk) {
- // Old VCT format, moving must respect block limits
- char *ps, *pt;
- int req, soff, toff;
-
- for (n = Fpos - Spos; n > 0; n -= req) {
- soff = Spos % Nrec;
- toff = Tpos % Nrec;
- req = (size_t)min(n, Nrec - max(soff, toff));
-
- for (i = 0; i < Ncol; i++) {
- ps = Memcol[i] + (Spos / Nrec) * Blksize + soff * Clens[i];
- pt = Memcol[i] + (Tpos / Nrec) * Blksize + toff * Clens[i];
- memmove(pt, ps, req * Clens[i]);
- } // endfor i
-
- Tpos += req;
- Spos += req;
- } // endfor n
-
- } else {
- // True vector format, all is simple...
- n = Fpos - Spos;
-
- for (i = 0; i < Ncol; i++) {
- m = Clens[i];
- memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, n * m);
- } // endfor i
-
- Tpos += n;
- } // endif MaxBlk
-
-#ifdef DEBTRACE
- htrc("move %d bytes\n", n);
-#endif
- } // endif n
-
- if (irc == RC_OK) {
- Spos = Fpos + 1; // New start position
-
-#ifdef DEBTRACE
- htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos);
-#endif
-
- } else {
- /*******************************************************************/
- /* Last call after EOF has been reached. Reset the Block and */
- /* Last values for TDBVCT::MakeBlockValues. */
- /*******************************************************************/
- Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
- Last = (Tpos + Nrec - 1) % Nrec + 1;
-
- if (!MaxBlk) {
- PFBLOCK fp = To_Fb;
-
- // Clean the unused part of the last block
- m = (Block - 1) * Blksize;
- n = Nrec - Last;
-
- for (i = 0; i < Ncol; i++)
- memset(Memcol[i] + m + Last * Clens[i],
- (Isnum[i]) ? 0 : ' ', n * Clens[i]);
-
- // We must Unmap the view and use the saved file handle
- // to put an EOF at the end of the last block of the file.
- CloseMemMap(fp->Memory, (size_t)fp->Length);
- fp->Count = 0; // Avoid doing it twice
-
- // Remove extra blocks
- n = Block * Blksize;
-
-#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
- } else
- // True vector table, Table file size does not change.
- // Just clean the unused part of the file.
- for (n = Fpos - Tpos, i = 0; i < Ncol; i++)
- memset(Memcol[i] + Tpos * Clens[i], 0, n * Clens[i]);
-
- // Reset Last and Block values in the catalog
- PlugCloseFile(g, To_Fb); // in case of Header
- ResetTableSize(g, Block, Last);
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Data Base close routine for VMP access method. */
-/***********************************************************************/
-void VCMFAM::CloseTableFile(PGLOBAL g)
- {
- int rc, wrc = RC_OK;
- MODE mode = Tdbp->GetMode();
-
- if (mode == MODE_INSERT) {
- if (!Closing) {
- if (CurNum) {
- // Some more inserted lines remain to be written
- Last = CurNum;
- Block = CurBlk + 1;
- Closing = true;
- wrc = WriteBuffer(g);
- } else {
- Last = Nrec;
- Block = CurBlk;
- wrc = RC_OK;
- } // endif CurNum
-
- } else
- wrc = RC_FX; // Last write was in error
-
- PlugCloseFile(g, To_Fb);
-
- if (wrc != RC_FX)
- rc = ResetTableSize(g, Block, Last);
-
- } else if (mode != MODE_DELETE)
- PlugCloseFile(g, To_Fb);
-
- } // end of CloseTableFile
-
-/***********************************************************************/
-/* ReadBlock: Read column values from current block. */
-/***********************************************************************/
-bool VCMFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
- {
- char *mempos;
- int i = colp->Index - 1;
- int n = Nrec * ((MaxBlk || Split) ? colp->Clen : Lrecl);
-
- /*********************************************************************/
- /* Calculate the start position of the column block to read. */
- /*********************************************************************/
- mempos = Memcol[i] + n * CurBlk;
-
-#ifdef DEBTRACE
- htrc("mempos=%p i=%d Nrec=%d Clen=%d CurBlk=%d\n",
- mempos, i, Nrec, colp->Clen, CurBlk);
-#endif
-
- if (colp->GetStatus(BUF_MAPPED))
- colp->Blk->SetValPointer(mempos);
-
-#ifdef DEBTRACE
- num_read++;
-#endif
- return false;
- } // end of ReadBlock
-
-/***********************************************************************/
-/* WriteBlock: Write back current column values for one block. */
-/* Note: there is nothing to do because we are working directly into */
-/* the mapped file, except when checking for Update but in this case */
-/* we do not want to write back the modifications either. */
-/***********************************************************************/
-bool VCMFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
- {
-#if defined(_DEBUG)
- char *mempos;
- int i = colp->Index - 1;
- int n = Nrec * colp->Clen;
-
- /*********************************************************************/
- /* Calculate the offset and size of the block to write. */
- /*********************************************************************/
- mempos = Memcol[i] + n * CurBlk;
-
-#ifdef DEBTRACE
- htrc("modif=%d mempos=%p i=%d Nrec=%d Clen=%d colblk=%d\n",
- Modif, mempos, i, Nrec, colp->Clen, colp->ColBlk);
-#endif
-
-#endif // _DEBUG
-
- return false;
- } // end of WriteBlock
-
-/* -------------------------- Class VECFAM --------------------------- */
-
-/***********************************************************************/
-/* Implementation of the VECFAM class. */
-/***********************************************************************/
-VECFAM::VECFAM(PVCTDEF tdp) : VCTFAM((PVCTDEF)tdp)
- {
- Streams = NULL;
- To_Fbs = NULL;
- To_Bufs = NULL;
- Split = true;
- Block = Last = -1;
- InitUpdate = false;
- } // end of VECFAM standard constructor
-
-VECFAM::VECFAM(PVECFAM txfp) : VCTFAM(txfp)
- {
- Streams = txfp->Streams;
- To_Fbs = txfp->To_Fbs;
- Clens = txfp->Clens;
- To_Bufs = txfp->To_Bufs;
- InitUpdate = txfp->InitUpdate;
- } // end of VECFAM copy constructor
-
-/***********************************************************************/
-/* VEC 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 VECFAM::OpenTableFile(PGLOBAL g)
- {
- char opmode[4];
- int i;
- bool b;
- PCOLDEF cdp;
- PVCTCOL cp;
- MODE mode = Tdbp->GetMode();
- PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
-
- /*********************************************************************/
- /* Call Cardinality to set Block and Last values in case it was not */
- /* already called (this happens indeed in test xmode) */
- /*********************************************************************/
- Cardinality(g);
-
- /*********************************************************************/
- /* Open according to input/output mode required. */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- strcpy(opmode, "rb");
- break;
- case MODE_DELETE:
- if (!Tdbp->GetNext()) {
- // Store the number of deleted lines
- DelRows = Cardinality(g);
-
- // This will delete the whole file
- strcpy(opmode, "wb");
-
- // This will stop the process by causing GetProgMax to return 0.
- ResetTableSize(g, 0, Nrec);
- break;
- } // endif filter
-
- // Selective delete, pass thru
- case MODE_UPDATE:
- UseTemp = Tdbp->IsUsingTemp(g);
- strcpy(opmode, (UseTemp) ? "r": "r+");
- break;
- case MODE_INSERT:
- strcpy(opmode, "ab");
- break;
- default:
- sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
- return true;
- } // endswitch Mode
-
- /*********************************************************************/
- /* Initialize the array of file structures. */
- /*********************************************************************/
- if (!Colfn) {
- // Prepare the column file name pattern and set Ncol
- Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
- Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
- } // endif Colfn
-
- Streams = (FILE* *)PlugSubAlloc(g, NULL, Ncol * sizeof(FILE*));
- To_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
-
- for (i = 0; i < Ncol; i++) {
- Streams[i] = NULL;
- To_Fbs[i] = NULL;
- } // endif i
-
- /*********************************************************************/
- /* Open the files corresponding to columns used in the query. */
- /*********************************************************************/
- if (mode == MODE_INSERT || mode == MODE_DELETE) {
- // All columns must be written or deleted
- for (i = 0, cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext())
- if (OpenColumnFile(g, opmode, i))
- return true;
-
- // Check for void table or missing columns
- for (b = !Streams[0], i = 1; i < Ncol; i++)
- if (b != !Streams[i])
- return true;
-
- } else {
- /*******************************************************************/
- /* Open the files corresponding to updated columns of the query. */
- /*******************************************************************/
- for (cp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols; cp;
- cp = (PVCTCOL)cp->Next)
- if (OpenColumnFile(g, opmode, cp->Index - 1))
- return true;
-
- // Open in read only mode the used columns not already open
- for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
- if (!cp->IsSpecial() && !Streams[cp->Index - 1])
- if (OpenColumnFile(g, "rb", cp->Index - 1))
- return true;
-
- // Check for void table or missing columns
- for (i = 0, cp = (PVCTCOL)Tdbp->GetColumns(); cp;
- cp = (PVCTCOL)cp->Next)
- if (!i++)
- b = !Streams[cp->Index - 1];
- else if (b != !Streams[cp->Index - 1])
- return true;
-
- } // endif mode
-
- /*********************************************************************/
- /* Allocate the table and column block buffer. */
- /*********************************************************************/
- return (b) ? false : AllocateBuffer(g);
- } // end of OpenTableFile
-
-/***********************************************************************/
-/* Open the file corresponding to one column. */
-/***********************************************************************/
-bool VECFAM::OpenColumnFile(PGLOBAL g, char *opmode, int i)
- {
- char filename[_MAX_PATH];
- PDBUSER dup = PlgGetUser(g);
-
- sprintf(filename, Colfn, i+1);
-
- if (!(Streams[i] = PlugOpenFile(g, filename, opmode))) {
-#ifdef DEBTRACE
- htrc("%s\n", g->Message);
-#endif
- return (Tdbp->GetMode() == MODE_READ && errno == ENOENT)
- ? PushWarning(g, Tdbp) : true;
- } // endif Streams
-
-#ifdef DEBTRACE
- htrc("File %s is open in mode %s\n", filename, opmode);
-#endif
-
- To_Fbs[i] = dup->Openlist; // Keep track of File blocks
- return false;
- } // end of OpenColumnFile
-
-/***********************************************************************/
-/* Allocate the block buffers for columns used in the query. */
-/***********************************************************************/
-bool VECFAM::AllocateBuffer(PGLOBAL g)
- {
- int i;
- PVCTCOL cp;
- PCOLDEF cdp;
- PTDBVCT tdbp = (PTDBVCT)Tdbp;
- MODE mode = tdbp->GetMode();
- PDOSDEF defp = (PDOSDEF)tdbp->GetDef();
-
- if (mode != MODE_READ) {
- // Allocate what is needed by all modes except Read
- T_Streams = (FILE* *)PlugSubAlloc(g, NULL, Ncol * sizeof(FILE*));
- Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
-
- // Give default values
- for (i = 0; i < Ncol; i++) {
- T_Streams[i] = Streams[i];
- Clens[i] = 0;
- } // endfor i
-
- } // endif mode
-
- if (mode == MODE_INSERT) {
- bool chk = PlgGetUser(g)->Check & CHK_TYPE;
-
- To_Bufs = (void**)PlugSubAlloc(g, NULL, Ncol * sizeof(void*));
- cdp = defp->GetCols();
-
- for (i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext()) {
- Clens[i] = cdp->GetClen();
- To_Bufs[i] = PlugSubAlloc(g, NULL, Nrec * Clens[i]);
-
- if (cdp->GetType() == TYPE_STRING)
- memset(To_Bufs[i], ' ', Nrec * Clens[i]);
- else
- memset(To_Bufs[i], 0, Nrec * Clens[i]);
-
- } // endfor cdp
-
- for (cp = (PVCTCOL)tdbp->Columns; cp; cp = (PVCTCOL)cp->Next)
- cp->Blk = AllocValBlock(g, To_Bufs[cp->Index - 1],
- cp->Buf_Type, Nrec, cp->Format.Length,
- cp->Format.Prec, chk);
-
- return InitInsert(g);
- } else {
- if (UseTemp || mode == MODE_DELETE) {
- // Allocate all that is needed to move lines and make Temp
- if (UseTemp) {
- Tempat = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
- strcpy(Tempat, Colfn);
- PlugSetPath(Tempat, Tempat, Tdbp->GetPath());
- strcat(PlugRemoveType(Tempat, Tempat), ".t");
- T_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
- } // endif UseTemp
-
- if (UseTemp)
- for (i = 0; i < Ncol; i++) {
- T_Streams[i] = (mode == MODE_UPDATE) ? (FILE*)1 : NULL;
- T_Fbs[i] = NULL;
- } // endfor i
-
- if (mode == MODE_DELETE) { // All columns are moved
- cdp = defp->GetCols();
-
- for (i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext()) {
- Clens[i] = cdp->GetClen();
- Buflen = max(Buflen, cdp->GetClen());
- } // endfor cdp
-
- } else { // Mode Update, only some columns are updated
- for (cp = (PVCTCOL)tdbp->To_SetCols; cp; cp = (PVCTCOL)cp->Next) {
- i = cp->Index -1;
-
- if (UseTemp)
- T_Streams[i] = NULL; // Mark the streams to open
-
- Clens[i] = cp->Clen;
- Buflen = max(Buflen, cp->Clen);
- } // endfor cp
-
- InitUpdate = true; // To be initialized
- } // endif mode
-
- To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen * Nrec);
- } // endif mode
-
- // Finally allocate column buffers for all modes
- for (cp = (PVCTCOL)tdbp->Columns; cp; cp = (PVCTCOL)cp->Next)
- if (!cp->IsSpecial()) // Not a pseudo column
- cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
- cp->Format.Length, cp->Format.Prec);
-
- } // endif mode
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* Do initial action when inserting. */
-/***********************************************************************/
-bool VECFAM::InitInsert(PGLOBAL g)
- {
- // We come here in MODE_INSERT only
- CurBlk = 0;
- CurNum = 0;
- AddBlock = true;
- return false;
- } // end of InitInsert
-
-/***********************************************************************/
-/* Reset buffer access according to indexing and to mode. */
-/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
-/***********************************************************************/
-void VECFAM::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() && Block > 1 && Tdbp->GetMode() == MODE_READ) {
- Nrec = 1; // Better for random access
- Rbuf = 0;
- OldBlk = -2; // Has no meaning anymore
- Block = Tdbp->Cardinality(g); // Blocks are one line now
- Last = 1; // Probably unuseful
- } // endif Mode
-
- } // end of ResetBuffer
-
-/***********************************************************************/
-/* Data Base write routine for VCT access method. */
-/***********************************************************************/
-int VECFAM::WriteBuffer(PGLOBAL g)
- {
-#ifdef DEBTRACE
- htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
- Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
-#endif
-
- if (Tdbp->GetMode() == MODE_INSERT) {
- if (Closing || ++CurNum == Nrec) {
- // Here we must add a new blocks to the files
- int i;
- size_t n = (size_t)CurNum;
-
- for (i = 0; i < Ncol; i++)
- if (n != fwrite(To_Bufs[i], (size_t)Clens[i], n, Streams[i])) {
- sprintf(g->Message, MSG(WRITE_STRERROR), To_File, strerror(errno));
- return RC_FX;
- } // endif
-
- if (!Closing) {
- CurBlk++;
- CurNum = 0;
- } // endif Closing
-
- } // endif Closing || CurNum
-
- } else // Mode Update
- // Writing updates being done in ReadDB we do initialization only.
- if (InitUpdate) {
- if (OpenTempFile(g))
- return RC_FX;
-
- InitUpdate = false; // Done
- } // endif InitUpdate
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for split vertical access methods. */
-/* Note: lines are moved directly in the files (ooops...) */
-/***********************************************************************/
-int VECFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- /*********************************************************************/
- /* There is an alternative here: */
- /* 1 - use a temporary file in which are copied all not deleted */
- /* lines, at the end the original file will be deleted and */
- /* the temporary file renamed to the original file name. */
- /* 2 - directly move the not deleted lines inside the original */
- /* file, and at the end erase all trailing records. */
- /* This depends on the Check setting, false by default. */
- /*********************************************************************/
-#ifdef DEBTRACE
- fprintf(debug,
- "VEC DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
- irc, UseTemp, Fpos, Tpos, Spos);
-#endif
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the end-of-file position. */
- /*******************************************************************/
- Fpos = Cardinality(g);
-#ifdef DEBTRACE
- htrc("Fpos placed at file end=%d\n", Fpos);
-#endif
- } else // Fpos is the Deleted line position
- Fpos = CurBlk * Nrec + CurNum;
-
- if (Tpos == Spos)
- // First line to delete
- if (UseTemp) {
- /*****************************************************************/
- /* Open the temporary files, Spos is at the beginning of file. */
- /*****************************************************************/
- if (OpenTempFile(g))
- return RC_FX;
-
- } else
- /*****************************************************************/
- /* Move of eventual preceeding lines is not required here. */
- /* Set the future Tpos, and give Spos a value to block copying. */
- /*****************************************************************/
- Spos = Tpos = Fpos;
-
- /*********************************************************************/
- /* Move any intermediate lines. */
- /*********************************************************************/
- if (MoveIntermediateLines(g))
- return RC_FX;
-
- if (irc == RC_OK) {
-#ifdef DEBTRACE
- assert(Spos == Fpos);
-#endif
- Spos++; // New start position is on next line
-
-#ifdef DEBTRACE
- htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- } else {
- /*******************************************************************/
- /* Last call after EOF has been reached. */
- /*******************************************************************/
- if (!UseTemp) {
- /*****************************************************************/
- /* Because the chsize functionality is only accessible with a */
- /* system call we must close the file and reopen it with the */
- /* open function (_fopen for MS??) this is still to be checked */
- /* for compatibility with other OS's. */
- /*****************************************************************/
- char filename[_MAX_PATH];
- int h, rc; // File handle, return code
-
- for (int i = 0; i < Ncol; i++) {
- sprintf(filename, Colfn, i + 1);
- rc = PlugCloseFile(g, To_Fbs[i]);
-
- if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
- return RC_FX;
-
- /***************************************************************/
- /* Remove extra records. */
- /***************************************************************/
-#if defined(UNIX)
- if (ftruncate(h, (off_t)(Tpos * Clens[i]))) {
- sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#else
- if (chsize(h, Tpos * Clens[i])) {
- sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
- close(h);
- return RC_FX;
- } // endif
-#endif
-
- close(h);
-
-#ifdef DEBTRACE
- htrc("done, h=%d irc=%d\n", h, irc);
-#endif
- } // endfor i
-
- } else // UseTemp
- // Ok, now delete old files and rename new temp files
- if (RenameTempFile(g) == RC_FX)
- return RC_FX;
-
- // Reset these values for TDBVCT::MakeBlockValues
- Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
- Last = (Tpos + Nrec - 1) % Nrec + 1;
-
- if (ResetTableSize(g, Block, Last))
- return RC_FX;
-
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Open temporary files used while updating or deleting. */
-/* Note: the files not updated have been given a T_Stream value of 1. */
-/***********************************************************************/
-bool VECFAM::OpenTempFile(PGLOBAL g)
- {
- char tempname[_MAX_PATH];
-
- for (int i = 0; i < Ncol; i++)
- if (!T_Streams[i]) {
- /*****************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*****************************************************************/
- sprintf(tempname, Tempat, i+1);
-
- if (!(T_Streams[i] = PlugOpenFile(g, tempname, "wb"))) {
-#ifdef DEBTRACE
- htrc("%s\n", g->Message);
-#endif
- return true;
- } else
- T_Fbs[i] = PlgGetUser(g)->Openlist;
-
- } else // This is a column that is not updated
- T_Streams[i] = NULL; // For RenameTempFile
-
- return false;
- } // end of OpenTempFile
-
-/***********************************************************************/
-/* Move intermediate updated lines before writing blocks. */
-/***********************************************************************/
-bool VECFAM::MoveLines(PGLOBAL g)
- {
- if (UseTemp && !InitUpdate) { // Don't do it in check pass
- Fpos = OldBlk * Nrec;
-
- if (MoveIntermediateLines(g)) {
- Closing = true; // ???
- return true;
- } // endif UseTemp
-
-// Spos = Fpos + Nrec;
- } // endif UseTemp
- return false;
-
- } // end of MoveLines
-
-/***********************************************************************/
-/* Move intermediate deleted or updated lines. */
-/***********************************************************************/
-bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *bn)
- {
- int i;
- int n;
- bool b = false;
- size_t req, len;
-
- for (n = Fpos - Spos; n > 0; n -= Nrec) {
- /*******************************************************************/
- /* Non consecutive line to delete. Move intermediate lines. */
- /*******************************************************************/
- req = (size_t)min(n, Nrec);
-
- for (i = 0; i < Ncol; i++) {
- if (!T_Streams[i])
- continue; // Non updated column
-
- if (!UseTemp || !b)
- if (fseek(Streams[i], Spos * Clens[i], SEEK_SET)) {
- sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- len = fread(To_Buf, Clens[i], req, Streams[i]);
-
-#ifdef DEBTRACE
- htrc("after read req=%d len=%d\n", req, len);
-#endif
-
- if (len != req) {
- sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
- return true;
- } // endif len
-
- if (!UseTemp)
- if (fseek(T_Streams[i], Tpos * Clens[i], SEEK_SET)) {
- sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
- return true;
- } // endif
-
- if ((len = fwrite(To_Buf, Clens[i], req, T_Streams[i])) != req) {
- sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
- return true;
- } // endif
-
-#ifdef DEBTRACE
- htrc("after write pos=%d\n", ftell(Streams[i]));
-#endif
- } // endfor i
-
- Tpos += (int)req;
- Spos += (int)req;
-
-#ifdef DEBTRACE
- htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- b = true;
- } // endfor n
-
- return false;
- } // end of MoveIntermediate Lines
-
-/***********************************************************************/
-/* Delete the old files and rename the new temporary files. */
-/***********************************************************************/
-int VECFAM::RenameTempFile(PGLOBAL g)
- {
- char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH];
- int rc = RC_OK;
-
- // Close all files.
- // This loop is necessary because, in case of join,
- // the table files can have been open several times.
- for (PFBLOCK fb = PlgGetUser(g)->Openlist; fb; fb = fb->Next)
- rc = PlugCloseFile(g, fb);
-
- for (int i = 0; i < Ncol && rc == RC_OK; i++) {
- if (!T_Fbs[i])
- continue;
-
- tempname = (char*)T_Fbs[i]->Fname;
- sprintf(filename, Colfn, i+1);
- PlugSetPath(filename, filename, Tdbp->GetPath());
- strcat(PlugRemoveType(filetemp, filename), ".ttt");
- remove(filetemp); // May still be there from previous error
-
- if (rename(filename, filetemp)) { // Save file for security
- sprintf(g->Message, MSG(RENAME_ERROR),
- filename, filetemp, strerror(errno));
- rc = RC_FX;
- } else if (rename(tempname, filename)) {
- sprintf(g->Message, MSG(RENAME_ERROR),
- tempname, filename, strerror(errno));
- rc = rename(filetemp, filename); // Restore saved file
- rc = RC_FX;
- } else if (remove(filetemp)) {
- sprintf(g->Message, MSG(REMOVE_ERROR),
- filetemp, strerror(errno));
- rc = RC_INFO; // Acceptable
- } // endif's
-
- } // endfor i
-
- return rc;
- } // end of RenameTempFile
-
-/***********************************************************************/
-/* Data Base close routine for VEC access method. */
-/***********************************************************************/
-void VECFAM::CloseTableFile(PGLOBAL g)
- {
- int rc, wrc = RC_OK;
- MODE mode = Tdbp->GetMode();
-
- if (mode == MODE_INSERT) {
- if (Closing)
- wrc = RC_FX; // Last write was in error
- else
- if (CurNum) {
- // Some more inserted lines remain to be written
- Last += (CurBlk * Nrec + CurNum -1);
- Block += (Last / Nrec);
- Last = Last % Nrec + 1;
- Closing = true;
- wrc = WriteBuffer(g);
- } else {
- Block += CurBlk;
- wrc = RC_OK;
- } // endif CurNum
-
- if (wrc != RC_FX)
- rc = ResetTableSize(g, Block, Last);
- else
- longjmp(g->jumper[g->jump_level], 44);
-
- } else if (mode == MODE_UPDATE) {
- if (UseTemp && !InitUpdate) {
- // Write any intermediate lines to temp file
- Fpos = OldBlk * Nrec;
- wrc = MoveIntermediateLines(g);
-// Spos = Fpos + Nrec;
- } // endif UseTemp
-
- // Write back to file any pending modifications
- if (wrc == RC_OK)
- for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols;
- colp; colp = (PVCTCOL)colp->Next)
- colp->WriteBlock(g);
-
- if (wrc == RC_OK && UseTemp && !InitUpdate) {
- // Write any intermediate lines to temp file
- Fpos = (Block - 1) * Nrec + Last;
- wrc = MoveIntermediateLines(g);
- } // endif UseTemp
-
- } // endif's mode
-
- if (UseTemp && !InitUpdate) {
- // If they are errors, leave files unchanged
- if (wrc == RC_OK)
- rc = RenameTempFile(g);
- else
- longjmp(g->jumper[g->jump_level], 44);
-
- } else if (Streams)
- for (int i = 0; i < Ncol; i++)
- if (Streams[i]) {
- rc = PlugCloseFile(g, To_Fbs[i]);
- Streams[i] = NULL;
- To_Fbs[i] = NULL;
- } // endif Streams
-
-#ifdef DEBTRACE
- htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n",
- To_File, wrc, rc);
-#endif
- } // end of CloseTableFile
-
-/***********************************************************************/
-/* ReadBlock: Read column values from current block. */
-/***********************************************************************/
-bool VECFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
- {
- int i, len;
- size_t n;
-
- /*********************************************************************/
- /* Calculate the offset and size of the block to read. */
- /*********************************************************************/
- len = Nrec * colp->Clen * CurBlk;
- i = colp->Index - 1;
-
-#ifdef DEBTRACE
- htrc("len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d\n",
- len, i, Nrec, colp->Deplac, Lrecl, CurBlk);
-#endif
-
- if (fseek(Streams[i], len, SEEK_SET)) {
- sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- n = fread(colp->Blk->GetValPointer(), (size_t)colp->Clen,
- (size_t)Nrec, Streams[i]);
-
- if (n != (size_t)Nrec && (CurBlk+1 != Block || n != (size_t)Last)) {
- char fn[_MAX_PATH];
-
- sprintf(fn, Colfn, colp->Index);
-#if defined(WIN32)
- if (feof(Streams[i]))
-#else // !WIN32
- if (errno == NO_ERROR)
-#endif // !WIN32
- sprintf(g->Message, MSG(BAD_READ_NUMBER), n, fn);
- else
- sprintf(g->Message, MSG(READ_ERROR),
- fn, strerror(errno));
-
-#ifdef DEBTRACE
- htrc(" Read error: %s\n", g->Message);
-#endif
- return true;
- } // endif
-
-#ifdef DEBTRACE
- num_read++;
-#endif
- return false;
- } // 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. */
-/***********************************************************************/
-bool VECFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
- {
- int i, len;
- size_t n;
-
- /*********************************************************************/
- /* Calculate the offset and size of the block to write. */
- /*********************************************************************/
- len = Nrec * colp->Clen * colp->ColBlk;
- i = colp->Index - 1;
-
-#ifdef DEBTRACE
- htrc("modif=%d len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n",
- Modif, len, i, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
-#endif
-
- if (Tdbp->GetMode() == MODE_UPDATE && !UseTemp)
- if (fseek(T_Streams[i], len, SEEK_SET)) {
- sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
- return true;
- } // endif
-
- // Here Nrec was changed to CurNum in mode Insert,
- // this is the true number of records to write,
- // this also avoid writing garbage in the file for true vector tables.
- n = (Tdbp->GetMode() == MODE_INSERT) ? CurNum
- : (colp->ColBlk == Block - 1) ? Last : Nrec;
-
- if (n != fwrite(colp->Blk->GetValPointer(),
- (size_t)colp->Clen, n, T_Streams[i])) {
- char fn[_MAX_PATH];
-
- sprintf(fn, (UseTemp) ? Tempat : Colfn, colp->Index);
- sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
-#ifdef DEBTRACE
- htrc("Write error: %s\n", strerror(errno));
-#endif
- return true;
- } else
- Spos = Fpos + n;
-
-#if defined(UNIX)
- fflush(Streams[i]); //NGC
-#endif
-
-#ifdef DEBTRACE
-//num_write++;
-#endif
-
- return false;
- } // end of WriteBlock
-
-/* -------------------------- Class VMPFAM --------------------------- */
-
-/***********************************************************************/
-/* Implementation of the VMPFAM class. */
-/***********************************************************************/
-VMPFAM::VMPFAM(PVCTDEF tdp) : VCMFAM((PVCTDEF)tdp)
- {
- To_Fbs = NULL;
- Split = true;
- Block = Last = -1;
- } // end of VMPFAM standard constructor
-
-VMPFAM::VMPFAM(PVMPFAM txfp) : VCMFAM(txfp)
- {
- To_Fbs = txfp->To_Fbs;
- } // end of VMPFAM copy constructor
-
-/***********************************************************************/
-/* 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 VMPFAM::OpenTableFile(PGLOBAL g)
- {
- int i;
- bool b;
- MODE mode = Tdbp->GetMode();
- PCOLDEF cdp;
- PVCTCOL cp;
- PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
-
- if (mode == MODE_DELETE && !Tdbp->GetNext()) {
- DelRows = Cardinality(g);
-
- // This will stop the process by causing GetProgMax to return 0.
- ResetTableSize(g, 0, Nrec);
- } else
- Cardinality(g); // See comment in VECFAM::OpenTbleFile
-
-
- /*********************************************************************/
- /* Prepare the filename pattern for column files and set Ncol. */
- /*********************************************************************/
- if (!Colfn) {
- // Prepare the column file name pattern
- Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
- Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
- } // endif Colfn
-
- /*********************************************************************/
- /* Initialize the array of file structures. */
- /*********************************************************************/
- Memcol = (char* *)PlugSubAlloc(g, NULL, Ncol * sizeof(char *));
- To_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
-
- for (i = 0; i < Ncol; i++) {
- Memcol[i] = NULL;
- To_Fbs[i] = NULL;
- } // endif i
-
- /*********************************************************************/
- /* Open the files corresponding to columns used in the query. */
- /*********************************************************************/
- if (mode == MODE_DELETE) {
- // All columns are used in Delete mode
- for (i = 0, cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext())
- if (MapColumnFile(g, mode, i))
- return true;
-
- } else {
- /*******************************************************************/
- /* Open the files corresponding updated columns of the query. */
- /*******************************************************************/
- for (cp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols; cp;
- cp = (PVCTCOL)cp->Next)
- if (MapColumnFile(g, MODE_UPDATE, cp->Index - 1))
- return true;
-
- /*******************************************************************/
- /* Open other non already open used columns (except pseudos) */
- /*******************************************************************/
- for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
- if (!cp->IsSpecial() && !Memcol[cp->Index - 1])
- if (MapColumnFile(g, MODE_READ, cp->Index - 1))
- return true;
-
- } // endif mode
-
- /*********************************************************************/
- /* Check for void table or missing columns */
- /*********************************************************************/
- for (b = !Memcol[0], i = 1; i < Ncol; i++)
- if (b != !Memcol[i])
- return true;
-
- /*********************************************************************/
- /* Allocate the table and column block buffer. */
- /*********************************************************************/
- return (b) ? false : AllocateBuffer(g);
- } // end of OpenTableFile
-
-/***********************************************************************/
-/* Open the file corresponding to one column. */
-/***********************************************************************/
-bool VMPFAM::MapColumnFile(PGLOBAL g, MODE mode, int i)
- {
- char filename[_MAX_PATH];
- int len;
- HANDLE hFile;
- MEMMAP mm;
- PFBLOCK fp;
- PDBUSER dup = PlgGetUser(g);
-
- sprintf(filename, Colfn, i+1);
-
- /*********************************************************************/
- /* 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 = dup->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++;
- Memcol[i] = fp->Memory;
- len = fp->Length;
- } else {
- /*******************************************************************/
- /* Create the mapping file object. */
- /*******************************************************************/
- hFile = CreateFileMap(g, filename, &mm, mode, DelRows);
-
- 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;
- Memcol[i] = (char *)mm.memory;
-
- if (!len) { // Empty or deleted file
- CloseFileHandle(hFile);
- ResetTableSize(g, 0, Nrec);
- return false;
- } // endif len
-
- if (!Memcol[i]) {
- 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 = dup->Openlist;
- dup->Openlist = fp;
- fp->Count = 1;
- fp->Length = len;
- fp->Memory = Memcol[i];
- fp->Mode = mode;
- fp->File = NULL;
- fp->Handle = hFile; // Used for Delete
- } // endif fp
-
- To_Fbs[i] = fp; // Useful when closing
-
-#ifdef DEBTRACE
- htrc("fp=%p count=%d MapView=%p len=%d\n",
- fp, fp->Count, Memcol[i], len);
-#endif
-
- return false;
- } // end of MapColumnFile
-
-/***********************************************************************/
-/* Allocate the block buffers for columns used in the query. */
-/* Give a dummy value (1) to prevent allocating the value block. */
-/* It will be set pointing into the memory map of the file. */
-/***********************************************************************/
-bool VMPFAM::AllocateBuffer(PGLOBAL g)
- {
- PVCTCOL cp;
-
- if (Tdbp->GetMode() == MODE_DELETE) {
- PCOLDEF cdp = Tdbp->GetDef()->GetCols();
-
- Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
-
- for (int i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext())
- Clens[i] = cdp->GetClen();
-
- } // endif mode
-
- for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
- if (!cp->IsSpecial()) { // Not a pseudo column
- cp->Blk = AllocValBlock(g, (void*)1, cp->Buf_Type, Nrec,
- cp->Format.Length, cp->Format.Prec);
- cp->AddStatus(BUF_MAPPED);
- } // endif IsSpecial
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for VMP access method. */
-/* Lines between deleted lines are moved in the mapfile view. */
-/***********************************************************************/
-int VMPFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- int i;
- int m, n;
-
-#ifdef DEBTRACE
- fprintf(debug,
- "VMP DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n",
- irc, To_Buf, Tpos, Spos);
-#endif
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the top of map position. */
- /*******************************************************************/
- Fpos = (Block - 1) * Nrec + Last;
-#ifdef DEBTRACE
- htrc("Fpos placed at file top=%p\n", Fpos);
-#endif
- } else // Fpos is the Deleted line position
- Fpos = CurBlk * Nrec + CurNum;
-
- 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. */
- /*******************************************************************/
- for (i = 0; i < Ncol; i++) {
- m = Clens[i];
- memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, m * n);
- } // endif i
-
- Tpos += n;
-
-#ifdef DEBTRACE
- htrc("move %d bytes\n", n);
-#endif
- } // endif n
-
- if (irc == RC_OK) {
- Spos = Fpos + 1; // 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;
-
- for (i = 0; i < Ncol; i++) {
- fp = To_Fbs[i];
- CloseMemMap(fp->Memory, (size_t)fp->Length);
- fp->Count = 0; // Avoid doing it twice
-
- /*****************************************************************/
- /* Remove extra records. */
- /*****************************************************************/
- n = Tpos * Clens[i];
-
-#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
- } // endfor i
-
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Data Base close routine for VMP access method. */
-/***********************************************************************/
-void VMPFAM::CloseTableFile(PGLOBAL g)
- {
- if (Tdbp->GetMode() == MODE_DELETE) {
- // Set Block and Nrec values for TDBVCT::MakeBlockValues
- Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
- Last = (Tpos + Nrec - 1) % Nrec + 1;
- ResetTableSize(g, Block, Last);
- } else if (Tdbp->GetMode() == MODE_INSERT)
- assert(false);
-
- for (int i = 0; i < Ncol; i++)
- PlugCloseFile(g, To_Fbs[i]);
-
- } // end of CloseTableFile
-
-/* -------------------------- Class BGVFAM --------------------------- */
-
-/***********************************************************************/
-/* Implementation of the BGVFAM class. */
-/***********************************************************************/
-// Constructors
-BGVFAM::BGVFAM(PVCTDEF tdp) : VCTFAM(tdp)
- {
- Hfile = INVALID_HANDLE_VALUE;
- Tfile = INVALID_HANDLE_VALUE;
- BigDep = NULL;
- } // end of BGVFAM constructor
-
-BGVFAM::BGVFAM(PBGVFAM txfp) : VCTFAM(txfp)
- {
- Hfile = txfp->Hfile;
- Tfile = txfp->Tfile;
- BigDep= txfp->BigDep;
- } // end of BGVFAM copy constructor
-
-/***********************************************************************/
-/* Set current position in a big file. */
-/***********************************************************************/
-bool BGVFAM::BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, bool b)
- {
-#if defined(WIN32)
- char buf[256];
- DWORD drc, m = (b) ? FILE_END : FILE_BEGIN;
- LARGE_INTEGER of;
-
- of.QuadPart = pos;
- of.LowPart = SetFilePointer(h, of.LowPart, &of.HighPart, m);
-
- if (of.LowPart == INVALID_SET_FILE_POINTER &&
- (drc = GetLastError()) != NO_ERROR) {
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- sprintf(g->Message, MSG(SFP_ERROR), buf);
- return true;
- } // endif
-#else // !WIN32
- if (lseek64(h, pos, (b) ? SEEK_END : SEEK_SET) < 0) {
- sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
- return true;
- } // endif
-#endif // !WIN32
-
- return false;
- } // end of BigSeek
-
-/***********************************************************************/
-/* Read from a big file. */
-/***********************************************************************/
-bool BGVFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req)
- {
- bool rc = false;
-
-#if defined(WIN32)
- DWORD nbr, drc, len = (DWORD)req;
- bool brc = ReadFile(h, inbuf, len, &nbr, NULL);
-
-#ifdef DEBTRACE
- htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr);
-#endif
-
- if (!brc || nbr != len) {
- char buf[256]; // , *fn = (h == Hfile) ? To_File : "Tempfile";
-
- if (brc)
- strcpy(buf, MSG(BAD_BYTE_READ));
- else {
- drc = GetLastError();
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- } // endelse brc
-
- sprintf(g->Message, MSG(READ_ERROR), To_File, buf);
-#ifdef DEBTRACE
- htrc("BIGREAD: %s\n", g->Message);
-#endif
- rc = true;
- } // endif brc || nbr
-#else // !WIN32
- size_t len = (size_t)req;
- ssize_t nbr = read(h, inbuf, len);
-
- if (nbr != (ssize_t)len) {
- const char *fn = (h == Hfile) ? To_File : "Tempfile";
-
- sprintf(g->Message, MSG(READ_ERROR), fn, strerror(errno));
-#ifdef DEBTRACE
- htrc("BIGREAD: nbr=%d len=%d errno=%d %s\n",
- nbr, len, errno, g->Message);
-#endif
- rc = true;
- } // endif nbr
-#endif // !WIN32
-
- return rc;
- } // end of BigRead
-
-/***********************************************************************/
-/* Write into a big file. */
-/***********************************************************************/
-bool BGVFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req)
- {
- bool rc = false;
-
-#if defined(WIN32)
- DWORD nbw, drc, len = (DWORD)req;
- bool brc = WriteFile(h, inbuf, len, &nbw, NULL);
-
-#ifdef DEBTRACE
- htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw);
-#endif
-
- if (!brc || nbw != len) {
- char buf[256], *fn = (h == Hfile) ? To_File : "Tempfile";
-
- if (brc)
- strcpy(buf, MSG(BAD_BYTE_NUM));
- else {
- drc = GetLastError();
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- } // endelse brc
-
- sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf);
-
-#ifdef DEBTRACE
- htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
- nbw, len, drc, g->Message);
-#endif
- rc = true;
- } // endif brc || nbw
-#else // !WIN32
- size_t len = (size_t)req;
- ssize_t nbw = write(h, inbuf, len);
-
- if (nbw != (ssize_t)len) {
- const char *fn = (h == Hfile) ? To_File : "Tempfile";
-
- sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
-#ifdef DEBTRACE
- htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
- nbw, len, errno, g->Message);
-#endif
- rc = true;
- } // endif nbr
-#endif // !WIN32
-
- return rc;
- } // end of BigWrite
-
-/***********************************************************************/
-/* Get the Headlen, Block and Last info from the file header. */
-/***********************************************************************/
-int BGVFAM::GetBlockInfo(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- int n;
- bool b;
- VECHEADER vh;
- HANDLE h;
-
- if (Header < 1 || Header > 3 || !MaxBlk) {
- sprintf(g->Message, "Invalid header value %d", Header);
- return -1;
- } else
- n = (Header == 1) ? (int)sizeof(VECHEADER) : 0;
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (Header == 2)
- strcat(PlugRemoveType(filename, filename), ".blk");
-
-#if defined(WIN32)
- h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
-#else // !WIN32
- h = open64(filename, O_RDONLY, 0);
-
- if (h == INVALID_HANDLE_VALUE) {
-#endif // !WIN32
- // Consider this is a void table
- Last = Nrec;
- Block = 0;
- return n;
- } else if (Header == 3)
- b = BigSeek(g, h, -(BIGINT)sizeof(vh), true);
-
- if (BigRead(g, h, &vh, sizeof(vh))) {
- sprintf(g->Message, "Error reading header file %s", filename);
- n = -1;
- } else if (MaxBlk * Nrec != vh.MaxRec) {
- sprintf(g->Message, "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d",
- vh.MaxRec, MaxBlk, Nrec);
- n = -1;
- } else {
- Block = (vh.NumRec > 0) ? (vh.NumRec + Nrec - 1) / Nrec : 0;
- Last = (vh.NumRec + Nrec - 1) % Nrec + 1;
- } // endif's
-
- CloseFileHandle(h);
- return n;
- } // end of GetBlockInfo
-
-/***********************************************************************/
-/* Set the MaxRec and NumRec info in the file header. */
-/***********************************************************************/
-bool BGVFAM::SetBlockInfo(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- bool bk, b = false, rc = false;
- VECHEADER vh;
- HANDLE h = INVALID_HANDLE_VALUE;
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
- if (Header != 2) {
- if (Hfile != INVALID_HANDLE_VALUE) {
- h = Hfile;
-
- if (Header == 1)
- bk = BigSeek(g, h, (BIGINT)0);
-
- } else
- b = true;
-
- } else // Header == 2
- strcat(PlugRemoveType(filename, filename), ".blk");
-
- if (h == INVALID_HANDLE_VALUE) {
-#if defined(WIN32)
- DWORD creation = (b) ? OPEN_EXISTING : TRUNCATE_EXISTING;
-
- h = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0,
- NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
-
-#else // !WIN32
- int oflag = (b) ? O_RDWR : O_RDWR | O_TRUNC;
-
- h = open64(filename, oflag, 0);
-#endif // !WIN32
-
- if (h == INVALID_HANDLE_VALUE) {
- sprintf(g->Message, "Error opening header file %s", filename);
- return true;
- } // endif h
-
- } // endif h
-
- if (Header == 3)
- bk = BigSeek(g, h, -(BIGINT)sizeof(vh), true);
-
- vh.MaxRec = MaxBlk * Bsize;
- vh.NumRec = (Block - 1) * Nrec + Last;
-
- if (BigWrite(g, h, &vh, sizeof(vh))) {
- sprintf(g->Message, "Error writing header file %s", filename);
- rc = true;
- } // endif fread
-
- if (Header > 1 || Hfile == INVALID_HANDLE_VALUE)
- CloseFileHandle(h);
-
- return rc;
- } // end of SetBlockInfo
-
-/***********************************************************************/
-/* VEC Create an empty file for new Vector formatted tables. */
-/***********************************************************************/
-bool BGVFAM::MakeEmptyFile(PGLOBAL g, char *fn)
- {
-#if defined(WIN32)
- // Vector formatted file this will create an empty file of the
- // required length if it does not exists yet.
- char *p, filename[_MAX_PATH], c = 0;
- DWORD rc;
- bool brc;
- LARGE_INTEGER of;
- HANDLE h;
-
- PlugSetPath(filename, fn, Tdbp->GetPath());
- h = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- p = MSG(OPENING);
- goto err;
- } // endif h
-
- of.QuadPart = (BIGINT)Headlen + (BIGINT)MaxBlk * (BIGINT)Blksize - (BIGINT)1;
-
- of.LowPart = SetFilePointer(h, of.LowPart,
- &of.HighPart, FILE_BEGIN);
-
- if (of.LowPart == INVALID_SET_FILE_POINTER &&
- GetLastError() != NO_ERROR) {
- p = MSG(MAKING);
- goto err;
- } // endif
-
- brc = WriteFile(h, &c, 1, &rc, NULL);
-
- if (!brc || rc != 1) {
- p = MSG(WRITING);
- goto err;
- } // endif
-
- CloseHandle(h);
- return false;
-
- err:
- rc = GetLastError();
- sprintf(g->Message, MSG(EMPTY_FILE), p, filename);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)filename, sizeof(filename), NULL);
- strcat(g->Message, filename);
-
- if (h != INVALID_HANDLE_VALUE)
- CloseHandle(h);
-
- return true;
-#else // !WIN32
- strcpy(g->Message, MSG(MKEMPTY_NIY));
- return true;
-#endif // !WIN32
- } // end of MakeEmptyFile
-
-/***********************************************************************/
-/* Vopen function: opens a file using Windows or Unix API's. */
-/***********************************************************************/
-bool BGVFAM::OpenTableFile(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- bool del = false;
- MODE mode = Tdbp->GetMode();
- PDBUSER dbuserp = PlgGetUser(g);
-
- if ((To_Fb && To_Fb->Count) || Hfile != INVALID_HANDLE_VALUE) {
- sprintf(g->Message, MSG(FILE_OPEN_YET), To_File);
- return true;
- } // endif
-
- /*********************************************************************/
- /* Update block info if necessary. */
- /*********************************************************************/
- if (Block < 0)
- if ((Headlen = GetBlockInfo(g)) < 0)
- return true;
-
- PlugSetPath(filename, To_File, Tdbp->GetPath());
-
-#ifdef DEBTRACE
- htrc("OpenTableFile: filename=%s mode=%d Last=%d\n",
- filename, mode, Last);
-#endif
-
-#if defined(WIN32)
- DWORD access, creation, share = 0, rc = 0;
-
- /*********************************************************************/
- /* Create the file object according to access mode */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- access = GENERIC_READ;
- share = FILE_SHARE_READ;
- creation = OPEN_EXISTING;
- break;
- case MODE_INSERT:
- if (MaxBlk) {
- if (!Block)
- if (MakeEmptyFile(g, To_File))
- return true;
-
- // Required to update empty blocks
- access = GENERIC_READ | GENERIC_WRITE;
- } else if (Last == Nrec)
- access = GENERIC_WRITE;
- else
- // Required to update the last block
- access = GENERIC_READ | GENERIC_WRITE;
-
- creation = OPEN_ALWAYS;
- break;
- case MODE_DELETE:
- if (!Tdbp->GetNext()) {
- // Store the number of deleted lines
- DelRows = Cardinality(g);
-
- // This will stop the process by
- // causing GetProgMax to return 0.
-// ResetTableSize(g, 0, Nrec); must be done later
- del = true;
-
- // This will delete the whole file
- access = GENERIC_READ | GENERIC_WRITE;
- creation = TRUNCATE_EXISTING;
- break;
- } // endif
-
- // Selective delete, pass thru
- case MODE_UPDATE:
- if ((UseTemp = Tdbp->IsUsingTemp(g)))
- access = GENERIC_READ;
- else
- access = GENERIC_READ | GENERIC_WRITE;
-
- creation = OPEN_EXISTING;
- break;
- default:
- sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
- return true;
- } // endswitch
-
- /*********************************************************************/
- /* Use specific Windows API functions. */
- /*********************************************************************/
- Hfile = CreateFile(filename, access, share, NULL, creation,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- rc = GetLastError();
- sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)filename, sizeof(filename), NULL);
- strcat(g->Message, filename);
- } // endif Hfile
-
-#ifdef DEBTRACE
- fprintf(debug,
- " rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n",
- drc, access, share, creation, Hfile, filename);
-#endif
-
- if (mode == MODE_INSERT) {
- /*******************************************************************/
- /* In Insert mode we must position the cursor at end of file. */
- /*******************************************************************/
- LARGE_INTEGER of;
-
- of.QuadPart = (BIGINT)0;
- of.LowPart = SetFilePointer(Hfile, of.LowPart,
- &of.HighPart, FILE_END);
-
- if (of.LowPart == INVALID_SET_FILE_POINTER &&
- (rc = GetLastError()) != NO_ERROR) {
- sprintf(g->Message, MSG(ERROR_IN_SFP), rc);
- CloseHandle(Hfile);
- Hfile = INVALID_HANDLE_VALUE;
- } // endif
-
- } // endif Mode
-
-#else // UNIX
- /*********************************************************************/
- /* The open() function has a transitional interface for 64-bit */
- /* file offsets. Note that using open64() is equivalent to using */
- /* open() with O_LARGEFILE set in oflag (see Xopen in tabfix.cpp). */
- /*********************************************************************/
- int rc = 0;
- int oflag;
- mode_t pmd = 0;
-
- /*********************************************************************/
- /* Create the file object according to access mode */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- oflag = O_RDONLY;
- break;
- case MODE_INSERT:
- oflag = O_WRONLY | O_CREAT | O_APPEND;
- pmd = S_IREAD | S_IWRITE;
- break;
- case MODE_DELETE:
- // This is temporary until a partial delete is implemented
- if (!Tdbp->GetNext()) {
- // Store the number of deleted lines
- DelRows = Cardinality(g);
- del = true;
-
- // This will delete the whole file and provoque ReadDB to
- // return immediately.
- oflag = O_RDWR | O_TRUNC;
- strcpy(g->Message, MSG(NO_VCT_DELETE));
- break;
- } // endif
-
- // Selective delete, pass thru
- case MODE_UPDATE:
- UseTemp = Tdbp->IsUsingTemp(g);
- oflag = (UseTemp) ? O_RDONLY : O_RDWR;
- break;
- default:
- sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
- return true;
- } // endswitch
-
- Hfile = open64(filename, oflag, pmd); // Enable file size > 2G
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- rc = errno;
- sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
- strcat(g->Message, strerror(errno));
- } // endif Hfile
-
-#ifdef DEBTRACE
- htrc(" lrc=%d oflag=%p mode=%p handle=%d fn=%s\n",
- lrc, oflag, mode, Hfile, filename);
-#endif
-
-#endif // UNIX
-
- if (!rc) {
- if (!To_Fb) {
- To_Fb = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
- To_Fb->Fname = To_File;
- To_Fb->Type = TYPE_FB_HANDLE;
- To_Fb->Memory = NULL;
- To_Fb->Length = 0;
- To_Fb->File = NULL;
- To_Fb->Next = dbuserp->Openlist;
- dbuserp->Openlist = To_Fb;
- } // endif To_Fb
-
- To_Fb->Count = 1;
- To_Fb->Mode = mode;
- To_Fb->Handle = Hfile;
-
-#ifdef DEBTRACE
- htrc("File %s is open in mode %d\n", filename, mode);
-#endif
-
- if (del)
- // This will stop the process by
- // causing GetProgMax to return 0.
- return ResetTableSize(g, 0, Nrec);
-
- /*********************************************************************/
- /* Allocate the table and column block buffers. */
- /*********************************************************************/
- return AllocateBuffer(g);
- } else
- return (mode == MODE_READ && rc == ENOENT)
- ? PushWarning(g, Tdbp) : true;
-
- } // end of OpenTableFile
-
-/***********************************************************************/
-/* Allocate the block buffers for columns used in the query. */
-/***********************************************************************/
-bool BGVFAM::AllocateBuffer(PGLOBAL g)
- {
- MODE mode = Tdbp->GetMode();
- PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
- PCOLDEF cdp;
- PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
-
- if (mode == MODE_INSERT) {
- if (!NewBlock) {
- // Not reopening after inserting the last block
- bool chk = PlgGetUser(g)->Check & CHK_TYPE;
-
- NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
-
- for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
- memset(NewBlock + Nrec * cdp->GetPoff(),
- (IsTypeNum(cdp->GetType()) ? 0 : ' '),
- Nrec * cdp->GetClen());
-
- for (; cp; cp = (PVCTCOL)cp->Next)
- cp->Blk = AllocValBlock(g, NewBlock + Nrec * cp->Deplac,
- cp->Buf_Type, Nrec, cp->Format.Length,
- cp->Format.Prec, chk);
-
- InitInsert(g); // Initialize inserting
-
- // Currently we don't use a temporary file for inserting
- Tfile = Hfile;
- } // endif NewBlock
-
- } else {
- if (UseTemp || mode == MODE_DELETE) {
- // Allocate all that is needed to move lines
- int i = 0;
-
- if (!Ncol)
- for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
- Ncol++;
-
- if (MaxBlk)
- BigDep = (BIGINT*)PlugSubAlloc(g, NULL, Ncol * sizeof(BIGINT));
- else
- Deplac = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
-
- Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
- Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
-
- for (cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext()) {
- if (MaxBlk)
- BigDep[i] = (BIGINT)Headlen
- + (BIGINT)(cdp->GetPoff() * Nrec) * (BIGINT)MaxBlk;
- else
- Deplac[i] = cdp->GetPoff() * Nrec;
-
- Clens[i] = cdp->GetClen();
- Isnum[i] = IsTypeNum(cdp->GetType());
- Buflen = max(Buflen, cdp->GetClen());
- } // endfor cdp
-
- if (!UseTemp || MaxBlk) {
- Buflen *= Nrec;
- To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
- } else
- NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
-
- } // endif mode
-
- for (; cp; cp = (PVCTCOL)cp->Next)
- if (!cp->IsSpecial()) // Not a pseudo column
- cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
- cp->Format.Length, cp->Format.Prec);
-
- } //endif mode
-
- return false;
- } // end of AllocateBuffer
-
-/***********************************************************************/
-/* Data Base write routine for huge VCT access method. */
-/***********************************************************************/
-int BGVFAM::WriteBuffer(PGLOBAL g)
- {
-#ifdef DEBTRACE
- htrc("BGV WriteDB: R%d Mode=%d CurNum=%d CurBlk=%d\n",
- Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
-#endif
-
- if (Tdbp->GetMode() == MODE_UPDATE) {
- // Mode Update is done in ReadDB, we just initialize it here
- if (Tfile == INVALID_HANDLE_VALUE) {
- if (UseTemp) {
- if (OpenTempFile(g))
- return RC_FX;
-
- // Most of the time, not all table columns are updated.
- // This why we must completely pre-fill the temporary file.
- Fpos = (MaxBlk) ? (Block - 1) * Nrec + Last
- : Block * Nrec; // To write last lock
-
- if (MoveIntermediateLines(g))
- return RC_FX;
-
- } else
- Tfile = Hfile;
-
- } // endif Tfile
-
- } else {
- // Mode Insert
- if (MaxBlk && CurBlk == MaxBlk) {
- strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
- return RC_EF; // Too many lines for a Vector formatted table
- } // endif MaxBlk
-
- if (Closing || ++CurNum == Nrec) {
- PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
-
- if (!AddBlock) {
- // Write back the updated last block values
- for (; cp; cp = (PVCTCOL)cp->Next)
- cp->WriteBlock(g);
-
- if (!Closing && !MaxBlk) {
- // Close the VCT file and reopen it in mode Insert
-//#if defined(WIN32) //OB
-// CloseHandle(Hfile);
-//#else // UNIX
-// close(Hfile);
-//#endif // UNIX
- CloseFileHandle(Hfile);
- Hfile = INVALID_HANDLE_VALUE;
- To_Fb->Count = 0;
- Last = Nrec; // Tested in OpenTableFile
-
- if (OpenTableFile(g)) {
- Closing = true; // Tell CloseDB of error
- return RC_FX;
- } // endif Vopen
-
- AddBlock = true;
- } // endif Closing
-
- } else {
- // Here we must add a new block to the VCT file
- if (Closing)
- // Reset the overwritten columns for last block extra records
- for (; cp; cp = (PVCTCOL)cp->Next)
- memset(NewBlock + Nrec * cp->Deplac + Last * cp->Clen,
- (cp->Buf_Type == TYPE_STRING) ? ' ' : '\0',
- (Nrec - Last) * cp->Clen);
-
- if (BigWrite(g, Hfile, NewBlock, Blksize))
- return RC_FX;
-
- } // endif AddBlock
-
- if (!Closing) {
- CurBlk++;
- CurNum = 0;
- } // endif Closing
-
- } // endif
-
- } // endif Mode
-
- return RC_OK;
- } // end of WriteBuffer
-
-/***********************************************************************/
-/* Data Base delete line routine for BGVFAM access method. */
-/***********************************************************************/
-int BGVFAM::DeleteRecords(PGLOBAL g, int irc)
- {
- bool eof = false;
-
- /*********************************************************************/
- /* There is an alternative here depending on UseTemp: */
- /* 1 - use a temporary file in which are copied all not deleted */
- /* lines, at the end the original file will be deleted and */
- /* the temporary file renamed to the original file name. */
- /* 2 - directly move the not deleted lines inside the original */
- /* file, and at the end erase all trailing records. */
- /*********************************************************************/
-#ifdef DEBTRACE
- fprintf(debug,
- "BGV DeleteDB: irc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
- irc, UseTemp, Fpos, Tpos, Spos);
-#endif
-
- if (irc != RC_OK) {
- /*******************************************************************/
- /* EOF: position Fpos at the end-of-file position. */
- /*******************************************************************/
- Fpos = (Block - 1) * Nrec + Last;
-#ifdef DEBTRACE
- htrc("Fpos placed at file end=%d\n", Fpos);
-#endif
- eof = UseTemp && !MaxBlk;
- } else // Fpos is the deleted line position
- Fpos = CurBlk * Nrec + CurNum;
-
- if (Tpos == Spos) {
- if (UseTemp) {
- /*****************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*****************************************************************/
- if (OpenTempFile(g))
- return RC_FX;
-
- } else {
- /*****************************************************************/
- /* Move of eventual preceeding lines is not required here. */
- /* Set the target file as being the source file itself. */
- /* Set the future Tpos, and give Spos a value to block copying. */
- /*****************************************************************/
- Tfile = Hfile;
- Spos = Tpos = Fpos;
- } // endif UseTemp
-
- } // endif Tpos == Spos
-
- /*********************************************************************/
- /* Move any intermediate lines. */
- /*********************************************************************/
- if (MoveIntermediateLines(g, &eof))
- return RC_FX;
-
- if (irc == RC_OK) {
-#ifdef DEBTRACE
- assert(Spos == Fpos);
-#endif
- Spos++; // New start position is on next line
-
-#ifdef DEBTRACE
- htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
-
- } else {
- /*******************************************************************/
- /* Last call after EOF has been reached. */
- /*******************************************************************/
- Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
- Last = (Tpos + Nrec - 1) % Nrec + 1;
-
- if (!UseTemp) { // The UseTemp case is treated in CloseTableFile
- if (!MaxBlk) {
- if (Last < Nrec) // Clean last block
- if (CleanUnusedSpace(g))
- return RC_FX;
-
- /***************************************************************/
- /* Remove extra records. */
- /***************************************************************/
-#if defined(WIN32)
- BIGINT pos = (BIGINT)Block * (BIGINT)Blksize;
-
- if (BigSeek(g, Hfile, pos))
- return RC_FX;
-
- if (!SetEndOfFile(Hfile)) {
- DWORD drc = GetLastError();
-
- sprintf(g->Message, MSG(SETEOF_ERROR), drc);
- return RC_FX;
- } // endif error
-#else // !WIN32
- if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) {
- sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
- return RC_FX;
- } // endif
-#endif // !WIN32
- } else // MaxBlk
- // Clean the unused space in the file, this is required when
- // inserting again with a partial column list.
- if (CleanUnusedSpace(g))
- return RC_FX;
-
- if (ResetTableSize(g, Block, Last))
- return RC_FX;
-
- } // endif UseTemp
-
- } // endif irc
-
- return RC_OK; // All is correct
- } // end of DeleteRecords
-
-/***********************************************************************/
-/* Open a temporary file used while updating or deleting. */
-/***********************************************************************/
-bool BGVFAM::OpenTempFile(PGLOBAL g)
- {
- char *tempname;
- PDBUSER dup = PlgGetUser(g);
-
- /*********************************************************************/
- /* Open the temporary file, Spos is at the beginning of file. */
- /*********************************************************************/
- tempname = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
- PlugSetPath(tempname, To_File, Tdbp->GetPath());
- strcat(PlugRemoveType(tempname, tempname), ".t");
-
- if (!MaxBlk)
- remove(tempname); // Be sure it does not exist yet
- else if (MakeEmptyFile(g, tempname))
- return true;
-
-#if defined(WIN32)
- DWORD access = (MaxBlk) ? OPEN_EXISTING : CREATE_NEW;
-
- Tfile = CreateFile(tempname, GENERIC_WRITE, 0, NULL,
- access, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (Tfile == INVALID_HANDLE_VALUE) {
- DWORD rc = GetLastError();
- sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_DELETE, tempname);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)tempname, _MAX_PATH, NULL);
- strcat(g->Message, tempname);
- return true;
- } // endif Tfile
-#else // UNIX
- int oflag = (MaxBlk) ? O_WRONLY : O_WRONLY | O_TRUNC;
-
- Tfile = open64(tempname, oflag, S_IWRITE);
-
- if (Tfile == INVALID_HANDLE_VALUE) {
- int rc = errno;
- sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
- strcat(g->Message, strerror(errno));
- return true;
- } //endif Tfile
-#endif // UNIX
-
- To_Fbt = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
- To_Fbt->Fname = tempname;
- To_Fbt->Type = TYPE_FB_HANDLE;
- To_Fbt->Memory = NULL;
- To_Fbt->Length = 0;
- To_Fbt->File = NULL;
- To_Fbt->Next = dup->Openlist;
- To_Fbt->Count = 1;
- To_Fbt->Mode = MODE_INSERT;
- To_Fbt->Handle = Tfile;
- dup->Openlist = To_Fbt;
- return false;
- } // end of OpenTempFile
-
-/***********************************************************************/
-/* Move intermediate deleted or updated lines. */
-/***********************************************************************/
-bool BGVFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
- {
- int i, n, req, dep;
- bool eof = (b) ? *b : false;
- BIGINT pos;
-
- for (n = Fpos - Spos; n > 0 || eof; n -= req) {
- /*******************************************************************/
- /* Non consecutive line to delete. Move intermediate lines. */
- /*******************************************************************/
- if (!MaxBlk)
- req = (DWORD)min(n, Nrec - max(Spos % Nrec, Tpos % Nrec));
- else
- req = (DWORD)min(n, Nrec);
-
- if (req) for (i = 0; i < Ncol; i++) {
- if (!MaxBlk) {
- if (UseTemp)
- To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
-
- pos = (BIGINT)Deplac[i] + (BIGINT)((Spos % Nrec) * Clens[i])
- + (BIGINT)(Spos / Nrec) * (BIGINT)Blksize;
- } else
- pos = BigDep[i] + (BIGINT)Spos * (BIGINT)Clens[i];
-
- if (BigSeek(g, Hfile, pos))
- return true;
-
- if (BigRead(g, Hfile, To_Buf, req * Clens[i]))
- return true;
-
- if (!UseTemp || MaxBlk) {
- if (!MaxBlk)
- pos = (BIGINT)Deplac[i] + (BIGINT)((Tpos % Nrec) * Clens[i])
- + (BIGINT)(Tpos / Nrec) * (BIGINT)Blksize;
- else
- pos = BigDep[i] + (BIGINT)Tpos * (BIGINT)Clens[i];
-
- if (BigSeek(g, Tfile, pos))
- return true;
-
- if (BigWrite(g, Tfile, To_Buf, req * Clens[i]))
- return true;
-
- } // endif UseTemp
-
- } // endfor i
-
- Tpos += (int)req;
- Spos += (int)req;
-
- if (UseTemp && !MaxBlk && (!(Tpos % Nrec) || (eof && Spos == Fpos))) {
- // Write the full or last block to the temporary file
- if ((dep = Nrec - (Tpos % Nrec)) < Nrec)
- // Clean the last block in case of future insert, must be
- // done here because Tfile was open in write only.
- for (i = 0; i < Ncol; i++) {
- To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
- memset(To_Buf, (Isnum[i]) ? 0 : ' ', dep * Clens[i]);
- } // endfor i
-
- if (BigWrite(g, Tfile, NewBlock, Blksize))
- return true;
-
- if (Spos == Fpos)
- eof = false;
-
- } // endif Usetemp...
-
-#ifdef DEBTRACE
- htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
-#endif
- } // endfor n
-
- return false;
- } // end of MoveIntermediateLines
-
-/***********************************************************************/
-/* Clean deleted space in a huge VCT or Vec table file. */
-/***********************************************************************/
-bool BGVFAM::CleanUnusedSpace(PGLOBAL g)
- {
- int i;
- int n;
- BIGINT pos, dep;
-
- if (!MaxBlk) {
- /*******************************************************************/
- /* Clean last block of the VCT table file. */
- /*******************************************************************/
- assert(!UseTemp); // This case is handled in MoveIntermediateLines
-
- if (!(n = Nrec - Last))
- return false;
-
- dep = (BIGINT)((Block - 1) * Blksize);
-
- for (i = 0; i < Ncol; i++) {
- memset(To_Buf, (Isnum[i]) ? 0 : ' ', n * Clens[i]);
- pos = dep + (BIGINT)(Deplac[i] + Last * Clens[i]);
-
- if (BigSeek(g, Hfile, pos))
- return true;
-
- if (BigWrite(g, Hfile, To_Buf, n * Clens[i]))
- return true;
-
- } // endfor i
-
- } else {
- int req;
-
- memset(To_Buf, 0, Buflen);
-
- for (n = Fpos - Tpos; n > 0; n -= req) {
- /*****************************************************************/
- /* Fill VEC file remaining lines with 0's. */
- /* This seems to work even column blocks have been made with */
- /* Blanks = true. Perhaps should it be set to false for VEC. */
- /*****************************************************************/
- req = min(n, Nrec);
-
- for (i = 0; i < Ncol; i++) {
- pos = BigDep[i] + (BIGINT)Tpos * (BIGINT)Clens[i];
-
- if (BigSeek(g, Tfile, pos))
- return true;
-
- if (BigWrite(g, Tfile, To_Buf, req * Clens[i]))
- return true;
-
- } // endfor i
-
- Tpos += req;
- } // endfor n
-
- } // endif MaxBlk
-
- return false;
- } // end of CleanUnusedSpace
-
-/***********************************************************************/
-/* Data Base close routine for huge VEC access method. */
-/***********************************************************************/
-void BGVFAM::CloseTableFile(PGLOBAL g)
- {
- int rc, wrc = RC_OK;
- MODE mode = Tdbp->GetMode();
-
- if (mode == MODE_INSERT) {
- if (Closing)
- wrc = RC_FX; // Last write was in error
- else
- if (CurNum) {
- // Some more inserted lines remain to be written
- Last = CurNum;
- Block = CurBlk + 1;
- Closing = true;
- wrc = WriteBuffer(g);
- } else {
- Last = Nrec;
- Block = CurBlk;
- wrc = RC_OK;
- } // endif CurNum
-
- if (wrc != RC_FX) {
- rc = ResetTableSize(g, Block, Last);
- } else if (AddBlock) {
- // Last block was not written
- rc = ResetTableSize(g, CurBlk, Nrec);
- longjmp(g->jumper[g->jump_level], 44);
- } // endif
-
- } else if (mode == MODE_UPDATE) {
- // Write back to file any pending modifications
- for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->GetSetCols();
- colp; colp = (PVCTCOL)colp->Next)
- colp->WriteBlock(g);
-
- if (UseTemp && Tfile) {
- rc = RenameTempFile(g);
- Hfile = Tfile = INVALID_HANDLE_VALUE;
-
- if (Header)
- // Header must be set because it was not set in temp file
- rc = SetBlockInfo(g);
-
- } // endif UseTemp
-
- } else if (mode == MODE_DELETE && UseTemp && Tfile) {
- if (MaxBlk)
- rc = CleanUnusedSpace(g);
-
- if ((rc = RenameTempFile(g)) != RC_FX) {
- Hfile = Tfile = INVALID_HANDLE_VALUE; // For SetBlockInfo
- rc = ResetTableSize(g, Block, Last);
- } // endif rc
-
- } // endif's mode
-
- if (Hfile != INVALID_HANDLE_VALUE)
- rc = PlugCloseFile(g, To_Fb);
-
-#ifdef DEBTRACE
- htrc("BGV CloseTableFile: closing %s wrc=%d rc=%d\n",
- To_File, wrc, rc);
-#endif
- Hfile = INVALID_HANDLE_VALUE;
- } // end of CloseDB
-
-/***********************************************************************/
-/* Rewind routine for huge VCT access method. */
-/***********************************************************************/
-void BGVFAM::Rewind(void)
- {
- // In mode update we need to read Set Column blocks
- if (Tdbp->GetMode() == MODE_UPDATE)
- OldBlk = -1;
-
- // Initialize so block optimization is called for 1st block
- CurBlk = -1;
- CurNum = Nrec - 1;
-
-#if 0 // This is probably unuseful as the file is directly accessed
-#if defined(WIN32) //OB
- SetFilePointer(Hfile, 0, NULL, FILE_BEGIN);
-#else // UNIX
- lseek64(Hfile, 0, SEEK_SET);
-#endif // UNIX
-#endif // 0
- } // end of Rewind
-
-/***********************************************************************/
-/* ReadBlock: Read column values from current block. */
-/***********************************************************************/
-bool BGVFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
- {
- BIGINT pos;
-
- /*********************************************************************/
- /* Calculate the offset and size of the block to read. */
- /*********************************************************************/
- if (MaxBlk) // File has Vector format
- pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac * (BIGINT)MaxBlk
- + (BIGINT)colp->Clen * (BIGINT)CurBlk) + (BIGINT)Headlen;
- else // Old VCT format
- pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac
- + (BIGINT)Lrecl * (BIGINT)CurBlk);
-
-#ifdef DEBTRACE
- fprintf(debug,
- "RB: offset=%lf Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d MaxBlk=%d\n",
- (double)pos, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk);
-#endif
-
- if (BigSeek(g, Hfile, pos))
- return true;
-
- if (BigRead(g, Hfile, colp->Blk->GetValPointer(), colp->Clen * Nrec))
- return true;
-
-#ifdef DEBTRACE
- num_read++;
-#endif
- return false;
- } // 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. */
-/***********************************************************************/
-bool BGVFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
- {
- int len;
- BIGINT pos;
-
- /*********************************************************************/
- /* Calculate the offset and size of the block to write. */
- /*********************************************************************/
- if (MaxBlk) // File has Vector format
- pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac * (BIGINT)MaxBlk
- + (BIGINT)colp->Clen * (BIGINT)colp->ColBlk) + (BIGINT)Headlen;
- else // Old VCT format
- pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac
- + (BIGINT)Lrecl * (BIGINT)colp->ColBlk);
-
-#ifdef DEBTRACE
- htrc("WB: offset=%lf Nrec=%d Deplac=%d Lrecl=%d ColBlk=%d\n",
- (double)pos, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
-#endif
-
- if (BigSeek(g, Tfile, pos))
- return true;
-
-//len = colp->Clen * Nrec; see comment in VCTFAM
- len = colp->Clen * ((Tdbp->GetMode() == MODE_INSERT) ? CurNum : Nrec);
-
- if (BigWrite(g, Tfile, colp->Blk->GetValPointer(), len))
- return true;
-
- return false;
- } // end of WriteBlock
-
-/* ----------------------- End of FilAMVct --------------------------- */
+/*********** File AM Vct C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMVCT */
+/* ------------- */
+/* Version 2.4 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the VCT file access method classes. */
+/* Added in version 2: */
+/* - Split Vec format. */
+/* - Partial delete. */
+/* - Use of tempfile for update. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* 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 // __BORLAND__
+//#include <windows.h>
+#include <sys/stat.h>
+#else // !WIN32
+#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 // !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 "osutil.h" // Unuseful for WIN32
+#include "plgdbsem.h"
+#include "valblk.h"
+#include "filamfix.h"
+#include "tabdos.h"
+#include "tabvct.h"
+#include "maputil.h"
+#include "filamvct.h"
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+extern int num_read, num_there; // Statistics
+static int num_write;
+
+#if defined(UNIX)
+// Add dummy strerror (NGC)
+char *strerror(int num);
+#endif // UNIX
+
+/***********************************************************************/
+/* Header containing block info for not split VEC tables. */
+/* Block and last values can be calculated from NumRec and Nrec. */
+/* This is better than directly storing Block and Last because it */
+/* make possible to use the same file with tables having a different */
+/* block size value (Element -> Nrec) */
+/* Note: can be in a separate file if header=1 or a true header (2) */
+/***********************************************************************/
+typedef struct _vecheader {
+//int Block; /* The number of used blocks */
+//int Last; /* The number of used records in last block */
+ int MaxRec; /* Max number of records (True vector format)*/
+ int NumRec; /* Number of valid records in the table */
+ } VECHEADER;
+
+/***********************************************************************/
+/* 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);
+bool PushWarning(PGLOBAL, PTDBASE);
+
+/* -------------------------- Class VCTFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VCTFAM class. */
+/***********************************************************************/
+VCTFAM::VCTFAM(PVCTDEF tdp) : FIXFAM((PDOSDEF)tdp)
+ {
+ Last = tdp->GetLast();
+ MaxBlk = (tdp->GetEstimate() > 0) ?
+ ((tdp->GetEstimate() - 1) / Nrec + 1) : 0;
+ NewBlock = NULL;
+ AddBlock = false;
+ Split = false;
+
+ if ((Header = (MaxBlk) ? tdp->Header : 0))
+ Block = Last = -1;
+
+ Bsize = Nrec;
+ CurNum = Nrec - 1;
+ Colfn = NULL;
+ Tempat = NULL;
+ Clens = NULL;
+ Deplac = NULL;
+ Isnum = NULL;
+ Ncol = 0;
+ } // end of VCTFAM standard constructor
+
+VCTFAM::VCTFAM(PVCTFAM txfp) : FIXFAM(txfp)
+ {
+ MaxBlk = txfp->MaxBlk;
+ NewBlock = NULL;
+ AddBlock = false;
+ Split = txfp->Split;
+ Header = txfp->Header;
+ Bsize = txfp->Bsize;
+ Colfn = txfp->Colfn;
+ Tempat = txfp->Tempat;
+ Clens = txfp->Clens;
+ Deplac = txfp->Deplac;
+ Isnum = txfp->Isnum;
+ Ncol = txfp->Ncol;
+ } // end of VCTFAM copy constructor
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void VCTFAM::Reset(void)
+ {
+ FIXFAM::Reset();
+ NewBlock = NULL;
+ AddBlock = false;
+ CurNum = Nrec - 1;
+ } // end of Reset
+
+/***********************************************************************/
+/* Get the Headlen, Block and Last info from the file header. */
+/***********************************************************************/
+int VCTFAM::GetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int k, n;
+ VECHEADER vh;
+ FILE *s;
+
+ if (Header < 1 || Header > 3 || !MaxBlk) {
+ sprintf(g->Message, "Invalid header value %d", Header);
+ return -1;
+ } else
+ n = (Header == 1) ? (int)sizeof(VECHEADER) : 0;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header == 2)
+ strcat(PlugRemoveType(filename, filename), ".blk");
+
+ if (!(s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb"))) {
+ // Consider this is a void table
+ Last = Nrec;
+ Block = 0;
+ return n;
+ } else if (Header == 3)
+ k = fseek(s, -(int)sizeof(VECHEADER), SEEK_END);
+
+ if (fread(&vh, sizeof(vh), 1, s) != 1) {
+ sprintf(g->Message, "Error reading header file %s", filename);
+ n = -1;
+ } else if (MaxBlk * Nrec != vh.MaxRec) {
+ sprintf(g->Message, "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d",
+ vh.MaxRec, MaxBlk, Nrec);
+ n = -1;
+ } else {
+ Block = (vh.NumRec > 0) ? (vh.NumRec + Nrec - 1) / Nrec : 0;
+ Last = (vh.NumRec + Nrec - 1) % Nrec + 1;
+ } // endif s
+
+ fclose(s);
+ return n;
+ } // end of GetBlockInfo
+
+/***********************************************************************/
+/* Get the Headlen, Block and Last info from the file header. */
+/***********************************************************************/
+bool VCTFAM::SetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool rc = false;
+ int k;
+ size_t n;
+ VECHEADER vh;
+ FILE *s;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header != 2) {
+ if (Stream) {
+ s = Stream;
+
+ if (Header == 1)
+ k = fseek(s, 0, SEEK_SET);
+
+ } else
+ s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r+b");
+
+ } else { // Header == 2
+ strcat(PlugRemoveType(filename, filename), ".blk");
+ s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "wb");
+ } // endif Header
+
+ if (!s) {
+ sprintf(g->Message, "Error opening header file %s", filename);
+ return true;
+ } else if (Header == 3)
+ k = fseek(s, -(int)sizeof(VECHEADER), SEEK_END);
+
+ vh.MaxRec = MaxBlk * Bsize;
+ vh.NumRec = (Block - 1) * Nrec + Last;
+
+ if ((n = fwrite(&vh, sizeof(vh), 1, s)) != 1) {
+ sprintf(g->Message, "Error writing header file %s", filename);
+ rc = true;
+ } // endif fread
+
+ if (Header == 2 || !Stream)
+ fclose(s);
+
+ return rc;
+ } // end of SetBlockInfo
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/***********************************************************************/
+int VCTFAM::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
+
+/***********************************************************************/
+/* VCT 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 VCTFAM::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 1;
+
+ if (Block < 0)
+ if (Split) {
+ // Separate column files and no pre setting of Block and Last
+ // This allows to see a table modified externally, but Block
+ // and Last must be set from the file cardinality.
+ // Only happens when called by sub classes.
+ char filename[_MAX_PATH];
+ PSZ savfn = To_File;
+ int len, clen, card = -1;
+ PCOLDEF cdp = Tdbp->GetDef()->GetCols();
+
+ if (!Colfn) {
+ // Prepare the column file name pattern
+ Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
+ } // endif Colfn
+
+ // Use the first column file to calculate the cardinality
+ clen = cdp->GetClen();
+ sprintf(filename, Colfn, 1);
+ To_File = filename;
+ len = GetFileLength(g);
+ To_File = savfn;
+
+ if (len >= 0) {
+ if (!(len % clen))
+ card = len / clen; // Fixed length file
+ else
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, clen);
+
+#ifdef DEBTRACE
+ htrc(" Computed max_K=%d Filen=%d Clen=%d\n",
+ card, len, clen);
+#endif
+ } else
+ card = 0;
+
+ // Set number of blocks for later use
+ Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
+ Last = (card + Nrec - 1) % Nrec + 1;
+ return card;
+ } else {
+ // Vector table having Block and Last info in a Header (file)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return -1; // Error
+
+ } // endif split
+
+ return (int)((Block - 1) * Nrec + Last);
+ } // end of Cardinality
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int VCTFAM::GetRowID(void)
+ {
+ return 1 + ((CurBlk < Block) ? CurNum + Nrec * CurBlk
+ : (Block - 1) * Nrec + Last);
+ } // end of GetRowID
+
+/***********************************************************************/
+/* VCT Create an empty file for Vector formatted tables. */
+/***********************************************************************/
+bool VCTFAM::MakeEmptyFile(PGLOBAL g, char *fn)
+ {
+ // Vector formatted file: this will create an empty file of the
+ // required length if it does not exists yet.
+ char filename[_MAX_PATH], c = 0;
+ int h, n;
+
+ PlugSetPath(filename, fn, Tdbp->GetPath());
+#if defined(WIN32)
+ h= global_open(g, MSGID_OPEN_EMPTY_FILE, filename, _O_CREAT | _O_WRONLY, S_IREAD | S_IWRITE);
+#else // !WIN32
+ h= global_open(g, MSGID_OPEN_EMPTY_FILE, filename, O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
+#endif // !WIN32
+
+ if (h == -1)
+ return true;
+
+ n = (Header == 1 || Header == 3) ? sizeof(VECHEADER) : 0;
+
+ if (lseek(h, n + MaxBlk * Nrec * Lrecl - 1, SEEK_SET) == -1) {
+ sprintf(g->Message, MSG(MAKE_EMPTY_FILE), To_File, strerror(errno));
+ close(h);
+ return true;
+ } // endif h
+
+ write(h, &c, 1); // This actually fills the empty file
+ close(h);
+ return false;
+ } // end of MakeEmptyFile
+
+/***********************************************************************/
+/* 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 VCTFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4], filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Update block info if necessary. */
+ /*********************************************************************/
+ if (Block < 0)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return true;
+
+ /*********************************************************************/
+ /* Open according to input/output mode required. */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "rb");
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ // This will delete the whole file
+ strcpy(opmode, "wb");
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ strcpy(opmode, (UseTemp) ? "rb" : "r+b");
+ break;
+ case MODE_INSERT:
+ if (MaxBlk) {
+ if (!Block)
+ if (MakeEmptyFile(g, To_File))
+ return true;
+
+ strcpy(opmode, "r+b"); // Required to update empty blocks
+ } else if (Last == Nrec)
+ strcpy(opmode, "ab");
+ else
+ strcpy(opmode, "r+b"); // Required to update the last block
+
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ /*********************************************************************/
+ /* Use conventionnal input/output functions. */
+ /*********************************************************************/
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream = PlugOpenFile(g, filename, opmode))) {
+#ifdef DEBTRACE
+ htrc("%s\n", g->Message);
+#endif
+ return (mode == MODE_READ && 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
+
+ if (!strcmp(opmode, "wb"))
+ // This will stop the process by
+ // causing GetProgMax to return 0.
+ return ResetTableSize(g, 0, Nrec);
+
+ num_read = num_there = num_write = 0;
+
+ // Allocate the table and column block buffer
+ return AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/***********************************************************************/
+bool VCTFAM::AllocateBuffer(PGLOBAL g)
+ {
+ MODE mode = Tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+ PCOLDEF cdp;
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (mode == MODE_INSERT) {
+ bool chk = PlgGetUser(g)->Check & CHK_TYPE;
+
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ memset(NewBlock + Nrec * cdp->GetPoff(),
+ (IsTypeNum(cdp->GetType()) ? 0 : ' '),
+ Nrec * cdp->GetClen());
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->Blk = AllocValBlock(g, NewBlock + Nrec * cp->Deplac,
+ cp->Buf_Type, Nrec, cp->Format.Length,
+ cp->Format.Prec, chk);
+
+ return InitInsert(g); // Initialize inserting
+ } else {
+ if (UseTemp || mode == MODE_DELETE) {
+ // Allocate all that is needed to move lines
+ int i = 0, n = (MaxBlk) ? MaxBlk : 1;
+
+ if (!Ncol)
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ Ncol++;
+
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Deplac = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
+
+ for (cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext()) {
+ Clens[i] = cdp->GetClen();
+ Deplac[i] = Headlen + cdp->GetPoff() * n * Nrec;
+ Isnum[i] = IsTypeNum(cdp->GetType());
+ Buflen = max(Buflen, cdp->GetClen());
+ } // endfor cdp
+
+ if (!UseTemp || MaxBlk) {
+ Buflen *= Nrec;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+ } else
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ } // endif mode
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) // Not a pseudo column
+ cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec);
+
+ } //endif mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Do initial action when inserting. */
+/***********************************************************************/
+bool VCTFAM::InitInsert(PGLOBAL g)
+ {
+ // We come here in MODE_INSERT only
+ if (Last == Nrec) {
+ CurBlk = Block;
+ CurNum = 0;
+ AddBlock = !MaxBlk;
+ } else {
+ int rc;
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ // The starting point must be at the end of file as for append.
+ CurBlk = Block - 1;
+ CurNum = Last;
+
+ // Prepare error return
+ if (g->jump_level == MAX_JUMP) {
+ strcpy(g->Message, MSG(TOO_MANY_JUMPS));
+ return true;
+ } // endif
+
+ if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) {
+ g->jump_level--;
+ return true;
+ } // endif
+
+ // Last block must be updated by new values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->ReadBlock(g);
+
+ g->jump_level--;
+ } // endif Last
+
+ // We are not currently using a temporary file for Insert
+ T_Stream = Stream;
+ return false;
+ } // end of InitInsert
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a VCT file. */
+/***********************************************************************/
+int VCTFAM::ReadBuffer(PGLOBAL g)
+ {
+ int rc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ if (Placed)
+ Placed = false;
+ else if ((++CurNum) >= ((CurBlk < Block - 1) ? Nrec : Last)) {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ if (++CurBlk == Block)
+ return RC_EF; // End of file
+
+ num_there++;
+ } // endif CurNum
+
+ if (OldBlk != CurBlk) {
+ if (mode == MODE_UPDATE) {
+ /*****************************************************************/
+ /* Flush the eventually modified column buffers in old blocks */
+ /* and read the blocks to modify attached to Set columns. */
+ /*****************************************************************/
+ if (MoveLines(g)) // For VECFAM
+ return RC_FX;
+
+ for (PVCTCOL colp = (PVCTCOL)Tdbp->GetSetCols();
+ colp; colp = (PVCTCOL)colp->Next) {
+ colp->WriteBlock(g);
+ colp->ReadBlock(g);
+ } // endfor colp
+
+ } // endif mode
+
+ OldBlk = CurBlk; // Last block actually read
+ } // endif oldblk
+
+#ifdef DEBTRACE
+ htrc(" Read: CurNum=%d CurBlk=%d rc=%d\n",
+ CurNum, CurBlk, RC_OK);
+#endif
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Data Base write routine for VCT access method. */
+/***********************************************************************/
+int VCTFAM::WriteBuffer(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+#endif
+
+ if (Tdbp->GetMode() == MODE_UPDATE) {
+ // Mode Update is done in ReadDB, we just initialize it here
+ if (!T_Stream) {
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ // Most of the time, not all table columns are updated.
+ // This why we must completely pre-fill the temporary file.
+ Fpos = (MaxBlk) ? (Block - 1) * Nrec + Last
+ : Block * Nrec; // To write last lock
+
+ if (MoveIntermediateLines(g))
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ } // endif T_Stream
+
+ } else {
+ // Mode Insert
+ if (MaxBlk && CurBlk == MaxBlk) {
+ strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
+ return RC_EF; // Too many lines for vector formatted table
+ } // endif MaxBlk
+
+ if (Closing || ++CurNum == Nrec) {
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (!AddBlock) {
+ // Write back the updated last block values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->WriteBlock(g);
+
+ if (!Closing && !MaxBlk) {
+ // For VCT tables, future blocks must be added
+ char filename[_MAX_PATH];
+
+ // Close the file and reopen it in mode Insert
+ fclose(Stream);
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "ab"))) {
+ Closing = true; // Tell CloseDB of error
+ return RC_FX;
+ } // endif Stream
+
+ AddBlock = true;
+ } // endif Closing
+
+ } else {
+ // Here we must add a new block to the file
+ if (Closing)
+ // Reset the overwritten columns for last block extra records
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ memset(NewBlock + Nrec * cp->Deplac + Last * cp->Clen,
+ (cp->Buf_Type == TYPE_STRING) ? ' ' : '\0',
+ (Nrec - Last) * cp->Clen);
+
+ if ((size_t)Nrec !=
+ fwrite(NewBlock, (size_t)Lrecl, (size_t)Nrec, Stream)) {
+ sprintf(g->Message, MSG(WRITE_STRERROR), To_File, strerror(errno));
+ return RC_FX;
+ } // endif
+
+ } // endif AddBlock
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+ } // endif Closing
+
+ } // endif Closing || CurNum
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for VCT access method. */
+/* Note: lines are moved directly in the files (ooops...) */
+/* Using temp file depends on the Check setting, false by default. */
+/***********************************************************************/
+int VCTFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool eof = false;
+#ifdef DEBTRACE
+ fprintf(debug,
+ "VCT DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+#endif
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+#ifdef DEBTRACE
+ htrc("Fpos placed at file end=%d\n", Fpos);
+#endif
+ eof = UseTemp && !MaxBlk;
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* First line to delete. Move of eventual preceeding lines is */
+ /* not required here, just the setting of future Spos and Tpos. */
+ /*****************************************************************/
+ T_Stream = Stream;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &eof))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ /*******************************************************************/
+ /* Reposition the file pointer and set Spos. */
+ /*******************************************************************/
+#ifdef DEBTRACE
+ assert(Spos == Fpos);
+#endif
+ Spos++; // New start position is on next line
+
+#ifdef DEBTRACE
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /* Update the Block and Last values. */
+ /*******************************************************************/
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (!UseTemp) { // The UseTemp case is treated in CloseTableFile
+ if (!MaxBlk) {
+ /***************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS ??) this is still to be */
+ /* checked for compatibility with Text files and other OS's. */
+ /***************************************************************/
+ char filename[_MAX_PATH];
+ int rc, h;
+
+ rc = CleanUnusedSpace(g); // Clean last block
+ rc = PlugCloseFile(g, To_Fb);
+ Stream = NULL; // For SetBlockInfo
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /***************************************************************/
+ /* Remove extra blocks. */
+ /***************************************************************/
+#if defined(UNIX)
+ if (ftruncate(h, (off_t)(Headlen + Block * Blksize))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (chsize(h, Headlen + Block * Blksize)) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+#ifdef DEBTRACE
+ htrc("done, h=%d irc=%d\n", h, irc);
+#endif
+ } else
+ // Clean the unused space in the file, this is required when
+ // inserting again with a partial column list.
+ if (CleanUnusedSpace(g))
+ return RC_FX;
+
+ if (ResetTableSize(g, Block, Last))
+ return RC_FX;
+
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool VCTFAM::OpenTempFile(PGLOBAL g)
+ {
+ char *opmode, tempname[_MAX_PATH];
+ bool rc = false;
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+
+ if (MaxBlk) {
+ if (MakeEmptyFile(g, tempname))
+ return true;
+
+ opmode = "r+b";
+ } else
+ opmode = "wb";
+
+ if (!(T_Stream = PlugOpenFile(g, tempname, opmode))) {
+#ifdef DEBTRACE
+ htrc("%s\n", g->Message);
+#endif
+ rc = true;
+ } else
+ To_Fbt = PlgGetUser(g)->Openlist;
+
+ return rc;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int i, dep, off;
+ int n;
+ bool eof = (b) ? *b : false;
+ size_t req, len;
+
+ for (n = Fpos - Spos; n > 0 || eof; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!MaxBlk)
+ req = (size_t)min(n, Nrec - max(Spos % Nrec, Tpos % Nrec));
+ else
+ req = (size_t)min(n, Nrec);
+
+ if (req) for (i = 0; i < Ncol; i++) {
+ if (MaxBlk) {
+ dep = Deplac[i];
+ off = Spos * Clens[i];
+ } else {
+ if (UseTemp)
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+
+ dep = Deplac[i] + (Spos / Nrec) * Blksize;
+ off = (Spos % Nrec) * Clens[i];
+ } // endif MaxBlk
+
+ if (fseek(Stream, dep + off, SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ len = fread(To_Buf, Clens[i], req, Stream);
+
+#ifdef DEBTRACE
+ htrc("after read req=%d len=%d\n", req, len);
+#endif
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
+ return true;
+ } // endif len
+
+ if (!UseTemp || MaxBlk) {
+ if (MaxBlk) {
+ dep = Deplac[i];
+ off = Tpos * Clens[i];
+ } else {
+ dep = Deplac[i] + (Tpos / Nrec) * Blksize;
+ off = (Tpos % Nrec) * Clens[i];
+ } // endif MaxBlk
+
+ if (fseek(T_Stream, dep + off, SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ } // endif UseTemp
+
+#ifdef DEBTRACE
+ htrc("after write pos=%d\n", ftell(Stream));
+#endif
+ } // endfor i
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (UseTemp && !MaxBlk && (Tpos % Nrec == 0 || (eof && Spos == Fpos))) {
+ // Write the full or last block to the temporary file
+ if ((dep = Nrec - (Tpos % Nrec)) < Nrec)
+ // Clean the last block in case of future insert,
+ // must be done here because T_Stream was open in write only.
+ for (i = 0; i < Ncol; i++) {
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', dep * Clens[i]);
+ } // endfor i
+
+ // Write a new block in the temporary file
+ len = (size_t)Blksize;
+
+ if (fwrite(NewBlock, 1, len, T_Stream) != len) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ if (Spos == Fpos)
+ eof = false;
+
+ } // endif UseTemp
+
+#ifdef DEBTRACE
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediateLines
+
+/***********************************************************************/
+/* Clean deleted space in a VCT or Vec table file. */
+/***********************************************************************/
+bool VCTFAM::CleanUnusedSpace(PGLOBAL g)
+ {
+ int i, dep;
+ int n;
+ size_t req, len;
+
+ if (!MaxBlk) {
+ /*******************************************************************/
+ /* Clean last block of the VCT table file. */
+ /*******************************************************************/
+ assert(!UseTemp);
+
+ if (!(n = Nrec - Last))
+ return false;
+
+ dep = (Block - 1) * Blksize;
+ req = (size_t)n;
+
+ for (i = 0; i < Ncol; i++) {
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', n * Clens[i]);
+
+ if (fseek(Stream, dep + Deplac[i] + Last * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ } // endfor i
+
+ } else for (n = Fpos - Tpos; n > 0; n -= req) {
+ /*******************************************************************/
+ /* Fill VEC file remaining lines with 0's. */
+ /* Note: this seems to work even column blocks have been made */
+ /* with Blanks = true. Perhaps should it be set to false for VEC. */
+ /*******************************************************************/
+ req = (size_t)min(n, Nrec);
+ memset(To_Buf, 0, Buflen);
+
+ for (i = 0; i < Ncol; i++) {
+ if (fseek(T_Stream, Deplac[i] + Tpos * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ } // endfor i
+
+ Tpos += (int)req;
+ } // endfor n
+
+ return false;
+ } // end of CleanUnusedSpace
+
+/***********************************************************************/
+/* Data Base close routine for VCT access method. */
+/***********************************************************************/
+void VCTFAM::CloseTableFile(PGLOBAL g)
+ {
+ int rc, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ if (mode == MODE_INSERT) {
+ if (Closing)
+ wrc = RC_FX; // Last write was in error
+ else
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last = CurNum;
+ Block = CurBlk + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Last = Nrec;
+ Block = CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ if (wrc != RC_FX) {
+ rc = ResetTableSize(g, Block, Last);
+ } else if (AddBlock) {
+ // Last block was not written
+ rc = ResetTableSize(g, CurBlk, Nrec);
+ longjmp(g->jumper[g->jump_level], 44);
+ } // endif
+
+ } else if (mode == MODE_UPDATE) {
+ // Write back to file any pending modifications
+ for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols;
+ colp; colp = (PVCTCOL)colp->Next)
+ colp->WriteBlock(g);
+
+ if (UseTemp && T_Stream) {
+ rc = RenameTempFile(g);
+
+ if (Header) {
+ // Header must be set because it was not set in temp file
+ Stream = T_Stream = NULL; // For SetBlockInfo
+ rc = SetBlockInfo(g);
+ } // endif Header
+
+ } // endif UseTemp
+
+ } else if (mode == MODE_DELETE && UseTemp && T_Stream) {
+ if (MaxBlk)
+ rc = CleanUnusedSpace(g);
+
+ if ((rc = RenameTempFile(g)) != RC_FX) {
+ Stream = T_Stream = NULL; // For SetBlockInfo
+ rc = ResetTableSize(g, Block, Last);
+ } // endif rc
+
+ } // endif's mode
+
+ if (!(UseTemp && T_Stream))
+ rc = PlugCloseFile(g, To_Fb);
+
+#ifdef DEBTRACE
+ htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n",
+ To_File, wrc, rc);
+#endif
+ Stream = NULL;
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Data Base close routine for VCT access method. */
+/***********************************************************************/
+bool VCTFAM::ResetTableSize(PGLOBAL g, int block, int last)
+ {
+ bool rc = false;
+
+ // Set Block and Last values for TDBVCT::MakeBlockValues
+ Block = block;
+ Last = last;
+
+ if (!Split) {
+ if (!Header) {
+ // Update catalog values for Block and Last
+ PVCTDEF defp = (PVCTDEF)Tdbp->GetDef();
+ LPCSTR name = Tdbp->GetName();
+ PCATLG cat = PlgGetCatalog(g);
+
+ defp->SetBlock(Block);
+ defp->SetLast(Last);
+
+ if (!cat->SetIntCatInfo(name, "Blocks", Block) ||
+ !cat->SetIntCatInfo(name, "Last", Last)) {
+ sprintf(g->Message, MSG(UPDATE_ERROR), "Header");
+ rc = true;
+ } // endif
+
+ } else
+ rc = SetBlockInfo(g);
+
+ } // endif Split
+
+ Tdbp->ResetSize();
+ return rc;
+ } // end of ResetTableSize
+
+/***********************************************************************/
+/* Rewind routine for VCT access method. */
+/***********************************************************************/
+void VCTFAM::Rewind(void)
+ {
+ // In mode update we need to read Set Column blocks
+ if (Tdbp->GetMode() == MODE_UPDATE)
+ OldBlk = -1;
+
+ // Initialize so block optimization is called for 1st block
+ CurBlk = -1;
+ CurNum = Nrec - 1;
+//rewind(Stream); will be placed by fseek
+ } // end of Rewind
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool VCTFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to read. */
+ /*********************************************************************/
+ if (MaxBlk) // True vector format
+ len = Headlen + Nrec * (colp->Deplac * MaxBlk + colp->Clen * CurBlk);
+ else // Blocked vector format
+ len = Nrec * (colp->Deplac + Lrecl * CurBlk);
+
+#ifdef DEBTRACE
+ htrc("len=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d maxblk=%d\n",
+ len, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk);
+#endif
+
+ if (fseek(Stream, len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ n = fread(colp->Blk->GetValPointer(), (size_t)colp->Clen,
+ (size_t)Nrec, Stream);
+
+ if (n != (size_t)Nrec) {
+ if (errno == NO_ERROR)
+ sprintf(g->Message, MSG(BAD_READ_NUMBER), n, To_File);
+ else
+ sprintf(g->Message, MSG(READ_ERROR),
+ To_File, strerror(errno));
+
+#ifdef DEBTRACE
+ htrc(" Read error: %s\n", g->Message);
+#endif
+ return true;
+ } // endif
+
+#ifdef DEBTRACE
+ num_read++;
+#endif
+ return false;
+ } // 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. */
+/***********************************************************************/
+bool VCTFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ if (MaxBlk) // File has Vector format
+ len = Headlen
+ + Nrec * (colp->Deplac * MaxBlk + colp->Clen * colp->ColBlk);
+ else // Old VCT format
+ len = Nrec * (colp->Deplac + Lrecl * colp->ColBlk);
+
+#ifdef DEBTRACE
+ htrc("modif=%d len=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n",
+ Modif, len, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
+#endif
+
+ if (fseek(T_Stream, len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ // Here Nrec was changed to CurNum in mode Insert,
+ // this is the true number of records to write,
+ // this also avoid writing garbage in the file for true vector tables.
+ n = (Tdbp->GetMode() == MODE_INSERT) ? CurNum : Nrec;
+
+ if (n != fwrite(colp->Blk->GetValPointer(),
+ (size_t)colp->Clen, n, T_Stream)) {
+ sprintf(g->Message, MSG(WRITE_STRERROR),
+ (UseTemp) ? To_Fbt->Fname : To_File, strerror(errno));
+#ifdef DEBTRACE
+ htrc("Write error: %s\n", strerror(errno));
+#endif
+ return true;
+ } // endif
+
+#if defined(UNIX)
+ fflush(T_Stream); //NGC
+#endif
+
+#ifdef _DEBUG
+ num_write++;
+#endif
+
+ return false;
+ } // end of WriteBlock
+
+/* -------------------------- Class VCMFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VCMFAM class. */
+/***********************************************************************/
+VCMFAM::VCMFAM(PVCTDEF tdp) : VCTFAM((PVCTDEF)tdp)
+ {
+ Memory = NULL;
+ Memcol = NULL;
+ } // end of VCMFAM standard constructor
+
+VCMFAM::VCMFAM(PVCMFAM txfp) : VCTFAM(txfp)
+ {
+ Memory = txfp->Memory;
+ Memcol = txfp->Memcol;
+ } // end of VCMFAM copy constructor
+
+/***********************************************************************/
+/* Mapped 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 VCMFAM::OpenTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int len;
+ MODE mode = Tdbp->GetMode();
+ PFBLOCK fp = NULL;
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ /*********************************************************************/
+ /* Update block info if necessary. */
+ /*********************************************************************/
+ if (Block < 0)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return true;
+
+ /*********************************************************************/
+ /* We used the file name relative to recorded datapath. */
+ /*********************************************************************/
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ /*********************************************************************/
+ /* 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 VCM file, fp=%p cnt=%d\n", fp, fp->Count);
+#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;
+ MODE mapmode = mode;
+
+ if (mode == MODE_INSERT) {
+ if (MaxBlk) {
+ if (!Block)
+ if (MakeEmptyFile(g, To_File))
+ return true;
+
+ // Inserting will be like updating the file
+ mapmode = MODE_UPDATE;
+ } else {
+ strcpy(g->Message, "MAP Insert is for VEC Estimate tables only");
+ return true;
+ } // endif MaxBlk
+
+ } // endif mode
+
+ del = mode == MODE_DELETE && !Tdbp->GetNext();
+
+ if (del) {
+ DelRows = Cardinality(g);
+
+ // This will stop the process by causing GetProgMax to return 0.
+// ResetTableSize(g, 0, Nrec); must be done later
+ } // endif del
+
+ /*******************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************/
+ hFile = CreateFileMap(g, filename, &mm, mapmode, 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);
+ return ResetTableSize(g, 0, Nrec);
+ } // 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
+
+#ifdef DEBTRACE
+ htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n",
+ fp, fp->Count, Memory, len);
+#endif
+
+ return AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/* Give a dummy value (1) to prevent allocating the value block. */
+/* It will be set pointing into the memory map of the file. */
+/* Note: Memcol must be set for all columns because it can be used */
+/* for set columns in Update. Clens values are used only in Delete. */
+/***********************************************************************/
+bool VCMFAM::AllocateBuffer(PGLOBAL g)
+ {
+ int m, i = 0;
+ bool b = Tdbp->GetMode() == MODE_DELETE;
+ PVCTCOL cp;
+ PCOLDEF cdp;
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ // Calculate the number of columns
+ if (!Ncol)
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ Ncol++;
+
+ // To store the start position of each column
+ Memcol = (char**)PlugSubAlloc(g, NULL, Ncol * sizeof(char*));
+ m = (MaxBlk) ? MaxBlk : 1;
+
+ // We will need all column sizes and type for Delete
+ if (b) {
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
+ } // endif b
+
+ for (cdp = defp->GetCols(); i < Ncol; i++, cdp = cdp->GetNext()) {
+ if (b) {
+ Clens[i] = cdp->GetClen();
+ Isnum[i] = IsTypeNum(cdp->GetType());
+ } // endif b
+
+ Memcol[i] = Memory + Headlen + cdp->GetPoff() * m * Nrec;
+ } // endfor cdp
+
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) { // Not a pseudo column
+ cp->Blk = AllocValBlock(g, (void*)1, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec);
+ cp->AddStatus(BUF_MAPPED);
+ } // endif IsSpecial
+
+ if (Tdbp->GetMode() == MODE_INSERT)
+ return InitInsert(g);
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Do initial action when inserting. */
+/***********************************************************************/
+bool VCMFAM::InitInsert(PGLOBAL g)
+ {
+ int rc;
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ // We come here in MODE_INSERT only
+ if (Last == Nrec) {
+ CurBlk = Block;
+ CurNum = 0;
+ AddBlock = !MaxBlk;
+ } else {
+ // The starting point must be at the end of file as for append.
+ CurBlk = Block - 1;
+ CurNum = Last;
+ } // endif Last
+
+ // Prepare error return
+ if (g->jump_level == MAX_JUMP) {
+ strcpy(g->Message, MSG(TOO_MANY_JUMPS));
+ return true;
+ } // endif
+
+ if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) {
+ g->jump_level--;
+ return true;
+ } // endif
+
+ // Initialize the column block pointer
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->ReadBlock(g);
+
+ g->jump_level--;
+ return false;
+ } // end of InitInsert
+
+/***********************************************************************/
+/* Data Base write routine for VMP access method. */
+/***********************************************************************/
+int VCMFAM::WriteBuffer(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ htrc("VCM WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+#endif
+
+ // Mode Update being done in ReadDB we process here Insert mode only.
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ if (CurBlk == MaxBlk) {
+ strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
+ return RC_EF; // Too many lines for vector formatted table
+ } // endif MaxBlk
+
+ if (Closing || ++CurNum == Nrec) {
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ // Write back the updated last block values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->WriteBlock(g);
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+
+ // Re-initialize the column block pointer
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ cp->ReadBlock(g);
+
+ } // endif Closing
+
+ } // endif Closing || CurNum
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for VMP access method. */
+/* Lines between deleted lines are moved in the mapfile view. */
+/***********************************************************************/
+int VCMFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ int i;
+ int m, n;
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ "VCM DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n",
+ irc, To_Buf, Tpos, Spos);
+#endif
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the top of map position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+#ifdef DEBTRACE
+ htrc("Fpos placed at file top=%p\n", Fpos);
+#endif
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ 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 (Fpos > Spos) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!MaxBlk) {
+ // Old VCT format, moving must respect block limits
+ char *ps, *pt;
+ int req, soff, toff;
+
+ for (n = Fpos - Spos; n > 0; n -= req) {
+ soff = Spos % Nrec;
+ toff = Tpos % Nrec;
+ req = (size_t)min(n, Nrec - max(soff, toff));
+
+ for (i = 0; i < Ncol; i++) {
+ ps = Memcol[i] + (Spos / Nrec) * Blksize + soff * Clens[i];
+ pt = Memcol[i] + (Tpos / Nrec) * Blksize + toff * Clens[i];
+ memmove(pt, ps, req * Clens[i]);
+ } // endfor i
+
+ Tpos += req;
+ Spos += req;
+ } // endfor n
+
+ } else {
+ // True vector format, all is simple...
+ n = Fpos - Spos;
+
+ for (i = 0; i < Ncol; i++) {
+ m = Clens[i];
+ memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, n * m);
+ } // endfor i
+
+ Tpos += n;
+ } // endif MaxBlk
+
+#ifdef DEBTRACE
+ htrc("move %d bytes\n", n);
+#endif
+ } // endif n
+
+ if (irc == RC_OK) {
+ Spos = Fpos + 1; // New start position
+
+#ifdef DEBTRACE
+ htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos);
+#endif
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. Reset the Block and */
+ /* Last values for TDBVCT::MakeBlockValues. */
+ /*******************************************************************/
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (!MaxBlk) {
+ PFBLOCK fp = To_Fb;
+
+ // Clean the unused part of the last block
+ m = (Block - 1) * Blksize;
+ n = Nrec - Last;
+
+ for (i = 0; i < Ncol; i++)
+ memset(Memcol[i] + m + Last * Clens[i],
+ (Isnum[i]) ? 0 : ' ', n * Clens[i]);
+
+ // We must Unmap the view and use the saved file handle
+ // to put an EOF at the end of the last block of the file.
+ CloseMemMap(fp->Memory, (size_t)fp->Length);
+ fp->Count = 0; // Avoid doing it twice
+
+ // Remove extra blocks
+ n = Block * Blksize;
+
+#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
+ } else
+ // True vector table, Table file size does not change.
+ // Just clean the unused part of the file.
+ for (n = Fpos - Tpos, i = 0; i < Ncol; i++)
+ memset(Memcol[i] + Tpos * Clens[i], 0, n * Clens[i]);
+
+ // Reset Last and Block values in the catalog
+ PlugCloseFile(g, To_Fb); // in case of Header
+ ResetTableSize(g, Block, Last);
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Data Base close routine for VMP access method. */
+/***********************************************************************/
+void VCMFAM::CloseTableFile(PGLOBAL g)
+ {
+ int rc, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ if (mode == MODE_INSERT) {
+ if (!Closing) {
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last = CurNum;
+ Block = CurBlk + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Last = Nrec;
+ Block = CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ } else
+ wrc = RC_FX; // Last write was in error
+
+ PlugCloseFile(g, To_Fb);
+
+ if (wrc != RC_FX)
+ rc = ResetTableSize(g, Block, Last);
+
+ } else if (mode != MODE_DELETE)
+ PlugCloseFile(g, To_Fb);
+
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool VCMFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ char *mempos;
+ int i = colp->Index - 1;
+ int n = Nrec * ((MaxBlk || Split) ? colp->Clen : Lrecl);
+
+ /*********************************************************************/
+ /* Calculate the start position of the column block to read. */
+ /*********************************************************************/
+ mempos = Memcol[i] + n * CurBlk;
+
+#ifdef DEBTRACE
+ htrc("mempos=%p i=%d Nrec=%d Clen=%d CurBlk=%d\n",
+ mempos, i, Nrec, colp->Clen, CurBlk);
+#endif
+
+ if (colp->GetStatus(BUF_MAPPED))
+ colp->Blk->SetValPointer(mempos);
+
+#ifdef DEBTRACE
+ num_read++;
+#endif
+ return false;
+ } // end of ReadBlock
+
+/***********************************************************************/
+/* WriteBlock: Write back current column values for one block. */
+/* Note: there is nothing to do because we are working directly into */
+/* the mapped file, except when checking for Update but in this case */
+/* we do not want to write back the modifications either. */
+/***********************************************************************/
+bool VCMFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
+ {
+#if defined(_DEBUG)
+ char *mempos;
+ int i = colp->Index - 1;
+ int n = Nrec * colp->Clen;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ mempos = Memcol[i] + n * CurBlk;
+
+#ifdef DEBTRACE
+ htrc("modif=%d mempos=%p i=%d Nrec=%d Clen=%d colblk=%d\n",
+ Modif, mempos, i, Nrec, colp->Clen, colp->ColBlk);
+#endif
+
+#endif // _DEBUG
+
+ return false;
+ } // end of WriteBlock
+
+/* -------------------------- Class VECFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VECFAM class. */
+/***********************************************************************/
+VECFAM::VECFAM(PVCTDEF tdp) : VCTFAM((PVCTDEF)tdp)
+ {
+ Streams = NULL;
+ To_Fbs = NULL;
+ To_Bufs = NULL;
+ Split = true;
+ Block = Last = -1;
+ InitUpdate = false;
+ } // end of VECFAM standard constructor
+
+VECFAM::VECFAM(PVECFAM txfp) : VCTFAM(txfp)
+ {
+ Streams = txfp->Streams;
+ To_Fbs = txfp->To_Fbs;
+ Clens = txfp->Clens;
+ To_Bufs = txfp->To_Bufs;
+ InitUpdate = txfp->InitUpdate;
+ } // end of VECFAM copy constructor
+
+/***********************************************************************/
+/* VEC 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 VECFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4];
+ int i;
+ bool b;
+ PCOLDEF cdp;
+ PVCTCOL cp;
+ MODE mode = Tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ /*********************************************************************/
+ /* Call Cardinality to set Block and Last values in case it was not */
+ /* already called (this happens indeed in test xmode) */
+ /*********************************************************************/
+ Cardinality(g);
+
+ /*********************************************************************/
+ /* Open according to input/output mode required. */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "rb");
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ // This will delete the whole file
+ strcpy(opmode, "wb");
+
+ // This will stop the process by causing GetProgMax to return 0.
+ ResetTableSize(g, 0, Nrec);
+ break;
+ } // endif filter
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ strcpy(opmode, (UseTemp) ? "r": "r+");
+ break;
+ case MODE_INSERT:
+ strcpy(opmode, "ab");
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ /*********************************************************************/
+ /* Initialize the array of file structures. */
+ /*********************************************************************/
+ if (!Colfn) {
+ // Prepare the column file name pattern and set Ncol
+ Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
+ } // endif Colfn
+
+ Streams = (FILE* *)PlugSubAlloc(g, NULL, Ncol * sizeof(FILE*));
+ To_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
+
+ for (i = 0; i < Ncol; i++) {
+ Streams[i] = NULL;
+ To_Fbs[i] = NULL;
+ } // endif i
+
+ /*********************************************************************/
+ /* Open the files corresponding to columns used in the query. */
+ /*********************************************************************/
+ if (mode == MODE_INSERT || mode == MODE_DELETE) {
+ // All columns must be written or deleted
+ for (i = 0, cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext())
+ if (OpenColumnFile(g, opmode, i))
+ return true;
+
+ // Check for void table or missing columns
+ for (b = !Streams[0], i = 1; i < Ncol; i++)
+ if (b != !Streams[i])
+ return true;
+
+ } else {
+ /*******************************************************************/
+ /* Open the files corresponding to updated columns of the query. */
+ /*******************************************************************/
+ for (cp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols; cp;
+ cp = (PVCTCOL)cp->Next)
+ if (OpenColumnFile(g, opmode, cp->Index - 1))
+ return true;
+
+ // Open in read only mode the used columns not already open
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial() && !Streams[cp->Index - 1])
+ if (OpenColumnFile(g, "rb", cp->Index - 1))
+ return true;
+
+ // Check for void table or missing columns
+ for (i = 0, cp = (PVCTCOL)Tdbp->GetColumns(); cp;
+ cp = (PVCTCOL)cp->Next)
+ if (!i++)
+ b = !Streams[cp->Index - 1];
+ else if (b != !Streams[cp->Index - 1])
+ return true;
+
+ } // endif mode
+
+ /*********************************************************************/
+ /* Allocate the table and column block buffer. */
+ /*********************************************************************/
+ return (b) ? false : AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Open the file corresponding to one column. */
+/***********************************************************************/
+bool VECFAM::OpenColumnFile(PGLOBAL g, char *opmode, int i)
+ {
+ char filename[_MAX_PATH];
+ PDBUSER dup = PlgGetUser(g);
+
+ sprintf(filename, Colfn, i+1);
+
+ if (!(Streams[i] = PlugOpenFile(g, filename, opmode))) {
+#ifdef DEBTRACE
+ htrc("%s\n", g->Message);
+#endif
+ return (Tdbp->GetMode() == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Streams
+
+#ifdef DEBTRACE
+ htrc("File %s is open in mode %s\n", filename, opmode);
+#endif
+
+ To_Fbs[i] = dup->Openlist; // Keep track of File blocks
+ return false;
+ } // end of OpenColumnFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/***********************************************************************/
+bool VECFAM::AllocateBuffer(PGLOBAL g)
+ {
+ int i;
+ PVCTCOL cp;
+ PCOLDEF cdp;
+ PTDBVCT tdbp = (PTDBVCT)Tdbp;
+ MODE mode = tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)tdbp->GetDef();
+
+ if (mode != MODE_READ) {
+ // Allocate what is needed by all modes except Read
+ T_Streams = (FILE* *)PlugSubAlloc(g, NULL, Ncol * sizeof(FILE*));
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+
+ // Give default values
+ for (i = 0; i < Ncol; i++) {
+ T_Streams[i] = Streams[i];
+ Clens[i] = 0;
+ } // endfor i
+
+ } // endif mode
+
+ if (mode == MODE_INSERT) {
+ bool chk = PlgGetUser(g)->Check & CHK_TYPE;
+
+ To_Bufs = (void**)PlugSubAlloc(g, NULL, Ncol * sizeof(void*));
+ cdp = defp->GetCols();
+
+ for (i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext()) {
+ Clens[i] = cdp->GetClen();
+ To_Bufs[i] = PlugSubAlloc(g, NULL, Nrec * Clens[i]);
+
+ if (cdp->GetType() == TYPE_STRING)
+ memset(To_Bufs[i], ' ', Nrec * Clens[i]);
+ else
+ memset(To_Bufs[i], 0, Nrec * Clens[i]);
+
+ } // endfor cdp
+
+ for (cp = (PVCTCOL)tdbp->Columns; cp; cp = (PVCTCOL)cp->Next)
+ cp->Blk = AllocValBlock(g, To_Bufs[cp->Index - 1],
+ cp->Buf_Type, Nrec, cp->Format.Length,
+ cp->Format.Prec, chk);
+
+ return InitInsert(g);
+ } else {
+ if (UseTemp || mode == MODE_DELETE) {
+ // Allocate all that is needed to move lines and make Temp
+ if (UseTemp) {
+ Tempat = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ strcpy(Tempat, Colfn);
+ PlugSetPath(Tempat, Tempat, Tdbp->GetPath());
+ strcat(PlugRemoveType(Tempat, Tempat), ".t");
+ T_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
+ } // endif UseTemp
+
+ if (UseTemp)
+ for (i = 0; i < Ncol; i++) {
+ T_Streams[i] = (mode == MODE_UPDATE) ? (FILE*)1 : NULL;
+ T_Fbs[i] = NULL;
+ } // endfor i
+
+ if (mode == MODE_DELETE) { // All columns are moved
+ cdp = defp->GetCols();
+
+ for (i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext()) {
+ Clens[i] = cdp->GetClen();
+ Buflen = max(Buflen, cdp->GetClen());
+ } // endfor cdp
+
+ } else { // Mode Update, only some columns are updated
+ for (cp = (PVCTCOL)tdbp->To_SetCols; cp; cp = (PVCTCOL)cp->Next) {
+ i = cp->Index -1;
+
+ if (UseTemp)
+ T_Streams[i] = NULL; // Mark the streams to open
+
+ Clens[i] = cp->Clen;
+ Buflen = max(Buflen, cp->Clen);
+ } // endfor cp
+
+ InitUpdate = true; // To be initialized
+ } // endif mode
+
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen * Nrec);
+ } // endif mode
+
+ // Finally allocate column buffers for all modes
+ for (cp = (PVCTCOL)tdbp->Columns; cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) // Not a pseudo column
+ cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec);
+
+ } // endif mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Do initial action when inserting. */
+/***********************************************************************/
+bool VECFAM::InitInsert(PGLOBAL g)
+ {
+ // We come here in MODE_INSERT only
+ CurBlk = 0;
+ CurNum = 0;
+ AddBlock = true;
+ return false;
+ } // end of InitInsert
+
+/***********************************************************************/
+/* Reset buffer access according to indexing and to mode. */
+/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
+/***********************************************************************/
+void VECFAM::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() && Block > 1 && Tdbp->GetMode() == MODE_READ) {
+ Nrec = 1; // Better for random access
+ Rbuf = 0;
+ OldBlk = -2; // Has no meaning anymore
+ Block = Tdbp->Cardinality(g); // Blocks are one line now
+ Last = 1; // Probably unuseful
+ } // endif Mode
+
+ } // end of ResetBuffer
+
+/***********************************************************************/
+/* Data Base write routine for VCT access method. */
+/***********************************************************************/
+int VECFAM::WriteBuffer(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+#endif
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ if (Closing || ++CurNum == Nrec) {
+ // Here we must add a new blocks to the files
+ int i;
+ size_t n = (size_t)CurNum;
+
+ for (i = 0; i < Ncol; i++)
+ if (n != fwrite(To_Bufs[i], (size_t)Clens[i], n, Streams[i])) {
+ sprintf(g->Message, MSG(WRITE_STRERROR), To_File, strerror(errno));
+ return RC_FX;
+ } // endif
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+ } // endif Closing
+
+ } // endif Closing || CurNum
+
+ } else // Mode Update
+ // Writing updates being done in ReadDB we do initialization only.
+ if (InitUpdate) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ InitUpdate = false; // Done
+ } // endif InitUpdate
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for split vertical access methods. */
+/* Note: lines are moved directly in the files (ooops...) */
+/***********************************************************************/
+int VECFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This depends on the Check setting, false by default. */
+ /*********************************************************************/
+#ifdef DEBTRACE
+ fprintf(debug,
+ "VEC DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+#endif
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = Cardinality(g);
+#ifdef DEBTRACE
+ htrc("Fpos placed at file end=%d\n", Fpos);
+#endif
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos)
+ // First line to delete
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary files, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ /*****************************************************************/
+ /* Move of eventual preceeding lines is not required here. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ Spos = Tpos = Fpos;
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+#ifdef DEBTRACE
+ assert(Spos == Fpos);
+#endif
+ Spos++; // New start position is on next line
+
+#ifdef DEBTRACE
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ if (!UseTemp) {
+ /*****************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS??) this is still to be checked */
+ /* for compatibility with other OS's. */
+ /*****************************************************************/
+ char filename[_MAX_PATH];
+ int h, rc; // File handle, return code
+
+ for (int i = 0; i < Ncol; i++) {
+ sprintf(filename, Colfn, i + 1);
+ rc = PlugCloseFile(g, To_Fbs[i]);
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /***************************************************************/
+ /* Remove extra records. */
+ /***************************************************************/
+#if defined(UNIX)
+ if (ftruncate(h, (off_t)(Tpos * Clens[i]))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (chsize(h, Tpos * Clens[i])) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+#ifdef DEBTRACE
+ htrc("done, h=%d irc=%d\n", h, irc);
+#endif
+ } // endfor i
+
+ } else // UseTemp
+ // Ok, now delete old files and rename new temp files
+ if (RenameTempFile(g) == RC_FX)
+ return RC_FX;
+
+ // Reset these values for TDBVCT::MakeBlockValues
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (ResetTableSize(g, Block, Last))
+ return RC_FX;
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open temporary files used while updating or deleting. */
+/* Note: the files not updated have been given a T_Stream value of 1. */
+/***********************************************************************/
+bool VECFAM::OpenTempFile(PGLOBAL g)
+ {
+ char tempname[_MAX_PATH];
+
+ for (int i = 0; i < Ncol; i++)
+ if (!T_Streams[i]) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ sprintf(tempname, Tempat, i+1);
+
+ if (!(T_Streams[i] = PlugOpenFile(g, tempname, "wb"))) {
+#ifdef DEBTRACE
+ htrc("%s\n", g->Message);
+#endif
+ return true;
+ } else
+ T_Fbs[i] = PlgGetUser(g)->Openlist;
+
+ } else // This is a column that is not updated
+ T_Streams[i] = NULL; // For RenameTempFile
+
+ return false;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate updated lines before writing blocks. */
+/***********************************************************************/
+bool VECFAM::MoveLines(PGLOBAL g)
+ {
+ if (UseTemp && !InitUpdate) { // Don't do it in check pass
+ Fpos = OldBlk * Nrec;
+
+ if (MoveIntermediateLines(g)) {
+ Closing = true; // ???
+ return true;
+ } // endif UseTemp
+
+// Spos = Fpos + Nrec;
+ } // endif UseTemp
+ return false;
+
+ } // end of MoveLines
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *bn)
+ {
+ int i;
+ int n;
+ bool b = false;
+ size_t req, len;
+
+ for (n = Fpos - Spos; n > 0; n -= Nrec) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ req = (size_t)min(n, Nrec);
+
+ for (i = 0; i < Ncol; i++) {
+ if (!T_Streams[i])
+ continue; // Non updated column
+
+ if (!UseTemp || !b)
+ if (fseek(Streams[i], Spos * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ len = fread(To_Buf, Clens[i], req, Streams[i]);
+
+#ifdef DEBTRACE
+ htrc("after read req=%d len=%d\n", req, len);
+#endif
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), req, len);
+ return true;
+ } // endif len
+
+ if (!UseTemp)
+ if (fseek(T_Streams[i], Tpos * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, T_Streams[i])) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+#ifdef DEBTRACE
+ htrc("after write pos=%d\n", ftell(Streams[i]));
+#endif
+ } // endfor i
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+#ifdef DEBTRACE
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediate Lines
+
+/***********************************************************************/
+/* Delete the old files and rename the new temporary files. */
+/***********************************************************************/
+int VECFAM::RenameTempFile(PGLOBAL g)
+ {
+ char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH];
+ int rc = RC_OK;
+
+ // Close all files.
+ // This loop is necessary because, in case of join,
+ // the table files can have been open several times.
+ for (PFBLOCK fb = PlgGetUser(g)->Openlist; fb; fb = fb->Next)
+ rc = PlugCloseFile(g, fb);
+
+ for (int i = 0; i < Ncol && rc == RC_OK; i++) {
+ if (!T_Fbs[i])
+ continue;
+
+ tempname = (char*)T_Fbs[i]->Fname;
+ sprintf(filename, Colfn, i+1);
+ PlugSetPath(filename, filename, Tdbp->GetPath());
+ strcat(PlugRemoveType(filetemp, filename), ".ttt");
+ remove(filetemp); // May still be there from previous error
+
+ if (rename(filename, filetemp)) { // Save file for security
+ sprintf(g->Message, MSG(RENAME_ERROR),
+ filename, filetemp, strerror(errno));
+ rc = RC_FX;
+ } else if (rename(tempname, filename)) {
+ sprintf(g->Message, MSG(RENAME_ERROR),
+ tempname, filename, strerror(errno));
+ rc = rename(filetemp, filename); // Restore saved file
+ rc = RC_FX;
+ } else if (remove(filetemp)) {
+ sprintf(g->Message, MSG(REMOVE_ERROR),
+ filetemp, strerror(errno));
+ rc = RC_INFO; // Acceptable
+ } // endif's
+
+ } // endfor i
+
+ return rc;
+ } // end of RenameTempFile
+
+/***********************************************************************/
+/* Data Base close routine for VEC access method. */
+/***********************************************************************/
+void VECFAM::CloseTableFile(PGLOBAL g)
+ {
+ int rc, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ if (mode == MODE_INSERT) {
+ if (Closing)
+ wrc = RC_FX; // Last write was in error
+ else
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last += (CurBlk * Nrec + CurNum -1);
+ Block += (Last / Nrec);
+ Last = Last % Nrec + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Block += CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ if (wrc != RC_FX)
+ rc = ResetTableSize(g, Block, Last);
+ else
+ longjmp(g->jumper[g->jump_level], 44);
+
+ } else if (mode == MODE_UPDATE) {
+ if (UseTemp && !InitUpdate) {
+ // Write any intermediate lines to temp file
+ Fpos = OldBlk * Nrec;
+ wrc = MoveIntermediateLines(g);
+// Spos = Fpos + Nrec;
+ } // endif UseTemp
+
+ // Write back to file any pending modifications
+ if (wrc == RC_OK)
+ for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols;
+ colp; colp = (PVCTCOL)colp->Next)
+ colp->WriteBlock(g);
+
+ if (wrc == RC_OK && UseTemp && !InitUpdate) {
+ // Write any intermediate lines to temp file
+ Fpos = (Block - 1) * Nrec + Last;
+ wrc = MoveIntermediateLines(g);
+ } // endif UseTemp
+
+ } // endif's mode
+
+ if (UseTemp && !InitUpdate) {
+ // If they are errors, leave files unchanged
+ if (wrc == RC_OK)
+ rc = RenameTempFile(g);
+ else
+ longjmp(g->jumper[g->jump_level], 44);
+
+ } else if (Streams)
+ for (int i = 0; i < Ncol; i++)
+ if (Streams[i]) {
+ rc = PlugCloseFile(g, To_Fbs[i]);
+ Streams[i] = NULL;
+ To_Fbs[i] = NULL;
+ } // endif Streams
+
+#ifdef DEBTRACE
+ htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n",
+ To_File, wrc, rc);
+#endif
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool VECFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int i, len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to read. */
+ /*********************************************************************/
+ len = Nrec * colp->Clen * CurBlk;
+ i = colp->Index - 1;
+
+#ifdef DEBTRACE
+ htrc("len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d\n",
+ len, i, Nrec, colp->Deplac, Lrecl, CurBlk);
+#endif
+
+ if (fseek(Streams[i], len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ n = fread(colp->Blk->GetValPointer(), (size_t)colp->Clen,
+ (size_t)Nrec, Streams[i]);
+
+ if (n != (size_t)Nrec && (CurBlk+1 != Block || n != (size_t)Last)) {
+ char fn[_MAX_PATH];
+
+ sprintf(fn, Colfn, colp->Index);
+#if defined(WIN32)
+ if (feof(Streams[i]))
+#else // !WIN32
+ if (errno == NO_ERROR)
+#endif // !WIN32
+ sprintf(g->Message, MSG(BAD_READ_NUMBER), n, fn);
+ else
+ sprintf(g->Message, MSG(READ_ERROR),
+ fn, strerror(errno));
+
+#ifdef DEBTRACE
+ htrc(" Read error: %s\n", g->Message);
+#endif
+ return true;
+ } // endif
+
+#ifdef DEBTRACE
+ num_read++;
+#endif
+ return false;
+ } // 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. */
+/***********************************************************************/
+bool VECFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int i, len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ len = Nrec * colp->Clen * colp->ColBlk;
+ i = colp->Index - 1;
+
+#ifdef DEBTRACE
+ htrc("modif=%d len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n",
+ Modif, len, i, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
+#endif
+
+ if (Tdbp->GetMode() == MODE_UPDATE && !UseTemp)
+ if (fseek(T_Streams[i], len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ // Here Nrec was changed to CurNum in mode Insert,
+ // this is the true number of records to write,
+ // this also avoid writing garbage in the file for true vector tables.
+ n = (Tdbp->GetMode() == MODE_INSERT) ? CurNum
+ : (colp->ColBlk == Block - 1) ? Last : Nrec;
+
+ if (n != fwrite(colp->Blk->GetValPointer(),
+ (size_t)colp->Clen, n, T_Streams[i])) {
+ char fn[_MAX_PATH];
+
+ sprintf(fn, (UseTemp) ? Tempat : Colfn, colp->Index);
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
+#ifdef DEBTRACE
+ htrc("Write error: %s\n", strerror(errno));
+#endif
+ return true;
+ } else
+ Spos = Fpos + n;
+
+#if defined(UNIX)
+ fflush(Streams[i]); //NGC
+#endif
+
+#ifdef DEBTRACE
+//num_write++;
+#endif
+
+ return false;
+ } // end of WriteBlock
+
+/* -------------------------- Class VMPFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VMPFAM class. */
+/***********************************************************************/
+VMPFAM::VMPFAM(PVCTDEF tdp) : VCMFAM((PVCTDEF)tdp)
+ {
+ To_Fbs = NULL;
+ Split = true;
+ Block = Last = -1;
+ } // end of VMPFAM standard constructor
+
+VMPFAM::VMPFAM(PVMPFAM txfp) : VCMFAM(txfp)
+ {
+ To_Fbs = txfp->To_Fbs;
+ } // end of VMPFAM copy constructor
+
+/***********************************************************************/
+/* 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 VMPFAM::OpenTableFile(PGLOBAL g)
+ {
+ int i;
+ bool b;
+ MODE mode = Tdbp->GetMode();
+ PCOLDEF cdp;
+ PVCTCOL cp;
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ if (mode == MODE_DELETE && !Tdbp->GetNext()) {
+ DelRows = Cardinality(g);
+
+ // This will stop the process by causing GetProgMax to return 0.
+ ResetTableSize(g, 0, Nrec);
+ } else
+ Cardinality(g); // See comment in VECFAM::OpenTbleFile
+
+
+ /*********************************************************************/
+ /* Prepare the filename pattern for column files and set Ncol. */
+ /*********************************************************************/
+ if (!Colfn) {
+ // Prepare the column file name pattern
+ Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
+ } // endif Colfn
+
+ /*********************************************************************/
+ /* Initialize the array of file structures. */
+ /*********************************************************************/
+ Memcol = (char* *)PlugSubAlloc(g, NULL, Ncol * sizeof(char *));
+ To_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
+
+ for (i = 0; i < Ncol; i++) {
+ Memcol[i] = NULL;
+ To_Fbs[i] = NULL;
+ } // endif i
+
+ /*********************************************************************/
+ /* Open the files corresponding to columns used in the query. */
+ /*********************************************************************/
+ if (mode == MODE_DELETE) {
+ // All columns are used in Delete mode
+ for (i = 0, cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext())
+ if (MapColumnFile(g, mode, i))
+ return true;
+
+ } else {
+ /*******************************************************************/
+ /* Open the files corresponding updated columns of the query. */
+ /*******************************************************************/
+ for (cp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols; cp;
+ cp = (PVCTCOL)cp->Next)
+ if (MapColumnFile(g, MODE_UPDATE, cp->Index - 1))
+ return true;
+
+ /*******************************************************************/
+ /* Open other non already open used columns (except pseudos) */
+ /*******************************************************************/
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial() && !Memcol[cp->Index - 1])
+ if (MapColumnFile(g, MODE_READ, cp->Index - 1))
+ return true;
+
+ } // endif mode
+
+ /*********************************************************************/
+ /* Check for void table or missing columns */
+ /*********************************************************************/
+ for (b = !Memcol[0], i = 1; i < Ncol; i++)
+ if (b != !Memcol[i])
+ return true;
+
+ /*********************************************************************/
+ /* Allocate the table and column block buffer. */
+ /*********************************************************************/
+ return (b) ? false : AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Open the file corresponding to one column. */
+/***********************************************************************/
+bool VMPFAM::MapColumnFile(PGLOBAL g, MODE mode, int i)
+ {
+ char filename[_MAX_PATH];
+ int len;
+ HANDLE hFile;
+ MEMMAP mm;
+ PFBLOCK fp;
+ PDBUSER dup = PlgGetUser(g);
+
+ sprintf(filename, Colfn, i+1);
+
+ /*********************************************************************/
+ /* 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 = dup->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++;
+ Memcol[i] = fp->Memory;
+ len = fp->Length;
+ } else {
+ /*******************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************/
+ hFile = CreateFileMap(g, filename, &mm, mode, DelRows);
+
+ 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;
+ Memcol[i] = (char *)mm.memory;
+
+ if (!len) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ ResetTableSize(g, 0, Nrec);
+ return false;
+ } // endif len
+
+ if (!Memcol[i]) {
+ 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 = dup->Openlist;
+ dup->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = len;
+ fp->Memory = Memcol[i];
+ fp->Mode = mode;
+ fp->File = NULL;
+ fp->Handle = hFile; // Used for Delete
+ } // endif fp
+
+ To_Fbs[i] = fp; // Useful when closing
+
+#ifdef DEBTRACE
+ htrc("fp=%p count=%d MapView=%p len=%d\n",
+ fp, fp->Count, Memcol[i], len);
+#endif
+
+ return false;
+ } // end of MapColumnFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/* Give a dummy value (1) to prevent allocating the value block. */
+/* It will be set pointing into the memory map of the file. */
+/***********************************************************************/
+bool VMPFAM::AllocateBuffer(PGLOBAL g)
+ {
+ PVCTCOL cp;
+
+ if (Tdbp->GetMode() == MODE_DELETE) {
+ PCOLDEF cdp = Tdbp->GetDef()->GetCols();
+
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+
+ for (int i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext())
+ Clens[i] = cdp->GetClen();
+
+ } // endif mode
+
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) { // Not a pseudo column
+ cp->Blk = AllocValBlock(g, (void*)1, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec);
+ cp->AddStatus(BUF_MAPPED);
+ } // endif IsSpecial
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for VMP access method. */
+/* Lines between deleted lines are moved in the mapfile view. */
+/***********************************************************************/
+int VMPFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ int i;
+ int m, n;
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ "VMP DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n",
+ irc, To_Buf, Tpos, Spos);
+#endif
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the top of map position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+#ifdef DEBTRACE
+ htrc("Fpos placed at file top=%p\n", Fpos);
+#endif
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ 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. */
+ /*******************************************************************/
+ for (i = 0; i < Ncol; i++) {
+ m = Clens[i];
+ memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, m * n);
+ } // endif i
+
+ Tpos += n;
+
+#ifdef DEBTRACE
+ htrc("move %d bytes\n", n);
+#endif
+ } // endif n
+
+ if (irc == RC_OK) {
+ Spos = Fpos + 1; // 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;
+
+ for (i = 0; i < Ncol; i++) {
+ fp = To_Fbs[i];
+ CloseMemMap(fp->Memory, (size_t)fp->Length);
+ fp->Count = 0; // Avoid doing it twice
+
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+ n = Tpos * Clens[i];
+
+#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
+ } // endfor i
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Data Base close routine for VMP access method. */
+/***********************************************************************/
+void VMPFAM::CloseTableFile(PGLOBAL g)
+ {
+ if (Tdbp->GetMode() == MODE_DELETE) {
+ // Set Block and Nrec values for TDBVCT::MakeBlockValues
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+ ResetTableSize(g, Block, Last);
+ } else if (Tdbp->GetMode() == MODE_INSERT)
+ assert(false);
+
+ for (int i = 0; i < Ncol; i++)
+ PlugCloseFile(g, To_Fbs[i]);
+
+ } // end of CloseTableFile
+
+/* -------------------------- Class BGVFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the BGVFAM class. */
+/***********************************************************************/
+// Constructors
+BGVFAM::BGVFAM(PVCTDEF tdp) : VCTFAM(tdp)
+ {
+ Hfile = INVALID_HANDLE_VALUE;
+ Tfile = INVALID_HANDLE_VALUE;
+ BigDep = NULL;
+ } // end of BGVFAM constructor
+
+BGVFAM::BGVFAM(PBGVFAM txfp) : VCTFAM(txfp)
+ {
+ Hfile = txfp->Hfile;
+ Tfile = txfp->Tfile;
+ BigDep= txfp->BigDep;
+ } // end of BGVFAM copy constructor
+
+/***********************************************************************/
+/* Set current position in a big file. */
+/***********************************************************************/
+bool BGVFAM::BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, bool b)
+ {
+#if defined(WIN32)
+ char buf[256];
+ DWORD drc, m = (b) ? FILE_END : FILE_BEGIN;
+ LARGE_INTEGER of;
+
+ of.QuadPart = pos;
+ of.LowPart = SetFilePointer(h, of.LowPart, &of.HighPart, m);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ (drc = GetLastError()) != NO_ERROR) {
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(SFP_ERROR), buf);
+ return true;
+ } // endif
+#else // !WIN32
+ if (lseek64(h, pos, (b) ? SEEK_END : SEEK_SET) < 0) {
+ sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
+ return true;
+ } // endif
+#endif // !WIN32
+
+ return false;
+ } // end of BigSeek
+
+/***********************************************************************/
+/* Read from a big file. */
+/***********************************************************************/
+bool BGVFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req)
+ {
+ bool rc = false;
+
+#if defined(WIN32)
+ DWORD nbr, drc, len = (DWORD)req;
+ bool brc = ReadFile(h, inbuf, len, &nbr, NULL);
+
+#ifdef DEBTRACE
+ htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr);
+#endif
+
+ if (!brc || nbr != len) {
+ char buf[256]; // , *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ if (brc)
+ strcpy(buf, MSG(BAD_BYTE_READ));
+ else {
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ } // endelse brc
+
+ sprintf(g->Message, MSG(READ_ERROR), To_File, buf);
+#ifdef DEBTRACE
+ htrc("BIGREAD: %s\n", g->Message);
+#endif
+ rc = true;
+ } // endif brc || nbr
+#else // !WIN32
+ size_t len = (size_t)req;
+ ssize_t nbr = read(h, inbuf, len);
+
+ if (nbr != (ssize_t)len) {
+ const char *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ sprintf(g->Message, MSG(READ_ERROR), fn, strerror(errno));
+#ifdef DEBTRACE
+ htrc("BIGREAD: nbr=%d len=%d errno=%d %s\n",
+ nbr, len, errno, g->Message);
+#endif
+ rc = true;
+ } // endif nbr
+#endif // !WIN32
+
+ return rc;
+ } // end of BigRead
+
+/***********************************************************************/
+/* Write into a big file. */
+/***********************************************************************/
+bool BGVFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req)
+ {
+ bool rc = false;
+
+#if defined(WIN32)
+ DWORD nbw, drc, len = (DWORD)req;
+ bool brc = WriteFile(h, inbuf, len, &nbw, NULL);
+
+#ifdef DEBTRACE
+ htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw);
+#endif
+
+ if (!brc || nbw != len) {
+ char buf[256], *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ if (brc)
+ strcpy(buf, MSG(BAD_BYTE_NUM));
+ else {
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ } // endelse brc
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf);
+
+#ifdef DEBTRACE
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, drc, g->Message);
+#endif
+ rc = true;
+ } // endif brc || nbw
+#else // !WIN32
+ size_t len = (size_t)req;
+ ssize_t nbw = write(h, inbuf, len);
+
+ if (nbw != (ssize_t)len) {
+ const char *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
+#ifdef DEBTRACE
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, errno, g->Message);
+#endif
+ rc = true;
+ } // endif nbr
+#endif // !WIN32
+
+ return rc;
+ } // end of BigWrite
+
+/***********************************************************************/
+/* Get the Headlen, Block and Last info from the file header. */
+/***********************************************************************/
+int BGVFAM::GetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int n;
+ bool b;
+ VECHEADER vh;
+ HANDLE h;
+
+ if (Header < 1 || Header > 3 || !MaxBlk) {
+ sprintf(g->Message, "Invalid header value %d", Header);
+ return -1;
+ } else
+ n = (Header == 1) ? (int)sizeof(VECHEADER) : 0;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header == 2)
+ strcat(PlugRemoveType(filename, filename), ".blk");
+
+#if defined(WIN32)
+ h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+#else // !WIN32
+ h = open64(filename, O_RDONLY, 0);
+
+ if (h == INVALID_HANDLE_VALUE) {
+#endif // !WIN32
+ // Consider this is a void table
+ Last = Nrec;
+ Block = 0;
+ return n;
+ } else if (Header == 3)
+ b = BigSeek(g, h, -(BIGINT)sizeof(vh), true);
+
+ if (BigRead(g, h, &vh, sizeof(vh))) {
+ sprintf(g->Message, "Error reading header file %s", filename);
+ n = -1;
+ } else if (MaxBlk * Nrec != vh.MaxRec) {
+ sprintf(g->Message, "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d",
+ vh.MaxRec, MaxBlk, Nrec);
+ n = -1;
+ } else {
+ Block = (vh.NumRec > 0) ? (vh.NumRec + Nrec - 1) / Nrec : 0;
+ Last = (vh.NumRec + Nrec - 1) % Nrec + 1;
+ } // endif's
+
+ CloseFileHandle(h);
+ return n;
+ } // end of GetBlockInfo
+
+/***********************************************************************/
+/* Set the MaxRec and NumRec info in the file header. */
+/***********************************************************************/
+bool BGVFAM::SetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool bk, b = false, rc = false;
+ VECHEADER vh;
+ HANDLE h = INVALID_HANDLE_VALUE;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header != 2) {
+ if (Hfile != INVALID_HANDLE_VALUE) {
+ h = Hfile;
+
+ if (Header == 1)
+ bk = BigSeek(g, h, (BIGINT)0);
+
+ } else
+ b = true;
+
+ } else // Header == 2
+ strcat(PlugRemoveType(filename, filename), ".blk");
+
+ if (h == INVALID_HANDLE_VALUE) {
+#if defined(WIN32)
+ DWORD creation = (b) ? OPEN_EXISTING : TRUNCATE_EXISTING;
+
+ h = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0,
+ NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
+
+#else // !WIN32
+ int oflag = (b) ? O_RDWR : O_RDWR | O_TRUNC;
+
+ h = open64(filename, oflag, 0);
+#endif // !WIN32
+
+ if (h == INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, "Error opening header file %s", filename);
+ return true;
+ } // endif h
+
+ } // endif h
+
+ if (Header == 3)
+ bk = BigSeek(g, h, -(BIGINT)sizeof(vh), true);
+
+ vh.MaxRec = MaxBlk * Bsize;
+ vh.NumRec = (Block - 1) * Nrec + Last;
+
+ if (BigWrite(g, h, &vh, sizeof(vh))) {
+ sprintf(g->Message, "Error writing header file %s", filename);
+ rc = true;
+ } // endif fread
+
+ if (Header > 1 || Hfile == INVALID_HANDLE_VALUE)
+ CloseFileHandle(h);
+
+ return rc;
+ } // end of SetBlockInfo
+
+/***********************************************************************/
+/* VEC Create an empty file for new Vector formatted tables. */
+/***********************************************************************/
+bool BGVFAM::MakeEmptyFile(PGLOBAL g, char *fn)
+ {
+#if defined(WIN32)
+ // Vector formatted file this will create an empty file of the
+ // required length if it does not exists yet.
+ char *p, filename[_MAX_PATH], c = 0;
+ DWORD rc;
+ bool brc;
+ LARGE_INTEGER of;
+ HANDLE h;
+
+ PlugSetPath(filename, fn, Tdbp->GetPath());
+ h = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ p = MSG(OPENING);
+ goto err;
+ } // endif h
+
+ of.QuadPart = (BIGINT)Headlen + (BIGINT)MaxBlk * (BIGINT)Blksize - (BIGINT)1;
+
+ of.LowPart = SetFilePointer(h, of.LowPart,
+ &of.HighPart, FILE_BEGIN);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ GetLastError() != NO_ERROR) {
+ p = MSG(MAKING);
+ goto err;
+ } // endif
+
+ brc = WriteFile(h, &c, 1, &rc, NULL);
+
+ if (!brc || rc != 1) {
+ p = MSG(WRITING);
+ goto err;
+ } // endif
+
+ CloseHandle(h);
+ return false;
+
+ err:
+ rc = GetLastError();
+ sprintf(g->Message, MSG(EMPTY_FILE), p, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+
+ if (h != INVALID_HANDLE_VALUE)
+ CloseHandle(h);
+
+ return true;
+#else // !WIN32
+ strcpy(g->Message, MSG(MKEMPTY_NIY));
+ return true;
+#endif // !WIN32
+ } // end of MakeEmptyFile
+
+/***********************************************************************/
+/* Vopen function: opens a file using Windows or Unix API's. */
+/***********************************************************************/
+bool BGVFAM::OpenTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool del = false;
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ if ((To_Fb && To_Fb->Count) || Hfile != INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, MSG(FILE_OPEN_YET), To_File);
+ return true;
+ } // endif
+
+ /*********************************************************************/
+ /* Update block info if necessary. */
+ /*********************************************************************/
+ if (Block < 0)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return true;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+#ifdef DEBTRACE
+ htrc("OpenTableFile: filename=%s mode=%d Last=%d\n",
+ filename, mode, Last);
+#endif
+
+#if defined(WIN32)
+ DWORD access, creation, share = 0, rc = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ access = GENERIC_READ;
+ share = FILE_SHARE_READ;
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_INSERT:
+ if (MaxBlk) {
+ if (!Block)
+ if (MakeEmptyFile(g, To_File))
+ return true;
+
+ // Required to update empty blocks
+ access = GENERIC_READ | GENERIC_WRITE;
+ } else if (Last == Nrec)
+ access = GENERIC_WRITE;
+ else
+ // Required to update the last block
+ access = GENERIC_READ | GENERIC_WRITE;
+
+ creation = OPEN_ALWAYS;
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ // This will stop the process by
+ // causing GetProgMax to return 0.
+// ResetTableSize(g, 0, Nrec); must be done later
+ del = true;
+
+ // This will delete the whole file
+ access = GENERIC_READ | GENERIC_WRITE;
+ creation = TRUNCATE_EXISTING;
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ if ((UseTemp = Tdbp->IsUsingTemp(g)))
+ access = GENERIC_READ;
+ else
+ access = GENERIC_READ | GENERIC_WRITE;
+
+ creation = OPEN_EXISTING;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ /*********************************************************************/
+ /* Use specific Windows API functions. */
+ /*********************************************************************/
+ Hfile = CreateFile(filename, access, share, NULL, creation,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ } // endif Hfile
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ " rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n",
+ drc, access, share, creation, Hfile, filename);
+#endif
+
+ if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode we must position the cursor at end of file. */
+ /*******************************************************************/
+ LARGE_INTEGER of;
+
+ of.QuadPart = (BIGINT)0;
+ of.LowPart = SetFilePointer(Hfile, of.LowPart,
+ &of.HighPart, FILE_END);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ (rc = GetLastError()) != NO_ERROR) {
+ sprintf(g->Message, MSG(ERROR_IN_SFP), rc);
+ CloseHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ } // endif
+
+ } // endif Mode
+
+#else // UNIX
+ /*********************************************************************/
+ /* The open() function has a transitional interface for 64-bit */
+ /* file offsets. Note that using open64() is equivalent to using */
+ /* open() with O_LARGEFILE set in oflag (see Xopen in tabfix.cpp). */
+ /*********************************************************************/
+ int rc = 0;
+ int oflag;
+ mode_t pmd = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ oflag = O_RDONLY;
+ break;
+ case MODE_INSERT:
+ oflag = O_WRONLY | O_CREAT | O_APPEND;
+ pmd = S_IREAD | S_IWRITE;
+ break;
+ case MODE_DELETE:
+ // This is temporary until a partial delete is implemented
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+ del = true;
+
+ // This will delete the whole file and provoque ReadDB to
+ // return immediately.
+ oflag = O_RDWR | O_TRUNC;
+ strcpy(g->Message, MSG(NO_VCT_DELETE));
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ oflag = (UseTemp) ? O_RDONLY : O_RDWR;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ Hfile = open64(filename, oflag, pmd); // Enable file size > 2G
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = errno;
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ strcat(g->Message, strerror(errno));
+ } // endif Hfile
+
+#ifdef DEBTRACE
+ htrc(" lrc=%d oflag=%p mode=%p handle=%d fn=%s\n",
+ lrc, oflag, mode, Hfile, filename);
+#endif
+
+#endif // UNIX
+
+ if (!rc) {
+ if (!To_Fb) {
+ To_Fb = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fb->Fname = To_File;
+ To_Fb->Type = TYPE_FB_HANDLE;
+ To_Fb->Memory = NULL;
+ To_Fb->Length = 0;
+ To_Fb->File = NULL;
+ To_Fb->Next = dbuserp->Openlist;
+ dbuserp->Openlist = To_Fb;
+ } // endif To_Fb
+
+ To_Fb->Count = 1;
+ To_Fb->Mode = mode;
+ To_Fb->Handle = Hfile;
+
+#ifdef DEBTRACE
+ htrc("File %s is open in mode %d\n", filename, mode);
+#endif
+
+ if (del)
+ // This will stop the process by
+ // causing GetProgMax to return 0.
+ return ResetTableSize(g, 0, Nrec);
+
+ /*********************************************************************/
+ /* Allocate the table and column block buffers. */
+ /*********************************************************************/
+ return AllocateBuffer(g);
+ } else
+ return (mode == MODE_READ && rc == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/***********************************************************************/
+bool BGVFAM::AllocateBuffer(PGLOBAL g)
+ {
+ MODE mode = Tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+ PCOLDEF cdp;
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (mode == MODE_INSERT) {
+ if (!NewBlock) {
+ // Not reopening after inserting the last block
+ bool chk = PlgGetUser(g)->Check & CHK_TYPE;
+
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ memset(NewBlock + Nrec * cdp->GetPoff(),
+ (IsTypeNum(cdp->GetType()) ? 0 : ' '),
+ Nrec * cdp->GetClen());
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->Blk = AllocValBlock(g, NewBlock + Nrec * cp->Deplac,
+ cp->Buf_Type, Nrec, cp->Format.Length,
+ cp->Format.Prec, chk);
+
+ InitInsert(g); // Initialize inserting
+
+ // Currently we don't use a temporary file for inserting
+ Tfile = Hfile;
+ } // endif NewBlock
+
+ } else {
+ if (UseTemp || mode == MODE_DELETE) {
+ // Allocate all that is needed to move lines
+ int i = 0;
+
+ if (!Ncol)
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ Ncol++;
+
+ if (MaxBlk)
+ BigDep = (BIGINT*)PlugSubAlloc(g, NULL, Ncol * sizeof(BIGINT));
+ else
+ Deplac = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
+
+ for (cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext()) {
+ if (MaxBlk)
+ BigDep[i] = (BIGINT)Headlen
+ + (BIGINT)(cdp->GetPoff() * Nrec) * (BIGINT)MaxBlk;
+ else
+ Deplac[i] = cdp->GetPoff() * Nrec;
+
+ Clens[i] = cdp->GetClen();
+ Isnum[i] = IsTypeNum(cdp->GetType());
+ Buflen = max(Buflen, cdp->GetClen());
+ } // endfor cdp
+
+ if (!UseTemp || MaxBlk) {
+ Buflen *= Nrec;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+ } else
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ } // endif mode
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) // Not a pseudo column
+ cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec);
+
+ } //endif mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Data Base write routine for huge VCT access method. */
+/***********************************************************************/
+int BGVFAM::WriteBuffer(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ htrc("BGV WriteDB: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+#endif
+
+ if (Tdbp->GetMode() == MODE_UPDATE) {
+ // Mode Update is done in ReadDB, we just initialize it here
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ // Most of the time, not all table columns are updated.
+ // This why we must completely pre-fill the temporary file.
+ Fpos = (MaxBlk) ? (Block - 1) * Nrec + Last
+ : Block * Nrec; // To write last lock
+
+ if (MoveIntermediateLines(g))
+ return RC_FX;
+
+ } else
+ Tfile = Hfile;
+
+ } // endif Tfile
+
+ } else {
+ // Mode Insert
+ if (MaxBlk && CurBlk == MaxBlk) {
+ strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
+ return RC_EF; // Too many lines for a Vector formatted table
+ } // endif MaxBlk
+
+ if (Closing || ++CurNum == Nrec) {
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (!AddBlock) {
+ // Write back the updated last block values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->WriteBlock(g);
+
+ if (!Closing && !MaxBlk) {
+ // Close the VCT file and reopen it in mode Insert
+//#if defined(WIN32) //OB
+// CloseHandle(Hfile);
+//#else // UNIX
+// close(Hfile);
+//#endif // UNIX
+ CloseFileHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ To_Fb->Count = 0;
+ Last = Nrec; // Tested in OpenTableFile
+
+ if (OpenTableFile(g)) {
+ Closing = true; // Tell CloseDB of error
+ return RC_FX;
+ } // endif Vopen
+
+ AddBlock = true;
+ } // endif Closing
+
+ } else {
+ // Here we must add a new block to the VCT file
+ if (Closing)
+ // Reset the overwritten columns for last block extra records
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ memset(NewBlock + Nrec * cp->Deplac + Last * cp->Clen,
+ (cp->Buf_Type == TYPE_STRING) ? ' ' : '\0',
+ (Nrec - Last) * cp->Clen);
+
+ if (BigWrite(g, Hfile, NewBlock, Blksize))
+ return RC_FX;
+
+ } // endif AddBlock
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+ } // endif Closing
+
+ } // endif
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for BGVFAM access method. */
+/***********************************************************************/
+int BGVFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool eof = false;
+
+ /*********************************************************************/
+ /* There is an alternative here depending on UseTemp: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /*********************************************************************/
+#ifdef DEBTRACE
+ fprintf(debug,
+ "BGV DeleteDB: irc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+#endif
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+#ifdef DEBTRACE
+ htrc("Fpos placed at file end=%d\n", Fpos);
+#endif
+ eof = UseTemp && !MaxBlk;
+ } else // Fpos is the deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceeding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ Tfile = Hfile;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &eof))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+#ifdef DEBTRACE
+ assert(Spos == Fpos);
+#endif
+ Spos++; // New start position is on next line
+
+#ifdef DEBTRACE
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (!UseTemp) { // The UseTemp case is treated in CloseTableFile
+ if (!MaxBlk) {
+ if (Last < Nrec) // Clean last block
+ if (CleanUnusedSpace(g))
+ return RC_FX;
+
+ /***************************************************************/
+ /* Remove extra records. */
+ /***************************************************************/
+#if defined(WIN32)
+ BIGINT pos = (BIGINT)Block * (BIGINT)Blksize;
+
+ if (BigSeek(g, Hfile, pos))
+ return RC_FX;
+
+ if (!SetEndOfFile(Hfile)) {
+ DWORD drc = GetLastError();
+
+ sprintf(g->Message, MSG(SETEOF_ERROR), drc);
+ return RC_FX;
+ } // endif error
+#else // !WIN32
+ if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+#endif // !WIN32
+ } else // MaxBlk
+ // Clean the unused space in the file, this is required when
+ // inserting again with a partial column list.
+ if (CleanUnusedSpace(g))
+ return RC_FX;
+
+ if (ResetTableSize(g, Block, Last))
+ return RC_FX;
+
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool BGVFAM::OpenTempFile(PGLOBAL g)
+ {
+ char *tempname;
+ PDBUSER dup = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ tempname = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+
+ if (!MaxBlk)
+ remove(tempname); // Be sure it does not exist yet
+ else if (MakeEmptyFile(g, tempname))
+ return true;
+
+#if defined(WIN32)
+ DWORD access = (MaxBlk) ? OPEN_EXISTING : CREATE_NEW;
+
+ Tfile = CreateFile(tempname, GENERIC_WRITE, 0, NULL,
+ access, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_DELETE, tempname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)tempname, _MAX_PATH, NULL);
+ strcat(g->Message, tempname);
+ return true;
+ } // endif Tfile
+#else // UNIX
+ int oflag = (MaxBlk) ? O_WRONLY : O_WRONLY | O_TRUNC;
+
+ Tfile = open64(tempname, oflag, S_IWRITE);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ int rc = errno;
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
+ strcat(g->Message, strerror(errno));
+ return true;
+ } //endif Tfile
+#endif // UNIX
+
+ To_Fbt = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fbt->Fname = tempname;
+ To_Fbt->Type = TYPE_FB_HANDLE;
+ To_Fbt->Memory = NULL;
+ To_Fbt->Length = 0;
+ To_Fbt->File = NULL;
+ To_Fbt->Next = dup->Openlist;
+ To_Fbt->Count = 1;
+ To_Fbt->Mode = MODE_INSERT;
+ To_Fbt->Handle = Tfile;
+ dup->Openlist = To_Fbt;
+ return false;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool BGVFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int i, n, req, dep;
+ bool eof = (b) ? *b : false;
+ BIGINT pos;
+
+ for (n = Fpos - Spos; n > 0 || eof; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!MaxBlk)
+ req = (DWORD)min(n, Nrec - max(Spos % Nrec, Tpos % Nrec));
+ else
+ req = (DWORD)min(n, Nrec);
+
+ if (req) for (i = 0; i < Ncol; i++) {
+ if (!MaxBlk) {
+ if (UseTemp)
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+
+ pos = (BIGINT)Deplac[i] + (BIGINT)((Spos % Nrec) * Clens[i])
+ + (BIGINT)(Spos / Nrec) * (BIGINT)Blksize;
+ } else
+ pos = BigDep[i] + (BIGINT)Spos * (BIGINT)Clens[i];
+
+ if (BigSeek(g, Hfile, pos))
+ return true;
+
+ if (BigRead(g, Hfile, To_Buf, req * Clens[i]))
+ return true;
+
+ if (!UseTemp || MaxBlk) {
+ if (!MaxBlk)
+ pos = (BIGINT)Deplac[i] + (BIGINT)((Tpos % Nrec) * Clens[i])
+ + (BIGINT)(Tpos / Nrec) * (BIGINT)Blksize;
+ else
+ pos = BigDep[i] + (BIGINT)Tpos * (BIGINT)Clens[i];
+
+ if (BigSeek(g, Tfile, pos))
+ return true;
+
+ if (BigWrite(g, Tfile, To_Buf, req * Clens[i]))
+ return true;
+
+ } // endif UseTemp
+
+ } // endfor i
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (UseTemp && !MaxBlk && (!(Tpos % Nrec) || (eof && Spos == Fpos))) {
+ // Write the full or last block to the temporary file
+ if ((dep = Nrec - (Tpos % Nrec)) < Nrec)
+ // Clean the last block in case of future insert, must be
+ // done here because Tfile was open in write only.
+ for (i = 0; i < Ncol; i++) {
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', dep * Clens[i]);
+ } // endfor i
+
+ if (BigWrite(g, Tfile, NewBlock, Blksize))
+ return true;
+
+ if (Spos == Fpos)
+ eof = false;
+
+ } // endif Usetemp...
+
+#ifdef DEBTRACE
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+#endif
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediateLines
+
+/***********************************************************************/
+/* Clean deleted space in a huge VCT or Vec table file. */
+/***********************************************************************/
+bool BGVFAM::CleanUnusedSpace(PGLOBAL g)
+ {
+ int i;
+ int n;
+ BIGINT pos, dep;
+
+ if (!MaxBlk) {
+ /*******************************************************************/
+ /* Clean last block of the VCT table file. */
+ /*******************************************************************/
+ assert(!UseTemp); // This case is handled in MoveIntermediateLines
+
+ if (!(n = Nrec - Last))
+ return false;
+
+ dep = (BIGINT)((Block - 1) * Blksize);
+
+ for (i = 0; i < Ncol; i++) {
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', n * Clens[i]);
+ pos = dep + (BIGINT)(Deplac[i] + Last * Clens[i]);
+
+ if (BigSeek(g, Hfile, pos))
+ return true;
+
+ if (BigWrite(g, Hfile, To_Buf, n * Clens[i]))
+ return true;
+
+ } // endfor i
+
+ } else {
+ int req;
+
+ memset(To_Buf, 0, Buflen);
+
+ for (n = Fpos - Tpos; n > 0; n -= req) {
+ /*****************************************************************/
+ /* Fill VEC file remaining lines with 0's. */
+ /* This seems to work even column blocks have been made with */
+ /* Blanks = true. Perhaps should it be set to false for VEC. */
+ /*****************************************************************/
+ req = min(n, Nrec);
+
+ for (i = 0; i < Ncol; i++) {
+ pos = BigDep[i] + (BIGINT)Tpos * (BIGINT)Clens[i];
+
+ if (BigSeek(g, Tfile, pos))
+ return true;
+
+ if (BigWrite(g, Tfile, To_Buf, req * Clens[i]))
+ return true;
+
+ } // endfor i
+
+ Tpos += req;
+ } // endfor n
+
+ } // endif MaxBlk
+
+ return false;
+ } // end of CleanUnusedSpace
+
+/***********************************************************************/
+/* Data Base close routine for huge VEC access method. */
+/***********************************************************************/
+void BGVFAM::CloseTableFile(PGLOBAL g)
+ {
+ int rc, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ if (mode == MODE_INSERT) {
+ if (Closing)
+ wrc = RC_FX; // Last write was in error
+ else
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last = CurNum;
+ Block = CurBlk + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Last = Nrec;
+ Block = CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ if (wrc != RC_FX) {
+ rc = ResetTableSize(g, Block, Last);
+ } else if (AddBlock) {
+ // Last block was not written
+ rc = ResetTableSize(g, CurBlk, Nrec);
+ longjmp(g->jumper[g->jump_level], 44);
+ } // endif
+
+ } else if (mode == MODE_UPDATE) {
+ // Write back to file any pending modifications
+ for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->GetSetCols();
+ colp; colp = (PVCTCOL)colp->Next)
+ colp->WriteBlock(g);
+
+ if (UseTemp && Tfile) {
+ rc = RenameTempFile(g);
+ Hfile = Tfile = INVALID_HANDLE_VALUE;
+
+ if (Header)
+ // Header must be set because it was not set in temp file
+ rc = SetBlockInfo(g);
+
+ } // endif UseTemp
+
+ } else if (mode == MODE_DELETE && UseTemp && Tfile) {
+ if (MaxBlk)
+ rc = CleanUnusedSpace(g);
+
+ if ((rc = RenameTempFile(g)) != RC_FX) {
+ Hfile = Tfile = INVALID_HANDLE_VALUE; // For SetBlockInfo
+ rc = ResetTableSize(g, Block, Last);
+ } // endif rc
+
+ } // endif's mode
+
+ if (Hfile != INVALID_HANDLE_VALUE)
+ rc = PlugCloseFile(g, To_Fb);
+
+#ifdef DEBTRACE
+ htrc("BGV CloseTableFile: closing %s wrc=%d rc=%d\n",
+ To_File, wrc, rc);
+#endif
+ Hfile = INVALID_HANDLE_VALUE;
+ } // end of CloseDB
+
+/***********************************************************************/
+/* Rewind routine for huge VCT access method. */
+/***********************************************************************/
+void BGVFAM::Rewind(void)
+ {
+ // In mode update we need to read Set Column blocks
+ if (Tdbp->GetMode() == MODE_UPDATE)
+ OldBlk = -1;
+
+ // Initialize so block optimization is called for 1st block
+ CurBlk = -1;
+ CurNum = Nrec - 1;
+
+#if 0 // This is probably unuseful as the file is directly accessed
+#if defined(WIN32) //OB
+ SetFilePointer(Hfile, 0, NULL, FILE_BEGIN);
+#else // UNIX
+ lseek64(Hfile, 0, SEEK_SET);
+#endif // UNIX
+#endif // 0
+ } // end of Rewind
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool BGVFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ BIGINT pos;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to read. */
+ /*********************************************************************/
+ if (MaxBlk) // File has Vector format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac * (BIGINT)MaxBlk
+ + (BIGINT)colp->Clen * (BIGINT)CurBlk) + (BIGINT)Headlen;
+ else // Old VCT format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac
+ + (BIGINT)Lrecl * (BIGINT)CurBlk);
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ "RB: offset=%lf Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d MaxBlk=%d\n",
+ (double)pos, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk);
+#endif
+
+ if (BigSeek(g, Hfile, pos))
+ return true;
+
+ if (BigRead(g, Hfile, colp->Blk->GetValPointer(), colp->Clen * Nrec))
+ return true;
+
+#ifdef DEBTRACE
+ num_read++;
+#endif
+ return false;
+ } // 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. */
+/***********************************************************************/
+bool BGVFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int len;
+ BIGINT pos;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ if (MaxBlk) // File has Vector format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac * (BIGINT)MaxBlk
+ + (BIGINT)colp->Clen * (BIGINT)colp->ColBlk) + (BIGINT)Headlen;
+ else // Old VCT format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac
+ + (BIGINT)Lrecl * (BIGINT)colp->ColBlk);
+
+#ifdef DEBTRACE
+ htrc("WB: offset=%lf Nrec=%d Deplac=%d Lrecl=%d ColBlk=%d\n",
+ (double)pos, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
+#endif
+
+ if (BigSeek(g, Tfile, pos))
+ return true;
+
+//len = colp->Clen * Nrec; see comment in VCTFAM
+ len = colp->Clen * ((Tdbp->GetMode() == MODE_INSERT) ? CurNum : Nrec);
+
+ if (BigWrite(g, Tfile, colp->Blk->GetValPointer(), len))
+ return true;
+
+ return false;
+ } // end of WriteBlock
+
+/* ----------------------- End of FilAMVct --------------------------- */
diff --git a/storage/connect/filamvct.h b/storage/connect/filamvct.h
index 666bb771be9..22665c6cd23 100644
--- a/storage/connect/filamvct.h
+++ b/storage/connect/filamvct.h
@@ -1,249 +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__
-
+/************** 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__
+
diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp
index 276aa5eec2b..b3f3b2d5cff 100644
--- a/storage/connect/filamzip.cpp
+++ b/storage/connect/filamzip.cpp
@@ -1,822 +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 ---------------------------- */
+/*********** 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 ---------------------------- */
diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h
index a92d8f49104..a83af78b19a 100644
--- a/storage/connect/filamzip.h
+++ b/storage/connect/filamzip.h
@@ -1,174 +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
+/************** 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
diff --git a/storage/connect/fmdlex.c b/storage/connect/fmdlex.c
index b2ee06f9362..9ab8f2e03c5 100644
--- a/storage/connect/fmdlex.c
+++ b/storage/connect/fmdlex.c
@@ -1,1525 +1,1525 @@
-#define yyFlexLexer fmdfFlexLexer
-#define yy_create_buffer fmdf_create_buffer
-#define yy_delete_buffer fmdf_delete_buffer
-#define yy_flex_debug fmdf_flex_debug
-#define yy_init_buffer fmdf_init_buffer
-#define yy_load_buffer_state fmdf_load_buffer_state
-#define yy_switch_to_buffer fmdf_switch_to_buffer
-#define yyin fmdfin
-#define yyleng fmdfleng
-#define yylex fmdflex
-#define yyout fmdfout
-#define yyrestart fmdfrestart
-#define yytext fmdftext
-#define yywrap fmdfwrap
-
-/* A lexical scanner generated by flex */
-
-/* Scanner skeleton version:
- * $Header: /home/daffy/u0/vern/flex/flex-2.4.7/RCS/flex.skl,v 1.2 94/08/03 11:13:24 vern Exp $
- */
-
-#define FLEX_SCANNER
-
-#if WIN32
-#define __STDC__ 1
-#endif
-
-#include <stdio.h>
-
-
-/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
-#ifdef c_plusplus
-#ifndef __cplusplus
-#define __cplusplus
-#endif
-#endif
-
-
-#ifdef __cplusplus
-
-#include <stdlib.h>
-#include <unistd.h>
-
-/* Use prototypes in function declarations. */
-#define YY_USE_PROTOS
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-#ifdef __STDC__
-
-#define YY_USE_PROTOS
-#define YY_USE_CONST
-
-#endif /* __STDC__ */
-#endif /* ! __cplusplus */
-
-
-#ifdef __TURBOC__
-#define YY_USE_CONST
-#endif
-
-
-#ifndef YY_USE_CONST
-#ifndef const
-#define const
-#endif
-#endif
-
-
-#ifdef YY_USE_PROTOS
-#define YY_PROTO(proto) proto
-#else
-#define YY_PROTO(proto) ()
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index. If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN yy_start = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state.
- */
-#define YY_START ((yy_start - 1) / 2)
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". Now included
- * only for backward compatibility with previous versions of flex.
- */
-#define YY_NEW_FILE yyrestart( yyin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#define YY_BUF_SIZE 16384
-
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-
-extern int yyleng;
-extern FILE *yyin, *yyout;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- extern int yywrap YY_PROTO(( void ));
-#ifdef __cplusplus
- }
-#endif
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-/* The funky do-while in the following #define is used to turn the definition
- * int a single C statement (which needs a semi-colon terminator). This
- * avoids problems with code like:
- *
- * if ( condition_holds )
- * yyless( 5 );
- * else
- * do_something_else();
- *
- * Prior to using the do-while the compiler would get upset at the
- * "else" because it interpreted the "if" statement as being all
- * done when it reached the ';' after the yyless() call.
- */
-
-/* Return all but the first 'n' matched characters back to the input stream. */
-
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- *yy_cp = yy_hold_char; \
- yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
- } \
- while ( 0 )
-
-#define unput(c) yyunput( c, yytext_ptr )
-
-
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- int yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via yyrestart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
- };
-
-static YY_BUFFER_STATE yy_current_buffer = 0;
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- */
-#define YY_CURRENT_BUFFER yy_current_buffer
-
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-
-
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1; /* whether we need to initialize */
-static int yy_start = 0; /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin. A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-static void yyunput YY_PROTO(( int c, char *buf_ptr ));
-void yyrestart YY_PROTO(( FILE *input_file ));
-void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
-void yy_load_buffer_state YY_PROTO(( void ));
-YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
-void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
-
-static int yy_start_stack_ptr = 0;
-static int yy_start_stack_depth = 0;
-static int *yy_start_stack = 0;
-static void yy_push_state YY_PROTO(( int new_state ));
-static void yy_pop_state YY_PROTO(( void ));
-static int yy_top_state YY_PROTO(( void ));
-
-static void *yy_flex_alloc YY_PROTO(( unsigned int ));
-static void *yy_flex_realloc YY_PROTO(( void *, unsigned int ));
-static void yy_flex_free YY_PROTO(( void * ));
-
-#define yy_new_buffer yy_create_buffer
-
-#define INITIAL 0
-#define txt 1
-#define sqt 2
-#define dqt 3
-typedef unsigned char YY_CHAR;
-typedef int yy_state_type;
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-extern char *yytext;
-#define yytext_ptr yytext
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy YY_PROTO(( char *, const char *, int ));
-#endif
-
-#ifdef __cplusplus
-static int yyinput YY_PROTO(( void ));
-#else
-static int input YY_PROTO(( void ));
-#endif
-
-static yy_state_type yy_get_previous_state YY_PROTO(( void ));
-static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
-static int yy_get_next_buffer YY_PROTO(( void ));
-static void yy_fatal_error YY_PROTO(( const char msg[] ));
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
- yytext_ptr = yy_bp; \
- yyleng = yy_cp - yy_bp; \
- yy_hold_char = *yy_cp; \
- *yy_cp = '\0'; \
- yy_c_buf_p = yy_cp;
-
-#define YY_END_OF_BUFFER 17
-static const short int yy_accept[45] =
- { 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 17, 15,
- 16, 14, 1, 13, 2, 3, 8, 7, 6, 9,
- 10, 11, 12, 15, 16, 5, 15, 16, 4, 1,
- 8, 8, 7, 7, 6, 9, 10, 11, 12, 0,
- 5, 0, 4, 0
- } ;
-
-static const int yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 2, 1, 4, 1, 1, 1, 1, 5, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 6, 1, 1,
- 1, 1, 1, 1, 1, 1, 7, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 8, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 9, 1, 1, 1, 1, 10, 1,
- 1, 1, 1, 1, 11, 12, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1
- } ;
-
-static const int yy_meta[13] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1
- } ;
-
-static const short int yy_base[52] =
- { 0,
- 49, 48, 0, 0, 10, 13, 16, 18, 50, 53,
- 53, 53, 47, 53, 53, 53, 42, 40, 38, 36,
- 34, 32, 30, 36, 35, 53, 35, 34, 53, 35,
- 53, 30, 53, 28, 26, 24, 22, 20, 18, 24,
- 53, 24, 53, 53, 26, 25, 24, 23, 22, 16,
- 13
- } ;
-
-static const short int yy_def[52] =
- { 0,
- 45, 45, 44, 3, 46, 46, 47, 47, 44, 44,
- 44, 44, 44, 44, 44, 44, 48, 49, 44, 44,
- 44, 44, 44, 50, 50, 44, 51, 51, 44, 44,
- 44, 48, 44, 49, 44, 44, 44, 44, 44, 50,
- 44, 51, 44, 0, 44, 44, 44, 44, 44, 44,
- 44
- } ;
-
-static const short int yy_nxt[66] =
- { 0,
- 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 25, 42, 26, 25, 40, 26, 28, 29,
- 28, 29, 33, 31, 27, 24, 10, 43, 41, 39,
- 38, 37, 36, 35, 34, 32, 30, 43, 43, 41,
- 41, 39, 38, 37, 36, 35, 34, 32, 30, 44,
- 11, 11, 9, 44, 44, 44, 44, 44, 44, 44,
- 44, 44, 44, 44, 44
- } ;
-
-static const short int yy_chk[66] =
- { 0,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 5, 51, 5, 6, 50, 6, 7, 7,
- 8, 8, 49, 48, 47, 46, 45, 42, 40, 39,
- 38, 37, 36, 35, 34, 32, 30, 28, 27, 25,
- 24, 23, 22, 21, 20, 19, 18, 17, 13, 9,
- 2, 1, 44, 44, 44, 44, 44, 44, 44, 44,
- 44, 44, 44, 44, 44
- } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-char *yytext;
-#if defined(UNIX)
-#define _fileno fileno
-#define istty _istty
-#else
-#include <stdlib.h>
-#include <io.h>
-#endif /* UNIX */
-#include <string.h>
-#include "preparse.h"
-
-#define isatty _isatty
-#define fileno _fileno
-#undef YY_DECL
-#define YY_DECL int yylex YY_PROTO((PDTP ppp))
-#define YYSTATE ((yy_start-1)/2)
-#undef YY_INPUT
-#define YY_INPUT(buf,n,m) \
- {n=(m<strlen(pp->Curp))?m:strlen(pp->Curp);strncpy(buf,pp->Curp,n);pp->Curp+=n;}
-#if defined(UNIX)
-#undef yywrap
-#define yywrap ddwrap
-#endif /* UNIX */
-static PDTP pp;
-static void MakeParm(int n);
-static void MakeMMDD(int n);
-static void MakeAMPM(int n);
-static void MakeIn(char *);
-static void MakeOut(char *);
-static void Quotin(char *);
-static void Quotout(char *);
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifdef YY_MALLOC_DECL
-YY_MALLOC_DECL
-#else
-#if __STDC__
-#ifndef __cplusplus
-#include <stdlib.h>
-#endif
-#else
-/* Just try to get by without declaring the routines. This will fail
- * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
- * or sizeof(void*) != sizeof(int).
- */
-#endif
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- if ( yy_current_buffer->yy_is_interactive ) \
- { \
- int c = getc( yyin ); \
- result = c == EOF ? 0 : 1; \
- buf[0] = (char) c; \
- } \
- else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
- && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" );
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL int yylex YY_PROTO(( void ))
-#endif
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-YY_DECL
- {
- register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
- register int yy_act;
-
-
-
- /*************************************************************************/
- /* Flex parser to analyze date format and produce input and/or output */
- /* formats. Non quoted blanks are significant (put in the output format) */
- /* unless the Flag is not null, then there are ignored for output fmt. */
- /*************************************************************************/
- BEGIN txt;
- pp = ppp;
- pp->Num = 0;
- if (pp->InFmt) {*pp->InFmt = '\0'; pp->InFmt[pp->Outsize -1] = '\0'; }
- if (pp->OutFmt) {*pp->OutFmt = '\0'; pp->OutFmt[pp->Outsize -1] = '\0'; }
- pp->Curp = pp->Format;
- if (!yy_init) { /* Restart that stupid Flex otherwise parsing last input */
- yy_init_buffer( yy_current_buffer, yyin );
- yy_load_buffer_state();
- } // endif yy_init
-
-
- if ( yy_init )
- {
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- if ( ! yy_start )
- yy_start = 1; /* first start state */
-
- if ( ! yyin )
- yyin = stdin;
-
- if ( ! yyout )
- yyout = stdout;
-
- if ( yy_current_buffer )
- yy_init_buffer( yy_current_buffer, yyin );
- else
- yy_current_buffer =
- yy_create_buffer( yyin, YY_BUF_SIZE );
-
- yy_load_buffer_state();
-
- yy_init = 0;
- }
-
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = yy_c_buf_p;
-
- /* Support of yytext. */
- *yy_cp = yy_hold_char;
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
- yy_current_state = yy_start;
-yy_match:
- do
- {
- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 45 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- ++yy_cp;
- }
- while ( yy_base[yy_current_state] != 53 );
-
-yy_find_action:
- yy_act = yy_accept[yy_current_state];
-
- YY_DO_BEFORE_ACTION;
-
-
-do_action: /* This label is used only to access EOF actions. */
-
-
- switch ( yy_act )
- { /* beginning of action switch */
- case 0: /* must back up */
- /* undo the effects of YY_DO_BEFORE_ACTION */
- *yy_cp = yy_hold_char;
- yy_cp = yy_last_accepting_cpos;
- yy_current_state = yy_last_accepting_state;
- goto yy_find_action;
-
-case 1:
-YY_USER_ACTION
-{MakeIn(" "); if (!pp->Flag) MakeOut(" ");}
- YY_BREAK
-case 2:
-YY_USER_ACTION
-{BEGIN dqt;}
- YY_BREAK
-case 3:
-YY_USER_ACTION
-{BEGIN sqt;}
- YY_BREAK
-case 4:
-YY_USER_ACTION
-{Quotin(yytext); Quotout(yytext);
-#ifdef DEBUG
- fprintf(stderr, "In double quote yytext=>>%s<<\n", yytext);
-#endif
- BEGIN txt;}
- YY_BREAK
-case 5:
-YY_USER_ACTION
-{Quotin(yytext); Quotout(yytext);
-#ifdef DEBUG
- fprintf(stderr, "In simple quote yytext=>>%s<<\n", yytext);
-#endif
- BEGIN txt;}
- YY_BREAK
-case 6:
-YY_USER_ACTION
-MakeParm(0);
- YY_BREAK
-case 7:
-YY_USER_ACTION
-MakeMMDD(1);
- YY_BREAK
-case 8:
-YY_USER_ACTION
-MakeMMDD(2);
- YY_BREAK
-case 9:
-YY_USER_ACTION
-MakeParm(3);
- YY_BREAK
-case 10:
-YY_USER_ACTION
-MakeParm(4);
- YY_BREAK
-case 11:
-YY_USER_ACTION
-MakeParm(5);
- YY_BREAK
-case 12:
-YY_USER_ACTION
-MakeAMPM(6);
- YY_BREAK
-case 13:
-YY_USER_ACTION
-
- YY_BREAK
-case 14:
-YY_USER_ACTION
-{MakeIn(yytext); MakeOut(yytext);
-#ifdef DEBUG
- fprintf(stderr, "No quote char=>>%s<<\n", yytext);
-#endif
- }
- YY_BREAK
-case 15:
-YY_USER_ACTION
-{pp->Flag = -1; yyterminate();}
- YY_BREAK
-case 16:
-YY_USER_ACTION
-YY_FATAL_ERROR( "flex scanner jammed" );
- YY_BREAK
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(txt):
-case YY_STATE_EOF(sqt):
-case YY_STATE_EOF(dqt):
- yyterminate();
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = yy_cp - yytext_ptr - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = yy_hold_char;
-
- if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed yyin at a new source and called
- * yylex(). If so, then we have to assure
- * consistency between yy_current_buffer and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- yy_n_chars = yy_current_buffer->yy_n_chars;
- yy_current_buffer->yy_input_file = yyin;
- yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state();
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state );
-
- yy_bp = yytext_ptr + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++yy_c_buf_p;
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
- yy_cp = yy_c_buf_p;
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer() )
- {
- case EOB_ACT_END_OF_FILE:
- {
- yy_did_buffer_switch_on_eof = 0;
-
- if ( yywrap() )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * yytext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! yy_did_buffer_switch_on_eof )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yy_c_buf_p =
- yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state();
-
- yy_cp = yy_c_buf_p;
- yy_bp = yytext_ptr + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- yy_c_buf_p =
- &yy_current_buffer->yy_ch_buf[yy_n_chars];
-
- yy_current_state = yy_get_previous_state();
-
- yy_cp = yy_c_buf_p;
- yy_bp = yytext_ptr + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
- } /* end of yylex */
-
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-
-static int yy_get_next_buffer()
- {
- register char *dest = yy_current_buffer->yy_ch_buf;
- register char *source = yytext_ptr - 1; /* copy prev. char, too */
- register int number_to_move, i;
- int ret_val;
-
- if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( yy_current_buffer->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
- {
- /* We matched a singled characater, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = yy_c_buf_p - yytext_ptr;
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- yy_n_chars = 0;
-
- else
- {
- int num_to_read =
- yy_current_buffer->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-#ifdef YY_USES_REJECT
- YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-#else
-
- /* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = yy_current_buffer;
-
- int yy_c_buf_p_offset = yy_c_buf_p - b->yy_ch_buf;
-
- b->yy_buf_size *= 2;
- b->yy_ch_buf = (char *)
- yy_flex_realloc( (void *) b->yy_ch_buf,
- b->yy_buf_size );
-
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR(
- "fatal error - scanner input buffer overflow" );
-
- yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
-
- num_to_read = yy_current_buffer->yy_buf_size -
- number_to_move - 1;
-#endif
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
- yy_n_chars, num_to_read );
- }
-
- if ( yy_n_chars == 0 )
- {
- if ( number_to_move - YY_MORE_ADJ == 1 )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- yyrestart( yyin );
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- yy_current_buffer->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- yy_n_chars += number_to_move;
- yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
- yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
-
- /* yytext begins at the second character in yy_ch_buf; the first
- * character is the one which preceded it before reading in the latest
- * buffer; it needs to be kept around in case it's a newline, so
- * yy_get_previous_state() will have with '^' rules active.
- */
-
- yytext_ptr = &yy_current_buffer->yy_ch_buf[1];
-
- return ret_val;
- }
-
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-static yy_state_type yy_get_previous_state()
- {
- register yy_state_type yy_current_state;
- register char *yy_cp;
-
- yy_current_state = yy_start;
-
- for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
- {
- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 45 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- }
-
- return yy_current_state;
- }
-
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
-
-#ifdef YY_USE_PROTOS
-static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
-#else
-static yy_state_type yy_try_NUL_trans( yy_current_state )
-yy_state_type yy_current_state;
-#endif
- {
- register int yy_is_jam;
- register char *yy_cp = yy_c_buf_p;
-
- register YY_CHAR yy_c = 1;
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 45 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 44);
-
- return yy_is_jam ? 0 : yy_current_state;
- }
-
-
-#ifdef YY_USE_PROTOS
-static void yyunput( int c, register char *yy_bp )
-#else
-static void yyunput( c, yy_bp )
-int c;
-register char *yy_bp;
-#endif
- {
- register char *yy_cp = yy_c_buf_p;
-
- /* undo effects of setting up yytext */
- *yy_cp = yy_hold_char;
-
- if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
- { /* need to shift things up to make room */
- /* +2 for EOB chars. */
- register int number_to_move = yy_n_chars + 2;
- register char *dest = &yy_current_buffer->yy_ch_buf[
- yy_current_buffer->yy_buf_size + 2];
- register char *source =
- &yy_current_buffer->yy_ch_buf[number_to_move];
-
- while ( source > yy_current_buffer->yy_ch_buf )
- *--dest = *--source;
-
- yy_cp += dest - source;
- yy_bp += dest - source;
- yy_n_chars = yy_current_buffer->yy_buf_size;
-
- if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
- YY_FATAL_ERROR( "flex scanner push-back overflow" );
- }
-
- if ( yy_cp > yy_bp && yy_cp[-1] == '\n' )
- yy_cp[-2] = '\n';
-
- *--yy_cp = (char) c;
-
-
- /* Note: the formal parameter *must* be called "yy_bp" for this
- * macro to now work correctly.
- */
- YY_DO_BEFORE_ACTION; /* set up yytext again */
- }
-
-
-#ifdef __cplusplus
-static int yyinput()
-#else
-static int input()
-#endif
- {
- int c;
-
- *yy_c_buf_p = yy_hold_char;
-
- if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
- /* This was really a NUL. */
- *yy_c_buf_p = '\0';
-
- else
- { /* need more input */
- yytext_ptr = yy_c_buf_p;
- ++yy_c_buf_p;
-
- switch ( yy_get_next_buffer() )
- {
- case EOB_ACT_END_OF_FILE:
- {
- if ( yywrap() )
- {
- yy_c_buf_p =
- yytext_ptr + YY_MORE_ADJ;
- return EOF;
- }
-
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput();
-#else
- return input();
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
- break;
-
- case EOB_ACT_LAST_MATCH:
-#ifdef __cplusplus
- YY_FATAL_ERROR(
- "unexpected last match in yyinput()" );
-#else
- YY_FATAL_ERROR(
- "unexpected last match in input()" );
-#endif
- }
- }
- }
-
- c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
- *yy_c_buf_p = '\0'; /* preserve yytext */
- yy_hold_char = *++yy_c_buf_p;
-
- return c;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yyrestart( FILE *input_file )
-#else
-void yyrestart( input_file )
-FILE *input_file;
-#endif
- {
- if ( ! yy_current_buffer )
- yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
-
- yy_init_buffer( yy_current_buffer, input_file );
- yy_load_buffer_state();
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
-#else
-void yy_switch_to_buffer( new_buffer )
-YY_BUFFER_STATE new_buffer;
-#endif
- {
- if ( yy_current_buffer == new_buffer )
- return;
-
- if ( yy_current_buffer )
- {
- /* Flush out information for old buffer. */
- *yy_c_buf_p = yy_hold_char;
- yy_current_buffer->yy_buf_pos = yy_c_buf_p;
- yy_current_buffer->yy_n_chars = yy_n_chars;
- }
-
- yy_current_buffer = new_buffer;
- yy_load_buffer_state();
-
- /* We don't actually know whether we did this switch during
- * EOF (yywrap()) processing, but the only time this flag
- * is looked at is after yywrap() is called, so it's safe
- * to go ahead and always set it.
- */
- yy_did_buffer_switch_on_eof = 1;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_load_buffer_state( void )
-#else
-void yy_load_buffer_state()
-#endif
- {
- yy_n_chars = yy_current_buffer->yy_n_chars;
- yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
- yyin = yy_current_buffer->yy_input_file;
- yy_hold_char = *yy_c_buf_p;
- }
-
-
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
-#else
-YY_BUFFER_STATE yy_create_buffer( file, size )
-FILE *file;
-int size;
-#endif
- {
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
-
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
-
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- yy_init_buffer( b, file );
-
- return b;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_delete_buffer( YY_BUFFER_STATE b )
-#else
-void yy_delete_buffer( b )
-YY_BUFFER_STATE b;
-#endif
- {
- if ( b == yy_current_buffer )
- yy_current_buffer = (YY_BUFFER_STATE) 0;
-
- yy_flex_free( (void *) b->yy_ch_buf );
- yy_flex_free( (void *) b );
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
-#else
-void yy_init_buffer( b, file )
-YY_BUFFER_STATE b;
-FILE *file;
-#endif
- {
- b->yy_input_file = file;
-
- /* We put in the '\n' and start reading from [1] so that an
- * initial match-at-newline will be true.
- */
-
- b->yy_ch_buf[0] = '\n';
- b->yy_n_chars = 1;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[1];
-
- b->yy_is_interactive = file ? isatty( fileno(file) ) : 0;
-
- b->yy_fill_buffer = 1;
-
- b->yy_buffer_status = YY_BUFFER_NEW;
- }
-
-
-#ifdef YY_USE_PROTOS
-static void yy_push_state( int new_state )
-#else
-static void yy_push_state( new_state )
-int new_state;
-#endif
- {
- if ( yy_start_stack_ptr >= yy_start_stack_depth )
- {
- int new_size;
-
- yy_start_stack_depth += YY_START_STACK_INCR;
- new_size = yy_start_stack_depth * sizeof( int );
-
- if ( ! yy_start_stack )
- yy_start_stack = (int *) yy_flex_alloc( new_size );
-
- else
- yy_start_stack = (int *) yy_flex_realloc(
- (void *) yy_start_stack, new_size );
-
- if ( ! yy_start_stack )
- YY_FATAL_ERROR(
- "out of memory expanding start-condition stack" );
- }
-
- yy_start_stack[yy_start_stack_ptr++] = YY_START;
-
- BEGIN(new_state);
- }
-
-
-static void yy_pop_state()
- {
- if ( --yy_start_stack_ptr < 0 )
- YY_FATAL_ERROR( "start-condition stack underflow" );
-
- BEGIN(yy_start_stack[yy_start_stack_ptr]);
- }
-
-
-static int yy_top_state()
- {
- return yy_start_stack[yy_start_stack_ptr - 1];
- }
-
-
-#ifdef YY_USE_PROTOS
-static void yy_fatal_error( const char msg[] )
-#else
-static void yy_fatal_error( msg )
-char msg[];
-#endif
- {
- (void) fprintf( stderr, "%s\n", msg );
- exit( 1 );
- }
-
-
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- yytext[yyleng] = yy_hold_char; \
- yy_c_buf_p = yytext + n - YY_MORE_ADJ; \
- yy_hold_char = *yy_c_buf_p; \
- *yy_c_buf_p = '\0'; \
- yyleng = n; \
- } \
- while ( 0 )
-
-
-/* Internal utility routines. */
-
-#ifndef yytext_ptr
-#ifdef YY_USE_PROTOS
-static void yy_flex_strncpy( char *s1, const char *s2, int n )
-#else
-static void yy_flex_strncpy( s1, s2, n )
-char *s1;
-const char *s2;
-int n;
-#endif
- {
- register int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
- }
-#endif
-
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_alloc( unsigned int size )
-#else
-static void *yy_flex_alloc( size )
-unsigned int size;
-#endif
- {
- return (void *) malloc( size );
- }
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_realloc( void *ptr, unsigned int size )
-#else
-static void *yy_flex_realloc( ptr, size )
-void *ptr;
-unsigned int size;
-#endif
- {
- return (void *) realloc( ptr, size );
- }
-
-#ifdef YY_USE_PROTOS
-static void yy_flex_free( void *ptr )
-#else
-static void yy_flex_free( ptr )
-void *ptr;
-#endif
- {
- free( ptr );
- }
-
-
-void MakeMMDD(int n)
- {
- int m = strlen(yytext) - 1;
- char c = yytext[m];
-
- if ((c == 'M' && n == 1) || (c == 'D' && n == 2)) {
- m++;
- c = 0;
- } /* endif c */
-
-#ifdef DEBUG
- fprintf(stderr, "MM: n=%d num=%d InFmt=%s OutFmt=%s;\n",
- n, pp->Num, pp->InFmt, pp->OutFmt);
-#endif
- pp->Index[pp->Num++] = (m < 3) ? n : (-n);
-
- switch (m) {
- case 1:
- MakeIn("%2d");
- MakeOut((n == 1) ? "%#m" : "%#d");
- break;
- case 2:
- MakeIn("%2d");
- MakeOut((n == 1) ? "%m" : "%d");
- break;
- case 3:
- MakeIn("%3s");
- MakeOut((n == 1) ? "%b" : "%a");
- break;
- default:
- if (c && c != ' ') {
- char fm[] = "%[^x]";
- fm[3] = c;
- MakeIn(fm);
- } else
- MakeIn("%s");
-
- MakeOut((n == 1) ? "%B" : "%A");
- } /* endswitch m */
-
- if (c)
- unput(c);
-
- } /* end of MakeMMDD */
-
-void MakeParm(int n)
- {
- int m = strlen(yytext);
-
-#ifdef DEBUG
- fprintf(stderr, "MP: n=%d num=%d InFmt=%s OutFmt=%s;\n",
- n, pp->Num, pp->InFmt, pp->OutFmt);
-#endif
- pp->Index[pp->Num++] = n;
-
- switch (m) {
- case 1:
- MakeIn("%2d");
- MakeOut((n == 0) ? "%#y" : (n == 3) ? "%#H"
- : (n == 4) ? "%#M" : "%#S");
- break;
- case 2:
- MakeIn("%2d");
- MakeOut((n == 0) ? "%y" : (n == 3) ? "%H"
- : (n == 4) ? "%M" : "%S");
- break;
- default:
- MakeIn("%4d");
- MakeOut("%Y");
- } /* endswitch m */
-
- } /* end of MakeParm */
-
-void MakeAMPM(int n)
- {
- char buf[8];
- int m = strlen(yytext);
-
-#ifdef DEBUG
- fprintf(stderr, "AM: n=%d num=%d InFmt=%s OutFmt=%s;\n",
- n, pp->Num, pp->InFmt, pp->OutFmt);
-#endif
- pp->Index[pp->Num++] = -n;
- sprintf(buf, "%%%ds", m);
- MakeIn(buf);
-
- if (pp->OutFmt) {
- char *p;
-
- if ((p = strstr(pp->OutFmt, "%H")))
- *(p + 1) = 'I'; // 12-hour format
- else if ((p = strstr(pp->OutFmt, "%#H")))
- *(p + 2) = 'I'; // 12-hour format
-
- MakeOut("%p");
- } /* endif Flag */
-
- } /* end of MakeAMPM */
-
-void MakeIn(char *text)
- {
- if (!pp->InFmt)
- return;
-
- strncat(pp->InFmt, text, (pp->Outsize - 1) - strlen(pp->InFmt));
- } /* end of MakeIn */
-
-void MakeOut(char *text)
- {
- if (!pp->OutFmt) return;
-
- strncat(pp->OutFmt, text, (pp->Outsize - 1) - strlen(pp->OutFmt));
- } /* end of MakeOut */
-
-void Quotin(char *text)
- {
- if (!pp->InFmt)
- return;
-
- MakeIn(text);
- pp->InFmt[strlen(pp->InFmt)-1] = '\0';
- } /* end of Quotin */
-
-void Quotout(char *text)
- {
- if (!pp->OutFmt)
- return;
-
- MakeOut(text);
- pp->OutFmt[strlen(pp->OutFmt)-1] = '\0';
- } /* end of Quotout */
-
-int yywrap(void)
- {
- return 1;
- } /* end of yywrap */
-
+#define yyFlexLexer fmdfFlexLexer
+#define yy_create_buffer fmdf_create_buffer
+#define yy_delete_buffer fmdf_delete_buffer
+#define yy_flex_debug fmdf_flex_debug
+#define yy_init_buffer fmdf_init_buffer
+#define yy_load_buffer_state fmdf_load_buffer_state
+#define yy_switch_to_buffer fmdf_switch_to_buffer
+#define yyin fmdfin
+#define yyleng fmdfleng
+#define yylex fmdflex
+#define yyout fmdfout
+#define yyrestart fmdfrestart
+#define yytext fmdftext
+#define yywrap fmdfwrap
+
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/flex-2.4.7/RCS/flex.skl,v 1.2 94/08/03 11:13:24 vern Exp $
+ */
+
+#define FLEX_SCANNER
+
+#if WIN32
+#define __STDC__ 1
+#endif
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#ifdef __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+
+#ifdef __TURBOC__
+#define YY_USE_CONST
+#endif
+
+
+#ifndef YY_USE_CONST
+#ifndef const
+#define const
+#endif
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.
+ */
+#define YY_START ((yy_start - 1) / 2)
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". Now included
+ * only for backward compatibility with previous versions of flex.
+ */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern int yywrap YY_PROTO(( void ));
+#ifdef __cplusplus
+ }
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+void yyrestart YY_PROTO(( FILE *input_file ));
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+static void yy_push_state YY_PROTO(( int new_state ));
+static void yy_pop_state YY_PROTO(( void ));
+static int yy_top_state YY_PROTO(( void ));
+
+static void *yy_flex_alloc YY_PROTO(( unsigned int ));
+static void *yy_flex_realloc YY_PROTO(( void *, unsigned int ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define INITIAL 0
+#define txt 1
+#define sqt 2
+#define dqt 3
+typedef unsigned char YY_CHAR;
+typedef int yy_state_type;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+extern char *yytext;
+#define yytext_ptr yytext
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, const char *, int ));
+#endif
+
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( const char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = yy_cp - yy_bp; \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_END_OF_BUFFER 17
+static const short int yy_accept[45] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 17, 15,
+ 16, 14, 1, 13, 2, 3, 8, 7, 6, 9,
+ 10, 11, 12, 15, 16, 5, 15, 16, 4, 1,
+ 8, 8, 7, 7, 6, 9, 10, 11, 12, 0,
+ 5, 0, 4, 0
+ } ;
+
+static const int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 1, 1, 1, 1, 5, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 6, 1, 1,
+ 1, 1, 1, 1, 1, 1, 7, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 8, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 9, 1, 1, 1, 1, 10, 1,
+ 1, 1, 1, 1, 11, 12, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const int yy_meta[13] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1
+ } ;
+
+static const short int yy_base[52] =
+ { 0,
+ 49, 48, 0, 0, 10, 13, 16, 18, 50, 53,
+ 53, 53, 47, 53, 53, 53, 42, 40, 38, 36,
+ 34, 32, 30, 36, 35, 53, 35, 34, 53, 35,
+ 53, 30, 53, 28, 26, 24, 22, 20, 18, 24,
+ 53, 24, 53, 53, 26, 25, 24, 23, 22, 16,
+ 13
+ } ;
+
+static const short int yy_def[52] =
+ { 0,
+ 45, 45, 44, 3, 46, 46, 47, 47, 44, 44,
+ 44, 44, 44, 44, 44, 44, 48, 49, 44, 44,
+ 44, 44, 44, 50, 50, 44, 51, 51, 44, 44,
+ 44, 48, 44, 49, 44, 44, 44, 44, 44, 50,
+ 44, 51, 44, 0, 44, 44, 44, 44, 44, 44,
+ 44
+ } ;
+
+static const short int yy_nxt[66] =
+ { 0,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 25, 42, 26, 25, 40, 26, 28, 29,
+ 28, 29, 33, 31, 27, 24, 10, 43, 41, 39,
+ 38, 37, 36, 35, 34, 32, 30, 43, 43, 41,
+ 41, 39, 38, 37, 36, 35, 34, 32, 30, 44,
+ 11, 11, 9, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44
+ } ;
+
+static const short int yy_chk[66] =
+ { 0,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 5, 51, 5, 6, 50, 6, 7, 7,
+ 8, 8, 49, 48, 47, 46, 45, 42, 40, 39,
+ 38, 37, 36, 35, 34, 32, 30, 28, 27, 25,
+ 24, 23, 22, 21, 20, 19, 18, 17, 13, 9,
+ 2, 1, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+char *yytext;
+#if defined(UNIX)
+#define _fileno fileno
+#define istty _istty
+#else
+#include <stdlib.h>
+#include <io.h>
+#endif /* UNIX */
+#include <string.h>
+#include "preparse.h"
+
+#define isatty _isatty
+#define fileno _fileno
+#undef YY_DECL
+#define YY_DECL int yylex YY_PROTO((PDTP ppp))
+#define YYSTATE ((yy_start-1)/2)
+#undef YY_INPUT
+#define YY_INPUT(buf,n,m) \
+ {n=(m<strlen(pp->Curp))?m:strlen(pp->Curp);strncpy(buf,pp->Curp,n);pp->Curp+=n;}
+#if defined(UNIX)
+#undef yywrap
+#define yywrap ddwrap
+#endif /* UNIX */
+static PDTP pp;
+static void MakeParm(int n);
+static void MakeMMDD(int n);
+static void MakeAMPM(int n);
+static void MakeIn(char *);
+static void MakeOut(char *);
+static void Quotin(char *);
+static void Quotout(char *);
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = getc( yyin ); \
+ result = c == EOF ? 0 : 1; \
+ buf[0] = (char) c; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+
+
+ /*************************************************************************/
+ /* Flex parser to analyze date format and produce input and/or output */
+ /* formats. Non quoted blanks are significant (put in the output format) */
+ /* unless the Flag is not null, then there are ignored for output fmt. */
+ /*************************************************************************/
+ BEGIN txt;
+ pp = ppp;
+ pp->Num = 0;
+ if (pp->InFmt) {*pp->InFmt = '\0'; pp->InFmt[pp->Outsize -1] = '\0'; }
+ if (pp->OutFmt) {*pp->OutFmt = '\0'; pp->OutFmt[pp->Outsize -1] = '\0'; }
+ pp->Curp = pp->Format;
+ if (!yy_init) { /* Restart that stupid Flex otherwise parsing last input */
+ yy_init_buffer( yy_current_buffer, yyin );
+ yy_load_buffer_state();
+ } // endif yy_init
+
+
+ if ( yy_init )
+ {
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( yy_current_buffer )
+ yy_init_buffer( yy_current_buffer, yyin );
+ else
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+
+ yy_init = 0;
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 45 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 53 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_USER_ACTION
+{MakeIn(" "); if (!pp->Flag) MakeOut(" ");}
+ YY_BREAK
+case 2:
+YY_USER_ACTION
+{BEGIN dqt;}
+ YY_BREAK
+case 3:
+YY_USER_ACTION
+{BEGIN sqt;}
+ YY_BREAK
+case 4:
+YY_USER_ACTION
+{Quotin(yytext); Quotout(yytext);
+#ifdef DEBUG
+ fprintf(stderr, "In double quote yytext=>>%s<<\n", yytext);
+#endif
+ BEGIN txt;}
+ YY_BREAK
+case 5:
+YY_USER_ACTION
+{Quotin(yytext); Quotout(yytext);
+#ifdef DEBUG
+ fprintf(stderr, "In simple quote yytext=>>%s<<\n", yytext);
+#endif
+ BEGIN txt;}
+ YY_BREAK
+case 6:
+YY_USER_ACTION
+MakeParm(0);
+ YY_BREAK
+case 7:
+YY_USER_ACTION
+MakeMMDD(1);
+ YY_BREAK
+case 8:
+YY_USER_ACTION
+MakeMMDD(2);
+ YY_BREAK
+case 9:
+YY_USER_ACTION
+MakeParm(3);
+ YY_BREAK
+case 10:
+YY_USER_ACTION
+MakeParm(4);
+ YY_BREAK
+case 11:
+YY_USER_ACTION
+MakeParm(5);
+ YY_BREAK
+case 12:
+YY_USER_ACTION
+MakeAMPM(6);
+ YY_BREAK
+case 13:
+YY_USER_ACTION
+
+ YY_BREAK
+case 14:
+YY_USER_ACTION
+{MakeIn(yytext); MakeOut(yytext);
+#ifdef DEBUG
+ fprintf(stderr, "No quote char=>>%s<<\n", yytext);
+#endif
+ }
+ YY_BREAK
+case 15:
+YY_USER_ACTION
+{pp->Flag = -1; yyterminate();}
+ YY_BREAK
+case 16:
+YY_USER_ACTION
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(txt):
+case YY_STATE_EOF(sqt):
+case YY_STATE_EOF(dqt):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = yy_cp - yytext_ptr - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr - 1; /* copy prev. char, too */
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a singled characater, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = yy_c_buf_p - yytext_ptr;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset = yy_c_buf_p - b->yy_ch_buf;
+
+ b->yy_buf_size *= 2;
+ b->yy_ch_buf = (char *)
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size );
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move - YY_MORE_ADJ == 1 )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ /* yytext begins at the second character in yy_ch_buf; the first
+ * character is the one which preceded it before reading in the latest
+ * buffer; it needs to be kept around in case it's a newline, so
+ * yy_get_previous_state() will have with '^' rules active.
+ */
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[1];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 45 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 45 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 44);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += dest - source;
+ yy_bp += dest - source;
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ if ( yy_cp > yy_bp && yy_cp[-1] == '\n' )
+ yy_cp[-2] = '\n';
+
+ *--yy_cp = (char) c;
+
+
+ /* Note: the formal parameter *must* be called "yy_bp" for this
+ * macro to now work correctly.
+ */
+ YY_DO_BEFORE_ACTION; /* set up yytext again */
+ }
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yytext_ptr = yy_c_buf_p;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ {
+ yy_c_buf_p =
+ yytext_ptr + YY_MORE_ADJ;
+ return EOF;
+ }
+
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+ break;
+
+ case EOB_ACT_LAST_MATCH:
+#ifdef __cplusplus
+ YY_FATAL_ERROR(
+ "unexpected last match in yyinput()" );
+#else
+ YY_FATAL_ERROR(
+ "unexpected last match in input()" );
+#endif
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ return c;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ yy_flex_free( (void *) b->yy_ch_buf );
+ yy_flex_free( (void *) b );
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+ {
+ b->yy_input_file = file;
+
+ /* We put in the '\n' and start reading from [1] so that an
+ * initial match-at-newline will be true.
+ */
+
+ b->yy_ch_buf[0] = '\n';
+ b->yy_n_chars = 1;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[1];
+
+ b->yy_is_interactive = file ? isatty( fileno(file) ) : 0;
+
+ b->yy_fill_buffer = 1;
+
+ b->yy_buffer_status = YY_BUFFER_NEW;
+ }
+
+
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ int new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+
+
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+
+
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( const char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( 1 );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n - YY_MORE_ADJ; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, const char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+const char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( unsigned int size )
+#else
+static void *yy_flex_alloc( size )
+unsigned int size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, unsigned int size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+unsigned int size;
+#endif
+ {
+ return (void *) realloc( ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+
+void MakeMMDD(int n)
+ {
+ int m = strlen(yytext) - 1;
+ char c = yytext[m];
+
+ if ((c == 'M' && n == 1) || (c == 'D' && n == 2)) {
+ m++;
+ c = 0;
+ } /* endif c */
+
+#ifdef DEBUG
+ fprintf(stderr, "MM: n=%d num=%d InFmt=%s OutFmt=%s;\n",
+ n, pp->Num, pp->InFmt, pp->OutFmt);
+#endif
+ pp->Index[pp->Num++] = (m < 3) ? n : (-n);
+
+ switch (m) {
+ case 1:
+ MakeIn("%2d");
+ MakeOut((n == 1) ? "%#m" : "%#d");
+ break;
+ case 2:
+ MakeIn("%2d");
+ MakeOut((n == 1) ? "%m" : "%d");
+ break;
+ case 3:
+ MakeIn("%3s");
+ MakeOut((n == 1) ? "%b" : "%a");
+ break;
+ default:
+ if (c && c != ' ') {
+ char fm[] = "%[^x]";
+ fm[3] = c;
+ MakeIn(fm);
+ } else
+ MakeIn("%s");
+
+ MakeOut((n == 1) ? "%B" : "%A");
+ } /* endswitch m */
+
+ if (c)
+ unput(c);
+
+ } /* end of MakeMMDD */
+
+void MakeParm(int n)
+ {
+ int m = strlen(yytext);
+
+#ifdef DEBUG
+ fprintf(stderr, "MP: n=%d num=%d InFmt=%s OutFmt=%s;\n",
+ n, pp->Num, pp->InFmt, pp->OutFmt);
+#endif
+ pp->Index[pp->Num++] = n;
+
+ switch (m) {
+ case 1:
+ MakeIn("%2d");
+ MakeOut((n == 0) ? "%#y" : (n == 3) ? "%#H"
+ : (n == 4) ? "%#M" : "%#S");
+ break;
+ case 2:
+ MakeIn("%2d");
+ MakeOut((n == 0) ? "%y" : (n == 3) ? "%H"
+ : (n == 4) ? "%M" : "%S");
+ break;
+ default:
+ MakeIn("%4d");
+ MakeOut("%Y");
+ } /* endswitch m */
+
+ } /* end of MakeParm */
+
+void MakeAMPM(int n)
+ {
+ char buf[8];
+ int m = strlen(yytext);
+
+#ifdef DEBUG
+ fprintf(stderr, "AM: n=%d num=%d InFmt=%s OutFmt=%s;\n",
+ n, pp->Num, pp->InFmt, pp->OutFmt);
+#endif
+ pp->Index[pp->Num++] = -n;
+ sprintf(buf, "%%%ds", m);
+ MakeIn(buf);
+
+ if (pp->OutFmt) {
+ char *p;
+
+ if ((p = strstr(pp->OutFmt, "%H")))
+ *(p + 1) = 'I'; // 12-hour format
+ else if ((p = strstr(pp->OutFmt, "%#H")))
+ *(p + 2) = 'I'; // 12-hour format
+
+ MakeOut("%p");
+ } /* endif Flag */
+
+ } /* end of MakeAMPM */
+
+void MakeIn(char *text)
+ {
+ if (!pp->InFmt)
+ return;
+
+ strncat(pp->InFmt, text, (pp->Outsize - 1) - strlen(pp->InFmt));
+ } /* end of MakeIn */
+
+void MakeOut(char *text)
+ {
+ if (!pp->OutFmt) return;
+
+ strncat(pp->OutFmt, text, (pp->Outsize - 1) - strlen(pp->OutFmt));
+ } /* end of MakeOut */
+
+void Quotin(char *text)
+ {
+ if (!pp->InFmt)
+ return;
+
+ MakeIn(text);
+ pp->InFmt[strlen(pp->InFmt)-1] = '\0';
+ } /* end of Quotin */
+
+void Quotout(char *text)
+ {
+ if (!pp->OutFmt)
+ return;
+
+ MakeOut(text);
+ pp->OutFmt[strlen(pp->OutFmt)-1] = '\0';
+ } /* end of Quotout */
+
+int yywrap(void)
+ {
+ return 1;
+ } /* end of yywrap */
+
diff --git a/storage/connect/frmsg1.h b/storage/connect/frmsg1.h
index 57bbe656592..e88440a3a9c 100644
--- a/storage/connect/frmsg1.h
+++ b/storage/connect/frmsg1.h
@@ -1,1013 +1,1013 @@
-#define MSG_ACCESS_VIOLATN "Violation accès mémoire"
-#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Activity"
-#define MSG_ADDVAL_ERROR "Erreur %d dans AddValue"
-#define MSG_ADD_BAD_TYPE "Ajout d'une valeur de type %s non conforme dans un tableau %s"
-#define MSG_ADD_NULL_DOM "Ajout de la chaîne %s à un domaine nul"
-#define MSG_ADPOS_IN_DICTP "ADPOS au travail dans User_Dictp"
-#define MSG_AFTER " après: "
-#define MSG_ALG_CHOICE_AUTO "Le choix du meilleur algorithme est automatique"
-#define MSG_ALG_CHOICE_BAD "Choix d'algorithme invalide, remis à AUTO"
-#define MSG_ALG_CHOICE_QRY "Utilise l'algorithme 'Query'"
-#define MSG_ALG_CURLY_BRK "Le choix de l'algorithme dépend des accolades externes"
-#define MSG_ALLOC_ERROR "Erreur d'allocation de %s"
-#define MSG_ALL_DELETED "Toutes les lignes enlevées en %.2lf sec"
-#define MSG_ALTER_DB_ERR "Impossible de déterminer la base de données à modifier"
-#define MSG_AMBIG_COL_QUAL "Qualificateur ambigu %s pour la colonne %s"
-#define MSG_AMBIG_CORREL "Select %s.* corrélation ambigue"
-#define MSG_AMBIG_SPEC_COL "Colonne spéciale ambiguë %s"
-#define MSG_ANSWER_TYPE "Réponse de type"
-#define MSG_API_CONF_ERROR "Erreur SQL: API_CONFORMANCE"
-#define MSG_APPL_ACCESSIBLE "Application %s accessible"
-#define MSG_APPL_ACTIVE "Application %s encore active"
-#define MSG_APPL_BAD_SAVE "Application %s partiellement sauvegardée"
-#define MSG_APPL_CREATED "Application %s crée"
-#define MSG_APPL_IS_ACTIVE "Application déjà active"
-#define MSG_APPL_NOT_INIT "Application non initialisée"
-#define MSG_APPL_NOT_LOADED "Application non chargée"
-#define MSG_APPL_QUIT "Fin de l'application %s"
-#define MSG_APPL_SAVED "Application %s sauvegardée"
-#define MSG_APP_STILL_ACTIV "Application du langage %s encore active (non libérable)"
-#define MSG_AREAFILE_NOTFND "Fichier Area introuvable"
-#define MSG_ARGS_SYNTAX_ERR "?SetArgs erreur de syntaxe: %s inattendu après %s"
-#define MSG_ARG_ALREADY_SET "Argument %d déjà alloué"
-#define MSG_ARG_NOT_AN_ATTR "L'argument n'est pas un attribut (type %d erroné)"
-#define MSG_ARG_OUT_CONTEXT "Argument de type @ utilisé hors contexte"
-#define MSG_ARG_OUT_RANGE "Argument de phrase valant %d hors limite"
-#define MSG_ARG_PTR_NOSEM "Argument valant %d pointe sur un noeud sans Sem"
-#define MSG_ARG_PTR_NOSEMS "Argument valant %d pointe sur un noeud sans sémantique"
-#define MSG_ARG_REF_LOOP "?Bouclage entre références croisées des arguments"
-#define MSG_ARG_TWO_CONST "Le 2ème argument de %s doit être constant"
-#define MSG_ARRAY_ALLOC_ERR "Erreur d'allocation mémoire dans ARRAY"
-#define MSG_ARRAY_BNDS_EXCD "Hors limite de tableau"
-#define MSG_ARRAY_ERROR "Erreur de fonctionnement k=%d n=%d"
-#define MSG_ATTRIBUTE_ERROR "Erreur règle %u attribut %s: "
-#define MSG_ATT_NOT_CASE "Mauvaise valeur %d pour attribut (pas une CaseValue)"
-#define MSG_ATT_POSCODE_BIG "Code attribut %d trop grand (max=%d)"
-#define MSG_AVGLEN_ERROR "avglen doit être entre %d et %d"
-#define MSG_BAD_AGGREG_FUNC "Fonction aggrégée %d non supportée"
-#define MSG_BAD_ARGTYPES "Argument de type invalide pour %s"
-#define MSG_BAD_ARGUMENTS "Argument not attachés pour %s"
-#define MSG_BAD_ARG_NUM "Nombre d'arguments invalide %d"
-#define MSG_BAD_ARG_TYPE "Type d'argument %d invalide"
-#define MSG_BAD_ARRAY_OPER "Les tableaux doivent utiliser l'opérateur IN"
-#define MSG_BAD_ARRAY_TYPE "Type=%d invalide pour un tableau"
-#define MSG_BAD_ARRAY_VAL "Les tableaux doivent avoir le même nombre de valeurs"
-#define MSG_BAD_BIN_FMT "Format invalide %c pour la colonne BIN %s"
-#define MSG_BAD_BLK_ESTIM "Nombre de blocs supérieur à l'estimation"
-#define MSG_BAD_BLK_SIZE "Taille du bloc %d non conforme"
-#define MSG_BAD_BYTE_NUM "Le nombre d'octets écrits est faux"
-#define MSG_BAD_BYTE_READ "Le nombre d'octets lus est faux"
-#define MSG_BAD_CARDINALITY "Appel invalide de Cardinality pour une table multiple"
-#define MSG_BAD_CASE_SPEC "Min/Maj: spécification %c incorrecte, recommencez: "
-#define MSG_BAD_CHAR_SPEC "Spécification '%s' invalide pour caractère"
-#define MSG_BAD_CHECK_TYPE "Sous-type %d invalide pour CheckColumn"
-#define MSG_BAD_CHECK_VAL "Valeur pour Check invalide '%s'"
-#define MSG_BAD_COLCRT_ARG "COLCRT: Arg invalide (type=%hd, domain=%hd)"
-#define MSG_BAD_COLDEF_TYPE "Coldefs: type illégal %d"
-#define MSG_BAD_COLIST_ITEM "Elément invalide dans une Colist"
-#define MSG_BAD_COLIST_TYPE "Mauvais type=%d pour une Colist"
-#define MSG_BAD_COLSIZE "Colsize %d trop petit pour cette base de données"
-#define MSG_BAD_COL_ENTRY "Entrée invalide pour la colonne %s"
-#define MSG_BAD_COL_FORMAT "Type de formattage %d invalide pour une colonne"
-#define MSG_BAD_COL_IN_FILT "Colonne incorrecte dans un filtre"
-#define MSG_BAD_COL_QUALIF "Qualificateur invalide %s pour la colonne %s"
-#define MSG_BAD_COL_TYPE "Type invalide %s pour la colonne %s"
-#define MSG_BAD_COL_XPATH "Xpath invalide colonne %s de la table HTML %s"
-#define MSG_BAD_COMPARE_OP "Opérateur de comparaison %d invalide"
-#define MSG_BAD_CONST_TYPE "Type=%d invalide pour une constante"
-#define MSG_BAD_CONV_TYPE "Convertion de type invalide %d"
-#define MSG_BAD_CORREL "Select %s.* corrélation absente"
-#define MSG_BAD_DATETIME "Valeur date/temps invalide"
-#define MSG_BAD_DATE_OPER "Opérateur de date inattendu %d"
-#define MSG_BAD_DBF_FILE "Le fichier DBF %s est altéré"
-#define MSG_BAD_DBF_REC "Fichier DBF %s altéré enregistrement %d"
-#define MSG_BAD_DBF_TYPE "Type DBF %c non supporté"
-#define MSG_BAD_DEF_ARG "Argument invalide pour INDEXDEF (type=%hd, domain=%hd)"
-#define MSG_BAD_DEF_READ "EOF inattendue en lecture différée"
-#define MSG_BAD_DEF_TYPE "Type de colonne invalide"
-#define MSG_BAD_DIRECTORY "Répertoire invalide %s: %s"
-#define MSG_BAD_DIST_JN_FIL "Filtre de jointure distincte invalide"
-#define MSG_BAD_DIST_JOIN "Spécification invalide de jointure distincte"
-#define MSG_BAD_DOM_COL_DEF "Définition de colonnes invalide pour un domaine"
-#define MSG_BAD_DOM_VALUE "La valeur %d n'appartient pas au domaine"
-#define MSG_BAD_EDIT_INIT "Coparm: édition %s initialisée improprement"
-#define MSG_BAD_EVAL_TYPE "Fonction scalaire de type=%d invalide"
-#define MSG_BAD_EXEC_MODE "Mode d'exécution invalide '%s'"
-#define MSG_BAD_EXP_ARGTYPE "Argument de type %d invalide pour une expression"
-#define MSG_BAD_EXP_OPER "Opérateur=%d invalide pour expression"
-#define MSG_BAD_FETCH_RC "Code retour inattendu de Fetch %d"
-#define MSG_BAD_FIELD_FMT "Format de champ invalide %c pour %s"
-#define MSG_BAD_FIELD_RANK "Rang %d invalide pour la colonne %s"
-#define MSG_BAD_FIELD_TYPE "Mauvais type de champ %s"
-#define MSG_BAD_FILE_HANDLE "Handle de fichier invalide: %s"
-#define MSG_BAD_FILE_LIST "La section liste de fichiers est erronée"
-#define MSG_BAD_FILTER "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"
-#define MSG_BAD_FILTER_CONV "Conversion filtre incorrecte, B_T=%d,%d"
-#define MSG_BAD_FILTER_LINK "Opérateur de chaînage illégal %d"
-#define MSG_BAD_FILTER_OP "Opérateur de filtre invalide %d"
-#define MSG_BAD_FILTEST_OP "Opérateur invalide %d %d pour FilTest"
-#define MSG_BAD_FLD_FORMAT "Format invalide pour le champs %d de %s"
-#define MSG_BAD_FLD_LENGTH "Champs %s trop long (%s --> %d) ligne %d de %s"
-#define MSG_BAD_FLOAT_CONV "Convertion invalide d'un tableau flottant"
-#define MSG_BAD_FPARM_NEXT "Coparm: FPARM avec Next non nul"
-#define MSG_BAD_FREQ_SET "Spécification erronnée de Freq pour la colonne %s"
-#define MSG_BAD_FUNC_ARG "Funcarg de type %d non implémenté"
-#define MSG_BAD_FUNC_ARGTYP "Mauvais type d'argument=%d pour une fonction"
-#define MSG_BAD_FUNC_MODE "%s: mode invalide %d"
-#define MSG_BAD_GENRE "Genre est invalide"
-#define MSG_BAD_GETVIEW_RET "GetView: type de retour %d invalide"
-#define MSG_BAD_HANDLE_VAL "Valeur Handle invalide"
-#define MSG_BAD_HAV_FILTER "Filtre Having sur une requête non groupée"
-#define MSG_BAD_HAV_FILTYPE "Filtre invalide pour clause Having"
-#define MSG_BAD_HEADER "Fichier %s: bloc en-tête altéré"
-#define MSG_BAD_HEADER_VAL "Valeur invalide pour Header"
-#define MSG_BAD_HEAD_END "Lecture fin d'en-tête impossible"
-#define MSG_BAD_INDEX_COL "Colonne %s invalide pour index %s"
-#define MSG_BAD_INDEX_DEF "Définition invalide pour index %s"
-#define MSG_BAD_INDEX_FILE "Fichier index %s corrompu"
-#define MSG_BAD_INDEX_PART "Définition colonne invalide pour index %s"
-#define MSG_BAD_INPUT "Entrée incorrecte"
-#define MSG_BAD_IN_ARGTYPE "Argument de type invalide pour l'opérateur IN"
-#define MSG_BAD_IN_ENDING "Erreur: fin de chaîne IN invalide"
-#define MSG_BAD_IN_STRING "La chaîne IN commence ou finie par des caractères invalides %c ... %c"
-#define MSG_BAD_JCOL_TYPE "Erreur logique JCT: disparité des types colonnes"
-#define MSG_BAD_JOIN_EXP "Expression invalide pour une jointure"
-#define MSG_BAD_JOIN_FILTER "Filtre de jointure invalide"
-#define MSG_BAD_JOIN_OP "Opérateur de joint invalide %d"
-#define MSG_BAD_LANG_SIZE "Le fichier langage a une mauvaise taille %d"
-#define MSG_BAD_LINEFLD_FMT "Format invalide ligne %d champs %d de %s"
-#define MSG_BAD_LINE_LEN "Longueur ligne non égale à Lrecl"
-#define MSG_BAD_LIST_TYPE "Type de liste invalide %d"
-#define MSG_BAD_LOCALE "Locale invalide %s"
-#define MSG_BAD_LOCDFON_ARG "Mauvais paramètre pour LOCDFON"
-#define MSG_BAD_LOCNODE_USE "Usage inattendu de LOCNODE"
-#define MSG_BAD_LRECL "Disparité lrecl table/fichier (%d,%hd)"
-#define MSG_BAD_MAX_HAVING "MAXTMP trop petit pour Having"
-#define MSG_BAD_MAX_NREC "MaxRec=%d ne correspond pas à MaxBlk=%d Nrec=%d"
-#define MSG_BAD_MAX_PARAM "Mauvais paramètres pour spécifier une valeur maximum"
-#define MSG_BAD_MAX_SETTING "Mauvaise valeur '%c' pour max"
-#define MSG_BAD_MERGE_TYPE "Le type %d ne pas être intercallé"
-#define MSG_BAD_NODE_TYPE "Type noeud erroné pour la table"
-#define MSG_BAD_OFFSET_VAL "Nul offset invalide pour une table CSV"
-#define MSG_BAD_OPEN_MODE "Mode d'ouverture invalide %d"
-#define MSG_BAD_OPERATOR "Opérateur invalide %s"
-#define MSG_BAD_ORDER_MODE "Mode de tri %c invalide"
-#define MSG_BAD_ORDER_TYPE "Tri sur objet de type=%d invalide"
-#define MSG_BAD_OUTER_JOIN "Jointure externe invalide sur table enfant"
-#define MSG_BAD_PAD_ARGTYP "Argument de type invalide pour Pad ou Justify"
-#define MSG_BAD_PARAMETERS "%.8s: Mauvais paramètres"
-#define MSG_BAD_PARAM_TYPE "%.8s: Paramètre de type=%d invalide"
-#define MSG_BAD_PARM_COUNT "Nombre de paramètres incohérent"
-#define MSG_BAD_PHASE_NUM "Numéro de phrase %d hors limite"
-#define MSG_BAD_PHRASE_NB "numéro de phrase hors limite %d rc=%d\n"
-#define MSG_BAD_POS_CODE "POS_code invalide %d"
-#define MSG_BAD_POS_TYPE "Type de POS_code invalide %d"
-#define MSG_BAD_PROJNUM "Mauvais projnum %d pour la colonne %s"
-#define MSG_BAD_QUERY_OPEN "Mode invalide %d pour l'ouverture d'une requête"
-#define MSG_BAD_QUERY_TYPE "Type de requête %d invalide pour %s"
-#define MSG_BAD_QUOTE_FIELD "Quote manquante dans %s champs %d ligne %d"
-#define MSG_BAD_READ_NUMBER "Mauvais nombre %d de valeurs lues dans %s"
-#define MSG_BAD_RECFM "Recfm type %d invalide pour DOSCOL"
-#define MSG_BAD_RECFM_VAL "Valeur invalide %d de Recfm"
-#define MSG_BAD_RESULT_TYPE "Mauvais type de résultat %d pour %s"
-#define MSG_BAD_RETURN_TYPE "Type de retour %d incorrect"
-#define MSG_BAD_ROW_VALIST "Liste de valeurs invalide pour ROW"
-#define MSG_BAD_ROW_VALNB "Nombre de valeurs inégal dans la liste"
-#define MSG_BAD_SCF_ARGTYPE "Argument %d de type=%s invalide pour %s"
-#define MSG_BAD_SEM_DOMAIN "Domain .%d invalide"
-#define MSG_BAD_SETTINGS "Certaines spécifications sont incompatibles avec le type de la table"
-#define MSG_BAD_SET_CASE "La casse d'un tableau ne peut pas passer de non respect à respecter"
-#define MSG_BAD_SET_STRING "SetValue: appel invalide pour STRING"
-#define MSG_BAD_SET_TYPE "Set type %hd invalide"
-#define MSG_BAD_SPECIAL_CMD "Commande spéciale invalide"
-#define MSG_BAD_SPECIAL_COL "Colonne spéciale invalide %s"
-#define MSG_BAD_SPEC_COLUMN "Colonne spéciale invalide pour ce type de table"
-#define MSG_BAD_SQL_PARAM "Paramètre SQL invalide pour FindColblk"
-#define MSG_BAD_SUBLST_TYPE "Coparm: type %d de sous-liste invalide"
-#define MSG_BAD_SUBSEL_IN_X "Sub-select invalide pour une expression"
-#define MSG_BAD_SUBSEL_TYPE "Type %d invalide retourné de Sub-Select"
-#define MSG_BAD_SUB_RESULT "Résultat indéfini de fonction Sub-Select"
-#define MSG_BAD_SUB_SELECT "Sub-select invalide comme argument de fonction"
-#define MSG_BAD_TABLE_LINE "Ligne '%s' illégale ou tronquée dans la section Tables"
-#define MSG_BAD_TABLE_LIST "Table %s absente de la liste des tables"
-#define MSG_BAD_TABLE_TYPE "Type invalide %s pour la table %s"
-#define MSG_BAD_TEST_TYPE "BlockTest sur tableau: types dépareillés %s %s"
-#define MSG_BAD_TRIM_ARGTYP "Argument de type invalide pour Trim"
-#define MSG_BAD_TYPE_FOR_IN "Types d'argument incompatibles pour la fonction IN"
-#define MSG_BAD_TYPE_FOR_S "Type incorrecte %d pour %s(%d)"
-#define MSG_BAD_TYPE_LIKE "Type(%d)= %d invalide pour LIKE"
-#define MSG_BAD_UPD_COR "Le qualificateur %s de la colonne %s ne se refère pas à la table mise à jour %s"
-#define MSG_BAD_USERBLK_LEN "Mauvaise longueur à l'écriture du bloc utilisateur"
-#define MSG_BAD_USETEMP "Usetemp invalide '%s'"
-#define MSG_BAD_USETEMP_VAL "Valeur pour Usetemp invalide %d"
-#define MSG_BAD_VALBLK_INDX "Valeur hors limites de l'index du bloc de valeurs"
-#define MSG_BAD_VALBLK_TYPE "Type=%d invalide pour un bloc de valeurs"
-#define MSG_BAD_VALNODE "Type %d invalide pour le noeud valeur colonne %s"
-#define MSG_BAD_VALUE_TYPE "Type de valeur invalide %d"
-#define MSG_BAD_VAL_UPDATE "Impossible de déterminer quelle valeur %s doit être mise à jour"
-#define MSG_BAD_VIEW_OPEN "Mode invalide %d pour l'ouverture d'une View"
-#define MSG_BAD_XMODE_VAL "Mode d'exécution %d invalide"
-#define MSG_BAD_XOBJ_TYPE "Mauvais type de Xobject %d"
-#define MSG_BAS_NS_LIST "Format invalide de la liste des espace-noms"
-#define MSG_BIN_F_TOO_LONG "Valeur trop longue pour le champ %s (%d --> %d)"
-#define MSG_BIN_MODE_FAIL "Echec mode binaire: %s"
-#define MSG_BLKTYPLEN_MISM "Disparité types/longueurs de bloc dans SetValue"
-#define MSG_BLK_IS_NULL "Blk est nul"
-#define MSG_BLOCK_NO_MATCH "Bloc non correspondant"
-#define MSG_BREAKPOINT "Point de contrôle"
-#define MSG_BUFF_TOO_SMALL "GetColData: Buffer trop petit"
-#define MSG_BUFSIZE_ERROR "Erreur en recherchant la taille du buffer"
-#define MSG_BUILDING_GROUPS "Formation des groupes"
-#define MSG_BUILD_DIST_GRPS "Formation des groupes distinctes"
-#define MSG_BUILD_INDEX "Construction index %s sur %s"
-#define MSG_BXP_NULL "Bxp nul dans PUTFON"
-#define MSG_CANNOT_OPEN "Ouverture impossible de %s"
-#define MSG_CD_ONE_STEP "Count Distinct doit être exécuté en une seule étape"
-#define MSG_CD_ORDER_ERROR "Erreur de tri dans Count Distinct"
-#define MSG_CHECKING_ROWS "Test des lignes à mettre à jour"
-#define MSG_CHECK_LEVEL "Niveau de vérification fixé à %u"
-#define MSG_CHSIZE_ERROR "Erreur dans chsize: %s"
-#define MSG_CLN_NOT_IN_JOIN "La colonne C%d n'est pas dans le join"
-#define MSG_CNTDIS_COL_LOST "Colonne du Count Distinct perdue"
-#define MSG_COLIST_BAD_TYPE "Type=%d invalide pour Colist"
-#define MSG_COLNAM_TOO_LONG "Nom de colonne trop long"
-#define MSG_COLSEC_TOO_BIG "Section colonne trop grande, table %s (%d)"
-#define MSG_COLS_REDUCED " (réduit par Maxcol)"
-#define MSG_COLUMN_ERROR "Erreur de colonne"
-#define MSG_COLUMN_MISMATCH "Colonne %s dépareillée"
-#define MSG_COLUMN_NOT_KEY "La colonne jointe R%d.%s n'est pas une clé"
-#define MSG_COL_ALLOC_ERR "Allocation impossible du noeud colonne"
-#define MSG_COL_ALLOC_ERROR "Erreur d'allocation mémoire pour la colonne %d"
-#define MSG_COL_HAS_NO_DEF "La colonne %s n'est pas définie"
-#define MSG_COL_INVAL_TABLE "La colonne %s.%s n'existe pas dans la table %s alias %s"
-#define MSG_COL_ISNOT_TABLE "La colonne %s n'est pas dans la table %s"
-#define MSG_COL_NB_MISM "Le nombre de colonnes ne correspond pas"
-#define MSG_COL_NOTIN_GRPBY "La colonne %s n'est pas dans la liste de Group By"
-#define MSG_COL_NOTIN_TABLE "La colonne %s n'est dans aucune table"
-#define MSG_COL_NOTIN_UPDT "%s n'appartient pas à la table mise à jour %s"
-#define MSG_COL_NOT_CODED "La colonne %s n'est pas codifiée"
-#define MSG_COL_NOT_EXIST "La colonne %s n'existe pas dans %s"
-#define MSG_COL_NOT_FOUND "La colonne %s n'est pas dans la table %s"
-#define MSG_COL_NOT_IN_DB "La colonne %s de la table %s n'est pas dans la base de données"
-#define MSG_COL_NOT_IN_JOIN "La colonne %s n'est pas dans le join"
-#define MSG_COL_NOT_SORTED "La colonne %s de la table %s n'est pas triée"
-#define MSG_COL_NUM_MISM "Disparité du nombre de colonnes"
-#define MSG_COL_USED_TWICE "Colonne %s utilisée deux fois ???"
-#define MSG_COMPUTE_ERROR "Erreur dans Compute, op=%d"
-#define MSG_COMPUTE_NIY "Compute non implémenté pour TOKEN"
-#define MSG_COMPUTING "Calculs en cours"
-#define MSG_COMPUTING_DIST "Comptage des valeurs distinctes"
-#define MSG_COMPUTING_FUNC "Calcul de(s) fonction(s)"
-#define MSG_COM_ERROR "Erreur Com"
-#define MSG_CONCAT_SUBNODE "Concaténation de sous-noeuds impossible"
-#define MSG_CONNECTED "Connecté"
-#define MSG_CONNECT_CANCEL "Connection interrompue par l'utilisateur"
-#define MSG_CONNECT_ERROR "Erreur %d se connectant à %s"
-#define MSG_CONN_CLOSED "%s(%d) fermée"
-#define MSG_CONN_CREATED "Connexion %s crée"
-#define MSG_CONN_DROPPED "Connexion %s supprimée"
-#define MSG_CONN_OPEN "%s(%d) ouverte (%s)"
-#define MSG_CONN_SUC_OPEN "%s(%d) ouverte avec succès"
-#define MSG_CONTROL_C_EXIT "Exit par Ctrl-C"
-#define MSG_COPY_BAD_PHASE "Copie de liste invalide en phase %d"
-#define MSG_COPY_INV_TYPE "Coparm: type non supporté %d"
-#define MSG_CORREL_NO_QRY "Les sous-requêtes corrélées ne peuvent pas être de type QRY"
-#define MSG_CREATED_PLUGDB " Créé par PlugDB %s "
-#define MSG_CURSOR_SET "Curseur remis à %d"
-#define MSG_DATABASE_ACTIVE "Base de données %s activée"
-#define MSG_DATABASE_LOADED "Base de données %s chargée"
-#define MSG_DATA_IS_NULL "ExecSpecialCmd: data est NULL"
-#define MSG_DATA_MISALIGN "Mauvais alignement pour ce type de données"
-#define MSG_DBASE_FILE "Fichier dBASE dbf: "
-#define MSG_DB_ALREADY_DEF "Base de données %s déjà définie"
-#define MSG_DB_ALTERED "Base de données modifiée"
-#define MSG_DB_CREATED "Base de données %s créée"
-#define MSG_DB_NOT_SPEC "Base de données non spécifiée"
-#define MSG_DB_REMOVED "Base de données %s retirée de la liste"
-#define MSG_DB_SORT_ERROR "Erreur de tri DB"
-#define MSG_DB_STOPPED "Arrêt de la base de données %s"
-#define MSG_DEBUG_NOT_ACTIV "Mode Debug inactif"
-#define MSG_DEBUG_SET_INV "Invalide pour Debug: %c"
-#define MSG_DEF_ALLOC_ERROR "Erreur d'allocation de la classe DEF %s"
-#define MSG_DELETING_ROWS "Suppression des lignes"
-#define MSG_DEL_FILE_ERR "Erreur à l'effacement de %s"
-#define MSG_DEL_READ_ERROR "Delete: erreur en lecture req=%d len=%d"
-#define MSG_DEL_WRITE_ERROR "Delete: erreur en écriture: %s"
-#define MSG_DEPREC_FLAG "Option Flag périmée, utiliser Coltype"
-#define MSG_DICTIONARY "Dictionnaire "
-#define MSG_DIRECT_VARTOK "Accès direct aux règles du Variable Token non implémenté"
-#define MSG_DISCONNECTED "Déconnecté"
-#define MSG_DISTINCT_ERROR "Plus d'un élément fonctionel DISTINCT"
-#define MSG_DISTINCT_ROWS "Sélection des lignes distinctes"
-#define MSG_DISTINCT_VALUES "Extraction des valeurs distinctes"
-#define MSG_DIS_NOHEAD_JOIN "Jointure distincte sur une table non en tête"
-#define MSG_DLL_LOAD_ERROR "Erreur %d au chargement du module %s"
-#define MSG_DOMAIN_EMPTY "Le domaine %s est vide"
-#define MSG_DOMAIN_ERROR "Colonne %s: disparité domaine(%s)/valeur(%s)"
-#define MSG_DOMAIN_FULL "Le domaine %s est plein (max=%d)"
-#define MSG_DOM_FILE_ERROR "Fichier domain %s introuvable"
-#define MSG_DOM_NOT_SUPP "MS-DOM non supporté par cette version"
-#define MSG_DOM_OPEN_ERROR "Erreur d'ouverture du domaine: %s"
-#define MSG_DOM_READ_ERROR "Erreur %d en lecture de domaine: %s"
-#define MSG_DOM_READ_ONLY "La table domaine %s est en lecture seulement"
-#define MSG_DOM_WRITE_ERROR "Erreur %d en écriture de domaine: %s"
-#define MSG_DONE "Effectué, rc=%d"
-#define MSG_DOSALMEM_NOMEM "Erreur d'allocation, pas assez de mémoire"
-#define MSG_DROP_DB_ERR "Echec du Drop sur le base de données %s"
-#define MSG_DSORT_LOG_ERROR "Kindex: Erreur logique de tri distincte"
-#define MSG_DUMMY_NO_COLS "Les tables DUMMY ne peuvent pas avoir de colonne"
-#define MSG_DUPLICAT_COUNT "Count sur plus d'une colonne"
-#define MSG_DUP_COL_NAME "La colonne %s existe en double"
-#define MSG_DUP_PROJNUM "Non unique projnum %d pour la colonne %s"
-#define MSG_DVAL_NOTIN_LIST "Valeur %s non trouvée dans la liste des valeurs distinctes de la colonne %s"
-#define MSG_EMPTY_DOC "Document vide"
-#define MSG_EMPTY_FILE "%s du fichier vide %s: "
-#define MSG_ENDSTR_MISMATCH "Fins de chaîne et de noeud ne correspondent pas"
-#define MSG_END_OF_DELETE "%d ligne(s) enlevée(s) en %.2lf sec"
-#define MSG_END_OF_INSERT "%d ligne(s) insérée(s) en %.2lf sec"
-#define MSG_END_OF_QUERY "%d ligne(s) extraite(s) en %.2lf sec"
-#define MSG_END_OF_UPDATE "%d ligne(s) modifiée(s) en %.2lf sec"
-#define MSG_EOF_AFTER_LINE "Fin de fichier après la ligne %d"
-#define MSG_EOF_INDEX_FILE "EOF lisant le fichier index"
-#define MSG_ERASED " et effacée"
-#define MSG_ERASE_FAILED " (échec de l'effacement)"
-#define MSG_ERROR "Erreur"
-#define MSG_ERROR_IN_LSK "Erreur %d dans lseek64"
-#define MSG_ERROR_IN_SFP "Erreur %d dans SetFilePointer"
-#define MSG_ERROR_NO_PARM "Paramètre absent (valide seulement pour %.8s.1 et %.8s.5)"
-#define MSG_ERROR_OPENING "Erreur à l'ouverture de : "
-#define MSG_ERR_NUM_GT_MAX "Erreur: Numval (%d) plus grand que Maxnum (%d)"
-#define MSG_ERR_READING_REC "Erreur lisant l'enregistrement %d de %s"
-#define MSG_ERR_RET_RULE "Retour erreur, règle=%u"
-#define MSG_ERR_RET_TYPE "Retour erreur, type=%d"
-#define MSG_EVAL_EXPIRED "Cette version d'évaluation est expirée"
-#define MSG_EVAL_ONLY "L'utilisation de cette Dll est pour évaluation seulement"
-#define MSG_EXECUTING "Exécution"
-#define MSG_EXECUTION_ERROR "Erreur d'exécution"
-#define MSG_EXEC_MODE_IS "Le mode d'exécution est %s"
-#define MSG_EXEC_MODE_RESET ". Mode remis à Execute"
-#define MSG_EXEC_MODE_SET "Mode d'exécution fixé à %s"
-#define MSG_EXIT_EVAL_ERR "Erreur pendant l'évaluation de Exit"
-#define MSG_EXIT_FROM_LANG "Fin du langage %s version %d.%d"
-#define MSG_FAIL_ADD_NODE "L'ajout du noeud %s dans la table a échoué"
-#define MSG_FETCHING_DATA "Recherche des données"
-#define MSG_FETCHING_ROWS "Recherche des lignes"
-#define MSG_FETCH_NO_RES "Fetch: Pas de Résultats"
-#define MSG_FIELD_TOO_LONG "Valeur trop longue pour le champs %d ligne %d"
-#define MSG_FILELEN_ERROR "Erreur dans %s pour %s"
-#define MSG_FILE_CLOSE_ERR "Erreur %d à la fermeture du fichier"
-#define MSG_FILE_IS_EMPTY "Le fichier %s est vide"
-#define MSG_FILE_MAP_ERR "Erreur de File mapping"
-#define MSG_FILE_MAP_ERROR "CreateFileMapping %s erreur rc=%d"
-#define MSG_FILE_NOT_FOUND "Fichier %s introuvable"
-#define MSG_FILE_OPEN_YET "Fichier %s déjà ouvert"
-#define MSG_FILE_UNFOUND "Fichier %s non trouvé"
-#define MSG_FILGRP_NO_TABLE "Table %d manquante pour groupe filtre"
-#define MSG_FILTER_ATTACH "Filtre passé à Attach"
-#define MSG_FILTER_NO_TABLE "Filtre: première table manquante"
-#define MSG_FIND_BAD_TYPE "Recherche dans un tableau: type non conforme %s %s"
-#define MSG_FIX_OVFLW_ADD "Dépassement de capacité en addition"
-#define MSG_FIX_OVFLW_TIMES "Dépassement de capacité en mutiplication"
-#define MSG_FIX_UNFLW_ADD "Sous dépassement de capacité en addition"
-#define MSG_FIX_UNFLW_TIMES "Sous dépassement de capacité en multiplication"
-#define MSG_FLD_TOO_LNG_FOR "Champs %d trop long pour %s ligne %d de %s"
-#define MSG_FLTST_NO_CORREL "FilTest ne devrait être appelé que pour les sous-requêtes corrélées"
-#define MSG_FLT_BAD_RESULT "Virgule flottante: résultat inexacte"
-#define MSG_FLT_DENORMAL_OP "Opérande virgule flottante non normalisé"
-#define MSG_FLT_INVALID_OP "Opération virgule flottante invalide"
-#define MSG_FLT_OVERFLOW "Dépassement de capacité virgule flottante"
-#define MSG_FLT_STACK_CHECK "Virgule flottante: Erreur de la pile"
-#define MSG_FLT_UNDERFLOW "Sous-dépassement de capacité virgule flottante"
-#define MSG_FLT_ZERO_DIVIDE "Virgule flottante: division par zéro"
-#define MSG_FMT_WRITE_NIY "L'écriture des fichiers %s n'est pas encore implémentée"
-#define MSG_FNC_NOTIN_SLIST "Fonction de tri absente de la liste de sélection"
-#define MSG_FORMAT_ERROR "Erreur de formattage"
-#define MSG_FOXPRO_FILE "Fichier FoxPro: "
-#define MSG_FPUTS_ERROR "Erreur dans fputs: %s"
-#define MSG_FSBPARP_NULL "PUTFON: fsbparp est nul"
-#define MSG_FSEEK_ERROR "Erreur dans fseek: %s"
-#define MSG_FSETPOS_ERROR "Erreur dans fseek pour i=%d"
-#define MSG_FTELL_ERROR "Erreur dans ftell enregistrement=%d: %s"
-#define MSG_FUNCTION_ERROR "Erreur dans %s: %d"
-#define MSG_FUNC_ERRNO "Erreur %d dans %s"
-#define MSG_FUNC_ERROR "Erreur dans %s"
-#define MSG_FUNC_ERR_S "Erreur dans %s: %s"
-#define MSG_FUNC_REF_DEL "Référence à une fonction définie (règle %d) qui a été supprimée"
-#define MSG_FWRITE_ERROR "Erreur dans fwrite: %s"
-#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
-#define MSG_GETFILESIZE_ERR "Erreur %d dans GetFileSize"
-#define MSG_GET_DIST_VALS "Récupération des valeurs distinctes de "
-#define MSG_GET_ERROR "Erreur dans %s (colonne %d)"
-#define MSG_GET_FUNC_ERR "Erreur en recherche de la fonction %s: %s"
-#define MSG_GET_NAME_ERR "Erreur en retrouvant le nom d'une table SYS"
-#define MSG_GLOBAL_ERROR "Erreur d'allocation de Global (taille=%d)\n"
-#define MSG_GRAM_ALLOC_ERR "Erreur d'allocation dans Grammar Up"
-#define MSG_GRAM_MISMATCH "Avertissement: version de GRAMMAR perimée (sauvé sous GRAMMAR v%u)"
-#define MSG_GRAM_SUBSET_ERR "Erreur d'initialisation du dictionnaire de la grammaire"
-#define MSG_GRBY_TAB_NOTIMP "Group by avec tables jointes non implémenté"
-#define MSG_GROUPBY_NOT_ALL "Group By doit inclure toutes les sélections non-fonctionnelles"
-#define MSG_GROUP_ON_FUNC "Group by invalide sur colonne fonctionnelle"
-#define MSG_GRP_COL_MISM "Disparité colonne des groupes"
-#define MSG_GRP_LIST_MISMAT "Le groupement ne couvre pas la liste de sélection"
-#define MSG_GUARD_PAGE "Violation de page de garde"
-#define MSG_GZOPEN_ERROR "gzopen %s: erreur %d sur %s"
-#define MSG_GZPUTS_ERROR "Erreur dans gzputs: %s"
-#define MSG_HANDLE_IS_NULL "%s est NULL: erreur code: %d"
-#define MSG_HARRY_COMP_NIY "Compute non implémenté pour les chaînes codées"
-#define MSG_HAVING_FILTER "Traitement du Filtre Having"
-#define MSG_HBUF_TOO_SMALL "Buffer(%d) trop petit pour entête(%d)"
-#define MSG_HEAD_OPEN_ERROR "Erreur à l'ouverture du fichier header"
-#define MSG_HEAD_READ_ERROR "Erreur en lecture du fichier header %s"
-#define MSG_HEAD_WRITE_ERR "Erreur en écriture du fichier header"
-#define MSG_HI_OFFSET_ERR "Offset supérieur non nul"
-#define MSG_HUGE_DEFAULT "Huge est %d par défault"
-#define MSG_HUGE_WARNING_1 "Mémoire Huge non compatible 16-bit pour %d\n"
-#define MSG_HUGE_WARNING_2 "Résultats imprévisibles possibles\n"
-#define MSG_IDLE "Au repos"
-#define MSG_ILLEGAL_INSTR "Instruction illégale"
-#define MSG_ILL_FILTER_CONV "Conversion implicite illégale dans un filtre"
-#define MSG_INDEX_CREATED "Index %s créé sur %s"
-#define MSG_INDEX_DEF_ERR "Erreur sauvegardant l'index définition pour %s"
-#define MSG_INDEX_DROPPED "Index %s supprimé de %s"
-#define MSG_INDEX_INIT_ERR "Echec de l'initialisation de l'index %s"
-#define MSG_INDEX_NOT_DEF "Index %s non défini"
-#define MSG_INDEX_NOT_UNIQ "L'index n'est pas Unique"
-#define MSG_INDEX_ONE_SAVE "Les index sont sauvegardés dans un fichier unique"
-#define MSG_INDEX_SEP_SAVE "Les index sont sauvegardés dans des fichiers séparés"
-#define MSG_INDEX_YET_ON "L'index %s existe déjà sur %s"
-#define MSG_INDX_ALL_DROP "Tous les index de %s supprimés"
-#define MSG_INDX_COL_NOTIN "La colonne index %s n'existe pas dans la table %s"
-#define MSG_INDX_EXIST_YET "L'entrée index existe déjà"
-#define MSG_INIT_ERROR "Erreur à l'initialisation de %s"
-#define MSG_INIT_FAILED "L'initialisation de %s a échoué"
-#define MSG_INPUT "Entrée: "
-#define MSG_INPUT_KEYBD_YET "L'entrée est déjà au clavier"
-#define MSG_INSERTING "Insertion: "
-#define MSG_INSERT_ERROR "Insert erreur: usage multiple du fichier %s"
-#define MSG_INSERT_MISMATCH "Les listes colonne et valeur ne correspondent pas"
-#define MSG_INTERNAL "interne"
-#define MSG_INT_COL_ERROR "Erreur interne sur la colonne index %s"
-#define MSG_INT_OVERFLOW "Dépassement de capacité sur entier"
-#define MSG_INT_ZERO_DIVIDE "Division entière par zéro"
-#define MSG_INVALID_BIP "Bip invalide .%d"
-#define MSG_INVALID_DISP "Disposition invalide"
-#define MSG_INVALID_FTYPE "SBV: Ftype %d invalide"
-#define MSG_INVALID_HANDLE "Poignée invalide"
-#define MSG_INVALID_OPER "Opérateur invalide %d pour %s"
-#define MSG_INVALID_OPTION "Option invalide %s"
-#define MSG_INV_COLUMN_TYPE "Type %d Invalide pour la colonne %s"
-#define MSG_INV_COL_DATATYP "Type de données %d invalide pour la colonne %d"
-#define MSG_INV_COL_NUM "Colonne invalide %d"
-#define MSG_INV_COL_TYPE "Type de colonne %s invalide"
-#define MSG_INV_CONC_BIP "Bip invalide (seuls valides: %.8s.0 .1 and .5)"
-#define MSG_INV_DATA_PATH "Chemin vers les données invalide"
-#define MSG_INV_DEF_READ "Lecture différée invalide rc=%d"
-#define MSG_INV_DIRCOL_OFST "Offset invalide pour une colonne DIR"
-#define MSG_INV_DOMAIN_TYPE "Type invalide %d"
-#define MSG_INV_FILTER "Filtre résiduel dans %s"
-#define MSG_INV_FNC_BUFTYPE "FNC: Type %d de l'argument invalide pour %s"
-#define MSG_INV_INFO_TYPE "Type d'info catalog invalide %d"
-#define MSG_INV_INIPATH "Inipath invalide "
-#define MSG_INV_MAP_POS "Position mémoire invalide"
-#define MSG_INV_OPERATOR "opérateur invalide %d\n"
-#define MSG_INV_PARAMETER "Paramètre invalide %s"
-#define MSG_INV_PARM_TYPE "Type de paramètre invalide"
-#define MSG_INV_QUALIFIER "Qalificateur '%s' invalide"
-#define MSG_INV_QUERY_TYPE "Type de requête %d invalide"
-#define MSG_INV_RAND_ACC "L'accès aléatoire d'une table non optimisée est impossible"
-#define MSG_INV_REC_POS "Position d'enregistrement invalide"
-#define MSG_INV_RESULT_TYPE "Type de résultat invalide %s"
-#define MSG_INV_SET_SUBTYPE "Type de formattage %d invalide"
-#define MSG_INV_SPECIAL_CMD "%s: Commande spéciale invalide"
-#define MSG_INV_SUBTYPE "Sous type invalide %s"
-#define MSG_INV_TOK_DOMAIN "Le domaine %s n'existe pas"
-#define MSG_INV_TOPSEM_CMD "Commande TopSem invalide %c"
-#define MSG_INV_TRANSF_USE "Usage invalide en règle transformationnelle"
-#define MSG_INV_TYPE_SPEC "Spécification de type invalide (%.8s.%d)"
-#define MSG_INV_UPDT_TABLE "Table %s invalide pour Update"
-#define MSG_INV_VALUE_LIST "Liste de valeurs invalide pour Insert"
-#define MSG_INV_WHERE_JOIN "Clause Where invalide dans une requête de jointure"
-#define MSG_INV_WORK_PATH "Chemin de travail invalide"
-#define MSG_IN_ARGTYPE_MISM "Arguments de types incompatibles pour une expression IN"
-#define MSG_IN_USE " et en activité"
-#define MSG_IN_WITHOUT_SUB "IN ou EXISTS sans tableau ou subquery"
-#define MSG_IS_NOT_CONN "%s n'est pas une connexion définie"
-#define MSG_JCT_MISS_COLS "Colonnes manquantes pour une table JCT"
-#define MSG_JCT_MISS_TABLE "Table jointe manquante pour JCT"
-#define MSG_JCT_NO_FILTER "Filtrage impossible des tables virtuelles JCT"
-#define MSG_JCT_NO_KEY "Erreur logique JCT: clé manquante"
-#define MSG_JOIN_KEY_NO_COL "La clé de jointure n'est pas une colonne"
-#define MSG_KEY_ALLOC_ERR "Erreur d'allocation d'un bloc offset clé"
-#define MSG_KEY_ALLOC_ERROR "Erreur d'allocation mémoire, Klen=%d n=%d"
-#define MSG_LANGUAGE_QUIT "%s libéré"
-#define MSG_LANG_ACTIVE "Langage %s actif"
-#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Lang"
-#define MSG_LANG_ALREADY_UP "Langage déjà en édition"
-#define MSG_LANG_BAD_SAVE "Langage %s peut-être incorrectement sauvegardé"
-#define MSG_LANG_NOT_FREED "Langage %s non libérable (pas dans la chaîne principale)"
-#define MSG_LANG_SAVED "Langage %s sauvegardé"
-#define MSG_LANG_WR_LEN_ERR "Erreur de longueur à l'écriture du bloc Lang"
-#define MSG_LDF_ALLOC_ERROR "Erreur d'allocation d'un LdfBlock"
-#define MSG_LDF_RN_MISMATCH "LDF: décalage des numéros de règle"
-#define MSG_LDF_WLEN_ERROR "Erreur de longueur en écrivant LdfData"
-#define MSG_LDF_W_LEN_ERROR "Erreur de longueur pour LdfData en écriture"
-#define MSG_LIC_NO_MYSQL "Votre licence actuelle ne permet pas l'utilisation du type MYSQL"
-#define MSG_LINEAR_ERROR "Erreur de linéarisation"
-#define MSG_LINE_LENGTH "Largeur d'impression fixée à %d"
-#define MSG_LINE_MAXLIN "Nombre de lignes de travail plafonné à %d"
-#define MSG_LINE_MAXRES "Nombre de lignes de résultat plafonné à %d"
-#define MSG_LINE_MAXTMP "Nombre de lignes intermédiaires plafonné à %d"
-#define MSG_LINE_TOO_LONG "La nouvelle ligne est trop longue"
-#define MSG_LINJOINDB_ERROR "Erreur système: appel incorrecte à LinJoinDB"
-#define MSG_LIST "--Liste--"
-#define MSG_LNG_NOT_IN_LIST "Le langage %s n'est pas dans la liste"
-#define MSG_LOADING_DB "Chargement description de la BD"
-#define MSG_LOADING_FAILED "Le chargement de %s a échoué"
-#define MSG_LOAD_CDLL_ERROR "Erreur au chargement de ConnDll: rc=%d"
-#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n trop grand ? (%d)\n"
-#define MSG_LOGICAL_ERROR "%s: Erreur logique"
-#define MSG_LRECL_TOO_SMALL "Lrecl trop petit (longueur en-tête = %d)"
-#define MSG_MAC_NO_DELETE "Pas de suppression de lignes pour les tables MAC"
-#define MSG_MAC_NO_INDEX "Pas d'accès direct aux tables MAC"
-#define MSG_MAC_READ_ONLY "Les tables MAC sont en lecture seulement"
-#define MSG_MAC_WIN_ONLY "Les tables MAC sont seulement sous Windows"
-#define MSG_MAKE_EMPTY_FILE "Génération du fichier vide %s: %s"
-#define MSG_MAKING "Génération"
-#define MSG_MAKING_DISTINCT "Regroupement des valeures distinctes"
-#define MSG_MALLOC_ERROR "Allocation mémoire impossible par %s"
-#define MSG_MALLOC_NULL "malloc retourne Null"
-#define MSG_MAP_NO_MORE "Le type %s n'est plus supporté"
-#define MSG_MAP_OBJ_ERR "Erreur %d à la fermeture du map objet"
-#define MSG_MAP_VEC_ONLY "MAP Insert permis seulement pour les tables VEC Estimate"
-#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s erreur rc=%d"
-#define MSG_MAXSIZE_ERROR "Maxsize incalculable sur table ouverte"
-#define MSG_MAXTMP_TRUNCATE "Résultats intermédiaires tronqués par maxtmp=%d"
-#define MSG_MAX_BITMAP "Taille maxi des bitmaps d'optimisation fixée à %d"
-#define MSG_MEMSIZE_TOO_BIG "Erreur: memsize (%d) trop grand pour Length (%d)"
-#define MSG_MEM_ALLOC_ERR "Erreur d'allocation mémoire, taille %s = %d"
-#define MSG_MEM_ALLOC_ERROR "Erreur d'allocation mémoire"
-#define MSG_MEM_ALLOC_YET "Mémoire déjà allouée"
-#define MSG_METAFILE_NOTFND "Fichier Meta introuvable"
-#define MSG_MISPLACED_QUOTE "Appostrophe mal placée ligne %d"
-#define MSG_MISSING "Manquant: Value=%p Argval=%p Builtin=%d"
-#define MSG_MISSING_ARG "Argument manquant pour l'opérateur %d"
-#define MSG_MISSING_COL_DEF "Définition des colonnes manquante"
-#define MSG_MISSING_CONNECT "Connection #1 manquante"
-#define MSG_MISSING_EOL "Fin de ligne manquante dans %s"
-#define MSG_MISSING_FIELD "Champs %d manquant dans %s ligne %d"
-#define MSG_MISSING_FNAME "Nom du fichier manquant"
-#define MSG_MISSING_NODE "Noeud %s manquant dans %s"
-#define MSG_MISSING_POS "POS code manquant"
-#define MSG_MISSING_ROWNODE "Impossible de trouver le noeud de la ligne %d"
-#define MSG_MISSING_SERV_DB "Indication serveur et/ou base de données manquante"
-#define MSG_MISS_LEAD_COL "Colonne majeure %s manquante"
-#define MSG_MISS_NAME_LRECL "Nom du fichier et/ou LRECL manquant"
-#define MSG_MISS_TABLE_LIST "Liste des tables manquante"
-#define MSG_MISS_VCT_ELMT "Taille de bloc vectoriel manquante (Elements)"
-#define MSG_MIS_TAG_LIST "Liste des balises colonne manquante"
-#define MSG_MKEMPTY_NIY "MakeEmptyFile: pas encore implementé pour Huge et Unix"
-#define MSG_MOVE_INV_TYPE "MOVPARM: paramètre de type invalide %d"
-#define MSG_MULT_DISTINCT "Distinct utilisé plus d'une fois"
-#define MSG_MULT_KEY_ERROR "Erreur sur clé multiple k=%d n=%d"
-#define MSG_MUL_MAKECOL_ERR "Erreur logique dans TABMUL::MakeCol"
-#define MSG_MYSQL_CNC_OFF "La connexion à MySQL est fermée"
-#define MSG_MYSQL_CNC_ON "La connexion à MySQL est établie"
-#define MSG_MYSQL_NOT_SUP "Pas de support de MySQL dans cette version"
-#define MSG_MY_CNC_ALREADY "La connexion à MySQL est déjà active"
-#define MSG_NAME_CONV_ERR "Erreur de convertion du nom de noeud"
-#define MSG_NAME_IS_USED "Le nom %s est déjà utilisé"
-#define MSG_NCOL_GT_MAXCOL "Trop de colonnes (%d > %d max)"
-#define MSG_NEW_CHAR_NULL "new char(%d) retourne Null"
-#define MSG_NEW_DOC_FAILED "Impossible de créer le nouveau document"
-#define MSG_NEW_RETURN_NULL "NULL renvoyé par New dans PlugEvalLike"
-#define MSG_NEW_TABLE_ERR "La nouvelle table %s ne peut pas être chargée"
-#define MSG_NEXT_FILE_ERROR "Erreur en recherche du fichier suivant. rc=%s"
-#define MSG_NODEF_FROM_VIEW "Pas de définition de table depuis une view"
-#define MSG_NODE_FOR_CHAR "Noeud %s trouvé au lieu d'un caractère"
-#define MSG_NODE_SUBSET_ERR "Erreur d'initialisation de la zone Noeud %d"
-#define MSG_NONCONT_EXCEPT "Exception non-continuable"
-#define MSG_NON_DUP_HAVING "Clause Having dans une requête non fonctionelle"
-#define MSG_NON_EVAL_SEM "Sem non évaluée: p_no=%d"
-#define MSG_NOP_ZLIB_INDEX "L'indexage d'une table zlib non optimisée est impossible"
-#define MSG_NOT_A_DBF_FILE "Le fichier n'a pas le format dBASE dbf "
-#define MSG_NOT_ENOUGH_COLS "Pas assez de colonnes dans %s"
-#define MSG_NOT_ENOUGH_MEM "Mémoire insuffisante pour cette opération"
-#define MSG_NOT_FIXED_LEN "Fichier %s non fixe, len=%d lrecl=%d"
-#define MSG_NOT_IMPLEMENTED "Non implementé: %.8s"
-#define MSG_NOT_IMPL_JOIN "Pas implémenté pour les jointures"
-#define MSG_NOT_IMPL_SET "Pas implémenté pour les opérateurs d'ensembles"
-#define MSG_NOT_IMPL_YET "Pas encore implementé"
-#define MSG_NOT_LINEARIZED "Arborescence des tables non linéarisée"
-#define MSG_NOT_MODIFIABLE " (non modifiable)"
-#define MSG_NO_0DH_HEAD "0DH manquant en fin d'en-tête (dbc=%d)"
-#define MSG_NO_ACTIVE_APPL "Pas d'application active"
-#define MSG_NO_ACTIVE_DB "Pas de base de données active"
-#define MSG_NO_ACTIVE_UDIC "Pas de dictionaire utilisateur actif"
-#define MSG_NO_AGGR_FUNC "Fonction aggrégée %d illégale à cet endroit"
-#define MSG_NO_AREA_FILE "Fichier Area introuvable"
-#define MSG_NO_AVAIL_RESULT "Pas de résultat disponible"
-#define MSG_NO_BIG_DELETE "Délétion Partielle non implémentée pour les fichiers HUGE"
-#define MSG_NO_CHAR_FROM "Conversion de type %d en caractères impossible"
-#define MSG_NO_CLUSTER_COL "Pas de colonne optimisable"
-#define MSG_NO_COL_ADDING "Ajouter des colonnes dans une définition existante est impossible"
-#define MSG_NO_COL_DEF_AS "La définitions des colonnes est incompatible avec AS Select"
-#define MSG_NO_COL_FOUND "La section colonne %s est vide"
-#define MSG_NO_COL_IN_TABLE "La colonne %d n'est pas dans la table %s"
-#define MSG_NO_COL_SECTION "Section colonne manquante pour la table %s"
-#define MSG_NO_CONNECT_ADDR "Adresse de connection non spécifiée"
-#define MSG_NO_CONST_FILTER "Filtres constants non implementés"
-#define MSG_NO_CURLY_BRKT "Pas d'accolade de fermeture"
-#define MSG_NO_DATABASE "Base de données %s introuvable"
-#define MSG_NO_DATE_FMT "Pas de format date pour le valblock de type %d"
-#define MSG_NO_DBF_INSERT "Insert pas encore implémenté pour les fichier DBF"
-#define MSG_NO_DEF_FNCCOL "Colonne fonction par défaut introuvable"
-#define MSG_NO_DEF_PIVOTCOL "Colonne pivot par défaut introuvable"
-#define MSG_NO_DIR_INDX_RD "Pas d'accès directe des tables %s"
-#define MSG_NO_DMY_DIR_ACC "Pas d'accès direct aux tables virtuelles DUMMY"
-#define MSG_NO_DOM_DELETE "Délétion Partielle non implémentée pour les domaines"
-#define MSG_NO_DOM_MATCH "Chaîne %.8s... non touvée dans le domaine %s"
-#define MSG_NO_EDITED_LANG "Coparm: Pas de langage en édition"
-#define MSG_NO_EXP_LINK "Liaison par expression invalide pour une table JCT"
-#define MSG_NO_EXT_FILTER "Le filtrage ne peut se référer à une autre table"
-#define MSG_NO_EXT_UPDATE "Pas de mise à jour en référence à une autre table"
-#define MSG_NO_FEAT_SUPPORT "%s non supporté dans cette version"
-#define MSG_NO_FILE_LIST "La table %s n'a pas de liste de fichiers"
-#define MSG_NO_FLD_FORMAT "Format absent pour le champs %d de %s"
-#define MSG_NO_FORMAT_COL "Type COLUMN informattable"
-#define MSG_NO_FORMAT_TYPE "Le format ne peut pas être défini à partir du type %d"
-#define MSG_NO_FULL_JOIN "Jointures autorisées seulement à égalité sur clé(s)"
-#define MSG_NO_FUL_OUT_JOIN "Jointures externes complètes non supportées"
-#define MSG_NO_FUNC_ORDER "Tri non supporté sur élément fonctionnel"
-#define MSG_NO_HEAD_JOIN "Jointure sur une table non en tête"
-#define MSG_NO_HQL_CONV "Conversion en HQL non disponible"
-#define MSG_NO_INDEX "La table %s n'a pas d'index"
-#define MSG_NO_INDEX_GBX "Pas ou mauvais index pour SQLGBX"
-#define MSG_NO_INDEX_IN "Pas d'index dans %s"
-#define MSG_NO_INDEX_READ "Pas d'accès directe des tables multiples"
-#define MSG_NO_INIT_LANG "Pas de langage initial"
-#define MSG_NO_JOIN_TO_EXP "Jointure vers une expression impossible"
-#define MSG_NO_JOIN_UPDEL "Pas de jointure avec Update/Delete"
-#define MSG_NO_KEY_COL "Pas de colonne clé trouvée"
-#define MSG_NO_KEY_UPDATE "Le nom des clés ne peut pas être modifié"
-#define MSG_NO_LANGUAGE "Pas de langage opérationnel\n"
-#define MSG_NO_LANG_TO_QUIT "Pas de langage à quitter"
-#define MSG_NO_LISTVAL_HERE "LSTBLK: Liste de valeurs utilisée hors contexte"
-#define MSG_NO_MAP_INSERT "MAP incompatible avec Insert"
-#define MSG_NO_MATCHING_COL "Pas de colonne correspondant à %s dans %s"
-#define MSG_NO_MATCH_COL "Colonne correspondante introuvable"
-#define MSG_NO_MEMORY "Mémoire pleine"
-#define MSG_NO_MEM_CORR_SUB "Subquery corrélée en mémoire non encore implémentée"
-#define MSG_NO_MODE_PADDED "Mode non supporté pour les fichiers 'padded'"
-#define MSG_NO_MORE_COL "La colonne %s n'est plus dans la table pivot"
-#define MSG_NO_MORE_LANG "Plus de langage, exit de %s\n"
-#define MSG_NO_MORE_VAR "Les fichiers VAR ne sont plus supportés"
-#define MSG_NO_MULCOL_JOIN "Jointure vers un index multi-colonne pas encore possible"
-#define MSG_NO_MULT_HAVING "Clauses Having multiples non implémentées"
-#define MSG_NO_MUL_DIR_ACC "Accès direct des tables multiples pas encore implémenté"
-#define MSG_NO_MUL_VCT "Les tables VCT ne peuvent pas être multiples"
-#define MSG_NO_MYSQL_CONN "Aucune connexion MySQL ouverte"
-#define MSG_NO_MYSQL_DELETE "Pas de Delete pour les tables MySQL"
-#define MSG_NO_NBCOL "Pas de NBcol"
-#define MSG_NO_NBLIN "Pas de NBlin, MaxSize ou Continued"
-#define MSG_NO_NBLIN_CONT "Fetch: Pas de NBlin ou Continued"
-#define MSG_NO_NULL_CONST "Les constantes <null> ne sont pas prises en charge"
-#define MSG_NO_ODBC_COL "Colonnes ODBC automatiques non supportées par cette version"
-#define MSG_NO_ODBC_DELETE "Delete ne devrait pas être appelé pour les tables ODBC"
-#define MSG_NO_ODBC_DIRECT "Accès directe des tables ODBC non encore implémenté"
-#define MSG_NO_ODBC_MUL "Multiple(2) non supporté pour les tables ODBC"
-#define MSG_NO_ODBC_SPECOL "Pas de colonne spéciale ODBC"
-#define MSG_NO_OPT_COLUMN "Pas optimisable ou pas de colonne optimisées"
-#define MSG_NO_OP_MODIF "Les modificateurs ne s'appliquent pas à %s"
-#define MSG_NO_PARAMETER "Pas de paramètre"
-#define MSG_NO_PART_DEL "Delete partiel des fichier %s impossible"
-#define MSG_NO_PART_MAP "Mapping partiel non implémenté pour cet OS"
-#define MSG_NO_PAR_BLK_INS "Insertion de bloc partiel impossible"
-#define MSG_NO_PIV_DIR_ACC "Pas d'accès directe aux tables PIVOT"
-#define MSG_NO_POS_ADDED "Pos_code non ajouté"
-#define MSG_NO_PROMPTING "Relance impossible pour les tables distribuées"
-#define MSG_NO_QRY_DELETE "Delete n'est pas utilisable pour les views QRY"
-#define MSG_NO_QUERY_ARRAY "Tableaux avec QUERY non encore implémentés"
-#define MSG_NO_RCUR_DSK_YET "Usage recursif de DISK non encore implementé"
-#define MSG_NO_READ_32 "Lecture de 32 octets impossible"
-#define MSG_NO_RECOV_SPACE "Espace non recouvrable dans le fichier index"
-#define MSG_NO_REF_DELETE "Pas de suppression en référence à une autre table"
-#define MSG_NO_REF_UPDATE "Pas de mise à jour en référence à une autre table"
-#define MSG_NO_REMOTE_FNC "Certaines fonctions ne peuvent pas être exécutées à distance"
-#define MSG_NO_ROWID_FOR_AM "Accès direct impossible de ROWID pour les tables de type %s"
-#define MSG_NO_ROW_NODE "Le nom du Rownode n'est pas défini"
-#define MSG_NO_SECTION_NAME "Nom de section manquant"
-#define MSG_NO_SEC_UPDATE "Les noms de section ne peuvent pas être modifiés"
-#define MSG_NO_SELECTED_DB "Aucune base de données sélectée"
-#define MSG_NO_SELF_PIVOT "Une table ne peut se pivoter elle-même !"
-#define MSG_NO_SERVER_FOUND "Serveur introuvable"
-#define MSG_NO_SETPOS_YET "SetPos pas encore implémenté pour les fichier %s"
-#define MSG_NO_SFEXIT_UNIX "Fonction %s non disponible sur Unix"
-#define MSG_NO_SOURCE " (pas de source)"
-#define MSG_NO_SPEC_COL "Pas de colonne spéciales MYSQL"
-#define MSG_NO_SQL_DELETE "Delete n'est pas utilisable actuellement pour les views SQL"
-#define MSG_NO_SUB_VAL "Pas de sous-value d'un tableau de type %d"
-#define MSG_NO_SUCH_INDEX "La table %s n'a pas l'index %s"
-#define MSG_NO_SUCH_SERVER "Serveur %s introuvable"
-#define MSG_NO_SUCH_TABLE "Table %s pas dans la base de données"
-#define MSG_NO_TABCOL_DATA "Pas de données pour la table %s colonne %s"
-#define MSG_NO_TABLE_COL "Aucune colonne trouvée pour %s"
-#define MSG_NO_TABLE_DEL "Delete non autorisé pour les tables %s "
-#define MSG_NO_TABLE_DESC "Pas de bloc descriptif de table"
-#define MSG_NO_TABLE_INDEX "La table %s n'a pas d'index"
-#define MSG_NO_TABLE_LIST "Pas de liste de tables"
-#define MSG_NO_TAB_DATA "Pas de données pour la table %s"
-#define MSG_NO_TERM_IN_TOK "Les non-terminaux ne sont pas utilisables dans les règles de Token"
-#define MSG_NO_TOKEN_DB "DB introuvable pour la colonne TOKEN %s"
-#define MSG_NO_UNIX_CATINFO "Pas d'info catalogue sous Unix"
-#define MSG_NO_UPDEL_JOIN "Pas de jointure de tables ODBC pour Update/Delete"
-#define MSG_NO_VCT_DELETE "Délétion Partielle non implémentée pour les fichiers VCT"
-#define MSG_NO_VIEW_COLDEF "Colonne définition impossible pour les views"
-#define MSG_NO_VIEW_SORT "La View fonctionnelle %s ne peut pas être triée ou jointe"
-#define MSG_NO_ZIP_DELETE "Delete sur fichier Zip non encore implementé"
-#define MSG_NO_ZIP_DIR_ACC "Accès directe des tables ZDOS non encore implementé"
-#define MSG_NULL_COL_VALUE "La colonne n'a pas de valeur"
-#define MSG_NULL_ENTRY "InitLang, entrée nulle %d %s"
-#define MSG_NULL_QUERY "Requête vide"
-#define MSG_NUMVAL_NOMATCH "Disparité de Numval pour %s"
-#define MSG_N_FULL_PARSES "%d significations"
-#define MSG_ODBC_READ_ONLY "ODBC est actuellement en lecture seulement"
-#define MSG_OFFSET_NOT_SUPP "Offset non supporté pour ce type de sous requête"
-#define MSG_ONE_LANG_YET "Un langage est déjà en édition"
-#define MSG_ONE_PARAM_ONLY "Un seul paramètre autorisé"
-#define MSG_ONLY_LOG10_IMPL "Seul Log10 est implementé"
-#define MSG_ON_LANGUAGE "Langage %.8s version %d niveau %d éditable"
-#define MSG_OPENING "Ouverture"
-#define MSG_OPENING_QUERY "Ouverture de la requête"
-#define MSG_OPEN_EMPTY_FILE "Ouverture du fichier vide %s: %s"
-#define MSG_OPEN_ERROR "Erreur d'ouverture %d en mode %d sur %s: "
-#define MSG_OPEN_ERROR_IS "Erreur à l'ouverture de %s: %s"
-#define MSG_OPEN_ERROR_ON "Erreur d'ouverture sur %s"
-#define MSG_OPEN_MODE_ERROR "Erreur d'ouverture(%s) %d sur %s"
-#define MSG_OPEN_SORT_ERROR "Erreur logique de tri dans QUERY Open"
-#define MSG_OPEN_STRERROR "Erreur à l'ouverture: %s"
-#define MSG_OPEN_W_ERROR "Erreur à l'ouverture de %s en écriture"
-#define MSG_OPTBLK_RD_ERR "Erreur à la lecture d'un bloc optimisation: %s"
-#define MSG_OPTBLK_WR_ERR "Erreur à l'écriture d'un bloc optimisation: %s"
-#define MSG_OPTIMIZING "Optimisation de "
-#define MSG_OPT_BMAP_RD_ERR "Erreur en lecture des bitmaps d'optimisation: %s"
-#define MSG_OPT_BMAP_WR_ERR "Erreur en écriture des bitmaps d'optimisation: %s"
-#define MSG_OPT_CANCELLED "Optimisation interrompue par l'utilisateur"
-#define MSG_OPT_DVAL_RD_ERR "Erreur en lecture des valeurs distinctes: %s"
-#define MSG_OPT_DVAL_WR_ERR "Erreur en écriture des valeurs distinctes: %s"
-#define MSG_OPT_HEAD_RD_ERR "Erreur en lecture de l'entête du fichier opt: %s"
-#define MSG_OPT_HEAD_WR_ERR "Erreur en écriture de l'entête du fichier opt: %s"
-#define MSG_OPT_INIT "Optimisation initialisée"
-#define MSG_OPT_LOGIC_ERR "Erreur logique dans SetBitmap, i=%d"
-#define MSG_OPT_MAX_RD_ERR "Erreur en lecture des valeurs maxi: %s"
-#define MSG_OPT_MAX_WR_ERR "Erreur en écriture des valeurs maxi: %s"
-#define MSG_OPT_MIN_RD_ERR "Erreur en lecture des valeurs mini: %s"
-#define MSG_OPT_MIN_WR_ERR "Erreur en écriture des valeurs mini: %s"
-#define MSG_OPT_NOT_MATCH "Le fichier opt %s n'est pas à jour"
-#define MSG_OP_RES_TOO_LONG "Résultat trop long pour l'opérateur=%d"
-#define MSG_ORDER_OUT_RANGE "Tri: Order %d hors limite"
-#define MSG_ORDER_TWICE "Un même élément est trié deux fois"
-#define MSG_PAGE_ERROR "Erreur de pagination"
-#define MSG_PARM_CNT_MISS "Disparité du nombre de Paramètres"
-#define MSG_PARSE_NULL_SEM "Sémantique nulle"
-#define MSG_PARSING_QUERY "Analyse de la requête"
-#define MSG_PIX_ERROR "Pix %s erreur règle no=%u\n"
-#define MSG_PIX_TEST_ERROR "Règle=%u: pix-TEST pas dans le premier noeud\n"
-#define MSG_PLG_READ_ONLY "PLG est actuellement en lecture seulement"
-#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp est NULL"
-#define MSG_PLUG_NOT_INIT "Plug n'est pas initialisé\n"
-#define MSG_PLUG_NOT_RUN "Plug n'est pas en marche"
-#define MSG_PNODE_RULE "(Noeud %d règle %d) "
-#define MSG_POS_TOO_LONG "%s trop long (>%d)"
-#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp est NULL"
-#define MSG_PRIV_INSTR "Instruction privilégiée"
-#define MSG_PROCADD_ERROR "Erreur %d sur l'adresse de %s"
-#define MSG_PROCESS_SUBQRY "Sub-Query en cours de traitement"
-#define MSG_PROC_WOULD_LOOP "Bouclage du traitement (maxres=%d maxlin=%d)"
-#define MSG_PROGRESS_INFO "Informations sur le traitement en cours"
-#define MSG_PROMPT_CANCEL "Relance annulée"
-#define MSG_PROMPT_NIY "Prompt non implémenté pour cette configuration"
-#define MSG_PTR_NOT_FOUND "Pointeur introuvable Num=%d ti1=%d"
-#define MSG_PXDEF_IS_NULL "Pxdef est NULL"
-#define MSG_QRY_READ_ONLY "Les views QRY sont en lecture seulement"
-#define MSG_QUERY_CANCELLED "Requête interrompue par l'utilisateur"
-#define MSG_QUERY_NOT_EXEC "Requête non exécutée"
-#define MSG_QUERY_SAVED "Requête %s sauvegardée"
-#define MSG_QUOTE_IN_QUOTE "Appostrophe dans un champ entre appostrophe ligne %d"
-#define MSG_RANGE_NIY "Range pas encore implémenté pour %s"
-#define MSG_RANGE_NO_JOIN "Range non compatible avec les index de jointure"
-#define MSG_RC_READING "rc=%d en lecture de la table %s"
-#define MSG_READB_BAD_INIT "%s ReadDB appelé avec Init=0"
-#define MSG_READCOL_ERROR "SQLCOL: erreur dans ReadColumn"
-#define MSG_READING "Lecture"
-#define MSG_READING_FROM "Lecture de %s"
-#define MSG_READING_RECORD "Erreur en lecture de l'enregistrement %d de %s"
-#define MSG_READY "Prêt"
-#define MSG_READ_ERROR "Erreur en lecture sur %s: %s"
-#define MSG_READ_ERROR_RC "Erreur en lecture, rc=%d"
-#define MSG_READ_MEM_ERROR "Lecture mémoire %d: taille=%d"
-#define MSG_READ_ONLY "Cette table protégée en lecture seule ne peut être modifiée"
-#define MSG_READ_SEEK_ERROR "Erreur de recherche en lecture: %s"
-#define MSG_READ_SEG_ERROR "Lecture segment %d: taille=%d"
-#define MSG_RECEIVED "Reçu %c\n"
-#define MSG_RECORD_ERROR "Erreur à la lecture de l'enregistrement %d de %s"
-#define MSG_RECORD_NO_SEP "Enregistrement sans séparateur"
-#define MSG_REC_SKIPPED " (%d lignes erronnées sautées par l'option MaxErr)"
-#define MSG_REDUCE_INDEX "Réduction de l'index"
-#define MSG_REGISTER_ERR "Enregistrement NS impossible, préfix='%s' et href='%s'"
-#define MSG_REMOTE_CONN_ERR "La connection éloignée a échoué"
-#define MSG_REMOVE_ERROR "Erreur en supprimant %s: %s"
-#define MSG_REMOVE_NOT_IMPL "Remove non implémenté pour TDB non Table"
-#define MSG_RENAME_ERROR "Erreur renommant %s en %s: %s"
-#define MSG_RENUM_RULES "Renumérotez les règles et réentrez ADD (règle sauvegardée dans la zone tampon)"
-#define MSG_REORDER_INDEX "Reclassement de l'index"
-#define MSG_REQU_ARG_NUM "La fonction %s doit avoir %d arguments"
-#define MSG_RESET_TO "%s remis à %d"
-#define MSG_RES_NOT_UNIQUE "Le résultat n'est pas unique"
-#define MSG_RET_FROM_LANG "Retour au language %s version %d.%d du language %s version %d.%d"
-#define MSG_ROWID_NOT_IMPL "RowNumber non implémenté pour les tables de type %s"
-#define MSG_ROWS_SELECTED "%d lignes sélectionnées en %.2lf sec"
-#define MSG_ROWS_TRUNCATED " (tronqué par MAXRES, LIMIT, FREQ ou AreaSize)"
-#define MSG_ROW_ARGNB_ERR "ROW: disparité du nombre d'arguments (%d,%d)"
-#define MSG_RPC_SERVER_ERR "Erreur logique dans TABMUL::MakeCol"
-#define MSG_RSC_ALLOC_ERROR "Erreur d'allocation mémoire dans Rescol %s"
-#define MSG_RULE_ENTERED "Règle %d entrée"
-#define MSG_RULE_SUBSET_ERR "Erreur d'initialisation de la zone Règles"
-#define MSG_SAVING_INDEX "Sauvegarde du fichier index"
-#define MSG_SCAN_NOT_IMP "Scan non implémenté"
-#define MSG_SEC_KEY_FIRST "Les sections et clés doivent être insérées en premier"
-#define MSG_SEC_NAME_FIRST "Le nom de section doit être en tête de liste en insertion"
-#define MSG_SEC_NOT_FOUND "Section %s absente de %s"
-#define MSG_SEEK_ERROR "Seek erreur dans CopyHeader"
-#define MSG_SEMANTIC_TREE "Arbre sémantique"
-#define MSG_SEM_BAD_REF "Sem @%d référence un argument de type non 0 ou 1"
-#define MSG_SEM_UNKNOWN "inconnue, rc=%d"
-#define MSG_SEP_IN_FIELD "Le champ %d contient le caractère séparateur"
-#define MSG_SEQUENCE_ERROR "HSTMT: Allocation hors séquence"
-#define MSG_SETEOF_ERROR "Erreur %d dans SetEndOfFile"
-#define MSG_SETRECPOS_NIY "SetRecpos non implémenté pour ce type de table"
-#define MSG_SET_LOCALE "Locale fixée à %s"
-#define MSG_SET_NULL_DOM "Valeur %d donnée à un domaine nul"
-#define MSG_SET_OP_NOT_IMPL "Opérateurs ensemblistes non implementés"
-#define MSG_SET_STR_TRUNC "SetValue: Chaîne de caractères tronquée"
-#define MSG_SEVERAL_TREES "Jointure non spécifiée pour certaines tables"
-#define MSG_SFP_ERROR "Erreur sur SetFilePointer: %s"
-#define MSG_SFUNC_NOT_IMPL "Fonction scalaire %s non implémentée"
-#define MSG_SHARED_LIB_ERR "Erreur au chargement de la librairie partagée %s: %s"
-#define MSG_SINGLE_STEP "Pas à pas"
-#define MSG_SLEEP "J'ai dormi %d milliseconds"
-#define MSG_SMART_SORTING "Récupération des lignes triées (passage %d de %d)"
-#define MSG_SMART_SORT_ERR "Erreur logique 1 dans Smart Sort"
-#define MSG_SORTING "Tri en cours"
-#define MSG_SORTING_INDEX "Tri de l'index"
-#define MSG_SORTING_VAL "Tri de %d valeurs"
-#define MSG_SORT_JOIN_INDEX "Tri de l'index de jointure"
-#define MSG_SPCOL_READONLY "La colonne spéciale %s est en lecture seulement"
-#define MSG_SPEC_CMD_SEP "Les commandes spéciales doivent être exécutées séparément"
-#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d non supporté"
-#define MSG_SQL_BLOCK_MISM "CheckColumn: bloc SQL courant non correspondant"
-#define MSG_SQL_CONF_ERROR "Erreur SQL: SQL_CONFORMANCE"
-#define MSG_SQL_READ_ONLY "Les views SQL sont actuellement en lecture seulement"
-#define MSG_SRCH_CLOSE_ERR "Erreur à la fermeture de l'Handle de recherche"
-#define MSG_SRC_TABLE_UNDEF "La table source n'est pas définie"
-#define MSG_STACK_ERROR "Erreur sur la pile, i=%d\n"
-#define MSG_STACK_OVERFLOW "Parser: Débordement de la pile\n"
-#define MSG_STRG_NOT_FOUND "Chaîne introuvable"
-#define MSG_STRING_INV_LIST "Liste invalide pour SemString"
-#define MSG_STRING_TOO_BIG "Chaîne trop grande pour le domaine %s"
-#define MSG_SUBALLOC_ERROR "Pas assez de mémoire en zone %p pour allouer %d (utilisé=%d libre=%d)"
-#define MSG_SUBAL_HUGE_ERR "Pas assez de mémoire en zone huge %p pour allouer %d"
-#define MSG_SUBARG_NOSEM "Argument @ ou sous-phrase de niveau %d pointe sur un noeud sans Sem"
-#define MSG_SUBARG_OUTRANGE "Argument @ ou sous-phrase de niveau %d hors limite"
-#define MSG_SUBQRY_ONEITEM "Une Sub-Query ne doit avoir qu'une sélection"
-#define MSG_SUBSET_ERROR "SubSet erreur dans LoadDB"
-#define MSG_SUB_OPEN_YET "Subquery déjà ouverte"
-#define MSG_SUB_RES_TOO_LNG "Résultat trop long pour SUBSTR"
-#define MSG_SYNTAX_ERROR "Erreur de syntaxe"
-#define MSG_SYSTEM_ERROR "Erreur système %d"
-#define MSG_S_ACCESS_DENIED "%s: accès non autorisé"
-#define MSG_S_ERROR "%s erreur"
-#define MSG_S_ERROR_NUM "%s: erreur=%d"
-#define MSG_S_INTRUPT_ERROR "%s: erreur interruption"
-#define MSG_S_INVALID_PARM "%s: paramètre invalide"
-#define MSG_S_INV_ADDRESS "%s: adresse invalide"
-#define MSG_S_UNKNOWN_ERROR "%s: erreur de code %u inconnu"
-#define MSG_TABDIR_READONLY "Les tables DIR sont en lecture seulement"
-#define MSG_TABLE_ALREADY "La table %s existe déjà"
-#define MSG_TABLE_ALTERED "Table %s %s altérée"
-#define MSG_TABLE_CREATED "%s table %s créée"
-#define MSG_TABLE_DROPPED "Table %s supprimée"
-#define MSG_TABLE_MULT_JOIN "Utilisation multiple de la table %s pour jointure"
-#define MSG_TABLE_NOT_IN_DB "La table %s n'existe pas dans %s"
-#define MSG_TABLE_NOT_OPT "Table non optimisable"
-#define MSG_TABLE_NO_INDEX "La table %s n'est pas indexable"
-#define MSG_TABLE_NO_OPT "La table %s n'existe pas ou de type non optimisable"
-#define MSG_TABLE_READ_ONLY "Les tables %s sont en lecture seulement "
-#define MSG_TABMUL_READONLY "Les tables multiples sont en lecture seulement"
-#define MSG_TAB_NOT_LOADED " (certaines tables n'ont put être chargées)"
-#define MSG_TAB_NOT_SPEC "Table non specifiée"
-#define MSG_TB_VW_NOTIN_DB "Table ou view %s pas dans la base de données"
-#define MSG_TDB_NXT_NOT_NUL "Tdb.Next non NULL"
-#define MSG_TDB_USE_ERROR "Erreur, Tdbp->Use=%d"
-#define MSG_TOO_MANY_COLS "Trop de colonnes"
-#define MSG_TOO_MANY_COLTAB "Trop de colonnes dans %s (%d)"
-#define MSG_TOO_MANY_FIELDS "Trop de champs ligne %d de %s"
-#define MSG_TOO_MANY_JUMPS "Trop de niveaux de saut"
-#define MSG_TOO_MANY_KEYS "Trop de clés (%d)"
-#define MSG_TOO_MANY_POS "Trop de pos_codes"
-#define MSG_TOO_MANY_TABLES "Trop de tables (%d)"
-#define MSG_TOPSEM_ERROR "Erreur inconnue dans TopSem"
-#define MSG_TO_BLK_IS_NULL "To Blk est nul"
-#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr n'est pas nul"
-#define MSG_TO_PIX_NOT_NULL "Set.To_Pix n'est pas nul"
-#define MSG_TO_SEM_NOT_NULL "Set.To_Sem n'est pas nul"
-#define MSG_TRUNCATE_ERROR "Erreur en troncation: %s"
-#define MSG_TRUNC_BY_ESTIM "Tronqué par l'option Estimate"
-#define MSG_TYPES_ERROR "Erreur sur Types(%d)"
-#define MSG_TYPE_CONV_ERROR "Type non convertible dans une expression"
-#define MSG_TYPE_DEF_MISM "Disparité entre type et définition"
-#define MSG_TYPE_MISMATCH "Clé et source ne sont pas du même type"
-#define MSG_TYPE_RECFM_MISM "Disparité entre Type et Recfm"
-#define MSG_TYPE_TO_VERIFY "Type à vérifier: %d"
-#define MSG_TYPE_VALUE_ERR "Colonne %s: disparité type(%s)/valeur(%s)"
-#define MSG_UNBALANCE_QUOTE "Appostrophe en trop ligne %d"
-#define MSG_UNDEFINED_AM "COLBLK %s: méthode d'accès indéfinie"
-#define MSG_UNDEFINED_PATH "Chemin d'accès indéfini pour Plgcnx.ini"
-#define MSG_UNDEF_COL_COUNT "Count sur colonne non définie"
-#define MSG_UNKNOWN_DOMAIN "Domaine inconnu %s"
-#define MSG_UNKNOWN_ERROR "Erreur inconnue"
-#define MSG_UNKNOWN_EXCPT "Exception non répertoriée"
-#define MSG_UNKNOWN_NAME "Nom inconnu: %.8s"
-#define MSG_UNKNOWN_PATH "Chemin d'accès inconnu pour Plgcnx.ini"
-#define MSG_UNKNOWN_POS "Nom pos_code inconnu: %s"
-#define MSG_UNKNOWN_SEM "Sem %.8s inconnue, rc=%d"
-#define MSG_UNKNOWN_SYNONYM "Synonyme inconnu"
-#define MSG_UNKNW_QRY_TYPE "ReadDB: type de requête inconnu"
-#define MSG_UNKN_ERR_CODE "Erreur de code %d inconnu"
-#define MSG_UNLOADABLE " inchargeable: "
-#define MSG_UNLOADABLE_PRM "%s inchargeable: %s"
-#define MSG_UNMATCH_FIL_ARG "Argument de filtre dépareillé"
-#define MSG_UNQ_COL_SEV_TAB "La colonne %s non qualifiée est dans plusieurs tables"
-#define MSG_UNRESOLVED_ARG "?Argument manquant: %s non résolu en %d ligne %d"
-#define MSG_UPDATE_ERROR "Erreur en Update sur %s"
-#define MSG_UPDATING_ROWS "Mise à jour des lignes"
-#define MSG_UPD_ZIP_NOT_IMP "Mise à jour des tables ZDOS non encore implementé"
-#define MSG_UP_LANGUAGE "Bloc langage %.8s version %d niveau %d chargé"
-#define MSG_USED_FREE_MEM "Sarea: utilisé %d, libre %d"
-#define MSG_USETEMP_IS "Usetemp est : %s"
-#define MSG_USETEMP_RESET ". Usetemp remis à Auto"
-#define MSG_USETEMP_SET "Usetemp fixé à %s"
-#define MSG_USE_NO_MATCH "Use non correspondant : Use=%d, ti2=%d, ti3=%d"
-#define MSG_USING_INDEX " (Indexé par"
-#define MSG_VALIST_MISMATCH "Disparité des listes de valeurs"
-#define MSG_VALSTR_TOO_LONG "Valeur %s trop longue pour une chaîne de longueur %d"
-#define MSG_VALTYPE_NOMATCH "Disparité types de valeur"
-#define MSG_VALUE_ERROR "Colonne %s: bloc valeur nul"
-#define MSG_VALUE_NOT_ALLOC "Valeur non allouée pour la colonne R%d %s"
-#define MSG_VALUE_TOO_BIG "Valeur %lld trop grande pour la colonne %s"
-#define MSG_VALUE_TOO_LONG "Valeur %s trop longue pour la colonne %s de longueur %d"
-#define MSG_VAL_ALLOC_ERR "Allocation impossible du noeud valeur"
-#define MSG_VAL_TOO_LONG "Valeur %s trop longue pour le champ %s"
-#define MSG_VIEW_ALREADY "La VIEW %s existe déjà"
-#define MSG_VIEW_CREATED "%s view %s créée"
-#define MSG_VIEW_DROPPED "View %s supprimée"
-#define MSG_VIEW_NOT_IN_DB "%s n'est pas une View de %s"
-#define MSG_VIR_NO_DELETE "Delete impossible sur les tables %s"
-#define MSG_VIR_READ_ONLY "Les tables virtuelles %s sont en lecture seulement"
-#define MSG_VM_LANG "Langage au format VM, non supporté"
-#define MSG_VOID_FIRST_ARG "Le premier argument ne doit pas être vide"
-#define MSG_VOID_IN_STRING "Erreur: chaîne IN vide"
-#define MSG_VOID_ORDER_LIST "Liste de tri vide, erreur système ?"
-#define MSG_VOID_POS_DICT "Dictionnaire interne du langage vide"
-#define MSG_VOID_QUERY "Requête vide %s"
-#define MSG_WORK_AREA "Espace de travail: %s"
-#define MSG_WORK_TOO_SMALL "Zone de travail trop petite, accroître AreaSize"
-#define MSG_WRITE_ERROR "Erreur à l'écriture de %s"
-#define MSG_WRITE_SEEK_ERR "Erreur de recherche en écriture: %s"
-#define MSG_WRITE_STRERROR "Erreur en écriture sur %s: %s"
-#define MSG_WRITING "Ecriture"
-#define MSG_WRITING_ERROR "Erreur à l'écriture de %s: %s"
-#define MSG_WRITING_QUERY "Erreur à l'écriture de la requête: "
-#define MSG_WRONG_ARG_NUM "La fonction %s ne prend pas %d arguments"
-#define MSG_WRONG_COL_NUM "Numéro de colonne %d trop grand pour %s"
-#define MSG_WRONG_DB_LIST "Liste des bases de données incorrecte ou vide"
-#define MSG_WRONG_FUNCTION "Mauvaise fonction %d"
-#define MSG_WRONG_OP_PARM "Mauvais opérateur ou paramètres pour %s"
-#define MSG_WRONG_PARMS "Mauvais paramètres pour %s"
-#define MSG_WRONG_PASSWORD "Mot de passe illégal pour %s"
-#define MSG_WRONG_TYPE "type non supporté"
-#define MSG_WRONG_USERFILE "La Userfile a une mauvaise taille %d"
-#define MSG_WS_CONV_ERR "Erreur de convertion de %s en WS"
-#define MSG_XCOL_MISMATCH "La colonne %s ne correspond pas à l'index"
-#define MSG_XDB_DEL_ERROR "Erreur en supprimant des entrées du fichier XDB"
-#define MSG_XFILE_READERR "Erreur %d en lisant le fichier index"
-#define MSG_XFILE_TOO_SMALL "Le fichier index est plus petit que la taille de l'index"
-#define MSG_XFILE_WRITERR "Erreur en écrivant le fichier index: %s"
-#define MSG_XMLTAB_INIT_ERR "Erreur d'initialisation de la table XML"
-#define MSG_XML_INIT_ERROR "Erreur d'initialisation du nouveau fichier XML"
-#define MSG_XPATH_CNTX_ERR "Le nouveau contexte XPath ne peut être créé"
-#define MSG_XPATH_EVAL_ERR "Impossible d'évaluer l'emplacement xpath '%s'"
-#define MSG_XPATH_NOT_SUPP "Xpath non supporté colonne %s"
-#define MSG_X_ARG_ADDED "%d arguments ajoutés"
-#define MSG_X_ARG_SET "%d arguments ont été initialisés"
-#define MSG_X_ON_TAB " %s sur %s("
-#define MSG_ZERO_DIVIDE "Division par zéro dans une expression"
+#define MSG_ACCESS_VIOLATN "Violation accès mémoire"
+#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Activity"
+#define MSG_ADDVAL_ERROR "Erreur %d dans AddValue"
+#define MSG_ADD_BAD_TYPE "Ajout d'une valeur de type %s non conforme dans un tableau %s"
+#define MSG_ADD_NULL_DOM "Ajout de la chaîne %s à un domaine nul"
+#define MSG_ADPOS_IN_DICTP "ADPOS au travail dans User_Dictp"
+#define MSG_AFTER " après: "
+#define MSG_ALG_CHOICE_AUTO "Le choix du meilleur algorithme est automatique"
+#define MSG_ALG_CHOICE_BAD "Choix d'algorithme invalide, remis à AUTO"
+#define MSG_ALG_CHOICE_QRY "Utilise l'algorithme 'Query'"
+#define MSG_ALG_CURLY_BRK "Le choix de l'algorithme dépend des accolades externes"
+#define MSG_ALLOC_ERROR "Erreur d'allocation de %s"
+#define MSG_ALL_DELETED "Toutes les lignes enlevées en %.2lf sec"
+#define MSG_ALTER_DB_ERR "Impossible de déterminer la base de données à modifier"
+#define MSG_AMBIG_COL_QUAL "Qualificateur ambigu %s pour la colonne %s"
+#define MSG_AMBIG_CORREL "Select %s.* corrélation ambigue"
+#define MSG_AMBIG_SPEC_COL "Colonne spéciale ambiguë %s"
+#define MSG_ANSWER_TYPE "Réponse de type"
+#define MSG_API_CONF_ERROR "Erreur SQL: API_CONFORMANCE"
+#define MSG_APPL_ACCESSIBLE "Application %s accessible"
+#define MSG_APPL_ACTIVE "Application %s encore active"
+#define MSG_APPL_BAD_SAVE "Application %s partiellement sauvegardée"
+#define MSG_APPL_CREATED "Application %s crée"
+#define MSG_APPL_IS_ACTIVE "Application déjà active"
+#define MSG_APPL_NOT_INIT "Application non initialisée"
+#define MSG_APPL_NOT_LOADED "Application non chargée"
+#define MSG_APPL_QUIT "Fin de l'application %s"
+#define MSG_APPL_SAVED "Application %s sauvegardée"
+#define MSG_APP_STILL_ACTIV "Application du langage %s encore active (non libérable)"
+#define MSG_AREAFILE_NOTFND "Fichier Area introuvable"
+#define MSG_ARGS_SYNTAX_ERR "?SetArgs erreur de syntaxe: %s inattendu après %s"
+#define MSG_ARG_ALREADY_SET "Argument %d déjà alloué"
+#define MSG_ARG_NOT_AN_ATTR "L'argument n'est pas un attribut (type %d erroné)"
+#define MSG_ARG_OUT_CONTEXT "Argument de type @ utilisé hors contexte"
+#define MSG_ARG_OUT_RANGE "Argument de phrase valant %d hors limite"
+#define MSG_ARG_PTR_NOSEM "Argument valant %d pointe sur un noeud sans Sem"
+#define MSG_ARG_PTR_NOSEMS "Argument valant %d pointe sur un noeud sans sémantique"
+#define MSG_ARG_REF_LOOP "?Bouclage entre références croisées des arguments"
+#define MSG_ARG_TWO_CONST "Le 2ème argument de %s doit être constant"
+#define MSG_ARRAY_ALLOC_ERR "Erreur d'allocation mémoire dans ARRAY"
+#define MSG_ARRAY_BNDS_EXCD "Hors limite de tableau"
+#define MSG_ARRAY_ERROR "Erreur de fonctionnement k=%d n=%d"
+#define MSG_ATTRIBUTE_ERROR "Erreur règle %u attribut %s: "
+#define MSG_ATT_NOT_CASE "Mauvaise valeur %d pour attribut (pas une CaseValue)"
+#define MSG_ATT_POSCODE_BIG "Code attribut %d trop grand (max=%d)"
+#define MSG_AVGLEN_ERROR "avglen doit être entre %d et %d"
+#define MSG_BAD_AGGREG_FUNC "Fonction aggrégée %d non supportée"
+#define MSG_BAD_ARGTYPES "Argument de type invalide pour %s"
+#define MSG_BAD_ARGUMENTS "Argument not attachés pour %s"
+#define MSG_BAD_ARG_NUM "Nombre d'arguments invalide %d"
+#define MSG_BAD_ARG_TYPE "Type d'argument %d invalide"
+#define MSG_BAD_ARRAY_OPER "Les tableaux doivent utiliser l'opérateur IN"
+#define MSG_BAD_ARRAY_TYPE "Type=%d invalide pour un tableau"
+#define MSG_BAD_ARRAY_VAL "Les tableaux doivent avoir le même nombre de valeurs"
+#define MSG_BAD_BIN_FMT "Format invalide %c pour la colonne BIN %s"
+#define MSG_BAD_BLK_ESTIM "Nombre de blocs supérieur à l'estimation"
+#define MSG_BAD_BLK_SIZE "Taille du bloc %d non conforme"
+#define MSG_BAD_BYTE_NUM "Le nombre d'octets écrits est faux"
+#define MSG_BAD_BYTE_READ "Le nombre d'octets lus est faux"
+#define MSG_BAD_CARDINALITY "Appel invalide de Cardinality pour une table multiple"
+#define MSG_BAD_CASE_SPEC "Min/Maj: spécification %c incorrecte, recommencez: "
+#define MSG_BAD_CHAR_SPEC "Spécification '%s' invalide pour caractère"
+#define MSG_BAD_CHECK_TYPE "Sous-type %d invalide pour CheckColumn"
+#define MSG_BAD_CHECK_VAL "Valeur pour Check invalide '%s'"
+#define MSG_BAD_COLCRT_ARG "COLCRT: Arg invalide (type=%hd, domain=%hd)"
+#define MSG_BAD_COLDEF_TYPE "Coldefs: type illégal %d"
+#define MSG_BAD_COLIST_ITEM "Elément invalide dans une Colist"
+#define MSG_BAD_COLIST_TYPE "Mauvais type=%d pour une Colist"
+#define MSG_BAD_COLSIZE "Colsize %d trop petit pour cette base de données"
+#define MSG_BAD_COL_ENTRY "Entrée invalide pour la colonne %s"
+#define MSG_BAD_COL_FORMAT "Type de formattage %d invalide pour une colonne"
+#define MSG_BAD_COL_IN_FILT "Colonne incorrecte dans un filtre"
+#define MSG_BAD_COL_QUALIF "Qualificateur invalide %s pour la colonne %s"
+#define MSG_BAD_COL_TYPE "Type invalide %s pour la colonne %s"
+#define MSG_BAD_COL_XPATH "Xpath invalide colonne %s de la table HTML %s"
+#define MSG_BAD_COMPARE_OP "Opérateur de comparaison %d invalide"
+#define MSG_BAD_CONST_TYPE "Type=%d invalide pour une constante"
+#define MSG_BAD_CONV_TYPE "Convertion de type invalide %d"
+#define MSG_BAD_CORREL "Select %s.* corrélation absente"
+#define MSG_BAD_DATETIME "Valeur date/temps invalide"
+#define MSG_BAD_DATE_OPER "Opérateur de date inattendu %d"
+#define MSG_BAD_DBF_FILE "Le fichier DBF %s est altéré"
+#define MSG_BAD_DBF_REC "Fichier DBF %s altéré enregistrement %d"
+#define MSG_BAD_DBF_TYPE "Type DBF %c non supporté"
+#define MSG_BAD_DEF_ARG "Argument invalide pour INDEXDEF (type=%hd, domain=%hd)"
+#define MSG_BAD_DEF_READ "EOF inattendue en lecture différée"
+#define MSG_BAD_DEF_TYPE "Type de colonne invalide"
+#define MSG_BAD_DIRECTORY "Répertoire invalide %s: %s"
+#define MSG_BAD_DIST_JN_FIL "Filtre de jointure distincte invalide"
+#define MSG_BAD_DIST_JOIN "Spécification invalide de jointure distincte"
+#define MSG_BAD_DOM_COL_DEF "Définition de colonnes invalide pour un domaine"
+#define MSG_BAD_DOM_VALUE "La valeur %d n'appartient pas au domaine"
+#define MSG_BAD_EDIT_INIT "Coparm: édition %s initialisée improprement"
+#define MSG_BAD_EVAL_TYPE "Fonction scalaire de type=%d invalide"
+#define MSG_BAD_EXEC_MODE "Mode d'exécution invalide '%s'"
+#define MSG_BAD_EXP_ARGTYPE "Argument de type %d invalide pour une expression"
+#define MSG_BAD_EXP_OPER "Opérateur=%d invalide pour expression"
+#define MSG_BAD_FETCH_RC "Code retour inattendu de Fetch %d"
+#define MSG_BAD_FIELD_FMT "Format de champ invalide %c pour %s"
+#define MSG_BAD_FIELD_RANK "Rang %d invalide pour la colonne %s"
+#define MSG_BAD_FIELD_TYPE "Mauvais type de champ %s"
+#define MSG_BAD_FILE_HANDLE "Handle de fichier invalide: %s"
+#define MSG_BAD_FILE_LIST "La section liste de fichiers est erronée"
+#define MSG_BAD_FILTER "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"
+#define MSG_BAD_FILTER_CONV "Conversion filtre incorrecte, B_T=%d,%d"
+#define MSG_BAD_FILTER_LINK "Opérateur de chaînage illégal %d"
+#define MSG_BAD_FILTER_OP "Opérateur de filtre invalide %d"
+#define MSG_BAD_FILTEST_OP "Opérateur invalide %d %d pour FilTest"
+#define MSG_BAD_FLD_FORMAT "Format invalide pour le champs %d de %s"
+#define MSG_BAD_FLD_LENGTH "Champs %s trop long (%s --> %d) ligne %d de %s"
+#define MSG_BAD_FLOAT_CONV "Convertion invalide d'un tableau flottant"
+#define MSG_BAD_FPARM_NEXT "Coparm: FPARM avec Next non nul"
+#define MSG_BAD_FREQ_SET "Spécification erronnée de Freq pour la colonne %s"
+#define MSG_BAD_FUNC_ARG "Funcarg de type %d non implémenté"
+#define MSG_BAD_FUNC_ARGTYP "Mauvais type d'argument=%d pour une fonction"
+#define MSG_BAD_FUNC_MODE "%s: mode invalide %d"
+#define MSG_BAD_GENRE "Genre est invalide"
+#define MSG_BAD_GETVIEW_RET "GetView: type de retour %d invalide"
+#define MSG_BAD_HANDLE_VAL "Valeur Handle invalide"
+#define MSG_BAD_HAV_FILTER "Filtre Having sur une requête non groupée"
+#define MSG_BAD_HAV_FILTYPE "Filtre invalide pour clause Having"
+#define MSG_BAD_HEADER "Fichier %s: bloc en-tête altéré"
+#define MSG_BAD_HEADER_VAL "Valeur invalide pour Header"
+#define MSG_BAD_HEAD_END "Lecture fin d'en-tête impossible"
+#define MSG_BAD_INDEX_COL "Colonne %s invalide pour index %s"
+#define MSG_BAD_INDEX_DEF "Définition invalide pour index %s"
+#define MSG_BAD_INDEX_FILE "Fichier index %s corrompu"
+#define MSG_BAD_INDEX_PART "Définition colonne invalide pour index %s"
+#define MSG_BAD_INPUT "Entrée incorrecte"
+#define MSG_BAD_IN_ARGTYPE "Argument de type invalide pour l'opérateur IN"
+#define MSG_BAD_IN_ENDING "Erreur: fin de chaîne IN invalide"
+#define MSG_BAD_IN_STRING "La chaîne IN commence ou finie par des caractères invalides %c ... %c"
+#define MSG_BAD_JCOL_TYPE "Erreur logique JCT: disparité des types colonnes"
+#define MSG_BAD_JOIN_EXP "Expression invalide pour une jointure"
+#define MSG_BAD_JOIN_FILTER "Filtre de jointure invalide"
+#define MSG_BAD_JOIN_OP "Opérateur de joint invalide %d"
+#define MSG_BAD_LANG_SIZE "Le fichier langage a une mauvaise taille %d"
+#define MSG_BAD_LINEFLD_FMT "Format invalide ligne %d champs %d de %s"
+#define MSG_BAD_LINE_LEN "Longueur ligne non égale à Lrecl"
+#define MSG_BAD_LIST_TYPE "Type de liste invalide %d"
+#define MSG_BAD_LOCALE "Locale invalide %s"
+#define MSG_BAD_LOCDFON_ARG "Mauvais paramètre pour LOCDFON"
+#define MSG_BAD_LOCNODE_USE "Usage inattendu de LOCNODE"
+#define MSG_BAD_LRECL "Disparité lrecl table/fichier (%d,%hd)"
+#define MSG_BAD_MAX_HAVING "MAXTMP trop petit pour Having"
+#define MSG_BAD_MAX_NREC "MaxRec=%d ne correspond pas à MaxBlk=%d Nrec=%d"
+#define MSG_BAD_MAX_PARAM "Mauvais paramètres pour spécifier une valeur maximum"
+#define MSG_BAD_MAX_SETTING "Mauvaise valeur '%c' pour max"
+#define MSG_BAD_MERGE_TYPE "Le type %d ne pas être intercallé"
+#define MSG_BAD_NODE_TYPE "Type noeud erroné pour la table"
+#define MSG_BAD_OFFSET_VAL "Nul offset invalide pour une table CSV"
+#define MSG_BAD_OPEN_MODE "Mode d'ouverture invalide %d"
+#define MSG_BAD_OPERATOR "Opérateur invalide %s"
+#define MSG_BAD_ORDER_MODE "Mode de tri %c invalide"
+#define MSG_BAD_ORDER_TYPE "Tri sur objet de type=%d invalide"
+#define MSG_BAD_OUTER_JOIN "Jointure externe invalide sur table enfant"
+#define MSG_BAD_PAD_ARGTYP "Argument de type invalide pour Pad ou Justify"
+#define MSG_BAD_PARAMETERS "%.8s: Mauvais paramètres"
+#define MSG_BAD_PARAM_TYPE "%.8s: Paramètre de type=%d invalide"
+#define MSG_BAD_PARM_COUNT "Nombre de paramètres incohérent"
+#define MSG_BAD_PHASE_NUM "Numéro de phrase %d hors limite"
+#define MSG_BAD_PHRASE_NB "numéro de phrase hors limite %d rc=%d\n"
+#define MSG_BAD_POS_CODE "POS_code invalide %d"
+#define MSG_BAD_POS_TYPE "Type de POS_code invalide %d"
+#define MSG_BAD_PROJNUM "Mauvais projnum %d pour la colonne %s"
+#define MSG_BAD_QUERY_OPEN "Mode invalide %d pour l'ouverture d'une requête"
+#define MSG_BAD_QUERY_TYPE "Type de requête %d invalide pour %s"
+#define MSG_BAD_QUOTE_FIELD "Quote manquante dans %s champs %d ligne %d"
+#define MSG_BAD_READ_NUMBER "Mauvais nombre %d de valeurs lues dans %s"
+#define MSG_BAD_RECFM "Recfm type %d invalide pour DOSCOL"
+#define MSG_BAD_RECFM_VAL "Valeur invalide %d de Recfm"
+#define MSG_BAD_RESULT_TYPE "Mauvais type de résultat %d pour %s"
+#define MSG_BAD_RETURN_TYPE "Type de retour %d incorrect"
+#define MSG_BAD_ROW_VALIST "Liste de valeurs invalide pour ROW"
+#define MSG_BAD_ROW_VALNB "Nombre de valeurs inégal dans la liste"
+#define MSG_BAD_SCF_ARGTYPE "Argument %d de type=%s invalide pour %s"
+#define MSG_BAD_SEM_DOMAIN "Domain .%d invalide"
+#define MSG_BAD_SETTINGS "Certaines spécifications sont incompatibles avec le type de la table"
+#define MSG_BAD_SET_CASE "La casse d'un tableau ne peut pas passer de non respect à respecter"
+#define MSG_BAD_SET_STRING "SetValue: appel invalide pour STRING"
+#define MSG_BAD_SET_TYPE "Set type %hd invalide"
+#define MSG_BAD_SPECIAL_CMD "Commande spéciale invalide"
+#define MSG_BAD_SPECIAL_COL "Colonne spéciale invalide %s"
+#define MSG_BAD_SPEC_COLUMN "Colonne spéciale invalide pour ce type de table"
+#define MSG_BAD_SQL_PARAM "Paramètre SQL invalide pour FindColblk"
+#define MSG_BAD_SUBLST_TYPE "Coparm: type %d de sous-liste invalide"
+#define MSG_BAD_SUBSEL_IN_X "Sub-select invalide pour une expression"
+#define MSG_BAD_SUBSEL_TYPE "Type %d invalide retourné de Sub-Select"
+#define MSG_BAD_SUB_RESULT "Résultat indéfini de fonction Sub-Select"
+#define MSG_BAD_SUB_SELECT "Sub-select invalide comme argument de fonction"
+#define MSG_BAD_TABLE_LINE "Ligne '%s' illégale ou tronquée dans la section Tables"
+#define MSG_BAD_TABLE_LIST "Table %s absente de la liste des tables"
+#define MSG_BAD_TABLE_TYPE "Type invalide %s pour la table %s"
+#define MSG_BAD_TEST_TYPE "BlockTest sur tableau: types dépareillés %s %s"
+#define MSG_BAD_TRIM_ARGTYP "Argument de type invalide pour Trim"
+#define MSG_BAD_TYPE_FOR_IN "Types d'argument incompatibles pour la fonction IN"
+#define MSG_BAD_TYPE_FOR_S "Type incorrecte %d pour %s(%d)"
+#define MSG_BAD_TYPE_LIKE "Type(%d)= %d invalide pour LIKE"
+#define MSG_BAD_UPD_COR "Le qualificateur %s de la colonne %s ne se refère pas à la table mise à jour %s"
+#define MSG_BAD_USERBLK_LEN "Mauvaise longueur à l'écriture du bloc utilisateur"
+#define MSG_BAD_USETEMP "Usetemp invalide '%s'"
+#define MSG_BAD_USETEMP_VAL "Valeur pour Usetemp invalide %d"
+#define MSG_BAD_VALBLK_INDX "Valeur hors limites de l'index du bloc de valeurs"
+#define MSG_BAD_VALBLK_TYPE "Type=%d invalide pour un bloc de valeurs"
+#define MSG_BAD_VALNODE "Type %d invalide pour le noeud valeur colonne %s"
+#define MSG_BAD_VALUE_TYPE "Type de valeur invalide %d"
+#define MSG_BAD_VAL_UPDATE "Impossible de déterminer quelle valeur %s doit être mise à jour"
+#define MSG_BAD_VIEW_OPEN "Mode invalide %d pour l'ouverture d'une View"
+#define MSG_BAD_XMODE_VAL "Mode d'exécution %d invalide"
+#define MSG_BAD_XOBJ_TYPE "Mauvais type de Xobject %d"
+#define MSG_BAS_NS_LIST "Format invalide de la liste des espace-noms"
+#define MSG_BIN_F_TOO_LONG "Valeur trop longue pour le champ %s (%d --> %d)"
+#define MSG_BIN_MODE_FAIL "Echec mode binaire: %s"
+#define MSG_BLKTYPLEN_MISM "Disparité types/longueurs de bloc dans SetValue"
+#define MSG_BLK_IS_NULL "Blk est nul"
+#define MSG_BLOCK_NO_MATCH "Bloc non correspondant"
+#define MSG_BREAKPOINT "Point de contrôle"
+#define MSG_BUFF_TOO_SMALL "GetColData: Buffer trop petit"
+#define MSG_BUFSIZE_ERROR "Erreur en recherchant la taille du buffer"
+#define MSG_BUILDING_GROUPS "Formation des groupes"
+#define MSG_BUILD_DIST_GRPS "Formation des groupes distinctes"
+#define MSG_BUILD_INDEX "Construction index %s sur %s"
+#define MSG_BXP_NULL "Bxp nul dans PUTFON"
+#define MSG_CANNOT_OPEN "Ouverture impossible de %s"
+#define MSG_CD_ONE_STEP "Count Distinct doit être exécuté en une seule étape"
+#define MSG_CD_ORDER_ERROR "Erreur de tri dans Count Distinct"
+#define MSG_CHECKING_ROWS "Test des lignes à mettre à jour"
+#define MSG_CHECK_LEVEL "Niveau de vérification fixé à %u"
+#define MSG_CHSIZE_ERROR "Erreur dans chsize: %s"
+#define MSG_CLN_NOT_IN_JOIN "La colonne C%d n'est pas dans le join"
+#define MSG_CNTDIS_COL_LOST "Colonne du Count Distinct perdue"
+#define MSG_COLIST_BAD_TYPE "Type=%d invalide pour Colist"
+#define MSG_COLNAM_TOO_LONG "Nom de colonne trop long"
+#define MSG_COLSEC_TOO_BIG "Section colonne trop grande, table %s (%d)"
+#define MSG_COLS_REDUCED " (réduit par Maxcol)"
+#define MSG_COLUMN_ERROR "Erreur de colonne"
+#define MSG_COLUMN_MISMATCH "Colonne %s dépareillée"
+#define MSG_COLUMN_NOT_KEY "La colonne jointe R%d.%s n'est pas une clé"
+#define MSG_COL_ALLOC_ERR "Allocation impossible du noeud colonne"
+#define MSG_COL_ALLOC_ERROR "Erreur d'allocation mémoire pour la colonne %d"
+#define MSG_COL_HAS_NO_DEF "La colonne %s n'est pas définie"
+#define MSG_COL_INVAL_TABLE "La colonne %s.%s n'existe pas dans la table %s alias %s"
+#define MSG_COL_ISNOT_TABLE "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NB_MISM "Le nombre de colonnes ne correspond pas"
+#define MSG_COL_NOTIN_GRPBY "La colonne %s n'est pas dans la liste de Group By"
+#define MSG_COL_NOTIN_TABLE "La colonne %s n'est dans aucune table"
+#define MSG_COL_NOTIN_UPDT "%s n'appartient pas à la table mise à jour %s"
+#define MSG_COL_NOT_CODED "La colonne %s n'est pas codifiée"
+#define MSG_COL_NOT_EXIST "La colonne %s n'existe pas dans %s"
+#define MSG_COL_NOT_FOUND "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NOT_IN_DB "La colonne %s de la table %s n'est pas dans la base de données"
+#define MSG_COL_NOT_IN_JOIN "La colonne %s n'est pas dans le join"
+#define MSG_COL_NOT_SORTED "La colonne %s de la table %s n'est pas triée"
+#define MSG_COL_NUM_MISM "Disparité du nombre de colonnes"
+#define MSG_COL_USED_TWICE "Colonne %s utilisée deux fois ???"
+#define MSG_COMPUTE_ERROR "Erreur dans Compute, op=%d"
+#define MSG_COMPUTE_NIY "Compute non implémenté pour TOKEN"
+#define MSG_COMPUTING "Calculs en cours"
+#define MSG_COMPUTING_DIST "Comptage des valeurs distinctes"
+#define MSG_COMPUTING_FUNC "Calcul de(s) fonction(s)"
+#define MSG_COM_ERROR "Erreur Com"
+#define MSG_CONCAT_SUBNODE "Concaténation de sous-noeuds impossible"
+#define MSG_CONNECTED "Connecté"
+#define MSG_CONNECT_CANCEL "Connection interrompue par l'utilisateur"
+#define MSG_CONNECT_ERROR "Erreur %d se connectant à %s"
+#define MSG_CONN_CLOSED "%s(%d) fermée"
+#define MSG_CONN_CREATED "Connexion %s crée"
+#define MSG_CONN_DROPPED "Connexion %s supprimée"
+#define MSG_CONN_OPEN "%s(%d) ouverte (%s)"
+#define MSG_CONN_SUC_OPEN "%s(%d) ouverte avec succès"
+#define MSG_CONTROL_C_EXIT "Exit par Ctrl-C"
+#define MSG_COPY_BAD_PHASE "Copie de liste invalide en phase %d"
+#define MSG_COPY_INV_TYPE "Coparm: type non supporté %d"
+#define MSG_CORREL_NO_QRY "Les sous-requêtes corrélées ne peuvent pas être de type QRY"
+#define MSG_CREATED_PLUGDB " Créé par PlugDB %s "
+#define MSG_CURSOR_SET "Curseur remis à %d"
+#define MSG_DATABASE_ACTIVE "Base de données %s activée"
+#define MSG_DATABASE_LOADED "Base de données %s chargée"
+#define MSG_DATA_IS_NULL "ExecSpecialCmd: data est NULL"
+#define MSG_DATA_MISALIGN "Mauvais alignement pour ce type de données"
+#define MSG_DBASE_FILE "Fichier dBASE dbf: "
+#define MSG_DB_ALREADY_DEF "Base de données %s déjà définie"
+#define MSG_DB_ALTERED "Base de données modifiée"
+#define MSG_DB_CREATED "Base de données %s créée"
+#define MSG_DB_NOT_SPEC "Base de données non spécifiée"
+#define MSG_DB_REMOVED "Base de données %s retirée de la liste"
+#define MSG_DB_SORT_ERROR "Erreur de tri DB"
+#define MSG_DB_STOPPED "Arrêt de la base de données %s"
+#define MSG_DEBUG_NOT_ACTIV "Mode Debug inactif"
+#define MSG_DEBUG_SET_INV "Invalide pour Debug: %c"
+#define MSG_DEF_ALLOC_ERROR "Erreur d'allocation de la classe DEF %s"
+#define MSG_DELETING_ROWS "Suppression des lignes"
+#define MSG_DEL_FILE_ERR "Erreur à l'effacement de %s"
+#define MSG_DEL_READ_ERROR "Delete: erreur en lecture req=%d len=%d"
+#define MSG_DEL_WRITE_ERROR "Delete: erreur en écriture: %s"
+#define MSG_DEPREC_FLAG "Option Flag périmée, utiliser Coltype"
+#define MSG_DICTIONARY "Dictionnaire "
+#define MSG_DIRECT_VARTOK "Accès direct aux règles du Variable Token non implémenté"
+#define MSG_DISCONNECTED "Déconnecté"
+#define MSG_DISTINCT_ERROR "Plus d'un élément fonctionel DISTINCT"
+#define MSG_DISTINCT_ROWS "Sélection des lignes distinctes"
+#define MSG_DISTINCT_VALUES "Extraction des valeurs distinctes"
+#define MSG_DIS_NOHEAD_JOIN "Jointure distincte sur une table non en tête"
+#define MSG_DLL_LOAD_ERROR "Erreur %d au chargement du module %s"
+#define MSG_DOMAIN_EMPTY "Le domaine %s est vide"
+#define MSG_DOMAIN_ERROR "Colonne %s: disparité domaine(%s)/valeur(%s)"
+#define MSG_DOMAIN_FULL "Le domaine %s est plein (max=%d)"
+#define MSG_DOM_FILE_ERROR "Fichier domain %s introuvable"
+#define MSG_DOM_NOT_SUPP "MS-DOM non supporté par cette version"
+#define MSG_DOM_OPEN_ERROR "Erreur d'ouverture du domaine: %s"
+#define MSG_DOM_READ_ERROR "Erreur %d en lecture de domaine: %s"
+#define MSG_DOM_READ_ONLY "La table domaine %s est en lecture seulement"
+#define MSG_DOM_WRITE_ERROR "Erreur %d en écriture de domaine: %s"
+#define MSG_DONE "Effectué, rc=%d"
+#define MSG_DOSALMEM_NOMEM "Erreur d'allocation, pas assez de mémoire"
+#define MSG_DROP_DB_ERR "Echec du Drop sur le base de données %s"
+#define MSG_DSORT_LOG_ERROR "Kindex: Erreur logique de tri distincte"
+#define MSG_DUMMY_NO_COLS "Les tables DUMMY ne peuvent pas avoir de colonne"
+#define MSG_DUPLICAT_COUNT "Count sur plus d'une colonne"
+#define MSG_DUP_COL_NAME "La colonne %s existe en double"
+#define MSG_DUP_PROJNUM "Non unique projnum %d pour la colonne %s"
+#define MSG_DVAL_NOTIN_LIST "Valeur %s non trouvée dans la liste des valeurs distinctes de la colonne %s"
+#define MSG_EMPTY_DOC "Document vide"
+#define MSG_EMPTY_FILE "%s du fichier vide %s: "
+#define MSG_ENDSTR_MISMATCH "Fins de chaîne et de noeud ne correspondent pas"
+#define MSG_END_OF_DELETE "%d ligne(s) enlevée(s) en %.2lf sec"
+#define MSG_END_OF_INSERT "%d ligne(s) insérée(s) en %.2lf sec"
+#define MSG_END_OF_QUERY "%d ligne(s) extraite(s) en %.2lf sec"
+#define MSG_END_OF_UPDATE "%d ligne(s) modifiée(s) en %.2lf sec"
+#define MSG_EOF_AFTER_LINE "Fin de fichier après la ligne %d"
+#define MSG_EOF_INDEX_FILE "EOF lisant le fichier index"
+#define MSG_ERASED " et effacée"
+#define MSG_ERASE_FAILED " (échec de l'effacement)"
+#define MSG_ERROR "Erreur"
+#define MSG_ERROR_IN_LSK "Erreur %d dans lseek64"
+#define MSG_ERROR_IN_SFP "Erreur %d dans SetFilePointer"
+#define MSG_ERROR_NO_PARM "Paramètre absent (valide seulement pour %.8s.1 et %.8s.5)"
+#define MSG_ERROR_OPENING "Erreur à l'ouverture de : "
+#define MSG_ERR_NUM_GT_MAX "Erreur: Numval (%d) plus grand que Maxnum (%d)"
+#define MSG_ERR_READING_REC "Erreur lisant l'enregistrement %d de %s"
+#define MSG_ERR_RET_RULE "Retour erreur, règle=%u"
+#define MSG_ERR_RET_TYPE "Retour erreur, type=%d"
+#define MSG_EVAL_EXPIRED "Cette version d'évaluation est expirée"
+#define MSG_EVAL_ONLY "L'utilisation de cette Dll est pour évaluation seulement"
+#define MSG_EXECUTING "Exécution"
+#define MSG_EXECUTION_ERROR "Erreur d'exécution"
+#define MSG_EXEC_MODE_IS "Le mode d'exécution est %s"
+#define MSG_EXEC_MODE_RESET ". Mode remis à Execute"
+#define MSG_EXEC_MODE_SET "Mode d'exécution fixé à %s"
+#define MSG_EXIT_EVAL_ERR "Erreur pendant l'évaluation de Exit"
+#define MSG_EXIT_FROM_LANG "Fin du langage %s version %d.%d"
+#define MSG_FAIL_ADD_NODE "L'ajout du noeud %s dans la table a échoué"
+#define MSG_FETCHING_DATA "Recherche des données"
+#define MSG_FETCHING_ROWS "Recherche des lignes"
+#define MSG_FETCH_NO_RES "Fetch: Pas de Résultats"
+#define MSG_FIELD_TOO_LONG "Valeur trop longue pour le champs %d ligne %d"
+#define MSG_FILELEN_ERROR "Erreur dans %s pour %s"
+#define MSG_FILE_CLOSE_ERR "Erreur %d à la fermeture du fichier"
+#define MSG_FILE_IS_EMPTY "Le fichier %s est vide"
+#define MSG_FILE_MAP_ERR "Erreur de File mapping"
+#define MSG_FILE_MAP_ERROR "CreateFileMapping %s erreur rc=%d"
+#define MSG_FILE_NOT_FOUND "Fichier %s introuvable"
+#define MSG_FILE_OPEN_YET "Fichier %s déjà ouvert"
+#define MSG_FILE_UNFOUND "Fichier %s non trouvé"
+#define MSG_FILGRP_NO_TABLE "Table %d manquante pour groupe filtre"
+#define MSG_FILTER_ATTACH "Filtre passé à Attach"
+#define MSG_FILTER_NO_TABLE "Filtre: première table manquante"
+#define MSG_FIND_BAD_TYPE "Recherche dans un tableau: type non conforme %s %s"
+#define MSG_FIX_OVFLW_ADD "Dépassement de capacité en addition"
+#define MSG_FIX_OVFLW_TIMES "Dépassement de capacité en mutiplication"
+#define MSG_FIX_UNFLW_ADD "Sous dépassement de capacité en addition"
+#define MSG_FIX_UNFLW_TIMES "Sous dépassement de capacité en multiplication"
+#define MSG_FLD_TOO_LNG_FOR "Champs %d trop long pour %s ligne %d de %s"
+#define MSG_FLTST_NO_CORREL "FilTest ne devrait être appelé que pour les sous-requêtes corrélées"
+#define MSG_FLT_BAD_RESULT "Virgule flottante: résultat inexacte"
+#define MSG_FLT_DENORMAL_OP "Opérande virgule flottante non normalisé"
+#define MSG_FLT_INVALID_OP "Opération virgule flottante invalide"
+#define MSG_FLT_OVERFLOW "Dépassement de capacité virgule flottante"
+#define MSG_FLT_STACK_CHECK "Virgule flottante: Erreur de la pile"
+#define MSG_FLT_UNDERFLOW "Sous-dépassement de capacité virgule flottante"
+#define MSG_FLT_ZERO_DIVIDE "Virgule flottante: division par zéro"
+#define MSG_FMT_WRITE_NIY "L'écriture des fichiers %s n'est pas encore implémentée"
+#define MSG_FNC_NOTIN_SLIST "Fonction de tri absente de la liste de sélection"
+#define MSG_FORMAT_ERROR "Erreur de formattage"
+#define MSG_FOXPRO_FILE "Fichier FoxPro: "
+#define MSG_FPUTS_ERROR "Erreur dans fputs: %s"
+#define MSG_FSBPARP_NULL "PUTFON: fsbparp est nul"
+#define MSG_FSEEK_ERROR "Erreur dans fseek: %s"
+#define MSG_FSETPOS_ERROR "Erreur dans fseek pour i=%d"
+#define MSG_FTELL_ERROR "Erreur dans ftell enregistrement=%d: %s"
+#define MSG_FUNCTION_ERROR "Erreur dans %s: %d"
+#define MSG_FUNC_ERRNO "Erreur %d dans %s"
+#define MSG_FUNC_ERROR "Erreur dans %s"
+#define MSG_FUNC_ERR_S "Erreur dans %s: %s"
+#define MSG_FUNC_REF_DEL "Référence à une fonction définie (règle %d) qui a été supprimée"
+#define MSG_FWRITE_ERROR "Erreur dans fwrite: %s"
+#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
+#define MSG_GETFILESIZE_ERR "Erreur %d dans GetFileSize"
+#define MSG_GET_DIST_VALS "Récupération des valeurs distinctes de "
+#define MSG_GET_ERROR "Erreur dans %s (colonne %d)"
+#define MSG_GET_FUNC_ERR "Erreur en recherche de la fonction %s: %s"
+#define MSG_GET_NAME_ERR "Erreur en retrouvant le nom d'une table SYS"
+#define MSG_GLOBAL_ERROR "Erreur d'allocation de Global (taille=%d)\n"
+#define MSG_GRAM_ALLOC_ERR "Erreur d'allocation dans Grammar Up"
+#define MSG_GRAM_MISMATCH "Avertissement: version de GRAMMAR perimée (sauvé sous GRAMMAR v%u)"
+#define MSG_GRAM_SUBSET_ERR "Erreur d'initialisation du dictionnaire de la grammaire"
+#define MSG_GRBY_TAB_NOTIMP "Group by avec tables jointes non implémenté"
+#define MSG_GROUPBY_NOT_ALL "Group By doit inclure toutes les sélections non-fonctionnelles"
+#define MSG_GROUP_ON_FUNC "Group by invalide sur colonne fonctionnelle"
+#define MSG_GRP_COL_MISM "Disparité colonne des groupes"
+#define MSG_GRP_LIST_MISMAT "Le groupement ne couvre pas la liste de sélection"
+#define MSG_GUARD_PAGE "Violation de page de garde"
+#define MSG_GZOPEN_ERROR "gzopen %s: erreur %d sur %s"
+#define MSG_GZPUTS_ERROR "Erreur dans gzputs: %s"
+#define MSG_HANDLE_IS_NULL "%s est NULL: erreur code: %d"
+#define MSG_HARRY_COMP_NIY "Compute non implémenté pour les chaînes codées"
+#define MSG_HAVING_FILTER "Traitement du Filtre Having"
+#define MSG_HBUF_TOO_SMALL "Buffer(%d) trop petit pour entête(%d)"
+#define MSG_HEAD_OPEN_ERROR "Erreur à l'ouverture du fichier header"
+#define MSG_HEAD_READ_ERROR "Erreur en lecture du fichier header %s"
+#define MSG_HEAD_WRITE_ERR "Erreur en écriture du fichier header"
+#define MSG_HI_OFFSET_ERR "Offset supérieur non nul"
+#define MSG_HUGE_DEFAULT "Huge est %d par défault"
+#define MSG_HUGE_WARNING_1 "Mémoire Huge non compatible 16-bit pour %d\n"
+#define MSG_HUGE_WARNING_2 "Résultats imprévisibles possibles\n"
+#define MSG_IDLE "Au repos"
+#define MSG_ILLEGAL_INSTR "Instruction illégale"
+#define MSG_ILL_FILTER_CONV "Conversion implicite illégale dans un filtre"
+#define MSG_INDEX_CREATED "Index %s créé sur %s"
+#define MSG_INDEX_DEF_ERR "Erreur sauvegardant l'index définition pour %s"
+#define MSG_INDEX_DROPPED "Index %s supprimé de %s"
+#define MSG_INDEX_INIT_ERR "Echec de l'initialisation de l'index %s"
+#define MSG_INDEX_NOT_DEF "Index %s non défini"
+#define MSG_INDEX_NOT_UNIQ "L'index n'est pas Unique"
+#define MSG_INDEX_ONE_SAVE "Les index sont sauvegardés dans un fichier unique"
+#define MSG_INDEX_SEP_SAVE "Les index sont sauvegardés dans des fichiers séparés"
+#define MSG_INDEX_YET_ON "L'index %s existe déjà sur %s"
+#define MSG_INDX_ALL_DROP "Tous les index de %s supprimés"
+#define MSG_INDX_COL_NOTIN "La colonne index %s n'existe pas dans la table %s"
+#define MSG_INDX_EXIST_YET "L'entrée index existe déjà"
+#define MSG_INIT_ERROR "Erreur à l'initialisation de %s"
+#define MSG_INIT_FAILED "L'initialisation de %s a échoué"
+#define MSG_INPUT "Entrée: "
+#define MSG_INPUT_KEYBD_YET "L'entrée est déjà au clavier"
+#define MSG_INSERTING "Insertion: "
+#define MSG_INSERT_ERROR "Insert erreur: usage multiple du fichier %s"
+#define MSG_INSERT_MISMATCH "Les listes colonne et valeur ne correspondent pas"
+#define MSG_INTERNAL "interne"
+#define MSG_INT_COL_ERROR "Erreur interne sur la colonne index %s"
+#define MSG_INT_OVERFLOW "Dépassement de capacité sur entier"
+#define MSG_INT_ZERO_DIVIDE "Division entière par zéro"
+#define MSG_INVALID_BIP "Bip invalide .%d"
+#define MSG_INVALID_DISP "Disposition invalide"
+#define MSG_INVALID_FTYPE "SBV: Ftype %d invalide"
+#define MSG_INVALID_HANDLE "Poignée invalide"
+#define MSG_INVALID_OPER "Opérateur invalide %d pour %s"
+#define MSG_INVALID_OPTION "Option invalide %s"
+#define MSG_INV_COLUMN_TYPE "Type %d Invalide pour la colonne %s"
+#define MSG_INV_COL_DATATYP "Type de données %d invalide pour la colonne %d"
+#define MSG_INV_COL_NUM "Colonne invalide %d"
+#define MSG_INV_COL_TYPE "Type de colonne %s invalide"
+#define MSG_INV_CONC_BIP "Bip invalide (seuls valides: %.8s.0 .1 and .5)"
+#define MSG_INV_DATA_PATH "Chemin vers les données invalide"
+#define MSG_INV_DEF_READ "Lecture différée invalide rc=%d"
+#define MSG_INV_DIRCOL_OFST "Offset invalide pour une colonne DIR"
+#define MSG_INV_DOMAIN_TYPE "Type invalide %d"
+#define MSG_INV_FILTER "Filtre résiduel dans %s"
+#define MSG_INV_FNC_BUFTYPE "FNC: Type %d de l'argument invalide pour %s"
+#define MSG_INV_INFO_TYPE "Type d'info catalog invalide %d"
+#define MSG_INV_INIPATH "Inipath invalide "
+#define MSG_INV_MAP_POS "Position mémoire invalide"
+#define MSG_INV_OPERATOR "opérateur invalide %d\n"
+#define MSG_INV_PARAMETER "Paramètre invalide %s"
+#define MSG_INV_PARM_TYPE "Type de paramètre invalide"
+#define MSG_INV_QUALIFIER "Qalificateur '%s' invalide"
+#define MSG_INV_QUERY_TYPE "Type de requête %d invalide"
+#define MSG_INV_RAND_ACC "L'accès aléatoire d'une table non optimisée est impossible"
+#define MSG_INV_REC_POS "Position d'enregistrement invalide"
+#define MSG_INV_RESULT_TYPE "Type de résultat invalide %s"
+#define MSG_INV_SET_SUBTYPE "Type de formattage %d invalide"
+#define MSG_INV_SPECIAL_CMD "%s: Commande spéciale invalide"
+#define MSG_INV_SUBTYPE "Sous type invalide %s"
+#define MSG_INV_TOK_DOMAIN "Le domaine %s n'existe pas"
+#define MSG_INV_TOPSEM_CMD "Commande TopSem invalide %c"
+#define MSG_INV_TRANSF_USE "Usage invalide en règle transformationnelle"
+#define MSG_INV_TYPE_SPEC "Spécification de type invalide (%.8s.%d)"
+#define MSG_INV_UPDT_TABLE "Table %s invalide pour Update"
+#define MSG_INV_VALUE_LIST "Liste de valeurs invalide pour Insert"
+#define MSG_INV_WHERE_JOIN "Clause Where invalide dans une requête de jointure"
+#define MSG_INV_WORK_PATH "Chemin de travail invalide"
+#define MSG_IN_ARGTYPE_MISM "Arguments de types incompatibles pour une expression IN"
+#define MSG_IN_USE " et en activité"
+#define MSG_IN_WITHOUT_SUB "IN ou EXISTS sans tableau ou subquery"
+#define MSG_IS_NOT_CONN "%s n'est pas une connexion définie"
+#define MSG_JCT_MISS_COLS "Colonnes manquantes pour une table JCT"
+#define MSG_JCT_MISS_TABLE "Table jointe manquante pour JCT"
+#define MSG_JCT_NO_FILTER "Filtrage impossible des tables virtuelles JCT"
+#define MSG_JCT_NO_KEY "Erreur logique JCT: clé manquante"
+#define MSG_JOIN_KEY_NO_COL "La clé de jointure n'est pas une colonne"
+#define MSG_KEY_ALLOC_ERR "Erreur d'allocation d'un bloc offset clé"
+#define MSG_KEY_ALLOC_ERROR "Erreur d'allocation mémoire, Klen=%d n=%d"
+#define MSG_LANGUAGE_QUIT "%s libéré"
+#define MSG_LANG_ACTIVE "Langage %s actif"
+#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Lang"
+#define MSG_LANG_ALREADY_UP "Langage déjà en édition"
+#define MSG_LANG_BAD_SAVE "Langage %s peut-être incorrectement sauvegardé"
+#define MSG_LANG_NOT_FREED "Langage %s non libérable (pas dans la chaîne principale)"
+#define MSG_LANG_SAVED "Langage %s sauvegardé"
+#define MSG_LANG_WR_LEN_ERR "Erreur de longueur à l'écriture du bloc Lang"
+#define MSG_LDF_ALLOC_ERROR "Erreur d'allocation d'un LdfBlock"
+#define MSG_LDF_RN_MISMATCH "LDF: décalage des numéros de règle"
+#define MSG_LDF_WLEN_ERROR "Erreur de longueur en écrivant LdfData"
+#define MSG_LDF_W_LEN_ERROR "Erreur de longueur pour LdfData en écriture"
+#define MSG_LIC_NO_MYSQL "Votre licence actuelle ne permet pas l'utilisation du type MYSQL"
+#define MSG_LINEAR_ERROR "Erreur de linéarisation"
+#define MSG_LINE_LENGTH "Largeur d'impression fixée à %d"
+#define MSG_LINE_MAXLIN "Nombre de lignes de travail plafonné à %d"
+#define MSG_LINE_MAXRES "Nombre de lignes de résultat plafonné à %d"
+#define MSG_LINE_MAXTMP "Nombre de lignes intermédiaires plafonné à %d"
+#define MSG_LINE_TOO_LONG "La nouvelle ligne est trop longue"
+#define MSG_LINJOINDB_ERROR "Erreur système: appel incorrecte à LinJoinDB"
+#define MSG_LIST "--Liste--"
+#define MSG_LNG_NOT_IN_LIST "Le langage %s n'est pas dans la liste"
+#define MSG_LOADING_DB "Chargement description de la BD"
+#define MSG_LOADING_FAILED "Le chargement de %s a échoué"
+#define MSG_LOAD_CDLL_ERROR "Erreur au chargement de ConnDll: rc=%d"
+#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n trop grand ? (%d)\n"
+#define MSG_LOGICAL_ERROR "%s: Erreur logique"
+#define MSG_LRECL_TOO_SMALL "Lrecl trop petit (longueur en-tête = %d)"
+#define MSG_MAC_NO_DELETE "Pas de suppression de lignes pour les tables MAC"
+#define MSG_MAC_NO_INDEX "Pas d'accès direct aux tables MAC"
+#define MSG_MAC_READ_ONLY "Les tables MAC sont en lecture seulement"
+#define MSG_MAC_WIN_ONLY "Les tables MAC sont seulement sous Windows"
+#define MSG_MAKE_EMPTY_FILE "Génération du fichier vide %s: %s"
+#define MSG_MAKING "Génération"
+#define MSG_MAKING_DISTINCT "Regroupement des valeures distinctes"
+#define MSG_MALLOC_ERROR "Allocation mémoire impossible par %s"
+#define MSG_MALLOC_NULL "malloc retourne Null"
+#define MSG_MAP_NO_MORE "Le type %s n'est plus supporté"
+#define MSG_MAP_OBJ_ERR "Erreur %d à la fermeture du map objet"
+#define MSG_MAP_VEC_ONLY "MAP Insert permis seulement pour les tables VEC Estimate"
+#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s erreur rc=%d"
+#define MSG_MAXSIZE_ERROR "Maxsize incalculable sur table ouverte"
+#define MSG_MAXTMP_TRUNCATE "Résultats intermédiaires tronqués par maxtmp=%d"
+#define MSG_MAX_BITMAP "Taille maxi des bitmaps d'optimisation fixée à %d"
+#define MSG_MEMSIZE_TOO_BIG "Erreur: memsize (%d) trop grand pour Length (%d)"
+#define MSG_MEM_ALLOC_ERR "Erreur d'allocation mémoire, taille %s = %d"
+#define MSG_MEM_ALLOC_ERROR "Erreur d'allocation mémoire"
+#define MSG_MEM_ALLOC_YET "Mémoire déjà allouée"
+#define MSG_METAFILE_NOTFND "Fichier Meta introuvable"
+#define MSG_MISPLACED_QUOTE "Appostrophe mal placée ligne %d"
+#define MSG_MISSING "Manquant: Value=%p Argval=%p Builtin=%d"
+#define MSG_MISSING_ARG "Argument manquant pour l'opérateur %d"
+#define MSG_MISSING_COL_DEF "Définition des colonnes manquante"
+#define MSG_MISSING_CONNECT "Connection #1 manquante"
+#define MSG_MISSING_EOL "Fin de ligne manquante dans %s"
+#define MSG_MISSING_FIELD "Champs %d manquant dans %s ligne %d"
+#define MSG_MISSING_FNAME "Nom du fichier manquant"
+#define MSG_MISSING_NODE "Noeud %s manquant dans %s"
+#define MSG_MISSING_POS "POS code manquant"
+#define MSG_MISSING_ROWNODE "Impossible de trouver le noeud de la ligne %d"
+#define MSG_MISSING_SERV_DB "Indication serveur et/ou base de données manquante"
+#define MSG_MISS_LEAD_COL "Colonne majeure %s manquante"
+#define MSG_MISS_NAME_LRECL "Nom du fichier et/ou LRECL manquant"
+#define MSG_MISS_TABLE_LIST "Liste des tables manquante"
+#define MSG_MISS_VCT_ELMT "Taille de bloc vectoriel manquante (Elements)"
+#define MSG_MIS_TAG_LIST "Liste des balises colonne manquante"
+#define MSG_MKEMPTY_NIY "MakeEmptyFile: pas encore implementé pour Huge et Unix"
+#define MSG_MOVE_INV_TYPE "MOVPARM: paramètre de type invalide %d"
+#define MSG_MULT_DISTINCT "Distinct utilisé plus d'une fois"
+#define MSG_MULT_KEY_ERROR "Erreur sur clé multiple k=%d n=%d"
+#define MSG_MUL_MAKECOL_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_MYSQL_CNC_OFF "La connexion à MySQL est fermée"
+#define MSG_MYSQL_CNC_ON "La connexion à MySQL est établie"
+#define MSG_MYSQL_NOT_SUP "Pas de support de MySQL dans cette version"
+#define MSG_MY_CNC_ALREADY "La connexion à MySQL est déjà active"
+#define MSG_NAME_CONV_ERR "Erreur de convertion du nom de noeud"
+#define MSG_NAME_IS_USED "Le nom %s est déjà utilisé"
+#define MSG_NCOL_GT_MAXCOL "Trop de colonnes (%d > %d max)"
+#define MSG_NEW_CHAR_NULL "new char(%d) retourne Null"
+#define MSG_NEW_DOC_FAILED "Impossible de créer le nouveau document"
+#define MSG_NEW_RETURN_NULL "NULL renvoyé par New dans PlugEvalLike"
+#define MSG_NEW_TABLE_ERR "La nouvelle table %s ne peut pas être chargée"
+#define MSG_NEXT_FILE_ERROR "Erreur en recherche du fichier suivant. rc=%s"
+#define MSG_NODEF_FROM_VIEW "Pas de définition de table depuis une view"
+#define MSG_NODE_FOR_CHAR "Noeud %s trouvé au lieu d'un caractère"
+#define MSG_NODE_SUBSET_ERR "Erreur d'initialisation de la zone Noeud %d"
+#define MSG_NONCONT_EXCEPT "Exception non-continuable"
+#define MSG_NON_DUP_HAVING "Clause Having dans une requête non fonctionelle"
+#define MSG_NON_EVAL_SEM "Sem non évaluée: p_no=%d"
+#define MSG_NOP_ZLIB_INDEX "L'indexage d'une table zlib non optimisée est impossible"
+#define MSG_NOT_A_DBF_FILE "Le fichier n'a pas le format dBASE dbf "
+#define MSG_NOT_ENOUGH_COLS "Pas assez de colonnes dans %s"
+#define MSG_NOT_ENOUGH_MEM "Mémoire insuffisante pour cette opération"
+#define MSG_NOT_FIXED_LEN "Fichier %s non fixe, len=%d lrecl=%d"
+#define MSG_NOT_IMPLEMENTED "Non implementé: %.8s"
+#define MSG_NOT_IMPL_JOIN "Pas implémenté pour les jointures"
+#define MSG_NOT_IMPL_SET "Pas implémenté pour les opérateurs d'ensembles"
+#define MSG_NOT_IMPL_YET "Pas encore implementé"
+#define MSG_NOT_LINEARIZED "Arborescence des tables non linéarisée"
+#define MSG_NOT_MODIFIABLE " (non modifiable)"
+#define MSG_NO_0DH_HEAD "0DH manquant en fin d'en-tête (dbc=%d)"
+#define MSG_NO_ACTIVE_APPL "Pas d'application active"
+#define MSG_NO_ACTIVE_DB "Pas de base de données active"
+#define MSG_NO_ACTIVE_UDIC "Pas de dictionaire utilisateur actif"
+#define MSG_NO_AGGR_FUNC "Fonction aggrégée %d illégale à cet endroit"
+#define MSG_NO_AREA_FILE "Fichier Area introuvable"
+#define MSG_NO_AVAIL_RESULT "Pas de résultat disponible"
+#define MSG_NO_BIG_DELETE "Délétion Partielle non implémentée pour les fichiers HUGE"
+#define MSG_NO_CHAR_FROM "Conversion de type %d en caractères impossible"
+#define MSG_NO_CLUSTER_COL "Pas de colonne optimisable"
+#define MSG_NO_COL_ADDING "Ajouter des colonnes dans une définition existante est impossible"
+#define MSG_NO_COL_DEF_AS "La définitions des colonnes est incompatible avec AS Select"
+#define MSG_NO_COL_FOUND "La section colonne %s est vide"
+#define MSG_NO_COL_IN_TABLE "La colonne %d n'est pas dans la table %s"
+#define MSG_NO_COL_SECTION "Section colonne manquante pour la table %s"
+#define MSG_NO_CONNECT_ADDR "Adresse de connection non spécifiée"
+#define MSG_NO_CONST_FILTER "Filtres constants non implementés"
+#define MSG_NO_CURLY_BRKT "Pas d'accolade de fermeture"
+#define MSG_NO_DATABASE "Base de données %s introuvable"
+#define MSG_NO_DATE_FMT "Pas de format date pour le valblock de type %d"
+#define MSG_NO_DBF_INSERT "Insert pas encore implémenté pour les fichier DBF"
+#define MSG_NO_DEF_FNCCOL "Colonne fonction par défaut introuvable"
+#define MSG_NO_DEF_PIVOTCOL "Colonne pivot par défaut introuvable"
+#define MSG_NO_DIR_INDX_RD "Pas d'accès directe des tables %s"
+#define MSG_NO_DMY_DIR_ACC "Pas d'accès direct aux tables virtuelles DUMMY"
+#define MSG_NO_DOM_DELETE "Délétion Partielle non implémentée pour les domaines"
+#define MSG_NO_DOM_MATCH "Chaîne %.8s... non touvée dans le domaine %s"
+#define MSG_NO_EDITED_LANG "Coparm: Pas de langage en édition"
+#define MSG_NO_EXP_LINK "Liaison par expression invalide pour une table JCT"
+#define MSG_NO_EXT_FILTER "Le filtrage ne peut se référer à une autre table"
+#define MSG_NO_EXT_UPDATE "Pas de mise à jour en référence à une autre table"
+#define MSG_NO_FEAT_SUPPORT "%s non supporté dans cette version"
+#define MSG_NO_FILE_LIST "La table %s n'a pas de liste de fichiers"
+#define MSG_NO_FLD_FORMAT "Format absent pour le champs %d de %s"
+#define MSG_NO_FORMAT_COL "Type COLUMN informattable"
+#define MSG_NO_FORMAT_TYPE "Le format ne peut pas être défini à partir du type %d"
+#define MSG_NO_FULL_JOIN "Jointures autorisées seulement à égalité sur clé(s)"
+#define MSG_NO_FUL_OUT_JOIN "Jointures externes complètes non supportées"
+#define MSG_NO_FUNC_ORDER "Tri non supporté sur élément fonctionnel"
+#define MSG_NO_HEAD_JOIN "Jointure sur une table non en tête"
+#define MSG_NO_HQL_CONV "Conversion en HQL non disponible"
+#define MSG_NO_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_INDEX_GBX "Pas ou mauvais index pour SQLGBX"
+#define MSG_NO_INDEX_IN "Pas d'index dans %s"
+#define MSG_NO_INDEX_READ "Pas d'accès directe des tables multiples"
+#define MSG_NO_INIT_LANG "Pas de langage initial"
+#define MSG_NO_JOIN_TO_EXP "Jointure vers une expression impossible"
+#define MSG_NO_JOIN_UPDEL "Pas de jointure avec Update/Delete"
+#define MSG_NO_KEY_COL "Pas de colonne clé trouvée"
+#define MSG_NO_KEY_UPDATE "Le nom des clés ne peut pas être modifié"
+#define MSG_NO_LANGUAGE "Pas de langage opérationnel\n"
+#define MSG_NO_LANG_TO_QUIT "Pas de langage à quitter"
+#define MSG_NO_LISTVAL_HERE "LSTBLK: Liste de valeurs utilisée hors contexte"
+#define MSG_NO_MAP_INSERT "MAP incompatible avec Insert"
+#define MSG_NO_MATCHING_COL "Pas de colonne correspondant à %s dans %s"
+#define MSG_NO_MATCH_COL "Colonne correspondante introuvable"
+#define MSG_NO_MEMORY "Mémoire pleine"
+#define MSG_NO_MEM_CORR_SUB "Subquery corrélée en mémoire non encore implémentée"
+#define MSG_NO_MODE_PADDED "Mode non supporté pour les fichiers 'padded'"
+#define MSG_NO_MORE_COL "La colonne %s n'est plus dans la table pivot"
+#define MSG_NO_MORE_LANG "Plus de langage, exit de %s\n"
+#define MSG_NO_MORE_VAR "Les fichiers VAR ne sont plus supportés"
+#define MSG_NO_MULCOL_JOIN "Jointure vers un index multi-colonne pas encore possible"
+#define MSG_NO_MULT_HAVING "Clauses Having multiples non implémentées"
+#define MSG_NO_MUL_DIR_ACC "Accès direct des tables multiples pas encore implémenté"
+#define MSG_NO_MUL_VCT "Les tables VCT ne peuvent pas être multiples"
+#define MSG_NO_MYSQL_CONN "Aucune connexion MySQL ouverte"
+#define MSG_NO_MYSQL_DELETE "Pas de Delete pour les tables MySQL"
+#define MSG_NO_NBCOL "Pas de NBcol"
+#define MSG_NO_NBLIN "Pas de NBlin, MaxSize ou Continued"
+#define MSG_NO_NBLIN_CONT "Fetch: Pas de NBlin ou Continued"
+#define MSG_NO_NULL_CONST "Les constantes <null> ne sont pas prises en charge"
+#define MSG_NO_ODBC_COL "Colonnes ODBC automatiques non supportées par cette version"
+#define MSG_NO_ODBC_DELETE "Delete ne devrait pas être appelé pour les tables ODBC"
+#define MSG_NO_ODBC_DIRECT "Accès directe des tables ODBC non encore implémenté"
+#define MSG_NO_ODBC_MUL "Multiple(2) non supporté pour les tables ODBC"
+#define MSG_NO_ODBC_SPECOL "Pas de colonne spéciale ODBC"
+#define MSG_NO_OPT_COLUMN "Pas optimisable ou pas de colonne optimisées"
+#define MSG_NO_OP_MODIF "Les modificateurs ne s'appliquent pas à %s"
+#define MSG_NO_PARAMETER "Pas de paramètre"
+#define MSG_NO_PART_DEL "Delete partiel des fichier %s impossible"
+#define MSG_NO_PART_MAP "Mapping partiel non implémenté pour cet OS"
+#define MSG_NO_PAR_BLK_INS "Insertion de bloc partiel impossible"
+#define MSG_NO_PIV_DIR_ACC "Pas d'accès directe aux tables PIVOT"
+#define MSG_NO_POS_ADDED "Pos_code non ajouté"
+#define MSG_NO_PROMPTING "Relance impossible pour les tables distribuées"
+#define MSG_NO_QRY_DELETE "Delete n'est pas utilisable pour les views QRY"
+#define MSG_NO_QUERY_ARRAY "Tableaux avec QUERY non encore implémentés"
+#define MSG_NO_RCUR_DSK_YET "Usage recursif de DISK non encore implementé"
+#define MSG_NO_READ_32 "Lecture de 32 octets impossible"
+#define MSG_NO_RECOV_SPACE "Espace non recouvrable dans le fichier index"
+#define MSG_NO_REF_DELETE "Pas de suppression en référence à une autre table"
+#define MSG_NO_REF_UPDATE "Pas de mise à jour en référence à une autre table"
+#define MSG_NO_REMOTE_FNC "Certaines fonctions ne peuvent pas être exécutées à distance"
+#define MSG_NO_ROWID_FOR_AM "Accès direct impossible de ROWID pour les tables de type %s"
+#define MSG_NO_ROW_NODE "Le nom du Rownode n'est pas défini"
+#define MSG_NO_SECTION_NAME "Nom de section manquant"
+#define MSG_NO_SEC_UPDATE "Les noms de section ne peuvent pas être modifiés"
+#define MSG_NO_SELECTED_DB "Aucune base de données sélectée"
+#define MSG_NO_SELF_PIVOT "Une table ne peut se pivoter elle-même !"
+#define MSG_NO_SERVER_FOUND "Serveur introuvable"
+#define MSG_NO_SETPOS_YET "SetPos pas encore implémenté pour les fichier %s"
+#define MSG_NO_SFEXIT_UNIX "Fonction %s non disponible sur Unix"
+#define MSG_NO_SOURCE " (pas de source)"
+#define MSG_NO_SPEC_COL "Pas de colonne spéciales MYSQL"
+#define MSG_NO_SQL_DELETE "Delete n'est pas utilisable actuellement pour les views SQL"
+#define MSG_NO_SUB_VAL "Pas de sous-value d'un tableau de type %d"
+#define MSG_NO_SUCH_INDEX "La table %s n'a pas l'index %s"
+#define MSG_NO_SUCH_SERVER "Serveur %s introuvable"
+#define MSG_NO_SUCH_TABLE "Table %s pas dans la base de données"
+#define MSG_NO_TABCOL_DATA "Pas de données pour la table %s colonne %s"
+#define MSG_NO_TABLE_COL "Aucune colonne trouvée pour %s"
+#define MSG_NO_TABLE_DEL "Delete non autorisé pour les tables %s "
+#define MSG_NO_TABLE_DESC "Pas de bloc descriptif de table"
+#define MSG_NO_TABLE_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_TABLE_LIST "Pas de liste de tables"
+#define MSG_NO_TAB_DATA "Pas de données pour la table %s"
+#define MSG_NO_TERM_IN_TOK "Les non-terminaux ne sont pas utilisables dans les règles de Token"
+#define MSG_NO_TOKEN_DB "DB introuvable pour la colonne TOKEN %s"
+#define MSG_NO_UNIX_CATINFO "Pas d'info catalogue sous Unix"
+#define MSG_NO_UPDEL_JOIN "Pas de jointure de tables ODBC pour Update/Delete"
+#define MSG_NO_VCT_DELETE "Délétion Partielle non implémentée pour les fichiers VCT"
+#define MSG_NO_VIEW_COLDEF "Colonne définition impossible pour les views"
+#define MSG_NO_VIEW_SORT "La View fonctionnelle %s ne peut pas être triée ou jointe"
+#define MSG_NO_ZIP_DELETE "Delete sur fichier Zip non encore implementé"
+#define MSG_NO_ZIP_DIR_ACC "Accès directe des tables ZDOS non encore implementé"
+#define MSG_NULL_COL_VALUE "La colonne n'a pas de valeur"
+#define MSG_NULL_ENTRY "InitLang, entrée nulle %d %s"
+#define MSG_NULL_QUERY "Requête vide"
+#define MSG_NUMVAL_NOMATCH "Disparité de Numval pour %s"
+#define MSG_N_FULL_PARSES "%d significations"
+#define MSG_ODBC_READ_ONLY "ODBC est actuellement en lecture seulement"
+#define MSG_OFFSET_NOT_SUPP "Offset non supporté pour ce type de sous requête"
+#define MSG_ONE_LANG_YET "Un langage est déjà en édition"
+#define MSG_ONE_PARAM_ONLY "Un seul paramètre autorisé"
+#define MSG_ONLY_LOG10_IMPL "Seul Log10 est implementé"
+#define MSG_ON_LANGUAGE "Langage %.8s version %d niveau %d éditable"
+#define MSG_OPENING "Ouverture"
+#define MSG_OPENING_QUERY "Ouverture de la requête"
+#define MSG_OPEN_EMPTY_FILE "Ouverture du fichier vide %s: %s"
+#define MSG_OPEN_ERROR "Erreur d'ouverture %d en mode %d sur %s: "
+#define MSG_OPEN_ERROR_IS "Erreur à l'ouverture de %s: %s"
+#define MSG_OPEN_ERROR_ON "Erreur d'ouverture sur %s"
+#define MSG_OPEN_MODE_ERROR "Erreur d'ouverture(%s) %d sur %s"
+#define MSG_OPEN_SORT_ERROR "Erreur logique de tri dans QUERY Open"
+#define MSG_OPEN_STRERROR "Erreur à l'ouverture: %s"
+#define MSG_OPEN_W_ERROR "Erreur à l'ouverture de %s en écriture"
+#define MSG_OPTBLK_RD_ERR "Erreur à la lecture d'un bloc optimisation: %s"
+#define MSG_OPTBLK_WR_ERR "Erreur à l'écriture d'un bloc optimisation: %s"
+#define MSG_OPTIMIZING "Optimisation de "
+#define MSG_OPT_BMAP_RD_ERR "Erreur en lecture des bitmaps d'optimisation: %s"
+#define MSG_OPT_BMAP_WR_ERR "Erreur en écriture des bitmaps d'optimisation: %s"
+#define MSG_OPT_CANCELLED "Optimisation interrompue par l'utilisateur"
+#define MSG_OPT_DVAL_RD_ERR "Erreur en lecture des valeurs distinctes: %s"
+#define MSG_OPT_DVAL_WR_ERR "Erreur en écriture des valeurs distinctes: %s"
+#define MSG_OPT_HEAD_RD_ERR "Erreur en lecture de l'entête du fichier opt: %s"
+#define MSG_OPT_HEAD_WR_ERR "Erreur en écriture de l'entête du fichier opt: %s"
+#define MSG_OPT_INIT "Optimisation initialisée"
+#define MSG_OPT_LOGIC_ERR "Erreur logique dans SetBitmap, i=%d"
+#define MSG_OPT_MAX_RD_ERR "Erreur en lecture des valeurs maxi: %s"
+#define MSG_OPT_MAX_WR_ERR "Erreur en écriture des valeurs maxi: %s"
+#define MSG_OPT_MIN_RD_ERR "Erreur en lecture des valeurs mini: %s"
+#define MSG_OPT_MIN_WR_ERR "Erreur en écriture des valeurs mini: %s"
+#define MSG_OPT_NOT_MATCH "Le fichier opt %s n'est pas à jour"
+#define MSG_OP_RES_TOO_LONG "Résultat trop long pour l'opérateur=%d"
+#define MSG_ORDER_OUT_RANGE "Tri: Order %d hors limite"
+#define MSG_ORDER_TWICE "Un même élément est trié deux fois"
+#define MSG_PAGE_ERROR "Erreur de pagination"
+#define MSG_PARM_CNT_MISS "Disparité du nombre de Paramètres"
+#define MSG_PARSE_NULL_SEM "Sémantique nulle"
+#define MSG_PARSING_QUERY "Analyse de la requête"
+#define MSG_PIX_ERROR "Pix %s erreur règle no=%u\n"
+#define MSG_PIX_TEST_ERROR "Règle=%u: pix-TEST pas dans le premier noeud\n"
+#define MSG_PLG_READ_ONLY "PLG est actuellement en lecture seulement"
+#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp est NULL"
+#define MSG_PLUG_NOT_INIT "Plug n'est pas initialisé\n"
+#define MSG_PLUG_NOT_RUN "Plug n'est pas en marche"
+#define MSG_PNODE_RULE "(Noeud %d règle %d) "
+#define MSG_POS_TOO_LONG "%s trop long (>%d)"
+#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp est NULL"
+#define MSG_PRIV_INSTR "Instruction privilégiée"
+#define MSG_PROCADD_ERROR "Erreur %d sur l'adresse de %s"
+#define MSG_PROCESS_SUBQRY "Sub-Query en cours de traitement"
+#define MSG_PROC_WOULD_LOOP "Bouclage du traitement (maxres=%d maxlin=%d)"
+#define MSG_PROGRESS_INFO "Informations sur le traitement en cours"
+#define MSG_PROMPT_CANCEL "Relance annulée"
+#define MSG_PROMPT_NIY "Prompt non implémenté pour cette configuration"
+#define MSG_PTR_NOT_FOUND "Pointeur introuvable Num=%d ti1=%d"
+#define MSG_PXDEF_IS_NULL "Pxdef est NULL"
+#define MSG_QRY_READ_ONLY "Les views QRY sont en lecture seulement"
+#define MSG_QUERY_CANCELLED "Requête interrompue par l'utilisateur"
+#define MSG_QUERY_NOT_EXEC "Requête non exécutée"
+#define MSG_QUERY_SAVED "Requête %s sauvegardée"
+#define MSG_QUOTE_IN_QUOTE "Appostrophe dans un champ entre appostrophe ligne %d"
+#define MSG_RANGE_NIY "Range pas encore implémenté pour %s"
+#define MSG_RANGE_NO_JOIN "Range non compatible avec les index de jointure"
+#define MSG_RC_READING "rc=%d en lecture de la table %s"
+#define MSG_READB_BAD_INIT "%s ReadDB appelé avec Init=0"
+#define MSG_READCOL_ERROR "SQLCOL: erreur dans ReadColumn"
+#define MSG_READING "Lecture"
+#define MSG_READING_FROM "Lecture de %s"
+#define MSG_READING_RECORD "Erreur en lecture de l'enregistrement %d de %s"
+#define MSG_READY "Prêt"
+#define MSG_READ_ERROR "Erreur en lecture sur %s: %s"
+#define MSG_READ_ERROR_RC "Erreur en lecture, rc=%d"
+#define MSG_READ_MEM_ERROR "Lecture mémoire %d: taille=%d"
+#define MSG_READ_ONLY "Cette table protégée en lecture seule ne peut être modifiée"
+#define MSG_READ_SEEK_ERROR "Erreur de recherche en lecture: %s"
+#define MSG_READ_SEG_ERROR "Lecture segment %d: taille=%d"
+#define MSG_RECEIVED "Reçu %c\n"
+#define MSG_RECORD_ERROR "Erreur à la lecture de l'enregistrement %d de %s"
+#define MSG_RECORD_NO_SEP "Enregistrement sans séparateur"
+#define MSG_REC_SKIPPED " (%d lignes erronnées sautées par l'option MaxErr)"
+#define MSG_REDUCE_INDEX "Réduction de l'index"
+#define MSG_REGISTER_ERR "Enregistrement NS impossible, préfix='%s' et href='%s'"
+#define MSG_REMOTE_CONN_ERR "La connection éloignée a échoué"
+#define MSG_REMOVE_ERROR "Erreur en supprimant %s: %s"
+#define MSG_REMOVE_NOT_IMPL "Remove non implémenté pour TDB non Table"
+#define MSG_RENAME_ERROR "Erreur renommant %s en %s: %s"
+#define MSG_RENUM_RULES "Renumérotez les règles et réentrez ADD (règle sauvegardée dans la zone tampon)"
+#define MSG_REORDER_INDEX "Reclassement de l'index"
+#define MSG_REQU_ARG_NUM "La fonction %s doit avoir %d arguments"
+#define MSG_RESET_TO "%s remis à %d"
+#define MSG_RES_NOT_UNIQUE "Le résultat n'est pas unique"
+#define MSG_RET_FROM_LANG "Retour au language %s version %d.%d du language %s version %d.%d"
+#define MSG_ROWID_NOT_IMPL "RowNumber non implémenté pour les tables de type %s"
+#define MSG_ROWS_SELECTED "%d lignes sélectionnées en %.2lf sec"
+#define MSG_ROWS_TRUNCATED " (tronqué par MAXRES, LIMIT, FREQ ou AreaSize)"
+#define MSG_ROW_ARGNB_ERR "ROW: disparité du nombre d'arguments (%d,%d)"
+#define MSG_RPC_SERVER_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_RSC_ALLOC_ERROR "Erreur d'allocation mémoire dans Rescol %s"
+#define MSG_RULE_ENTERED "Règle %d entrée"
+#define MSG_RULE_SUBSET_ERR "Erreur d'initialisation de la zone Règles"
+#define MSG_SAVING_INDEX "Sauvegarde du fichier index"
+#define MSG_SCAN_NOT_IMP "Scan non implémenté"
+#define MSG_SEC_KEY_FIRST "Les sections et clés doivent être insérées en premier"
+#define MSG_SEC_NAME_FIRST "Le nom de section doit être en tête de liste en insertion"
+#define MSG_SEC_NOT_FOUND "Section %s absente de %s"
+#define MSG_SEEK_ERROR "Seek erreur dans CopyHeader"
+#define MSG_SEMANTIC_TREE "Arbre sémantique"
+#define MSG_SEM_BAD_REF "Sem @%d référence un argument de type non 0 ou 1"
+#define MSG_SEM_UNKNOWN "inconnue, rc=%d"
+#define MSG_SEP_IN_FIELD "Le champ %d contient le caractère séparateur"
+#define MSG_SEQUENCE_ERROR "HSTMT: Allocation hors séquence"
+#define MSG_SETEOF_ERROR "Erreur %d dans SetEndOfFile"
+#define MSG_SETRECPOS_NIY "SetRecpos non implémenté pour ce type de table"
+#define MSG_SET_LOCALE "Locale fixée à %s"
+#define MSG_SET_NULL_DOM "Valeur %d donnée à un domaine nul"
+#define MSG_SET_OP_NOT_IMPL "Opérateurs ensemblistes non implementés"
+#define MSG_SET_STR_TRUNC "SetValue: Chaîne de caractères tronquée"
+#define MSG_SEVERAL_TREES "Jointure non spécifiée pour certaines tables"
+#define MSG_SFP_ERROR "Erreur sur SetFilePointer: %s"
+#define MSG_SFUNC_NOT_IMPL "Fonction scalaire %s non implémentée"
+#define MSG_SHARED_LIB_ERR "Erreur au chargement de la librairie partagée %s: %s"
+#define MSG_SINGLE_STEP "Pas à pas"
+#define MSG_SLEEP "J'ai dormi %d milliseconds"
+#define MSG_SMART_SORTING "Récupération des lignes triées (passage %d de %d)"
+#define MSG_SMART_SORT_ERR "Erreur logique 1 dans Smart Sort"
+#define MSG_SORTING "Tri en cours"
+#define MSG_SORTING_INDEX "Tri de l'index"
+#define MSG_SORTING_VAL "Tri de %d valeurs"
+#define MSG_SORT_JOIN_INDEX "Tri de l'index de jointure"
+#define MSG_SPCOL_READONLY "La colonne spéciale %s est en lecture seulement"
+#define MSG_SPEC_CMD_SEP "Les commandes spéciales doivent être exécutées séparément"
+#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d non supporté"
+#define MSG_SQL_BLOCK_MISM "CheckColumn: bloc SQL courant non correspondant"
+#define MSG_SQL_CONF_ERROR "Erreur SQL: SQL_CONFORMANCE"
+#define MSG_SQL_READ_ONLY "Les views SQL sont actuellement en lecture seulement"
+#define MSG_SRCH_CLOSE_ERR "Erreur à la fermeture de l'Handle de recherche"
+#define MSG_SRC_TABLE_UNDEF "La table source n'est pas définie"
+#define MSG_STACK_ERROR "Erreur sur la pile, i=%d\n"
+#define MSG_STACK_OVERFLOW "Parser: Débordement de la pile\n"
+#define MSG_STRG_NOT_FOUND "Chaîne introuvable"
+#define MSG_STRING_INV_LIST "Liste invalide pour SemString"
+#define MSG_STRING_TOO_BIG "Chaîne trop grande pour le domaine %s"
+#define MSG_SUBALLOC_ERROR "Pas assez de mémoire en zone %p pour allouer %d (utilisé=%d libre=%d)"
+#define MSG_SUBAL_HUGE_ERR "Pas assez de mémoire en zone huge %p pour allouer %d"
+#define MSG_SUBARG_NOSEM "Argument @ ou sous-phrase de niveau %d pointe sur un noeud sans Sem"
+#define MSG_SUBARG_OUTRANGE "Argument @ ou sous-phrase de niveau %d hors limite"
+#define MSG_SUBQRY_ONEITEM "Une Sub-Query ne doit avoir qu'une sélection"
+#define MSG_SUBSET_ERROR "SubSet erreur dans LoadDB"
+#define MSG_SUB_OPEN_YET "Subquery déjà ouverte"
+#define MSG_SUB_RES_TOO_LNG "Résultat trop long pour SUBSTR"
+#define MSG_SYNTAX_ERROR "Erreur de syntaxe"
+#define MSG_SYSTEM_ERROR "Erreur système %d"
+#define MSG_S_ACCESS_DENIED "%s: accès non autorisé"
+#define MSG_S_ERROR "%s erreur"
+#define MSG_S_ERROR_NUM "%s: erreur=%d"
+#define MSG_S_INTRUPT_ERROR "%s: erreur interruption"
+#define MSG_S_INVALID_PARM "%s: paramètre invalide"
+#define MSG_S_INV_ADDRESS "%s: adresse invalide"
+#define MSG_S_UNKNOWN_ERROR "%s: erreur de code %u inconnu"
+#define MSG_TABDIR_READONLY "Les tables DIR sont en lecture seulement"
+#define MSG_TABLE_ALREADY "La table %s existe déjà"
+#define MSG_TABLE_ALTERED "Table %s %s altérée"
+#define MSG_TABLE_CREATED "%s table %s créée"
+#define MSG_TABLE_DROPPED "Table %s supprimée"
+#define MSG_TABLE_MULT_JOIN "Utilisation multiple de la table %s pour jointure"
+#define MSG_TABLE_NOT_IN_DB "La table %s n'existe pas dans %s"
+#define MSG_TABLE_NOT_OPT "Table non optimisable"
+#define MSG_TABLE_NO_INDEX "La table %s n'est pas indexable"
+#define MSG_TABLE_NO_OPT "La table %s n'existe pas ou de type non optimisable"
+#define MSG_TABLE_READ_ONLY "Les tables %s sont en lecture seulement "
+#define MSG_TABMUL_READONLY "Les tables multiples sont en lecture seulement"
+#define MSG_TAB_NOT_LOADED " (certaines tables n'ont put être chargées)"
+#define MSG_TAB_NOT_SPEC "Table non specifiée"
+#define MSG_TB_VW_NOTIN_DB "Table ou view %s pas dans la base de données"
+#define MSG_TDB_NXT_NOT_NUL "Tdb.Next non NULL"
+#define MSG_TDB_USE_ERROR "Erreur, Tdbp->Use=%d"
+#define MSG_TOO_MANY_COLS "Trop de colonnes"
+#define MSG_TOO_MANY_COLTAB "Trop de colonnes dans %s (%d)"
+#define MSG_TOO_MANY_FIELDS "Trop de champs ligne %d de %s"
+#define MSG_TOO_MANY_JUMPS "Trop de niveaux de saut"
+#define MSG_TOO_MANY_KEYS "Trop de clés (%d)"
+#define MSG_TOO_MANY_POS "Trop de pos_codes"
+#define MSG_TOO_MANY_TABLES "Trop de tables (%d)"
+#define MSG_TOPSEM_ERROR "Erreur inconnue dans TopSem"
+#define MSG_TO_BLK_IS_NULL "To Blk est nul"
+#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr n'est pas nul"
+#define MSG_TO_PIX_NOT_NULL "Set.To_Pix n'est pas nul"
+#define MSG_TO_SEM_NOT_NULL "Set.To_Sem n'est pas nul"
+#define MSG_TRUNCATE_ERROR "Erreur en troncation: %s"
+#define MSG_TRUNC_BY_ESTIM "Tronqué par l'option Estimate"
+#define MSG_TYPES_ERROR "Erreur sur Types(%d)"
+#define MSG_TYPE_CONV_ERROR "Type non convertible dans une expression"
+#define MSG_TYPE_DEF_MISM "Disparité entre type et définition"
+#define MSG_TYPE_MISMATCH "Clé et source ne sont pas du même type"
+#define MSG_TYPE_RECFM_MISM "Disparité entre Type et Recfm"
+#define MSG_TYPE_TO_VERIFY "Type à vérifier: %d"
+#define MSG_TYPE_VALUE_ERR "Colonne %s: disparité type(%s)/valeur(%s)"
+#define MSG_UNBALANCE_QUOTE "Appostrophe en trop ligne %d"
+#define MSG_UNDEFINED_AM "COLBLK %s: méthode d'accès indéfinie"
+#define MSG_UNDEFINED_PATH "Chemin d'accès indéfini pour Plgcnx.ini"
+#define MSG_UNDEF_COL_COUNT "Count sur colonne non définie"
+#define MSG_UNKNOWN_DOMAIN "Domaine inconnu %s"
+#define MSG_UNKNOWN_ERROR "Erreur inconnue"
+#define MSG_UNKNOWN_EXCPT "Exception non répertoriée"
+#define MSG_UNKNOWN_NAME "Nom inconnu: %.8s"
+#define MSG_UNKNOWN_PATH "Chemin d'accès inconnu pour Plgcnx.ini"
+#define MSG_UNKNOWN_POS "Nom pos_code inconnu: %s"
+#define MSG_UNKNOWN_SEM "Sem %.8s inconnue, rc=%d"
+#define MSG_UNKNOWN_SYNONYM "Synonyme inconnu"
+#define MSG_UNKNW_QRY_TYPE "ReadDB: type de requête inconnu"
+#define MSG_UNKN_ERR_CODE "Erreur de code %d inconnu"
+#define MSG_UNLOADABLE " inchargeable: "
+#define MSG_UNLOADABLE_PRM "%s inchargeable: %s"
+#define MSG_UNMATCH_FIL_ARG "Argument de filtre dépareillé"
+#define MSG_UNQ_COL_SEV_TAB "La colonne %s non qualifiée est dans plusieurs tables"
+#define MSG_UNRESOLVED_ARG "?Argument manquant: %s non résolu en %d ligne %d"
+#define MSG_UPDATE_ERROR "Erreur en Update sur %s"
+#define MSG_UPDATING_ROWS "Mise à jour des lignes"
+#define MSG_UPD_ZIP_NOT_IMP "Mise à jour des tables ZDOS non encore implementé"
+#define MSG_UP_LANGUAGE "Bloc langage %.8s version %d niveau %d chargé"
+#define MSG_USED_FREE_MEM "Sarea: utilisé %d, libre %d"
+#define MSG_USETEMP_IS "Usetemp est : %s"
+#define MSG_USETEMP_RESET ". Usetemp remis à Auto"
+#define MSG_USETEMP_SET "Usetemp fixé à %s"
+#define MSG_USE_NO_MATCH "Use non correspondant : Use=%d, ti2=%d, ti3=%d"
+#define MSG_USING_INDEX " (Indexé par"
+#define MSG_VALIST_MISMATCH "Disparité des listes de valeurs"
+#define MSG_VALSTR_TOO_LONG "Valeur %s trop longue pour une chaîne de longueur %d"
+#define MSG_VALTYPE_NOMATCH "Disparité types de valeur"
+#define MSG_VALUE_ERROR "Colonne %s: bloc valeur nul"
+#define MSG_VALUE_NOT_ALLOC "Valeur non allouée pour la colonne R%d %s"
+#define MSG_VALUE_TOO_BIG "Valeur %lld trop grande pour la colonne %s"
+#define MSG_VALUE_TOO_LONG "Valeur %s trop longue pour la colonne %s de longueur %d"
+#define MSG_VAL_ALLOC_ERR "Allocation impossible du noeud valeur"
+#define MSG_VAL_TOO_LONG "Valeur %s trop longue pour le champ %s"
+#define MSG_VIEW_ALREADY "La VIEW %s existe déjà"
+#define MSG_VIEW_CREATED "%s view %s créée"
+#define MSG_VIEW_DROPPED "View %s supprimée"
+#define MSG_VIEW_NOT_IN_DB "%s n'est pas une View de %s"
+#define MSG_VIR_NO_DELETE "Delete impossible sur les tables %s"
+#define MSG_VIR_READ_ONLY "Les tables virtuelles %s sont en lecture seulement"
+#define MSG_VM_LANG "Langage au format VM, non supporté"
+#define MSG_VOID_FIRST_ARG "Le premier argument ne doit pas être vide"
+#define MSG_VOID_IN_STRING "Erreur: chaîne IN vide"
+#define MSG_VOID_ORDER_LIST "Liste de tri vide, erreur système ?"
+#define MSG_VOID_POS_DICT "Dictionnaire interne du langage vide"
+#define MSG_VOID_QUERY "Requête vide %s"
+#define MSG_WORK_AREA "Espace de travail: %s"
+#define MSG_WORK_TOO_SMALL "Zone de travail trop petite, accroître AreaSize"
+#define MSG_WRITE_ERROR "Erreur à l'écriture de %s"
+#define MSG_WRITE_SEEK_ERR "Erreur de recherche en écriture: %s"
+#define MSG_WRITE_STRERROR "Erreur en écriture sur %s: %s"
+#define MSG_WRITING "Ecriture"
+#define MSG_WRITING_ERROR "Erreur à l'écriture de %s: %s"
+#define MSG_WRITING_QUERY "Erreur à l'écriture de la requête: "
+#define MSG_WRONG_ARG_NUM "La fonction %s ne prend pas %d arguments"
+#define MSG_WRONG_COL_NUM "Numéro de colonne %d trop grand pour %s"
+#define MSG_WRONG_DB_LIST "Liste des bases de données incorrecte ou vide"
+#define MSG_WRONG_FUNCTION "Mauvaise fonction %d"
+#define MSG_WRONG_OP_PARM "Mauvais opérateur ou paramètres pour %s"
+#define MSG_WRONG_PARMS "Mauvais paramètres pour %s"
+#define MSG_WRONG_PASSWORD "Mot de passe illégal pour %s"
+#define MSG_WRONG_TYPE "type non supporté"
+#define MSG_WRONG_USERFILE "La Userfile a une mauvaise taille %d"
+#define MSG_WS_CONV_ERR "Erreur de convertion de %s en WS"
+#define MSG_XCOL_MISMATCH "La colonne %s ne correspond pas à l'index"
+#define MSG_XDB_DEL_ERROR "Erreur en supprimant des entrées du fichier XDB"
+#define MSG_XFILE_READERR "Erreur %d en lisant le fichier index"
+#define MSG_XFILE_TOO_SMALL "Le fichier index est plus petit que la taille de l'index"
+#define MSG_XFILE_WRITERR "Erreur en écrivant le fichier index: %s"
+#define MSG_XMLTAB_INIT_ERR "Erreur d'initialisation de la table XML"
+#define MSG_XML_INIT_ERROR "Erreur d'initialisation du nouveau fichier XML"
+#define MSG_XPATH_CNTX_ERR "Le nouveau contexte XPath ne peut être créé"
+#define MSG_XPATH_EVAL_ERR "Impossible d'évaluer l'emplacement xpath '%s'"
+#define MSG_XPATH_NOT_SUPP "Xpath non supporté colonne %s"
+#define MSG_X_ARG_ADDED "%d arguments ajoutés"
+#define MSG_X_ARG_SET "%d arguments ont été initialisés"
+#define MSG_X_ON_TAB " %s sur %s("
+#define MSG_ZERO_DIVIDE "Division par zéro dans une expression"
diff --git a/storage/connect/frmsg2.h b/storage/connect/frmsg2.h
index d9768d740dd..487db3395fb 100644
--- a/storage/connect/frmsg2.h
+++ b/storage/connect/frmsg2.h
@@ -1,1013 +1,1013 @@
-#define MSG_ACCESS_VIOLATN "Violation accŠs m‚moire"
-#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Activity"
-#define MSG_ADDVAL_ERROR "Erreur %d dans AddValue"
-#define MSG_ADD_BAD_TYPE "Ajout d'une valeur de type %s non conforme dans un tableau %s"
-#define MSG_ADD_NULL_DOM "Ajout de la chaŒne %s … un domaine nul"
-#define MSG_ADPOS_IN_DICTP "ADPOS au travail dans User_Dictp"
-#define MSG_AFTER " aprŠs: "
-#define MSG_ALG_CHOICE_AUTO "Le choix du meilleur algorithme est automatique"
-#define MSG_ALG_CHOICE_BAD "Choix d'algorithme invalide, remis … AUTO"
-#define MSG_ALG_CHOICE_QRY "Utilise l'algorithme 'Query'"
-#define MSG_ALG_CURLY_BRK "Le choix de l'algorithme d‚pend des accolades externes"
-#define MSG_ALLOC_ERROR "Erreur d'allocation de %s"
-#define MSG_ALL_DELETED "Toutes les lignes enlev‚es en %.2lf sec"
-#define MSG_ALTER_DB_ERR "Impossible de d‚terminer la base de donn‚es … modifier"
-#define MSG_AMBIG_COL_QUAL "Qualificateur ambigu %s pour la colonne %s"
-#define MSG_AMBIG_CORREL "Select %s.* corr‚lation ambigue"
-#define MSG_AMBIG_SPEC_COL "Colonne sp‚ciale ambigue %s"
-#define MSG_ANSWER_TYPE "R‚ponse de type"
-#define MSG_API_CONF_ERROR "Erreur SQL: API_CONFORMANCE"
-#define MSG_APPL_ACCESSIBLE "Application %s accessible"
-#define MSG_APPL_ACTIVE "Application %s encore active"
-#define MSG_APPL_BAD_SAVE "Application %s partiellement sauvegard‚e"
-#define MSG_APPL_CREATED "Application %s cr‚‚"
-#define MSG_APPL_IS_ACTIVE "Application d‚j… active"
-#define MSG_APPL_NOT_INIT "Application non initialis‚e"
-#define MSG_APPL_NOT_LOADED "Application non charg‚e"
-#define MSG_APPL_QUIT "Fin de l'application %s"
-#define MSG_APPL_SAVED "Application %s sauvegard‚e"
-#define MSG_APP_STILL_ACTIV "Application du langage %s encore active (non lib‚rable)"
-#define MSG_AREAFILE_NOTFND "Fichier Area introuvable"
-#define MSG_ARGS_SYNTAX_ERR "?SetArgs erreur de syntaxe: %s inattendu aprŠs %s"
-#define MSG_ARG_ALREADY_SET "Argument %d d‚j… allou‚"
-#define MSG_ARG_NOT_AN_ATTR "L'argument n'est pas un attribut (type %d erron‚)"
-#define MSG_ARG_OUT_CONTEXT "Argument de type @ utilis‚ hors contexte"
-#define MSG_ARG_OUT_RANGE "Argument de phrase valant %d hors limite"
-#define MSG_ARG_PTR_NOSEM "Argument valant %d pointe sur un noeud sans Sem"
-#define MSG_ARG_PTR_NOSEMS "Argument valant %d pointe sur un noeud sans s‚mantique"
-#define MSG_ARG_REF_LOOP "?Bouclage entre r‚f‚rences crois‚es des arguments"
-#define MSG_ARG_TWO_CONST "Le 2Šme argument de %s doit ˆtre constant"
-#define MSG_ARRAY_ALLOC_ERR "Erreur d'allocation m‚moire dans ARRAY"
-#define MSG_ARRAY_BNDS_EXCD "Hors limite de tableau"
-#define MSG_ARRAY_ERROR "Erreur de fonctionnement k=%d n=%d"
-#define MSG_ATTRIBUTE_ERROR "Erreur rŠgle %u attribut %s: "
-#define MSG_ATT_NOT_CASE "Mauvaise valeur %d pour attribut (pas une CaseValue)"
-#define MSG_ATT_POSCODE_BIG "Code attribut %d trop grand (max=%d)"
-#define MSG_AVGLEN_ERROR "avglen doit ˆtre entre %d et %d"
-#define MSG_BAD_AGGREG_FUNC "Fonction aggr‚g‚e %d non support‚e"
-#define MSG_BAD_ARGTYPES "Argument de type invalide pour %s"
-#define MSG_BAD_ARGUMENTS "Argument non attach‚s pour %s"
-#define MSG_BAD_ARG_NUM "Nombre d'arguments invalide %d"
-#define MSG_BAD_ARG_TYPE "Type d'argument %d invalide"
-#define MSG_BAD_ARRAY_OPER "Les tableaux doivent utiliser l'op‚rateur IN"
-#define MSG_BAD_ARRAY_TYPE "Type=%d invalide pour un tableau"
-#define MSG_BAD_ARRAY_VAL "Les tableaux doivent avoir le mˆme nombre de valeurs"
-#define MSG_BAD_BIN_FMT "Format invalide %c pour la colonne BIN %s"
-#define MSG_BAD_BLK_ESTIM "Nombre de blocs sup‚rieur … l'estimation"
-#define MSG_BAD_BLK_SIZE "Taille du bloc %d non conforme"
-#define MSG_BAD_BYTE_NUM "Le nombre d'octets ‚crits est faux"
-#define MSG_BAD_BYTE_READ "Le nombre d'octets lus est faux"
-#define MSG_BAD_CARDINALITY "Appel invalide de Cardinality pour une table multiple"
-#define MSG_BAD_CASE_SPEC "Min/Maj: sp‚cification %c incorrecte, recommencez: "
-#define MSG_BAD_CHAR_SPEC "Sp‚cification '%s' invalide pour caractŠre"
-#define MSG_BAD_CHECK_TYPE "Sous-type %d invalide pour CheckColumn"
-#define MSG_BAD_CHECK_VAL "Valeur pour Check invalide '%s'"
-#define MSG_BAD_COLCRT_ARG "COLCRT: Arg invalide (type=%hd, domain=%hd)"
-#define MSG_BAD_COLDEF_TYPE "Coldefs: type ill‚gal %d"
-#define MSG_BAD_COLIST_ITEM "El‚ment invalide dans une Colist"
-#define MSG_BAD_COLIST_TYPE "Mauvais type=%d pour une Colist"
-#define MSG_BAD_COLSIZE "Colsize %d trop petit pour cette base de donn‚es"
-#define MSG_BAD_COL_ENTRY "Entr‚e invalide pour la colonne %s"
-#define MSG_BAD_COL_FORMAT "Type de formattage %d invalide pour une colonne"
-#define MSG_BAD_COL_IN_FILT "Colonne incorrecte dans un filtre"
-#define MSG_BAD_COL_QUALIF "Qualificateur invalide %s pour la colonne %s"
-#define MSG_BAD_COL_TYPE "Type invalide %s pour la colonne %s"
-#define MSG_BAD_COL_XPATH "Xpath invalide colonne %s de la table HTML %s"
-#define MSG_BAD_COMPARE_OP "Op‚rateur de comparaison %d invalide"
-#define MSG_BAD_CONST_TYPE "Type=%d invalide pour une constante"
-#define MSG_BAD_CONV_TYPE "Convertion de type invalide %d"
-#define MSG_BAD_CORREL "Select %s.* corr‚lation absente"
-#define MSG_BAD_DATETIME "Valeur date/temps invalide"
-#define MSG_BAD_DATE_OPER "Op‚rateur de date inattendu %d"
-#define MSG_BAD_DBF_FILE "Le fichier DBF %s est alt‚r‚"
-#define MSG_BAD_DBF_REC "Fichier DBF %s alt‚r‚ enregistrement %d"
-#define MSG_BAD_DBF_TYPE "Type DBF %c non support‚"
-#define MSG_BAD_DEF_ARG "Argument invalide pour INDEXDEF (type=%hd, domain=%hd)"
-#define MSG_BAD_DEF_READ "EOF inattendue en lecture diff‚r‚e"
-#define MSG_BAD_DEF_TYPE "Type de colonne invalide"
-#define MSG_BAD_DIRECTORY "R‚pertoire invalide %s: %s"
-#define MSG_BAD_DIST_JN_FIL "Filtre de jointure distincte invalide"
-#define MSG_BAD_DIST_JOIN "Sp‚cification invalide de jointure distincte"
-#define MSG_BAD_DOM_COL_DEF "D‚finition de colonnes invalide pour un domaine"
-#define MSG_BAD_DOM_VALUE "La valeur %d n'appartient pas au domaine"
-#define MSG_BAD_EDIT_INIT "Coparm: ‚dition %s initialis‚e improprement"
-#define MSG_BAD_EVAL_TYPE "Fonction scalaire de type=%d invalide"
-#define MSG_BAD_EXEC_MODE "Mode d'ex‚cution invalide '%s'"
-#define MSG_BAD_EXP_ARGTYPE "Argument de type %d invalide pour une expression"
-#define MSG_BAD_EXP_OPER "Op‚rateur=%d invalide pour expression"
-#define MSG_BAD_FETCH_RC "Code retour inattendu de Fetch %d"
-#define MSG_BAD_FIELD_FMT "Format de champ invalide %c pour %s"
-#define MSG_BAD_FIELD_RANK "Rang %d invalide pour la colonne %s"
-#define MSG_BAD_FIELD_TYPE "Mauvais type de champ %s"
-#define MSG_BAD_FILE_HANDLE "Handle de fichier invalide: %s"
-#define MSG_BAD_FILE_LIST "La section liste de fichiers est erron‚e"
-#define MSG_BAD_FILTER "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"
-#define MSG_BAD_FILTER_CONV "Conversion filtre incorrecte, B_T=%d,%d"
-#define MSG_BAD_FILTER_LINK "Op‚rateur de chaŒnage ill‚gal %d"
-#define MSG_BAD_FILTER_OP "Op‚rateur de filtre invalide %d"
-#define MSG_BAD_FILTEST_OP "Op‚rateur invalide %d %d pour FilTest"
-#define MSG_BAD_FLD_FORMAT "Format invalide pour le champs %d de %s"
-#define MSG_BAD_FLD_LENGTH "Champs %s trop long (%s --> %d) ligne %d de %s"
-#define MSG_BAD_FLOAT_CONV "Convertion invalide d'un tableau flottant"
-#define MSG_BAD_FPARM_NEXT "Coparm: FPARM avec Next non nul"
-#define MSG_BAD_FREQ_SET "Sp‚cification erronn‚e de Freq pour la colonne %s"
-#define MSG_BAD_FUNC_ARG "Funcarg de type %d non impl‚ment‚"
-#define MSG_BAD_FUNC_ARGTYP "Mauvais type d'argument=%d pour une fonction"
-#define MSG_BAD_FUNC_MODE "%s: mode invalide %d"
-#define MSG_BAD_GENRE "Genre est invalide"
-#define MSG_BAD_GETVIEW_RET "GetView: type de retour %d invalide"
-#define MSG_BAD_HANDLE_VAL "Valeur Handle invalide"
-#define MSG_BAD_HAV_FILTER "Filtre Having sur une requˆte non group‚e"
-#define MSG_BAD_HAV_FILTYPE "Filtre invalide pour clause Having"
-#define MSG_BAD_HEADER "Fichier %s: bloc en-tˆte alt‚r‚"
-#define MSG_BAD_HEADER_VAL "Valeur invalide pour Header"
-#define MSG_BAD_HEAD_END "Lecture fin d'en-tˆte impossible"
-#define MSG_BAD_INDEX_COL "Colonne %s invalide pour index %s"
-#define MSG_BAD_INDEX_DEF "D‚finition invalide pour index %s"
-#define MSG_BAD_INDEX_FILE "Fichier index %s corrompu"
-#define MSG_BAD_INDEX_PART "D‚finition colonne invalide pour index %s"
-#define MSG_BAD_INPUT "Entr‚e incorrecte"
-#define MSG_BAD_IN_ARGTYPE "Argument de type invalide pour l'op‚rateur IN"
-#define MSG_BAD_IN_ENDING "Erreur: fin de chaŒne IN invalide"
-#define MSG_BAD_IN_STRING "La chaŒne IN commence ou finie par des caractŠres invalides %c ... %c"
-#define MSG_BAD_JCOL_TYPE "Erreur logique JCT: disparit‚ des types colonnes"
-#define MSG_BAD_JOIN_EXP "Expression invalide pour une jointure"
-#define MSG_BAD_JOIN_FILTER "Filtre de jointure invalide"
-#define MSG_BAD_JOIN_OP "Op‚rateur de joint invalide %d"
-#define MSG_BAD_LANG_SIZE "Le fichier langage a une mauvaise taille %d"
-#define MSG_BAD_LINEFLD_FMT "Format invalide ligne %d champs %d de %s"
-#define MSG_BAD_LINE_LEN "Longueur ligne non ‚gale … Lrecl"
-#define MSG_BAD_LIST_TYPE "Type de liste invalide %d"
-#define MSG_BAD_LOCALE "Locale invalide %s"
-#define MSG_BAD_LOCDFON_ARG "Mauvais paramŠtre pour LOCDFON"
-#define MSG_BAD_LOCNODE_USE "Usage inattendu de LOCNODE"
-#define MSG_BAD_LRECL "Disparit‚ lrecl table/fichier (%d,%hd)"
-#define MSG_BAD_MAX_HAVING "MAXTMP trop petit pour Having"
-#define MSG_BAD_MAX_NREC "MaxRec=%d ne correspond pas … MaxBlk=%d Nrec=%d"
-#define MSG_BAD_MAX_PARAM "Mauvais paramŠtres pour sp‚cifier une valeur maximum"
-#define MSG_BAD_MAX_SETTING "Mauvaise valeur '%c' pour max"
-#define MSG_BAD_MERGE_TYPE "Le type %d ne pas ˆtre intercall‚"
-#define MSG_BAD_NODE_TYPE "Type noeud erron‚ pour la table"
-#define MSG_BAD_OFFSET_VAL "Nul offset invalide pour une table CSV"
-#define MSG_BAD_OPEN_MODE "Mode d'ouverture invalide %d"
-#define MSG_BAD_OPERATOR "Op‚rateur invalide %s"
-#define MSG_BAD_ORDER_MODE "Mode de tri %c invalide"
-#define MSG_BAD_ORDER_TYPE "Tri sur objet de type=%d invalide"
-#define MSG_BAD_OUTER_JOIN "Jointure externe invalide sur table enfant"
-#define MSG_BAD_PAD_ARGTYP "Argument de type invalide pour Pad ou Justify"
-#define MSG_BAD_PARAMETERS "%.8s: Mauvais paramŠtres"
-#define MSG_BAD_PARAM_TYPE "%.8s: ParamŠtre de type=%d invalide"
-#define MSG_BAD_PARM_COUNT "Nombre de paramŠtres incoh‚rent"
-#define MSG_BAD_PHASE_NUM "Num‚ro de phrase %d hors limite"
-#define MSG_BAD_PHRASE_NB "num‚ro de phrase hors limite %d rc=%d\n"
-#define MSG_BAD_POS_CODE "POS_code invalide %d"
-#define MSG_BAD_POS_TYPE "Type de POS_code invalide %d"
-#define MSG_BAD_PROJNUM "Mauvais projnum %d pour la colonne %s"
-#define MSG_BAD_QUERY_OPEN "Mode invalide %d pour l'ouverture d'une requˆte"
-#define MSG_BAD_QUERY_TYPE "Type de requˆte %d invalide pour %s"
-#define MSG_BAD_QUOTE_FIELD "Quote manquante dans %s champs %d ligne %d"
-#define MSG_BAD_READ_NUMBER "Mauvais nombre %d de valeurs lues dans %s"
-#define MSG_BAD_RECFM "Recfm type %d invalide pour DOSCOL"
-#define MSG_BAD_RECFM_VAL "Valeur invalide %d de Recfm"
-#define MSG_BAD_RESULT_TYPE "Mauvais type de r‚sultat %d pour %s"
-#define MSG_BAD_RETURN_TYPE "Type de retour %d incorrect"
-#define MSG_BAD_ROW_VALIST "Liste de valeurs invalide pour ROW"
-#define MSG_BAD_ROW_VALNB "Nombre de valeurs in‚gal dans la liste"
-#define MSG_BAD_SCF_ARGTYPE "Argument %d de type=%s invalide pour %s"
-#define MSG_BAD_SEM_DOMAIN "Domain .%d invalide"
-#define MSG_BAD_SETTINGS "Certaines sp‚cifications sont incompatibles avec le type de la table"
-#define MSG_BAD_SET_CASE "La casse d'un tableau ne peut pas passer de non respect … respecter"
-#define MSG_BAD_SET_STRING "SetValue: appel invalide pour STRING"
-#define MSG_BAD_SET_TYPE "Set type %hd invalide"
-#define MSG_BAD_SPECIAL_CMD "Commande sp‚ciale invalide"
-#define MSG_BAD_SPECIAL_COL "Colonne sp‚ciale invalide %s"
-#define MSG_BAD_SPEC_COLUMN "Colonne sp‚ciale invalide pour ce type de table"
-#define MSG_BAD_SQL_PARAM "ParamŠtre SQL invalide pour FindColblk"
-#define MSG_BAD_SUBLST_TYPE "Coparm: type %d de sous-liste invalide"
-#define MSG_BAD_SUBSEL_IN_X "Sub-select invalide pour une expression"
-#define MSG_BAD_SUBSEL_TYPE "Type %d invalide retourn‚ de Sub-Select"
-#define MSG_BAD_SUB_RESULT "R‚sultat ind‚fini de fonction Sub-Select"
-#define MSG_BAD_SUB_SELECT "Sub-select invalide comme argument de fonction"
-#define MSG_BAD_TABLE_LINE "Ligne '%s' ill‚gale ou tronqu‚e dans la section Tables"
-#define MSG_BAD_TABLE_LIST "Table %s absente de la liste des tables"
-#define MSG_BAD_TABLE_TYPE "Type invalide %s pour la table %s"
-#define MSG_BAD_TEST_TYPE "BlockTest sur tableau: types d‚pareill‚s %s %s"
-#define MSG_BAD_TRIM_ARGTYP "Argument de type invalide pour Trim"
-#define MSG_BAD_TYPE_FOR_IN "Types d'argument incompatibles pour la fonction IN"
-#define MSG_BAD_TYPE_FOR_S "Type incorrecte %d pour %s(%d)"
-#define MSG_BAD_TYPE_LIKE "Type(%d)= %d invalide pour LIKE"
-#define MSG_BAD_UPD_COR "Le qualificateur %s de la colonne %s ne se refŠre pas … la table mise … jour %s"
-#define MSG_BAD_USERBLK_LEN "Mauvaise longueur … l'‚criture du bloc utilisateur"
-#define MSG_BAD_USETEMP "Usetemp invalide '%s'"
-#define MSG_BAD_USETEMP_VAL "Valeur pour Usetemp invalide %d"
-#define MSG_BAD_VALBLK_INDX "Valeur hors limites de l'index du bloc de valeurs"
-#define MSG_BAD_VALBLK_TYPE "Type=%d invalide pour un bloc de valeurs"
-#define MSG_BAD_VALNODE "Type %d invalide pour le noeud valeur colonne %s"
-#define MSG_BAD_VALUE_TYPE "Type de valeur invalide %d"
-#define MSG_BAD_VAL_UPDATE "Impossible de d‚terminer quelle valeur %s doit ˆtre mise … jour"
-#define MSG_BAD_VIEW_OPEN "Mode invalide %d pour l'ouverture d'une View"
-#define MSG_BAD_XMODE_VAL "Mode d'ex‚cution %d invalide"
-#define MSG_BAD_XOBJ_TYPE "Mauvais type de Xobject %d"
-#define MSG_BAS_NS_LIST "Format invalide de la liste des espace-noms"
-#define MSG_BIN_F_TOO_LONG "Valeur trop longue pour le champ %s (%d --> %d)"
-#define MSG_BIN_MODE_FAIL "Echec mode binaire: %s"
-#define MSG_BLKTYPLEN_MISM "Disparit‚ types/longueurs de bloc dans SetValue"
-#define MSG_BLK_IS_NULL "Blk est nul"
-#define MSG_BLOCK_NO_MATCH "Bloc non correspondant"
-#define MSG_BREAKPOINT "Point de controle"
-#define MSG_BUFF_TOO_SMALL "GetColData: Buffer trop petit"
-#define MSG_BUFSIZE_ERROR "Erreur en recherchant la taille du buffer"
-#define MSG_BUILDING_GROUPS "Formation des groupes"
-#define MSG_BUILD_DIST_GRPS "Formation des groupes distinctes"
-#define MSG_BUILD_INDEX "Construction index %s sur %s"
-#define MSG_BXP_NULL "Bxp nul dans PUTFON"
-#define MSG_CANNOT_OPEN "Ouverture impossible de %s"
-#define MSG_CD_ONE_STEP "Count Distinct doit ˆtre ex‚cut‚ en une seule ‚tape"
-#define MSG_CD_ORDER_ERROR "Erreur de tri dans Count Distinct"
-#define MSG_CHECKING_ROWS "Test des lignes … mettre … jour"
-#define MSG_CHECK_LEVEL "Niveau de v‚rification fix‚ … %u"
-#define MSG_CHSIZE_ERROR "Erreur dans chsize: %s"
-#define MSG_CLN_NOT_IN_JOIN "La colonne C%d n'est pas dans le join"
-#define MSG_CNTDIS_COL_LOST "Colonne du Count Distinct perdue"
-#define MSG_COLIST_BAD_TYPE "Type=%d invalide pour Colist"
-#define MSG_COLNAM_TOO_LONG "Nom de colonne trop long"
-#define MSG_COLSEC_TOO_BIG "Section colonne trop grande, table %s (%d)"
-#define MSG_COLS_REDUCED " (r‚duit par Maxcol)"
-#define MSG_COLUMN_ERROR "Erreur de colonne"
-#define MSG_COLUMN_MISMATCH "Colonne %s d‚pareill‚e"
-#define MSG_COLUMN_NOT_KEY "La colonne jointe R%d.%s n'est pas une cl‚"
-#define MSG_COL_ALLOC_ERR "Allocation impossible du noeud colonne"
-#define MSG_COL_ALLOC_ERROR "Erreur d'allocation m‚moire pour la colonne %d"
-#define MSG_COL_HAS_NO_DEF "La colonne %s n'est pas d‚finie"
-#define MSG_COL_INVAL_TABLE "La colonne %s.%s n'existe pas dans la table %s alias %s"
-#define MSG_COL_ISNOT_TABLE "La colonne %s n'est pas dans la table %s"
-#define MSG_COL_NB_MISM "Le nombre de colonnes ne correspond pas"
-#define MSG_COL_NOTIN_GRPBY "La colonne %s n'est pas dans la liste de Group By"
-#define MSG_COL_NOTIN_TABLE "La colonne %s n'est dans aucune table"
-#define MSG_COL_NOTIN_UPDT "%s n'appartient pas … la table mise … jour %s"
-#define MSG_COL_NOT_CODED "La colonne %s n'est pas codifi‚e"
-#define MSG_COL_NOT_EXIST "La colonne %s n'existe pas dans %s"
-#define MSG_COL_NOT_FOUND "La colonne %s n'est pas dans la table %s"
-#define MSG_COL_NOT_IN_DB "La colonne %s de la table %s n'est pas dans la base de donn‚es"
-#define MSG_COL_NOT_IN_JOIN "La colonne %s n'est pas dans le join"
-#define MSG_COL_NOT_SORTED "La colonne %s de la table %s n'est pas tri‚e"
-#define MSG_COL_NUM_MISM "Disparit‚ du nombre de colonnes"
-#define MSG_COL_USED_TWICE "Colonne %s utilis‚e deux fois ???"
-#define MSG_COMPUTE_ERROR "Erreur dans Compute, op=%d"
-#define MSG_COMPUTE_NIY "Compute non impl‚ment‚ pour TOKEN"
-#define MSG_COMPUTING "Calculs en cours"
-#define MSG_COMPUTING_DIST "Comptage des valeurs distinctes"
-#define MSG_COMPUTING_FUNC "Calcul de(s) fonction(s)"
-#define MSG_COM_ERROR "Erreur Com"
-#define MSG_CONCAT_SUBNODE "Concat‚nation de sous-noeuds impossible"
-#define MSG_CONNECTED "Connect‚e"
-#define MSG_CONNECT_CANCEL "Connection interrompue par l'utilisateur"
-#define MSG_CONNECT_ERROR "Erreur %d se connectant à %s"
-#define MSG_CONN_CLOSED "%s(%d) ferm‚e"
-#define MSG_CONN_CREATED "Connexion %s cr‚e"
-#define MSG_CONN_DROPPED "Connexion %s supprim‚e"
-#define MSG_CONN_OPEN "%s(%d) ouverte (%s)"
-#define MSG_CONN_SUC_OPEN "%s(%d) ouverte avec succŠs"
-#define MSG_CONTROL_C_EXIT "Exit par Ctrl-C"
-#define MSG_COPY_BAD_PHASE "Copie de liste invalide en phase %d"
-#define MSG_COPY_INV_TYPE "Coparm: type non support‚ %d"
-#define MSG_CORREL_NO_QRY "Les sous-requˆtes corr‚l‚es ne peuvent pas ˆtre de type QRY"
-#define MSG_CREATED_PLUGDB " Cr‚‚ par PlugDB %s "
-#define MSG_CURSOR_SET "Curseur remis … %d"
-#define MSG_DATABASE_ACTIVE "Base de donn‚es %s activ‚e"
-#define MSG_DATABASE_LOADED "Base de donn‚es %s charg‚e"
-#define MSG_DATA_IS_NULL "ExecSpecialCmd: data est NULL"
-#define MSG_DATA_MISALIGN "Mauvais alignement pour ce type de donn‚es"
-#define MSG_DBASE_FILE "Fichier dBASE dbf: "
-#define MSG_DB_ALREADY_DEF "Base de donn‚es %s d‚j… d‚finie"
-#define MSG_DB_ALTERED "Base de donn‚es modifi‚e"
-#define MSG_DB_CREATED "Base de donn‚es %s cr‚‚e"
-#define MSG_DB_NOT_SPEC "Base de donn‚es non sp‚cifi‚e"
-#define MSG_DB_REMOVED "Base de donn‚es %s retir‚e de la liste"
-#define MSG_DB_SORT_ERROR "Erreur de tri DB"
-#define MSG_DB_STOPPED "Arrˆt de la base de donn‚es %s"
-#define MSG_DEBUG_NOT_ACTIV "Mode Debug inactif"
-#define MSG_DEBUG_SET_INV "Invalide pour Debug: %c"
-#define MSG_DEF_ALLOC_ERROR "Erreur d'allocation de la classe DEF %s"
-#define MSG_DELETING_ROWS "Suppression des lignes"
-#define MSG_DEL_FILE_ERR "Erreur … l'effacement de %s"
-#define MSG_DEL_READ_ERROR "Delete: erreur en lecture req=%d len=%d"
-#define MSG_DEL_WRITE_ERROR "Delete: erreur en ‚criture: %s"
-#define MSG_DEPREC_FLAG "Option Flag p‚rim‚e, utiliser Coltype"
-#define MSG_DICTIONARY "Dictionnaire "
-#define MSG_DIRECT_VARTOK "AccŠs direct aux rŠgles du Variable Token non impl‚ment‚"
-#define MSG_DISCONNECTED "D‚connect‚"
-#define MSG_DISTINCT_ERROR "Plus d'un ‚l‚ment fonctionel DISTINCT"
-#define MSG_DISTINCT_ROWS "S‚lection des lignes distinctes"
-#define MSG_DISTINCT_VALUES "Extraction des valeurs distinctes"
-#define MSG_DIS_NOHEAD_JOIN "Jointure distincte sur une table non en tˆte"
-#define MSG_DLL_LOAD_ERROR "Erreur %d au chargement du module %s"
-#define MSG_DOMAIN_EMPTY "Le domaine %s est vide"
-#define MSG_DOMAIN_ERROR "Colonne %s: disparit‚ domaine(%s)/valeur(%s)"
-#define MSG_DOMAIN_FULL "Le domaine %s est plein (max=%d)"
-#define MSG_DOM_FILE_ERROR "Fichier domain %s introuvable"
-#define MSG_DOM_NOT_SUPP "MS-DOM non support‚ par cette version"
-#define MSG_DOM_OPEN_ERROR "Erreur d'ouverture du domaine: %s"
-#define MSG_DOM_READ_ERROR "Erreur %d en lecture de domaine: %s"
-#define MSG_DOM_READ_ONLY "La table domaine %s est en lecture seulement"
-#define MSG_DOM_WRITE_ERROR "Erreur %d en ‚criture de domaine: %s"
-#define MSG_DONE "Effectu‚, rc=%d"
-#define MSG_DOSALMEM_NOMEM "Erreur d'allocation, pas assez de m‚moire"
-#define MSG_DROP_DB_ERR "Echec du Drop sur le base de donn‚es %s"
-#define MSG_DSORT_LOG_ERROR "Kindex: Erreur logique de tri distincte"
-#define MSG_DUMMY_NO_COLS "Les tables DUMMY ne peuvent pas avoir de colonne"
-#define MSG_DUPLICAT_COUNT "Count sur plus d'une colonne"
-#define MSG_DUP_COL_NAME "La colonne %s existe en double"
-#define MSG_DUP_PROJNUM "Non unique projnum %d pour la colonne %s"
-#define MSG_DVAL_NOTIN_LIST "Valeur %s non trouv‚e dans la liste des valeurs distinctes de la colonne %s"
-#define MSG_EMPTY_DOC "Document vide"
-#define MSG_EMPTY_FILE "%s du fichier vide %s: "
-#define MSG_ENDSTR_MISMATCH "Fins de chaŒne et de noeud ne correspondent pas"
-#define MSG_END_OF_DELETE "%d ligne(s) enlev‚e(s) en %.2lf sec"
-#define MSG_END_OF_INSERT "%d ligne(s) ins‚r‚e(s) en %.2lf sec"
-#define MSG_END_OF_QUERY "%d ligne(s) extraite(s) en %.2lf sec"
-#define MSG_END_OF_UPDATE "%d ligne(s) modifi‚e(s) en %.2lf sec"
-#define MSG_EOF_AFTER_LINE "Fin de fichier aprŠs la ligne %d"
-#define MSG_EOF_INDEX_FILE "EOF lisant le fichier index"
-#define MSG_ERASED " et effac‚e"
-#define MSG_ERASE_FAILED " (‚chec de l'effacement)"
-#define MSG_ERROR "Erreur"
-#define MSG_ERROR_IN_LSK "Erreur %d dans lseek64"
-#define MSG_ERROR_IN_SFP "Erreur %d dans SetFilePointer"
-#define MSG_ERROR_NO_PARM "ParamŠtre absent (valide seulement pour %.8s.1 et %.8s.5)"
-#define MSG_ERROR_OPENING "Erreur … l'ouverture de : "
-#define MSG_ERR_NUM_GT_MAX "Erreur: Numval (%d) plus grand que Maxnum (%d)"
-#define MSG_ERR_READING_REC "Erreur lisant l'enregistrement %d de %s"
-#define MSG_ERR_RET_RULE "Retour erreur, rŠgle=%u"
-#define MSG_ERR_RET_TYPE "Retour erreur, type=%d"
-#define MSG_EVAL_EXPIRED "Cette version d'évaluation est expir‚e"
-#define MSG_EVAL_ONLY "L'utilisation de cette Dll est pour ‚valuation seulement"
-#define MSG_EXECUTING "Ex‚cution"
-#define MSG_EXECUTION_ERROR "Erreur d'ex‚cution"
-#define MSG_EXEC_MODE_IS "Le mode d'ex‚cution est %s"
-#define MSG_EXEC_MODE_RESET ". Mode remis … Execute"
-#define MSG_EXEC_MODE_SET "Mode d'ex‚cution fix‚ … %s"
-#define MSG_EXIT_EVAL_ERR "Erreur pendant l'‚valuation de Exit"
-#define MSG_EXIT_FROM_LANG "Fin du langage %s version %d.%d"
-#define MSG_FAIL_ADD_NODE "L'ajout du noeud %s dans la table a ‚chou‚"
-#define MSG_FETCHING_DATA "Recherche des donn‚es"
-#define MSG_FETCHING_ROWS "Recherche des lignes"
-#define MSG_FETCH_NO_RES "Fetch: Pas de R‚sultats"
-#define MSG_FIELD_TOO_LONG "Valeur trop longue pour le champs %d ligne %d"
-#define MSG_FILELEN_ERROR "Erreur dans %s pour %s"
-#define MSG_FILE_CLOSE_ERR "Erreur %d … la fermeture du fichier"
-#define MSG_FILE_IS_EMPTY "Le fichier %s est vide"
-#define MSG_FILE_MAP_ERR "Erreur de File mapping"
-#define MSG_FILE_MAP_ERROR "CreateFileMapping %s erreur rc=%d"
-#define MSG_FILE_NOT_FOUND "Fichier %s introuvable"
-#define MSG_FILE_OPEN_YET "Fichier %s d‚j… ouvert"
-#define MSG_FILE_UNFOUND "Fichier %s non trouv‚"
-#define MSG_FILGRP_NO_TABLE "Table %d manquante pour groupe filtre"
-#define MSG_FILTER_ATTACH "Filtre pass‚ … Attach"
-#define MSG_FILTER_NO_TABLE "Filtre: premiŠre table manquante"
-#define MSG_FIND_BAD_TYPE "Recherche dans un tableau: type non conforme %s %s"
-#define MSG_FIX_OVFLW_ADD "D‚passement de capacit‚ en addition"
-#define MSG_FIX_OVFLW_TIMES "D‚passement de capacit‚ en mutiplication"
-#define MSG_FIX_UNFLW_ADD "Sous d‚passement de capacit‚ en addition"
-#define MSG_FIX_UNFLW_TIMES "Sous d‚passement de capacit‚ en multiplication"
-#define MSG_FLD_TOO_LNG_FOR "Champs %d trop long pour %s ligne %d de %s"
-#define MSG_FLTST_NO_CORREL "FilTest ne devrait ˆtre appel‚ que pour les sous-requˆtes corr‚l‚es"
-#define MSG_FLT_BAD_RESULT "Virgule flottante: r‚sultat inexacte"
-#define MSG_FLT_DENORMAL_OP "Op‚rande virgule flottante non normalis‚"
-#define MSG_FLT_INVALID_OP "Op‚ration virgule flottante invalide"
-#define MSG_FLT_OVERFLOW "D‚passement de capacit‚ virgule flottante"
-#define MSG_FLT_STACK_CHECK "Virgule flottante: Erreur de la pile"
-#define MSG_FLT_UNDERFLOW "Sous-d‚passement de capacit‚ virgule flottante"
-#define MSG_FLT_ZERO_DIVIDE "Virgule flottante: division par z‚ro"
-#define MSG_FMT_WRITE_NIY "L'‚criture des fichiers %s n'est pas encore impl‚ment‚e"
-#define MSG_FNC_NOTIN_SLIST "Fonction de tri absente de la liste de s‚lection"
-#define MSG_FORMAT_ERROR "Erreur de formattage"
-#define MSG_FOXPRO_FILE "Fichier FoxPro: "
-#define MSG_FPUTS_ERROR "Erreur dans fputs: %s"
-#define MSG_FSBPARP_NULL "PUTFON: fsbparp est nul"
-#define MSG_FSEEK_ERROR "Erreur dans fseek: %s"
-#define MSG_FSETPOS_ERROR "Erreur dans fseek pour i=%d"
-#define MSG_FTELL_ERROR "Erreur dans ftell enregistrement=%d: %s"
-#define MSG_FUNCTION_ERROR "Erreur dans %s: %d"
-#define MSG_FUNC_ERRNO "Erreur %d dans %s"
-#define MSG_FUNC_ERROR "Erreur dans %s"
-#define MSG_FUNC_ERR_S "Erreur dans %s: %s"
-#define MSG_FUNC_REF_DEL "R‚f‚rence … une fonction d‚finie (rŠgle %d) qui a ‚t‚ supprim‚e"
-#define MSG_FWRITE_ERROR "Erreur dans fwrite: %s"
-#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
-#define MSG_GETFILESIZE_ERR "Erreur %d dans GetFileSize"
-#define MSG_GET_DIST_VALS "R‚cup‚ration des valeurs distinctes de "
-#define MSG_GET_ERROR "Erreur dans %s (colonne %d)"
-#define MSG_GET_FUNC_ERR "Erreur en recherche de la fonction %s: %s"
-#define MSG_GET_NAME_ERR "Erreur en retrouvant le nom d'une table SYS"
-#define MSG_GLOBAL_ERROR "Erreur d'allocation de Global (taille=%d)\n"
-#define MSG_GRAM_ALLOC_ERR "Erreur d'allocation dans Grammar Up"
-#define MSG_GRAM_MISMATCH "Avertissement: version de GRAMMAR p‚rim‚e (sauv‚ sous GRAMMAR v%u)"
-#define MSG_GRAM_SUBSET_ERR "Erreur d'initialisation du dictionnaire de la grammaire"
-#define MSG_GRBY_TAB_NOTIMP "Group by avec tables jointes non impl‚ment‚"
-#define MSG_GROUPBY_NOT_ALL "Group By doit inclure toutes les s‚lections non-fonctionnelles"
-#define MSG_GROUP_ON_FUNC "Group by invalide sur colonne fonctionnelle"
-#define MSG_GRP_COL_MISM "Disparit‚ colonne des groupes"
-#define MSG_GRP_LIST_MISMAT "Le groupement ne couvre pas la liste de s‚lection"
-#define MSG_GUARD_PAGE "Violation de page de garde"
-#define MSG_GZOPEN_ERROR "gzopen %s: erreur %d sur %s"
-#define MSG_GZPUTS_ERROR "Erreur dans gzputs: %s"
-#define MSG_HANDLE_IS_NULL "%s est NULL: erreur code: %d"
-#define MSG_HARRY_COMP_NIY "Compute non impl‚ment‚ pour les chaŒnes cod‚es"
-#define MSG_HAVING_FILTER "Traitement du Filtre Having"
-#define MSG_HBUF_TOO_SMALL "Buffer(%d) trop petit pour entˆte(%d)"
-#define MSG_HEAD_OPEN_ERROR "Erreur … l'ouverture du fichier header"
-#define MSG_HEAD_READ_ERROR "Erreur en lecture du fichier header %s"
-#define MSG_HEAD_WRITE_ERR "Erreur en ‚criture du fichier header"
-#define MSG_HI_OFFSET_ERR "Offset sup‚rieur non nul"
-#define MSG_HUGE_DEFAULT "Huge est %d par d‚fault"
-#define MSG_HUGE_WARNING_1 "M‚moire Huge non compatible 16-bit pour %d\n"
-#define MSG_HUGE_WARNING_2 "R‚sultats impr‚visibles possibles\n"
-#define MSG_IDLE "Au repos"
-#define MSG_ILLEGAL_INSTR "Instruction ill‚gale"
-#define MSG_ILL_FILTER_CONV "Conversion implicite ill‚gale dans un filtre"
-#define MSG_INDEX_CREATED "Index %s cr‚‚ sur %s"
-#define MSG_INDEX_DEF_ERR "Erreur sauvegardant l'index d‚finition pour %s"
-#define MSG_INDEX_DROPPED "Index %s supprim‚ de %s"
-#define MSG_INDEX_INIT_ERR "Echec de l'initialisation de l'index %s"
-#define MSG_INDEX_NOT_DEF "Index %s non d‚fini"
-#define MSG_INDEX_NOT_UNIQ "L'index n'est pas Unique"
-#define MSG_INDEX_ONE_SAVE "Les index sont sauvegard‚s dans un fichier unique"
-#define MSG_INDEX_SEP_SAVE "Les index sont sauvegard‚s dans des fichiers s‚par‚s"
-#define MSG_INDEX_YET_ON "L'index %s existe d‚j… sur %s"
-#define MSG_INDX_ALL_DROP "Tous les index de %s supprim‚s"
-#define MSG_INDX_COL_NOTIN "La colonne index %s n'existe pas dans la table %s"
-#define MSG_INDX_EXIST_YET "L'entr‚e index existe d‚j…"
-#define MSG_INIT_ERROR "Erreur à l'initialisation de %s"
-#define MSG_INIT_FAILED "L'initialisation de %s a ‚chou‚"
-#define MSG_INPUT "Entr‚e: "
-#define MSG_INPUT_KEYBD_YET "L'entr‚e est d‚j… au clavier"
-#define MSG_INSERTING "Insertion: "
-#define MSG_INSERT_ERROR "Insert erreur: usage multiple du fichier %s"
-#define MSG_INSERT_MISMATCH "Les listes colonne et valeur ne correspondent pas"
-#define MSG_INTERNAL "interne"
-#define MSG_INT_COL_ERROR "Erreur interne sur la colonne index %s"
-#define MSG_INT_OVERFLOW "D‚passement de capacit‚ sur entier"
-#define MSG_INT_ZERO_DIVIDE "Division entiŠre par z‚ro"
-#define MSG_INVALID_BIP "Bip invalide .%d"
-#define MSG_INVALID_DISP "Disposition invalide"
-#define MSG_INVALID_FTYPE "SBV: Ftype %d invalide"
-#define MSG_INVALID_HANDLE "Poign‚e invalide"
-#define MSG_INVALID_OPER "Op‚rateur invalide %d pour %s"
-#define MSG_INVALID_OPTION "Option invalide %s"
-#define MSG_INV_COLUMN_TYPE "Type %d Invalide pour la colonne %s"
-#define MSG_INV_COL_DATATYP "Type de donn‚es %d invalide pour la colonne %d"
-#define MSG_INV_COL_NUM "Colonne invalide %d"
-#define MSG_INV_COL_TYPE "Type de colonne %s invalide"
-#define MSG_INV_CONC_BIP "Bip invalide (seuls valides: %.8s.0 .1 and .5)"
-#define MSG_INV_DATA_PATH "Chemin vers les donn‚es invalide"
-#define MSG_INV_DEF_READ "Lecture diff‚r‚e invalide rc=%d"
-#define MSG_INV_DIRCOL_OFST "Offset invalide pour une colonne DIR"
-#define MSG_INV_DOMAIN_TYPE "Type invalide %d"
-#define MSG_INV_FILTER "Filtre r‚siduel dans %s"
-#define MSG_INV_FNC_BUFTYPE "FNC: Type %d de l'argument invalide pour %s"
-#define MSG_INV_INFO_TYPE "Type d'info catalog invalide %d"
-#define MSG_INV_INIPATH "Inipath invalide "
-#define MSG_INV_MAP_POS "Position m‚moire invalide"
-#define MSG_INV_OPERATOR "op‚rateur invalide %d\n"
-#define MSG_INV_PARAMETER "ParamŠtre invalide %s"
-#define MSG_INV_PARM_TYPE "Type de paramŠtre invalide"
-#define MSG_INV_QUALIFIER "Qalificateur '%s' invalide"
-#define MSG_INV_QUERY_TYPE "Type de requˆte %d invalide"
-#define MSG_INV_RAND_ACC "L'accŠs al‚atoire d'une table non optimis‚e est impossible"
-#define MSG_INV_REC_POS "Position d'enregistrement invalide"
-#define MSG_INV_RESULT_TYPE "Type de r‚sultat invalide %s"
-#define MSG_INV_SET_SUBTYPE "Type de formattage %d invalide"
-#define MSG_INV_SPECIAL_CMD "%s: Commande sp‚ciale invalide"
-#define MSG_INV_SUBTYPE "Sous type invalide %s"
-#define MSG_INV_TOK_DOMAIN "Le domaine %s n'existe pas"
-#define MSG_INV_TOPSEM_CMD "Commande TopSem invalide %c"
-#define MSG_INV_TRANSF_USE "Usage invalide en rŠgle transformationnelle"
-#define MSG_INV_TYPE_SPEC "Sp‚cification de type invalide (%.8s.%d)"
-#define MSG_INV_UPDT_TABLE "Table %s invalide pour Update"
-#define MSG_INV_VALUE_LIST "Liste de valeurs invalide pour Insert"
-#define MSG_INV_WHERE_JOIN "Clause Where invalide dans une requˆte de jointure"
-#define MSG_INV_WORK_PATH "Chemin de travail invalide"
-#define MSG_IN_ARGTYPE_MISM "Arguments de types incompatibles pour une expression IN"
-#define MSG_IN_USE " et en activit‚"
-#define MSG_IN_WITHOUT_SUB "IN ou EXISTS sans tableau ou subquery"
-#define MSG_IS_NOT_CONN "%s n'est pas une connexion d‚finie"
-#define MSG_JCT_MISS_COLS "Colonnes manquantes pour une table JCT"
-#define MSG_JCT_MISS_TABLE "Table jointe manquante pour JCT"
-#define MSG_JCT_NO_FILTER "Filtrage impossible des tables virtuelles JCT"
-#define MSG_JCT_NO_KEY "Erreur logique JCT: cl‚ manquante"
-#define MSG_JOIN_KEY_NO_COL "La cl‚ de jointure n'est pas une colonne"
-#define MSG_KEY_ALLOC_ERR "Erreur d'allocation d'un bloc offset cl‚"
-#define MSG_KEY_ALLOC_ERROR "Erreur d'allocation m‚moire, Klen=%d n=%d"
-#define MSG_LANGUAGE_QUIT "%s lib‚r‚"
-#define MSG_LANG_ACTIVE "Langage %s actif"
-#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Lang"
-#define MSG_LANG_ALREADY_UP "Langage d‚j… en ‚dition"
-#define MSG_LANG_BAD_SAVE "Langage %s peut-ˆtre incorrectement sauvegard‚"
-#define MSG_LANG_NOT_FREED "Langage %s non lib‚rable (pas dans la chaŒne principale)"
-#define MSG_LANG_SAVED "Langage %s sauvegard‚"
-#define MSG_LANG_WR_LEN_ERR "Erreur de longueur … l'‚criture du bloc Lang"
-#define MSG_LDF_ALLOC_ERROR "Erreur d'allocation d'un LdfBlock"
-#define MSG_LDF_RN_MISMATCH "LDF: d‚calage des num‚ros de rŠgle"
-#define MSG_LDF_WLEN_ERROR "Erreur de longueur en ‚crivant LdfData"
-#define MSG_LDF_W_LEN_ERROR "Erreur de longueur pour LdfData en ‚criture"
-#define MSG_LIC_NO_MYSQL "Votre licence actuelle ne permet pas l'utilisation du type MYSQL"
-#define MSG_LINEAR_ERROR "Erreur de lin‚arisation"
-#define MSG_LINE_LENGTH "Largeur d'impression fix‚e … %d"
-#define MSG_LINE_MAXLIN "Nombre de lignes de travail plafonn‚ … %d"
-#define MSG_LINE_MAXRES "Nombre de lignes de r‚sultat plafonn‚ … %d"
-#define MSG_LINE_MAXTMP "Nombre de lignes interm‚diaires plafonn‚ … %d"
-#define MSG_LINE_TOO_LONG "La nouvelle ligne est trop longue"
-#define MSG_LINJOINDB_ERROR "Erreur systŠme: appel incorrecte … LinJoinDB"
-#define MSG_LIST "--Liste--"
-#define MSG_LNG_NOT_IN_LIST "Le langage %s n'est pas dans la liste"
-#define MSG_LOADING_DB "Chargement description de la BD"
-#define MSG_LOADING_FAILED "Le chargement de %s a ‚chou‚"
-#define MSG_LOAD_CDLL_ERROR "Erreur au chargement de ConnDll: rc=%d"
-#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n trop grand ? (%d)\n"
-#define MSG_LOGICAL_ERROR "%s: Erreur logique"
-#define MSG_LRECL_TOO_SMALL "Lrecl trop petit (longueur en-tˆte = %d)"
-#define MSG_MAC_NO_DELETE "Pas de suppression de lignes pour les tables MAC"
-#define MSG_MAC_NO_INDEX "Pas d'accŠs direct aux tables MAC"
-#define MSG_MAC_READ_ONLY "Les tables MAC sont en lecture seulement"
-#define MSG_MAC_WIN_ONLY "Les tables MAC sont seulement sous Windows"
-#define MSG_MAKE_EMPTY_FILE "G‚n‚ration du fichier vide %s: %s"
-#define MSG_MAKING "G‚n‚ration"
-#define MSG_MAKING_DISTINCT "Regroupement des valeures distinctes"
-#define MSG_MALLOC_ERROR "Allocation m‚moire impossible par %s"
-#define MSG_MALLOC_NULL "malloc retourne Null"
-#define MSG_MAP_NO_MORE "Le type %s n'est plus support‚"
-#define MSG_MAP_OBJ_ERR "Erreur %d … la fermeture du map objet"
-#define MSG_MAP_VEC_ONLY "MAP Insert permis seulement pour les tables VEC Estimate"
-#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s erreur rc=%d"
-#define MSG_MAXSIZE_ERROR "Maxsize incalculable sur table ouverte"
-#define MSG_MAXTMP_TRUNCATE "R‚sultats interm‚diaires tronqu‚s par maxtmp=%d"
-#define MSG_MAX_BITMAP "Taille maxi des bitmaps d'optimisation fix‚e … %d"
-#define MSG_MEMSIZE_TOO_BIG "Erreur: memsize (%d) trop grand pour Length (%d)"
-#define MSG_MEM_ALLOC_ERR "Erreur d'allocation m‚moire, taille %s = %d"
-#define MSG_MEM_ALLOC_ERROR "Erreur d'allocation m‚moire"
-#define MSG_MEM_ALLOC_YET "M‚moire d‚j… allou‚e"
-#define MSG_METAFILE_NOTFND "Fichier Meta introuvable"
-#define MSG_MISPLACED_QUOTE "Appostrophe mal plac‚e ligne %d"
-#define MSG_MISSING "Manquant: Value=%p Argval=%p Builtin=%d"
-#define MSG_MISSING_ARG "Argument manquant pour l'op‚rateur %d"
-#define MSG_MISSING_COL_DEF "D‚finition des colonnes manquante"
-#define MSG_MISSING_CONNECT "Connection #1 manquante"
-#define MSG_MISSING_EOL "Fin de ligne manquante dans %s"
-#define MSG_MISSING_FIELD "Champs %d manquant dans %s ligne %d"
-#define MSG_MISSING_FNAME "Nom du fichier manquant"
-#define MSG_MISSING_NODE "Noeud %s manquant dans %s"
-#define MSG_MISSING_POS "POS code manquant"
-#define MSG_MISSING_ROWNODE "Impossible de trouver le noeud de la ligne %d"
-#define MSG_MISSING_SERV_DB "Indication serveur et/ou base de donn‚es manquante"
-#define MSG_MISS_LEAD_COL "Colonne majeure %s manquante"
-#define MSG_MISS_NAME_LRECL "Nom du fichier et/ou LRECL manquant"
-#define MSG_MISS_TABLE_LIST "Liste des tables manquante"
-#define MSG_MISS_VCT_ELMT "Taille de bloc vectoriel manquante (Elements)"
-#define MSG_MIS_TAG_LIST "Liste des balises colonne manquante"
-#define MSG_MKEMPTY_NIY "MakeEmptyFile: pas encore implement‚ pour Huge et Unix"
-#define MSG_MOVE_INV_TYPE "MOVPARM: paramŠtre de type invalide %d"
-#define MSG_MULT_DISTINCT "Distinct utilis‚ plus d'une fois"
-#define MSG_MULT_KEY_ERROR "Erreur sur cl‚ multiple k=%d n=%d"
-#define MSG_MUL_MAKECOL_ERR "Erreur logique dans TABMUL::MakeCol"
-#define MSG_MYSQL_CNC_OFF "La connexion … MySQL est ferm‚e"
-#define MSG_MYSQL_CNC_ON "La connexion … MySQL est ‚tablie"
-#define MSG_MYSQL_NOT_SUP "Pas de support de MySQL dans cette version"
-#define MSG_MY_CNC_ALREADY "La connexion … MySQL est d‚j… active"
-#define MSG_NAME_CONV_ERR "Erreur de convertion du nom de noeud"
-#define MSG_NAME_IS_USED "Le nom %s est d‚j… utilis‚"
-#define MSG_NCOL_GT_MAXCOL "Trop de colonnes (%d > %d max)"
-#define MSG_NEW_CHAR_NULL "new char(%d) retourne Null"
-#define MSG_NEW_DOC_FAILED "Impossible de cr‚er le nouveau document"
-#define MSG_NEW_RETURN_NULL "NULL renvoy‚ par New dans PlugEvalLike"
-#define MSG_NEW_TABLE_ERR "La nouvelle table %s ne peut pas ˆtre charg‚e"
-#define MSG_NEXT_FILE_ERROR "Erreur en recherche du fichier suivant. rc=%s"
-#define MSG_NODEF_FROM_VIEW "Pas de d‚finition de table depuis une view"
-#define MSG_NODE_FOR_CHAR "Noeud %s trouve au lieu d'un caractŠre"
-#define MSG_NODE_SUBSET_ERR "Erreur d'initialisation de la zone Noeud %d"
-#define MSG_NONCONT_EXCEPT "Exception non-continuable"
-#define MSG_NON_DUP_HAVING "Clause Having dans une requˆte non fonctionelle"
-#define MSG_NON_EVAL_SEM "Sem non ‚valu‚e: p_no=%d"
-#define MSG_NOP_ZLIB_INDEX "L'indexage d'une table zlib non optimis‚e est impossible"
-#define MSG_NOT_A_DBF_FILE "Le fichier n'a pas le format dBASE dbf "
-#define MSG_NOT_ENOUGH_COLS "Pas assez de colonnes dans %s"
-#define MSG_NOT_ENOUGH_MEM "M‚moire insuffisante pour cette op‚ration"
-#define MSG_NOT_FIXED_LEN "Fichier %s non fixe, len=%d lrecl=%d"
-#define MSG_NOT_IMPLEMENTED "Non implement‚: %.8s"
-#define MSG_NOT_IMPL_JOIN "Pas impl‚ment‚ pour les jointures"
-#define MSG_NOT_IMPL_SET "Pas impl‚ment‚ pour les op‚rateurs d'ensembles"
-#define MSG_NOT_IMPL_YET "Pas encore implement‚"
-#define MSG_NOT_LINEARIZED "Arborescence des tables non lin‚aris‚e"
-#define MSG_NOT_MODIFIABLE " (non modifiable)"
-#define MSG_NO_0DH_HEAD "0DH manquant en fin d'en-tˆte (dbc=%d)"
-#define MSG_NO_ACTIVE_APPL "Pas d'application active"
-#define MSG_NO_ACTIVE_DB "Pas de base de donn‚es active"
-#define MSG_NO_ACTIVE_UDIC "Pas de dictionaire utilisateur actif"
-#define MSG_NO_AGGR_FUNC "Fonction aggr‚g‚e %d ill‚gale … cet endroit"
-#define MSG_NO_AREA_FILE "Fichier Area introuvable"
-#define MSG_NO_AVAIL_RESULT "Pas de r‚sultat disponible"
-#define MSG_NO_BIG_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les fichiers HUGE"
-#define MSG_NO_CHAR_FROM "Conversion de type %d en caractŠres impossible"
-#define MSG_NO_CLUSTER_COL "Pas de colonne optimisable"
-#define MSG_NO_COL_ADDING "Ajouter des colonnes dans une d‚finition existante est impossible"
-#define MSG_NO_COL_DEF_AS "La d‚finitions des colonnes est incompatible avec AS Select"
-#define MSG_NO_COL_FOUND "La section colonne %s est vide"
-#define MSG_NO_COL_IN_TABLE "La colonne %d n'est pas dans la table %s"
-#define MSG_NO_COL_SECTION "Section colonne manquante pour la table %s"
-#define MSG_NO_CONNECT_ADDR "Adresse de connection non sp‚cifi‚e"
-#define MSG_NO_CONST_FILTER "Filtres constants non implement‚s"
-#define MSG_NO_CURLY_BRKT "Pas d'accolade de fermeture"
-#define MSG_NO_DATABASE "Base de donn‚es %s introuvable"
-#define MSG_NO_DATE_FMT "Pas de format date pour le valblock de type %d"
-#define MSG_NO_DBF_INSERT "Insert pas encore impl‚ment‚ pour les fichier DBF"
-#define MSG_NO_DEF_FNCCOL "Colonne fonction par d‚faut introuvable"
-#define MSG_NO_DEF_PIVOTCOL "Colonne pivot par d‚faut introuvable"
-#define MSG_NO_DIR_INDX_RD "Pas d'accŠs directe des tables %s"
-#define MSG_NO_DMY_DIR_ACC "Pas d'accŠs direct aux tables virtuelles DUMMY"
-#define MSG_NO_DOM_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les domaines"
-#define MSG_NO_DOM_MATCH "ChaŒne %.8s... non touv‚e dans le domaine %s"
-#define MSG_NO_EDITED_LANG "Coparm: Pas de langage en ‚dition"
-#define MSG_NO_EXP_LINK "Liaison par expression invalide pour une table JCT"
-#define MSG_NO_EXT_FILTER "Le filtrage ne peut se r‚f‚rer … une autre table"
-#define MSG_NO_EXT_UPDATE "Pas de mise … jour en r‚f‚rence … une autre table"
-#define MSG_NO_FEAT_SUPPORT "%s non support‚ dans cette version"
-#define MSG_NO_FILE_LIST "La table %s n'a pas de liste de fichiers"
-#define MSG_NO_FLD_FORMAT "Format absent pour le champs %d de %s"
-#define MSG_NO_FORMAT_COL "Type COLUMN informattable"
-#define MSG_NO_FORMAT_TYPE "Le format ne peut pas ˆtre d‚fini … partir du type %d"
-#define MSG_NO_FULL_JOIN "Jointures autoris‚es seulement … ‚galit‚ sur cl‚(s)"
-#define MSG_NO_FUL_OUT_JOIN "Jointures externes complŠtes non support‚es"
-#define MSG_NO_FUNC_ORDER "Tri non support‚ sur ‚l‚ment fonctionnel"
-#define MSG_NO_HEAD_JOIN "Jointure sur une table non en tˆte"
-#define MSG_NO_HQL_CONV "Conversion en HQL non disponible"
-#define MSG_NO_INDEX "La table %s n'a pas d'index"
-#define MSG_NO_INDEX_GBX "Pas ou mauvais index pour SQLGBX"
-#define MSG_NO_INDEX_IN "Pas d'index dans %s"
-#define MSG_NO_INDEX_READ "Pas d'accŠs directe des tables multiples"
-#define MSG_NO_INIT_LANG "Pas de langage initial"
-#define MSG_NO_JOIN_TO_EXP "Jointure vers une expression impossible"
-#define MSG_NO_JOIN_UPDEL "Pas de jointure avec Update/Delete"
-#define MSG_NO_KEY_COL "Pas de colonne cl‚ trouv‚e"
-#define MSG_NO_KEY_UPDATE "Le nom des cl‚s ne peut pas ˆtre modifi‚"
-#define MSG_NO_LANGUAGE "Pas de langage op‚rationnel\n"
-#define MSG_NO_LANG_TO_QUIT "Pas de langage … quitter"
-#define MSG_NO_LISTVAL_HERE "LSTBLK: Liste de valeurs utilis‚e hors contexte"
-#define MSG_NO_MAP_INSERT "MAP incompatible avec Insert"
-#define MSG_NO_MATCHING_COL "Pas de colonne correspondant … %s dans %s"
-#define MSG_NO_MATCH_COL "Colonne correspondante introuvable"
-#define MSG_NO_MEMORY "M‚moire pleine"
-#define MSG_NO_MEM_CORR_SUB "Subquery corr‚l‚e en m‚moire non encore impl‚ment‚e"
-#define MSG_NO_MODE_PADDED "Mode non support‚ pour les fichiers 'padded'"
-#define MSG_NO_MORE_COL "La colonne %s n'est plus dans la table pivot"
-#define MSG_NO_MORE_LANG "Plus de langage, exit de %s\n"
-#define MSG_NO_MORE_VAR "Les fichiers VAR ne sont plus support‚s"
-#define MSG_NO_MULCOL_JOIN "Jointure vers un index multi-colonne pas encore possible"
-#define MSG_NO_MULT_HAVING "Clauses Having multiples non impl‚ment‚es"
-#define MSG_NO_MUL_DIR_ACC "AccŠs direct des tables multiples pas encore impl‚ment‚"
-#define MSG_NO_MUL_VCT "Les tables VCT ne peuvent pas ˆtre multiples"
-#define MSG_NO_MYSQL_CONN "Aucune connexion MySQL ouverte"
-#define MSG_NO_MYSQL_DELETE "Pas de Delete pour les tables MySQL"
-#define MSG_NO_NBCOL "Pas de NBcol"
-#define MSG_NO_NBLIN "Pas de NBlin, MaxSize ou Continued"
-#define MSG_NO_NBLIN_CONT "Fetch: Pas de NBlin ou Continued"
-#define MSG_NO_NULL_CONST "Les constantes <null> ne sont pas prises en charge"
-#define MSG_NO_ODBC_COL "Colonnes ODBC automatiques non support‚es par cette version"
-#define MSG_NO_ODBC_DELETE "Delete ne devrait pas ˆtre appel‚ pour les tables ODBC"
-#define MSG_NO_ODBC_DIRECT "AccŠs directe des tables ODBC non encore impl‚ment‚"
-#define MSG_NO_ODBC_MUL "Multiple(2) non support‚ pour les tables ODBC"
-#define MSG_NO_ODBC_SPECOL "Pas de colonne sp‚ciale ODBC"
-#define MSG_NO_OPT_COLUMN "Pas optimisable ou pas de colonne optimis‚es"
-#define MSG_NO_OP_MODIF "Les modificateurs ne s'appliquent pas … %s"
-#define MSG_NO_PARAMETER "Pas de paramŠtre"
-#define MSG_NO_PART_DEL "Delete partiel des fichier %s impossible"
-#define MSG_NO_PART_MAP "Mapping partiel non impl‚ment‚ pour cet OS"
-#define MSG_NO_PAR_BLK_INS "Insertion de bloc partiel impossible"
-#define MSG_NO_PIV_DIR_ACC "Pas d'accŠs directe aux tables PIVOT"
-#define MSG_NO_POS_ADDED "Pos_code non ajout‚"
-#define MSG_NO_PROMPTING "Relance impossible pour les tables distribu‚es"
-#define MSG_NO_QRY_DELETE "Delete n'est pas utilisable pour les views QRY"
-#define MSG_NO_QUERY_ARRAY "Tableaux avec QUERY non encore impl‚ment‚s"
-#define MSG_NO_RCUR_DSK_YET "Usage r‚cursif de DISK non encore implement‚"
-#define MSG_NO_READ_32 "Lecture de 32 octets impossible"
-#define MSG_NO_RECOV_SPACE "Espace non recouvrable dans le fichier index"
-#define MSG_NO_REF_DELETE "Pas de suppression en r‚f‚rence … une autre table"
-#define MSG_NO_REF_UPDATE "Pas de mise … jour en r‚f‚rence … une autre table"
-#define MSG_NO_REMOTE_FNC "Certaines fonctions ne peuvent pas ˆtre ex‚cut‚es … distance"
-#define MSG_NO_ROWID_FOR_AM "AccŠs direct impossible de ROWID pour les tables de type %s"
-#define MSG_NO_ROW_NODE "Le nom du Rownode n'est pas d‚fini"
-#define MSG_NO_SECTION_NAME "Nom de section manquant"
-#define MSG_NO_SEC_UPDATE "Les noms de section ne peuvent pas ˆtre modifi‚s"
-#define MSG_NO_SELECTED_DB "Aucune base de donn‚es s‚lect‚e"
-#define MSG_NO_SELF_PIVOT "Une table ne peut se pivoter elle-mˆme !"
-#define MSG_NO_SERVER_FOUND "Serveur introuvable"
-#define MSG_NO_SETPOS_YET "SetPos pas encore impl‚ment‚ pour les fichier %s"
-#define MSG_NO_SFEXIT_UNIX "Fonction %s non disponible sur Unix"
-#define MSG_NO_SOURCE " (pas de source)"
-#define MSG_NO_SPEC_COL "Pas de colonne sp‚ciales MYSQL"
-#define MSG_NO_SQL_DELETE "Delete n'est pas utilisable actuellement pour les views SQL"
-#define MSG_NO_SUB_VAL "Pas de sous-value d'un tableau de type %d"
-#define MSG_NO_SUCH_INDEX "La table %s n'a pas l'index %s"
-#define MSG_NO_SUCH_SERVER "Serveur %s introuvable"
-#define MSG_NO_SUCH_TABLE "Table %s pas dans la base de donn‚es"
-#define MSG_NO_TABCOL_DATA "Pas de donn‚es pour la table %s colonne %s"
-#define MSG_NO_TABLE_COL "Aucune colonne trouv‚e pour %s"
-#define MSG_NO_TABLE_DEL "Delete non autoris‚ pour les tables %s "
-#define MSG_NO_TABLE_DESC "Pas de bloc descriptif de table"
-#define MSG_NO_TABLE_INDEX "La table %s n'a pas d'index"
-#define MSG_NO_TABLE_LIST "Pas de liste de tables"
-#define MSG_NO_TAB_DATA "Pas de donn‚es pour la table %s"
-#define MSG_NO_TERM_IN_TOK "Les non-terminaux ne sont pas utilisables dans les rŠgles de Token"
-#define MSG_NO_TOKEN_DB "DB introuvable pour la colonne TOKEN %s"
-#define MSG_NO_UNIX_CATINFO "Pas d'info catalogue sous Unix"
-#define MSG_NO_UPDEL_JOIN "Pas de jointure de tables ODBC pour Update/Delete"
-#define MSG_NO_VCT_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les fichiers VCT"
-#define MSG_NO_VIEW_COLDEF "Colonne d‚finition impossible pour les views"
-#define MSG_NO_VIEW_SORT "La View fonctionnelle %s ne peut pas ˆtre tri‚e ou jointe"
-#define MSG_NO_ZIP_DELETE "Delete sur fichier Zip non encore implement‚"
-#define MSG_NO_ZIP_DIR_ACC "AccŠs directe des tables ZDOS non encore implement‚"
-#define MSG_NULL_COL_VALUE "La colonne n'a pas de valeur"
-#define MSG_NULL_ENTRY "InitLang, entr‚e nulle %d %s"
-#define MSG_NULL_QUERY "Requˆte vide"
-#define MSG_NUMVAL_NOMATCH "Disparit‚ de Numval pour %s"
-#define MSG_N_FULL_PARSES "%d significations"
-#define MSG_ODBC_READ_ONLY "ODBC est actuellement en lecture seulement"
-#define MSG_OFFSET_NOT_SUPP "Offset non support‚ pour ce type de sous requˆte"
-#define MSG_ONE_LANG_YET "Un langage est d‚j… en ‚dition"
-#define MSG_ONE_PARAM_ONLY "Un seul paramŠtre autoris‚"
-#define MSG_ONLY_LOG10_IMPL "Seul Log10 est implement‚"
-#define MSG_ON_LANGUAGE "Langage %.8s version %d niveau %d ‚ditable"
-#define MSG_OPENING "Ouverture"
-#define MSG_OPENING_QUERY "Ouverture de la requˆte"
-#define MSG_OPEN_EMPTY_FILE "Ouverture du fichier vide %s: %s"
-#define MSG_OPEN_ERROR "Erreur d'ouverture %d en mode %d sur %s: "
-#define MSG_OPEN_ERROR_IS "Erreur … l'ouverture de %s: %s"
-#define MSG_OPEN_ERROR_ON "Erreur d'ouverture sur %s"
-#define MSG_OPEN_MODE_ERROR "Erreur d'ouverture(%s) %d sur %s"
-#define MSG_OPEN_SORT_ERROR "Erreur logique de tri dans QUERY Open"
-#define MSG_OPEN_STRERROR "Erreur … l'ouverture: %s"
-#define MSG_OPEN_W_ERROR "Erreur … l'ouverture de %s en ‚criture"
-#define MSG_OPTBLK_RD_ERR "Erreur … la lecture d'un bloc optimisation: %s"
-#define MSG_OPTBLK_WR_ERR "Erreur … l'‚criture d'un bloc optimisation: %s"
-#define MSG_OPTIMIZING "Optimisation de "
-#define MSG_OPT_BMAP_RD_ERR "Erreur en lecture des bitmaps d'optimisation: %s"
-#define MSG_OPT_BMAP_WR_ERR "Erreur en ‚criture des bitmaps d'optimisation: %s"
-#define MSG_OPT_CANCELLED "Optimisation interrompue par l'utilisateur"
-#define MSG_OPT_DVAL_RD_ERR "Erreur en lecture des valeurs distinctes: %s"
-#define MSG_OPT_DVAL_WR_ERR "Erreur en ‚criture des valeurs distinctes: %s"
-#define MSG_OPT_HEAD_RD_ERR "Erreur en lecture de l'entˆte du fichier opt: %s"
-#define MSG_OPT_HEAD_WR_ERR "Erreur en ‚criture de l'entˆte du fichier opt: %s"
-#define MSG_OPT_INIT "Optimisation initialis‚e"
-#define MSG_OPT_LOGIC_ERR "Erreur logique dans SetBitmap, i=%d"
-#define MSG_OPT_MAX_RD_ERR "Erreur en lecture des valeurs maxi: %s"
-#define MSG_OPT_MAX_WR_ERR "Erreur en ‚criture des valeurs maxi: %s"
-#define MSG_OPT_MIN_RD_ERR "Erreur en lecture des valeurs mini: %s"
-#define MSG_OPT_MIN_WR_ERR "Erreur en ‚criture des valeurs mini: %s"
-#define MSG_OPT_NOT_MATCH "Le fichier opt %s n'est pas … jour"
-#define MSG_OP_RES_TOO_LONG "R‚sultat trop long pour l'op‚rateur=%d"
-#define MSG_ORDER_OUT_RANGE "Tri: Order %d hors limite"
-#define MSG_ORDER_TWICE "Un mˆme ‚l‚ment est tri‚ deux fois"
-#define MSG_PAGE_ERROR "Erreur de pagination"
-#define MSG_PARM_CNT_MISS "Disparit‚ du nombre de ParamŠtres"
-#define MSG_PARSE_NULL_SEM "S‚mantique nulle"
-#define MSG_PARSING_QUERY "Analyse de la requˆte"
-#define MSG_PIX_ERROR "Pix %s erreur rŠgle no=%u\n"
-#define MSG_PIX_TEST_ERROR "RŠgle=%u: pix-TEST pas dans le premier noeud\n"
-#define MSG_PLG_READ_ONLY "PLG est actuellement en lecture seulement"
-#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp est NULL"
-#define MSG_PLUG_NOT_INIT "Plug n'est pas initialis‚\n"
-#define MSG_PLUG_NOT_RUN "Plug n'est pas en marche"
-#define MSG_PNODE_RULE "(Noeud %d rŠgle %d) "
-#define MSG_POS_TOO_LONG "%s trop long (>%d)"
-#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp est NULL"
-#define MSG_PRIV_INSTR "Instruction privil‚gi‚e"
-#define MSG_PROCADD_ERROR "Erreur %d sur l'adresse de %s"
-#define MSG_PROCESS_SUBQRY "Sub-Query en cours de traitement"
-#define MSG_PROC_WOULD_LOOP "Bouclage du traitement (maxres=%d maxlin=%d)"
-#define MSG_PROGRESS_INFO "Informations sur le traitement en cours"
-#define MSG_PROMPT_CANCEL "Relance annul‚e"
-#define MSG_PROMPT_NIY "Prompt non impl‚ment‚ pour cette configuration"
-#define MSG_PTR_NOT_FOUND "Pointeur introuvable Num=%d ti1=%d"
-#define MSG_PXDEF_IS_NULL "Pxdef est NULL"
-#define MSG_QRY_READ_ONLY "Les views QRY sont en lecture seulement"
-#define MSG_QUERY_CANCELLED "Requˆte interrompue par l'utilisateur"
-#define MSG_QUERY_NOT_EXEC "Requˆte non ex‚cut‚e"
-#define MSG_QUERY_SAVED "Requˆte %s sauvegard‚e"
-#define MSG_QUOTE_IN_QUOTE "Appostrophe dans un champ entre appostrophe ligne %d"
-#define MSG_RANGE_NIY "Range pas encore impl‚ment‚ pour %s"
-#define MSG_RANGE_NO_JOIN "Range non compatible avec les index de jointure"
-#define MSG_RC_READING "rc=%d en lecture de la table %s"
-#define MSG_READB_BAD_INIT "%s ReadDB appel‚ avec Init=0"
-#define MSG_READCOL_ERROR "SQLCOL: erreur dans ReadColumn"
-#define MSG_READING "Lecture"
-#define MSG_READING_FROM "Lecture de %s"
-#define MSG_READING_RECORD "Erreur en lecture de l'enregistrement %d de %s"
-#define MSG_READY "Prˆt"
-#define MSG_READ_ERROR "Erreur en lecture sur %s: %s"
-#define MSG_READ_ERROR_RC "Erreur en lecture, rc=%d"
-#define MSG_READ_MEM_ERROR "Lecture m‚moire %d: taille=%d"
-#define MSG_READ_ONLY "Cette table prot‚g‚e en lecture seule ne peut ˆtre modifi‚e"
-#define MSG_READ_SEEK_ERROR "Erreur de recherche en lecture: %s"
-#define MSG_READ_SEG_ERROR "Lecture segment %d: taille=%d"
-#define MSG_RECEIVED "Re‡u %c\n"
-#define MSG_RECORD_ERROR "Erreur … la lecture de l'enregistrement %d de %s"
-#define MSG_RECORD_NO_SEP "Enregistrement sans s‚parateur"
-#define MSG_REC_SKIPPED " (%d lignes erronn‚es saut‚es par l'option MaxErr)"
-#define MSG_REDUCE_INDEX "Réduction de l'index"
-#define MSG_REGISTER_ERR "Enregistrement NS impossible, pr‚fix='%s' et href='%s'"
-#define MSG_REMOTE_CONN_ERR "La connection ‚loign‚e a ‚chou‚"
-#define MSG_REMOVE_ERROR "Erreur en supprimant %s: %s"
-#define MSG_REMOVE_NOT_IMPL "Remove non impl‚ment‚ pour TDB non Table"
-#define MSG_RENAME_ERROR "Erreur renommant %s en %s: %s"
-#define MSG_RENUM_RULES "Renum‚rotez les rŠgles et r‚entrez ADD (rŠgle sauvegard‚e dans la zone tampon)"
-#define MSG_REORDER_INDEX "Reclassement de l'index"
-#define MSG_REQU_ARG_NUM "La fonction %s doit avoir %d arguments"
-#define MSG_RESET_TO "%s remis … %d"
-#define MSG_RES_NOT_UNIQUE "Le r‚sultat n'est pas unique"
-#define MSG_RET_FROM_LANG "Retour au language %s version %d.%d du language %s version %d.%d"
-#define MSG_ROWID_NOT_IMPL "RowNumber non impl‚ment‚ pour les tables de type %s"
-#define MSG_ROWS_SELECTED "%d lignes s‚lectionn‚es en %.2lf sec"
-#define MSG_ROWS_TRUNCATED " (tronqu‚ par MAXRES, LIMIT, FREQ ou AreaSize)"
-#define MSG_ROW_ARGNB_ERR "ROW: disparit‚ du nombre d'arguments (%d,%d)"
-#define MSG_RPC_SERVER_ERR "Erreur logique dans TABMUL::MakeCol"
-#define MSG_RSC_ALLOC_ERROR "Erreur d'allocation m‚moire dans Rescol %s"
-#define MSG_RULE_ENTERED "RŠgle %d entr‚e"
-#define MSG_RULE_SUBSET_ERR "Erreur d'initialisation de la zone RŠgles"
-#define MSG_SAVING_INDEX "Sauvegarde du fichier index"
-#define MSG_SCAN_NOT_IMP "Scan non impl‚ment‚"
-#define MSG_SEC_KEY_FIRST "Les sections et cl‚s doivent ˆtre ins‚r‚es en premier"
-#define MSG_SEC_NAME_FIRST "Le nom de section doit ˆtre en tˆte de liste en insertion"
-#define MSG_SEC_NOT_FOUND "Section %s absente de %s"
-#define MSG_SEEK_ERROR "Seek erreur dans CopyHeader"
-#define MSG_SEMANTIC_TREE "Arbre s‚mantique"
-#define MSG_SEM_BAD_REF "Sem @%d r‚f‚rence un argument de type non 0 ou 1"
-#define MSG_SEM_UNKNOWN "inconnue, rc=%d"
-#define MSG_SEP_IN_FIELD "Le champ %d contient le caractŠre s‚parateur"
-#define MSG_SEQUENCE_ERROR "HSTMT: Allocation hors s‚quence"
-#define MSG_SETEOF_ERROR "Erreur %d dans SetEndOfFile"
-#define MSG_SETRECPOS_NIY "SetRecpos non impl‚ment‚ pour ce type de table"
-#define MSG_SET_LOCALE "Locale fix‚e … %s"
-#define MSG_SET_NULL_DOM "Valeur %d donn‚e … un domaine nul"
-#define MSG_SET_OP_NOT_IMPL "Op‚rateurs ensemblistes non impl‚ment‚s"
-#define MSG_SET_STR_TRUNC "SetValue: ChaŒne de caractŠres tronqu‚e"
-#define MSG_SEVERAL_TREES "Jointure non sp‚cifi‚e pour certaines tables"
-#define MSG_SFP_ERROR "Erreur sur SetFilePointer: %s"
-#define MSG_SFUNC_NOT_IMPL "Fonction scalaire %s non impl‚ment‚e"
-#define MSG_SHARED_LIB_ERR "Erreur au chargement de la librairie partag‚e %s: %s"
-#define MSG_SINGLE_STEP "Pas … pas"
-#define MSG_SLEEP "J'ai dormi %d milliseconds"
-#define MSG_SMART_SORTING "R‚cup‚ration des lignes tri‚es (passage %d de %d)"
-#define MSG_SMART_SORT_ERR "Erreur logique 1 dans Smart Sort"
-#define MSG_SORTING "Tri en cours"
-#define MSG_SORTING_INDEX "Tri de l'index"
-#define MSG_SORTING_VAL "Tri de %d valeurs"
-#define MSG_SORT_JOIN_INDEX "Tri de l'index de jointure"
-#define MSG_SPCOL_READONLY "La colonne sp‚ciale %s est en lecture seulement"
-#define MSG_SPEC_CMD_SEP "Les commandes sp‚ciales doivent ˆtre ex‚cut‚es s‚par‚ment"
-#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d non support‚"
-#define MSG_SQL_BLOCK_MISM "CheckColumn: bloc SQL courant non correspondant"
-#define MSG_SQL_CONF_ERROR "Erreur SQL: SQL_CONFORMANCE"
-#define MSG_SQL_READ_ONLY "Les views SQL sont actuellement en lecture seulement"
-#define MSG_SRCH_CLOSE_ERR "Erreur … la fermeture de l'Handle de recherche"
-#define MSG_SRC_TABLE_UNDEF "La table source n'est pas d‚finie"
-#define MSG_STACK_ERROR "Erreur sur la pile, i=%d\n"
-#define MSG_STACK_OVERFLOW "Parser: D‚bordement de la pile\n"
-#define MSG_STRG_NOT_FOUND "ChaŒne introuvable"
-#define MSG_STRING_INV_LIST "Liste invalide pour SemString"
-#define MSG_STRING_TOO_BIG "ChaŒne trop grande pour le domaine %s"
-#define MSG_SUBALLOC_ERROR "Pas assez de m‚moire en zone %p pour allouer %d (utilis‚=%d libre=%d)"
-#define MSG_SUBAL_HUGE_ERR "Pas assez de m‚moire en zone huge %p pour allouer %d"
-#define MSG_SUBARG_NOSEM "Argument @ ou sous-phrase de niveau %d pointe sur un noeud sans Sem"
-#define MSG_SUBARG_OUTRANGE "Argument @ ou sous-phrase de niveau %d hors limite"
-#define MSG_SUBQRY_ONEITEM "Une Sub-Query ne doit avoir qu'une s‚lection"
-#define MSG_SUBSET_ERROR "SubSet erreur dans LoadDB"
-#define MSG_SUB_OPEN_YET "Subquery d‚j… ouverte"
-#define MSG_SUB_RES_TOO_LNG "R‚sultat trop long pour SUBSTR"
-#define MSG_SYNTAX_ERROR "Erreur de syntaxe"
-#define MSG_SYSTEM_ERROR "Erreur systŠme %d"
-#define MSG_S_ACCESS_DENIED "%s: accŠs non autoris‚"
-#define MSG_S_ERROR "%s erreur"
-#define MSG_S_ERROR_NUM "%s: erreur=%d"
-#define MSG_S_INTRUPT_ERROR "%s: erreur interruption"
-#define MSG_S_INVALID_PARM "%s: paramŠtre invalide"
-#define MSG_S_INV_ADDRESS "%s: adresse invalide"
-#define MSG_S_UNKNOWN_ERROR "%s: erreur de code %u inconnu"
-#define MSG_TABDIR_READONLY "Les tables DIR sont en lecture seulement"
-#define MSG_TABLE_ALREADY "La table %s existe d‚j…"
-#define MSG_TABLE_ALTERED "Table %s %s alt‚r‚e"
-#define MSG_TABLE_CREATED "%s table %s cr‚‚e"
-#define MSG_TABLE_DROPPED "Table %s supprim‚e"
-#define MSG_TABLE_MULT_JOIN "Utilisation multiple de la table %s pour jointure"
-#define MSG_TABLE_NOT_IN_DB "La table %s n'existe pas dans %s"
-#define MSG_TABLE_NOT_OPT "Table non optimisable"
-#define MSG_TABLE_NO_INDEX "La table %s n'est pas indexable"
-#define MSG_TABLE_NO_OPT "La table %s n'existe pas ou de type non optimisable"
-#define MSG_TABLE_READ_ONLY "Les tables %s sont en lecture seulement "
-#define MSG_TABMUL_READONLY "Les tables multiples sont en lecture seulement"
-#define MSG_TAB_NOT_LOADED " (certaines tables n'ont put ˆtre charg‚es)"
-#define MSG_TAB_NOT_SPEC "Table non specifi‚e"
-#define MSG_TB_VW_NOTIN_DB "Table ou view %s pas dans la base de donn‚es"
-#define MSG_TDB_NXT_NOT_NUL "Tdb.Next non NULL"
-#define MSG_TDB_USE_ERROR "Erreur, Tdbp->Use=%d"
-#define MSG_TOO_MANY_COLS "Trop de colonnes"
-#define MSG_TOO_MANY_COLTAB "Trop de colonnes dans %s (%d)"
-#define MSG_TOO_MANY_FIELDS "Trop de champs ligne %d de %s"
-#define MSG_TOO_MANY_JUMPS "Trop de niveaux de saut"
-#define MSG_TOO_MANY_KEYS "Trop de cl‚s (%d)"
-#define MSG_TOO_MANY_POS "Trop de pos_codes"
-#define MSG_TOO_MANY_TABLES "Trop de tables (%d)"
-#define MSG_TOPSEM_ERROR "Erreur inconnue dans TopSem"
-#define MSG_TO_BLK_IS_NULL "To Blk est nul"
-#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr n'est pas nul"
-#define MSG_TO_PIX_NOT_NULL "Set.To_Pix n'est pas nul"
-#define MSG_TO_SEM_NOT_NULL "Set.To_Sem n'est pas nul"
-#define MSG_TRUNCATE_ERROR "Erreur en troncation: %s"
-#define MSG_TRUNC_BY_ESTIM "Tronqu‚ par l'option Estimate"
-#define MSG_TYPES_ERROR "Erreur sur Types(%d)"
-#define MSG_TYPE_CONV_ERROR "Type non convertible dans une expression"
-#define MSG_TYPE_DEF_MISM "Disparit‚ entre type et d‚finition"
-#define MSG_TYPE_MISMATCH "Cl‚ et source ne sont pas du mˆme type"
-#define MSG_TYPE_RECFM_MISM "Disparit‚ entre Type et Recfm"
-#define MSG_TYPE_TO_VERIFY "Type … v‚rifier: %d"
-#define MSG_TYPE_VALUE_ERR "Colonne %s: disparit‚ type(%s)/valeur(%s)"
-#define MSG_UNBALANCE_QUOTE "Appostrophe en trop ligne %d"
-#define MSG_UNDEFINED_AM "COLBLK %s: m‚thode d'accŠs ind‚finie"
-#define MSG_UNDEFINED_PATH "Chemin d'accŠs ind‚fini pour Plgcnx.ini"
-#define MSG_UNDEF_COL_COUNT "Count sur colonne non d‚finie"
-#define MSG_UNKNOWN_DOMAIN "Domaine inconnu %s"
-#define MSG_UNKNOWN_ERROR "Erreur inconnue"
-#define MSG_UNKNOWN_EXCPT "Exception non r‚pertori‚e"
-#define MSG_UNKNOWN_NAME "Nom inconnu: %.8s"
-#define MSG_UNKNOWN_PATH "Chemin d'accŠs inconnu pour Plgcnx.ini"
-#define MSG_UNKNOWN_POS "Nom pos_code inconnu: %s"
-#define MSG_UNKNOWN_SEM "Sem %.8s inconnue, rc=%d"
-#define MSG_UNKNOWN_SYNONYM "Synonyme inconnu"
-#define MSG_UNKNW_QRY_TYPE "ReadDB: type de requˆte inconnu"
-#define MSG_UNKN_ERR_CODE "Erreur de code %d inconnu"
-#define MSG_UNLOADABLE " inchargeable: "
-#define MSG_UNLOADABLE_PRM "%s inchargeable: %s"
-#define MSG_UNMATCH_FIL_ARG "Argument de filtre d‚pareill‚"
-#define MSG_UNQ_COL_SEV_TAB "La colonne %s non qualifi‚e est dans plusieurs tables"
-#define MSG_UNRESOLVED_ARG "?Argument manquant: %s non r‚solu en %d ligne %d"
-#define MSG_UPDATE_ERROR "Erreur en Update sur %s"
-#define MSG_UPDATING_ROWS "Mise … jour des lignes"
-#define MSG_UPD_ZIP_NOT_IMP "Mise … jour des tables ZDOS non encore implement‚"
-#define MSG_UP_LANGUAGE "Bloc langage %.8s version %d niveau %d charg‚"
-#define MSG_USED_FREE_MEM "Sarea: utilis‚ %d, libre %d"
-#define MSG_USETEMP_IS "Usetemp est : %s"
-#define MSG_USETEMP_RESET ". Usetemp remis … Auto"
-#define MSG_USETEMP_SET "Usetemp fix‚ … %s"
-#define MSG_USE_NO_MATCH "Use non correspondant : Use=%d, ti2=%d, ti3=%d"
-#define MSG_USING_INDEX " (Index‚ par"
-#define MSG_VALIST_MISMATCH "Disparit‚ des listes de valeurs"
-#define MSG_VALSTR_TOO_LONG "Valeur %s trop longue pour une chaŒne de longueur %d"
-#define MSG_VALTYPE_NOMATCH "Disparit‚ types de valeur"
-#define MSG_VALUE_ERROR "Colonne %s: bloc valeur nul"
-#define MSG_VALUE_NOT_ALLOC "Valeur non allou‚e pour la colonne R%d %s"
-#define MSG_VALUE_TOO_BIG "Valeur %lld trop grande pour la colonne %s"
-#define MSG_VALUE_TOO_LONG "Valeur %s trop longue pour la colonne %s de longueur %d"
-#define MSG_VAL_ALLOC_ERR "Allocation impossible du noeud valeur"
-#define MSG_VAL_TOO_LONG "Valeur %s trop longue pour le champ %s"
-#define MSG_VIEW_ALREADY "La VIEW %s existe d‚j…"
-#define MSG_VIEW_CREATED "%s view %s cr‚‚e"
-#define MSG_VIEW_DROPPED "View %s supprim‚e"
-#define MSG_VIEW_NOT_IN_DB "%s n'est pas une View de %s"
-#define MSG_VIR_NO_DELETE "Delete impossible sur les tables %s"
-#define MSG_VIR_READ_ONLY "Les tables virtuelles %s sont en lecture seulement"
-#define MSG_VM_LANG "Langage au format VM, non support‚"
-#define MSG_VOID_FIRST_ARG "Le premier argument ne doit pas ˆtre vide"
-#define MSG_VOID_IN_STRING "Erreur: chaŒne IN vide"
-#define MSG_VOID_ORDER_LIST "Liste de tri vide, erreur systŠme ?"
-#define MSG_VOID_POS_DICT "Dictionnaire interne du langage vide"
-#define MSG_VOID_QUERY "Requˆte vide %s"
-#define MSG_WORK_AREA "Espace de travail: %s"
-#define MSG_WORK_TOO_SMALL "Zone de travail trop petite, accroŒtre AreaSize"
-#define MSG_WRITE_ERROR "Erreur … l'‚criture de %s"
-#define MSG_WRITE_SEEK_ERR "Erreur de recherche en ‚criture: %s"
-#define MSG_WRITE_STRERROR "Erreur en ‚criture sur %s: %s"
-#define MSG_WRITING "Ecriture"
-#define MSG_WRITING_ERROR "Erreur … l'‚criture de %s: %s"
-#define MSG_WRITING_QUERY "Erreur … l'‚criture de la requˆte: "
-#define MSG_WRONG_ARG_NUM "La fonction %s ne prend pas %d arguments"
-#define MSG_WRONG_COL_NUM "Num‚ro de colonne %d trop grand pour %s"
-#define MSG_WRONG_DB_LIST "Liste des bases de donn‚es incorrecte ou vide"
-#define MSG_WRONG_FUNCTION "Mauvaise fonction %d"
-#define MSG_WRONG_OP_PARM "Mauvais op‚rateur ou paramŠtres pour %s"
-#define MSG_WRONG_PARMS "Mauvais paramŠtres pour %s"
-#define MSG_WRONG_PASSWORD "Mot de passe ill‚gal pour %s"
-#define MSG_WRONG_TYPE "type non support‚"
-#define MSG_WRONG_USERFILE "La Userfile a une mauvaise taille %d"
-#define MSG_WS_CONV_ERR "Erreur de convertion de %s en WS"
-#define MSG_XCOL_MISMATCH "La colonne %s ne correspond pas … l'index"
-#define MSG_XDB_DEL_ERROR "Erreur en supprimant des entr‚es du fichier XDB"
-#define MSG_XFILE_READERR "Erreur %d en lisant le fichier index"
-#define MSG_XFILE_TOO_SMALL "Le fichier index est plus petit que la taille de l'index"
-#define MSG_XFILE_WRITERR "Erreur en ‚crivant le fichier index: %s"
-#define MSG_XMLTAB_INIT_ERR "Erreur d'initialisation de la table XML"
-#define MSG_XML_INIT_ERROR "Erreur d'initialisation du nouveau fichier XML"
-#define MSG_XPATH_CNTX_ERR "Le nouveau contexte XPath ne peut ˆtre cr‚‚"
-#define MSG_XPATH_EVAL_ERR "Impossible d'‚valuer l'emplacement xpath '%s'"
-#define MSG_XPATH_NOT_SUPP "Xpath non support‚ colonne %s"
-#define MSG_X_ARG_ADDED "%d arguments ajout‚s"
-#define MSG_X_ARG_SET "%d arguments ont ‚t‚ initialis‚s"
-#define MSG_X_ON_TAB " %s sur %s("
-#define MSG_ZERO_DIVIDE "Division par z‚ro dans une expression"
+#define MSG_ACCESS_VIOLATN "Violation accŠs m‚moire"
+#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Activity"
+#define MSG_ADDVAL_ERROR "Erreur %d dans AddValue"
+#define MSG_ADD_BAD_TYPE "Ajout d'une valeur de type %s non conforme dans un tableau %s"
+#define MSG_ADD_NULL_DOM "Ajout de la chaŒne %s … un domaine nul"
+#define MSG_ADPOS_IN_DICTP "ADPOS au travail dans User_Dictp"
+#define MSG_AFTER " aprŠs: "
+#define MSG_ALG_CHOICE_AUTO "Le choix du meilleur algorithme est automatique"
+#define MSG_ALG_CHOICE_BAD "Choix d'algorithme invalide, remis … AUTO"
+#define MSG_ALG_CHOICE_QRY "Utilise l'algorithme 'Query'"
+#define MSG_ALG_CURLY_BRK "Le choix de l'algorithme d‚pend des accolades externes"
+#define MSG_ALLOC_ERROR "Erreur d'allocation de %s"
+#define MSG_ALL_DELETED "Toutes les lignes enlev‚es en %.2lf sec"
+#define MSG_ALTER_DB_ERR "Impossible de d‚terminer la base de donn‚es … modifier"
+#define MSG_AMBIG_COL_QUAL "Qualificateur ambigu %s pour la colonne %s"
+#define MSG_AMBIG_CORREL "Select %s.* corr‚lation ambigue"
+#define MSG_AMBIG_SPEC_COL "Colonne sp‚ciale ambigue %s"
+#define MSG_ANSWER_TYPE "R‚ponse de type"
+#define MSG_API_CONF_ERROR "Erreur SQL: API_CONFORMANCE"
+#define MSG_APPL_ACCESSIBLE "Application %s accessible"
+#define MSG_APPL_ACTIVE "Application %s encore active"
+#define MSG_APPL_BAD_SAVE "Application %s partiellement sauvegard‚e"
+#define MSG_APPL_CREATED "Application %s cr‚‚"
+#define MSG_APPL_IS_ACTIVE "Application d‚j… active"
+#define MSG_APPL_NOT_INIT "Application non initialis‚e"
+#define MSG_APPL_NOT_LOADED "Application non charg‚e"
+#define MSG_APPL_QUIT "Fin de l'application %s"
+#define MSG_APPL_SAVED "Application %s sauvegard‚e"
+#define MSG_APP_STILL_ACTIV "Application du langage %s encore active (non lib‚rable)"
+#define MSG_AREAFILE_NOTFND "Fichier Area introuvable"
+#define MSG_ARGS_SYNTAX_ERR "?SetArgs erreur de syntaxe: %s inattendu aprŠs %s"
+#define MSG_ARG_ALREADY_SET "Argument %d d‚j… allou‚"
+#define MSG_ARG_NOT_AN_ATTR "L'argument n'est pas un attribut (type %d erron‚)"
+#define MSG_ARG_OUT_CONTEXT "Argument de type @ utilis‚ hors contexte"
+#define MSG_ARG_OUT_RANGE "Argument de phrase valant %d hors limite"
+#define MSG_ARG_PTR_NOSEM "Argument valant %d pointe sur un noeud sans Sem"
+#define MSG_ARG_PTR_NOSEMS "Argument valant %d pointe sur un noeud sans s‚mantique"
+#define MSG_ARG_REF_LOOP "?Bouclage entre r‚f‚rences crois‚es des arguments"
+#define MSG_ARG_TWO_CONST "Le 2Šme argument de %s doit ˆtre constant"
+#define MSG_ARRAY_ALLOC_ERR "Erreur d'allocation m‚moire dans ARRAY"
+#define MSG_ARRAY_BNDS_EXCD "Hors limite de tableau"
+#define MSG_ARRAY_ERROR "Erreur de fonctionnement k=%d n=%d"
+#define MSG_ATTRIBUTE_ERROR "Erreur rŠgle %u attribut %s: "
+#define MSG_ATT_NOT_CASE "Mauvaise valeur %d pour attribut (pas une CaseValue)"
+#define MSG_ATT_POSCODE_BIG "Code attribut %d trop grand (max=%d)"
+#define MSG_AVGLEN_ERROR "avglen doit ˆtre entre %d et %d"
+#define MSG_BAD_AGGREG_FUNC "Fonction aggr‚g‚e %d non support‚e"
+#define MSG_BAD_ARGTYPES "Argument de type invalide pour %s"
+#define MSG_BAD_ARGUMENTS "Argument non attach‚s pour %s"
+#define MSG_BAD_ARG_NUM "Nombre d'arguments invalide %d"
+#define MSG_BAD_ARG_TYPE "Type d'argument %d invalide"
+#define MSG_BAD_ARRAY_OPER "Les tableaux doivent utiliser l'op‚rateur IN"
+#define MSG_BAD_ARRAY_TYPE "Type=%d invalide pour un tableau"
+#define MSG_BAD_ARRAY_VAL "Les tableaux doivent avoir le mˆme nombre de valeurs"
+#define MSG_BAD_BIN_FMT "Format invalide %c pour la colonne BIN %s"
+#define MSG_BAD_BLK_ESTIM "Nombre de blocs sup‚rieur … l'estimation"
+#define MSG_BAD_BLK_SIZE "Taille du bloc %d non conforme"
+#define MSG_BAD_BYTE_NUM "Le nombre d'octets ‚crits est faux"
+#define MSG_BAD_BYTE_READ "Le nombre d'octets lus est faux"
+#define MSG_BAD_CARDINALITY "Appel invalide de Cardinality pour une table multiple"
+#define MSG_BAD_CASE_SPEC "Min/Maj: sp‚cification %c incorrecte, recommencez: "
+#define MSG_BAD_CHAR_SPEC "Sp‚cification '%s' invalide pour caractŠre"
+#define MSG_BAD_CHECK_TYPE "Sous-type %d invalide pour CheckColumn"
+#define MSG_BAD_CHECK_VAL "Valeur pour Check invalide '%s'"
+#define MSG_BAD_COLCRT_ARG "COLCRT: Arg invalide (type=%hd, domain=%hd)"
+#define MSG_BAD_COLDEF_TYPE "Coldefs: type ill‚gal %d"
+#define MSG_BAD_COLIST_ITEM "El‚ment invalide dans une Colist"
+#define MSG_BAD_COLIST_TYPE "Mauvais type=%d pour une Colist"
+#define MSG_BAD_COLSIZE "Colsize %d trop petit pour cette base de donn‚es"
+#define MSG_BAD_COL_ENTRY "Entr‚e invalide pour la colonne %s"
+#define MSG_BAD_COL_FORMAT "Type de formattage %d invalide pour une colonne"
+#define MSG_BAD_COL_IN_FILT "Colonne incorrecte dans un filtre"
+#define MSG_BAD_COL_QUALIF "Qualificateur invalide %s pour la colonne %s"
+#define MSG_BAD_COL_TYPE "Type invalide %s pour la colonne %s"
+#define MSG_BAD_COL_XPATH "Xpath invalide colonne %s de la table HTML %s"
+#define MSG_BAD_COMPARE_OP "Op‚rateur de comparaison %d invalide"
+#define MSG_BAD_CONST_TYPE "Type=%d invalide pour une constante"
+#define MSG_BAD_CONV_TYPE "Convertion de type invalide %d"
+#define MSG_BAD_CORREL "Select %s.* corr‚lation absente"
+#define MSG_BAD_DATETIME "Valeur date/temps invalide"
+#define MSG_BAD_DATE_OPER "Op‚rateur de date inattendu %d"
+#define MSG_BAD_DBF_FILE "Le fichier DBF %s est alt‚r‚"
+#define MSG_BAD_DBF_REC "Fichier DBF %s alt‚r‚ enregistrement %d"
+#define MSG_BAD_DBF_TYPE "Type DBF %c non support‚"
+#define MSG_BAD_DEF_ARG "Argument invalide pour INDEXDEF (type=%hd, domain=%hd)"
+#define MSG_BAD_DEF_READ "EOF inattendue en lecture diff‚r‚e"
+#define MSG_BAD_DEF_TYPE "Type de colonne invalide"
+#define MSG_BAD_DIRECTORY "R‚pertoire invalide %s: %s"
+#define MSG_BAD_DIST_JN_FIL "Filtre de jointure distincte invalide"
+#define MSG_BAD_DIST_JOIN "Sp‚cification invalide de jointure distincte"
+#define MSG_BAD_DOM_COL_DEF "D‚finition de colonnes invalide pour un domaine"
+#define MSG_BAD_DOM_VALUE "La valeur %d n'appartient pas au domaine"
+#define MSG_BAD_EDIT_INIT "Coparm: ‚dition %s initialis‚e improprement"
+#define MSG_BAD_EVAL_TYPE "Fonction scalaire de type=%d invalide"
+#define MSG_BAD_EXEC_MODE "Mode d'ex‚cution invalide '%s'"
+#define MSG_BAD_EXP_ARGTYPE "Argument de type %d invalide pour une expression"
+#define MSG_BAD_EXP_OPER "Op‚rateur=%d invalide pour expression"
+#define MSG_BAD_FETCH_RC "Code retour inattendu de Fetch %d"
+#define MSG_BAD_FIELD_FMT "Format de champ invalide %c pour %s"
+#define MSG_BAD_FIELD_RANK "Rang %d invalide pour la colonne %s"
+#define MSG_BAD_FIELD_TYPE "Mauvais type de champ %s"
+#define MSG_BAD_FILE_HANDLE "Handle de fichier invalide: %s"
+#define MSG_BAD_FILE_LIST "La section liste de fichiers est erron‚e"
+#define MSG_BAD_FILTER "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"
+#define MSG_BAD_FILTER_CONV "Conversion filtre incorrecte, B_T=%d,%d"
+#define MSG_BAD_FILTER_LINK "Op‚rateur de chaŒnage ill‚gal %d"
+#define MSG_BAD_FILTER_OP "Op‚rateur de filtre invalide %d"
+#define MSG_BAD_FILTEST_OP "Op‚rateur invalide %d %d pour FilTest"
+#define MSG_BAD_FLD_FORMAT "Format invalide pour le champs %d de %s"
+#define MSG_BAD_FLD_LENGTH "Champs %s trop long (%s --> %d) ligne %d de %s"
+#define MSG_BAD_FLOAT_CONV "Convertion invalide d'un tableau flottant"
+#define MSG_BAD_FPARM_NEXT "Coparm: FPARM avec Next non nul"
+#define MSG_BAD_FREQ_SET "Sp‚cification erronn‚e de Freq pour la colonne %s"
+#define MSG_BAD_FUNC_ARG "Funcarg de type %d non impl‚ment‚"
+#define MSG_BAD_FUNC_ARGTYP "Mauvais type d'argument=%d pour une fonction"
+#define MSG_BAD_FUNC_MODE "%s: mode invalide %d"
+#define MSG_BAD_GENRE "Genre est invalide"
+#define MSG_BAD_GETVIEW_RET "GetView: type de retour %d invalide"
+#define MSG_BAD_HANDLE_VAL "Valeur Handle invalide"
+#define MSG_BAD_HAV_FILTER "Filtre Having sur une requˆte non group‚e"
+#define MSG_BAD_HAV_FILTYPE "Filtre invalide pour clause Having"
+#define MSG_BAD_HEADER "Fichier %s: bloc en-tˆte alt‚r‚"
+#define MSG_BAD_HEADER_VAL "Valeur invalide pour Header"
+#define MSG_BAD_HEAD_END "Lecture fin d'en-tˆte impossible"
+#define MSG_BAD_INDEX_COL "Colonne %s invalide pour index %s"
+#define MSG_BAD_INDEX_DEF "D‚finition invalide pour index %s"
+#define MSG_BAD_INDEX_FILE "Fichier index %s corrompu"
+#define MSG_BAD_INDEX_PART "D‚finition colonne invalide pour index %s"
+#define MSG_BAD_INPUT "Entr‚e incorrecte"
+#define MSG_BAD_IN_ARGTYPE "Argument de type invalide pour l'op‚rateur IN"
+#define MSG_BAD_IN_ENDING "Erreur: fin de chaŒne IN invalide"
+#define MSG_BAD_IN_STRING "La chaŒne IN commence ou finie par des caractŠres invalides %c ... %c"
+#define MSG_BAD_JCOL_TYPE "Erreur logique JCT: disparit‚ des types colonnes"
+#define MSG_BAD_JOIN_EXP "Expression invalide pour une jointure"
+#define MSG_BAD_JOIN_FILTER "Filtre de jointure invalide"
+#define MSG_BAD_JOIN_OP "Op‚rateur de joint invalide %d"
+#define MSG_BAD_LANG_SIZE "Le fichier langage a une mauvaise taille %d"
+#define MSG_BAD_LINEFLD_FMT "Format invalide ligne %d champs %d de %s"
+#define MSG_BAD_LINE_LEN "Longueur ligne non ‚gale … Lrecl"
+#define MSG_BAD_LIST_TYPE "Type de liste invalide %d"
+#define MSG_BAD_LOCALE "Locale invalide %s"
+#define MSG_BAD_LOCDFON_ARG "Mauvais paramŠtre pour LOCDFON"
+#define MSG_BAD_LOCNODE_USE "Usage inattendu de LOCNODE"
+#define MSG_BAD_LRECL "Disparit‚ lrecl table/fichier (%d,%hd)"
+#define MSG_BAD_MAX_HAVING "MAXTMP trop petit pour Having"
+#define MSG_BAD_MAX_NREC "MaxRec=%d ne correspond pas … MaxBlk=%d Nrec=%d"
+#define MSG_BAD_MAX_PARAM "Mauvais paramŠtres pour sp‚cifier une valeur maximum"
+#define MSG_BAD_MAX_SETTING "Mauvaise valeur '%c' pour max"
+#define MSG_BAD_MERGE_TYPE "Le type %d ne pas ˆtre intercall‚"
+#define MSG_BAD_NODE_TYPE "Type noeud erron‚ pour la table"
+#define MSG_BAD_OFFSET_VAL "Nul offset invalide pour une table CSV"
+#define MSG_BAD_OPEN_MODE "Mode d'ouverture invalide %d"
+#define MSG_BAD_OPERATOR "Op‚rateur invalide %s"
+#define MSG_BAD_ORDER_MODE "Mode de tri %c invalide"
+#define MSG_BAD_ORDER_TYPE "Tri sur objet de type=%d invalide"
+#define MSG_BAD_OUTER_JOIN "Jointure externe invalide sur table enfant"
+#define MSG_BAD_PAD_ARGTYP "Argument de type invalide pour Pad ou Justify"
+#define MSG_BAD_PARAMETERS "%.8s: Mauvais paramŠtres"
+#define MSG_BAD_PARAM_TYPE "%.8s: ParamŠtre de type=%d invalide"
+#define MSG_BAD_PARM_COUNT "Nombre de paramŠtres incoh‚rent"
+#define MSG_BAD_PHASE_NUM "Num‚ro de phrase %d hors limite"
+#define MSG_BAD_PHRASE_NB "num‚ro de phrase hors limite %d rc=%d\n"
+#define MSG_BAD_POS_CODE "POS_code invalide %d"
+#define MSG_BAD_POS_TYPE "Type de POS_code invalide %d"
+#define MSG_BAD_PROJNUM "Mauvais projnum %d pour la colonne %s"
+#define MSG_BAD_QUERY_OPEN "Mode invalide %d pour l'ouverture d'une requˆte"
+#define MSG_BAD_QUERY_TYPE "Type de requˆte %d invalide pour %s"
+#define MSG_BAD_QUOTE_FIELD "Quote manquante dans %s champs %d ligne %d"
+#define MSG_BAD_READ_NUMBER "Mauvais nombre %d de valeurs lues dans %s"
+#define MSG_BAD_RECFM "Recfm type %d invalide pour DOSCOL"
+#define MSG_BAD_RECFM_VAL "Valeur invalide %d de Recfm"
+#define MSG_BAD_RESULT_TYPE "Mauvais type de r‚sultat %d pour %s"
+#define MSG_BAD_RETURN_TYPE "Type de retour %d incorrect"
+#define MSG_BAD_ROW_VALIST "Liste de valeurs invalide pour ROW"
+#define MSG_BAD_ROW_VALNB "Nombre de valeurs in‚gal dans la liste"
+#define MSG_BAD_SCF_ARGTYPE "Argument %d de type=%s invalide pour %s"
+#define MSG_BAD_SEM_DOMAIN "Domain .%d invalide"
+#define MSG_BAD_SETTINGS "Certaines sp‚cifications sont incompatibles avec le type de la table"
+#define MSG_BAD_SET_CASE "La casse d'un tableau ne peut pas passer de non respect … respecter"
+#define MSG_BAD_SET_STRING "SetValue: appel invalide pour STRING"
+#define MSG_BAD_SET_TYPE "Set type %hd invalide"
+#define MSG_BAD_SPECIAL_CMD "Commande sp‚ciale invalide"
+#define MSG_BAD_SPECIAL_COL "Colonne sp‚ciale invalide %s"
+#define MSG_BAD_SPEC_COLUMN "Colonne sp‚ciale invalide pour ce type de table"
+#define MSG_BAD_SQL_PARAM "ParamŠtre SQL invalide pour FindColblk"
+#define MSG_BAD_SUBLST_TYPE "Coparm: type %d de sous-liste invalide"
+#define MSG_BAD_SUBSEL_IN_X "Sub-select invalide pour une expression"
+#define MSG_BAD_SUBSEL_TYPE "Type %d invalide retourn‚ de Sub-Select"
+#define MSG_BAD_SUB_RESULT "R‚sultat ind‚fini de fonction Sub-Select"
+#define MSG_BAD_SUB_SELECT "Sub-select invalide comme argument de fonction"
+#define MSG_BAD_TABLE_LINE "Ligne '%s' ill‚gale ou tronqu‚e dans la section Tables"
+#define MSG_BAD_TABLE_LIST "Table %s absente de la liste des tables"
+#define MSG_BAD_TABLE_TYPE "Type invalide %s pour la table %s"
+#define MSG_BAD_TEST_TYPE "BlockTest sur tableau: types d‚pareill‚s %s %s"
+#define MSG_BAD_TRIM_ARGTYP "Argument de type invalide pour Trim"
+#define MSG_BAD_TYPE_FOR_IN "Types d'argument incompatibles pour la fonction IN"
+#define MSG_BAD_TYPE_FOR_S "Type incorrecte %d pour %s(%d)"
+#define MSG_BAD_TYPE_LIKE "Type(%d)= %d invalide pour LIKE"
+#define MSG_BAD_UPD_COR "Le qualificateur %s de la colonne %s ne se refŠre pas … la table mise … jour %s"
+#define MSG_BAD_USERBLK_LEN "Mauvaise longueur … l'‚criture du bloc utilisateur"
+#define MSG_BAD_USETEMP "Usetemp invalide '%s'"
+#define MSG_BAD_USETEMP_VAL "Valeur pour Usetemp invalide %d"
+#define MSG_BAD_VALBLK_INDX "Valeur hors limites de l'index du bloc de valeurs"
+#define MSG_BAD_VALBLK_TYPE "Type=%d invalide pour un bloc de valeurs"
+#define MSG_BAD_VALNODE "Type %d invalide pour le noeud valeur colonne %s"
+#define MSG_BAD_VALUE_TYPE "Type de valeur invalide %d"
+#define MSG_BAD_VAL_UPDATE "Impossible de d‚terminer quelle valeur %s doit ˆtre mise … jour"
+#define MSG_BAD_VIEW_OPEN "Mode invalide %d pour l'ouverture d'une View"
+#define MSG_BAD_XMODE_VAL "Mode d'ex‚cution %d invalide"
+#define MSG_BAD_XOBJ_TYPE "Mauvais type de Xobject %d"
+#define MSG_BAS_NS_LIST "Format invalide de la liste des espace-noms"
+#define MSG_BIN_F_TOO_LONG "Valeur trop longue pour le champ %s (%d --> %d)"
+#define MSG_BIN_MODE_FAIL "Echec mode binaire: %s"
+#define MSG_BLKTYPLEN_MISM "Disparit‚ types/longueurs de bloc dans SetValue"
+#define MSG_BLK_IS_NULL "Blk est nul"
+#define MSG_BLOCK_NO_MATCH "Bloc non correspondant"
+#define MSG_BREAKPOINT "Point de controle"
+#define MSG_BUFF_TOO_SMALL "GetColData: Buffer trop petit"
+#define MSG_BUFSIZE_ERROR "Erreur en recherchant la taille du buffer"
+#define MSG_BUILDING_GROUPS "Formation des groupes"
+#define MSG_BUILD_DIST_GRPS "Formation des groupes distinctes"
+#define MSG_BUILD_INDEX "Construction index %s sur %s"
+#define MSG_BXP_NULL "Bxp nul dans PUTFON"
+#define MSG_CANNOT_OPEN "Ouverture impossible de %s"
+#define MSG_CD_ONE_STEP "Count Distinct doit ˆtre ex‚cut‚ en une seule ‚tape"
+#define MSG_CD_ORDER_ERROR "Erreur de tri dans Count Distinct"
+#define MSG_CHECKING_ROWS "Test des lignes … mettre … jour"
+#define MSG_CHECK_LEVEL "Niveau de v‚rification fix‚ … %u"
+#define MSG_CHSIZE_ERROR "Erreur dans chsize: %s"
+#define MSG_CLN_NOT_IN_JOIN "La colonne C%d n'est pas dans le join"
+#define MSG_CNTDIS_COL_LOST "Colonne du Count Distinct perdue"
+#define MSG_COLIST_BAD_TYPE "Type=%d invalide pour Colist"
+#define MSG_COLNAM_TOO_LONG "Nom de colonne trop long"
+#define MSG_COLSEC_TOO_BIG "Section colonne trop grande, table %s (%d)"
+#define MSG_COLS_REDUCED " (r‚duit par Maxcol)"
+#define MSG_COLUMN_ERROR "Erreur de colonne"
+#define MSG_COLUMN_MISMATCH "Colonne %s d‚pareill‚e"
+#define MSG_COLUMN_NOT_KEY "La colonne jointe R%d.%s n'est pas une cl‚"
+#define MSG_COL_ALLOC_ERR "Allocation impossible du noeud colonne"
+#define MSG_COL_ALLOC_ERROR "Erreur d'allocation m‚moire pour la colonne %d"
+#define MSG_COL_HAS_NO_DEF "La colonne %s n'est pas d‚finie"
+#define MSG_COL_INVAL_TABLE "La colonne %s.%s n'existe pas dans la table %s alias %s"
+#define MSG_COL_ISNOT_TABLE "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NB_MISM "Le nombre de colonnes ne correspond pas"
+#define MSG_COL_NOTIN_GRPBY "La colonne %s n'est pas dans la liste de Group By"
+#define MSG_COL_NOTIN_TABLE "La colonne %s n'est dans aucune table"
+#define MSG_COL_NOTIN_UPDT "%s n'appartient pas … la table mise … jour %s"
+#define MSG_COL_NOT_CODED "La colonne %s n'est pas codifi‚e"
+#define MSG_COL_NOT_EXIST "La colonne %s n'existe pas dans %s"
+#define MSG_COL_NOT_FOUND "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NOT_IN_DB "La colonne %s de la table %s n'est pas dans la base de donn‚es"
+#define MSG_COL_NOT_IN_JOIN "La colonne %s n'est pas dans le join"
+#define MSG_COL_NOT_SORTED "La colonne %s de la table %s n'est pas tri‚e"
+#define MSG_COL_NUM_MISM "Disparit‚ du nombre de colonnes"
+#define MSG_COL_USED_TWICE "Colonne %s utilis‚e deux fois ???"
+#define MSG_COMPUTE_ERROR "Erreur dans Compute, op=%d"
+#define MSG_COMPUTE_NIY "Compute non impl‚ment‚ pour TOKEN"
+#define MSG_COMPUTING "Calculs en cours"
+#define MSG_COMPUTING_DIST "Comptage des valeurs distinctes"
+#define MSG_COMPUTING_FUNC "Calcul de(s) fonction(s)"
+#define MSG_COM_ERROR "Erreur Com"
+#define MSG_CONCAT_SUBNODE "Concat‚nation de sous-noeuds impossible"
+#define MSG_CONNECTED "Connect‚e"
+#define MSG_CONNECT_CANCEL "Connection interrompue par l'utilisateur"
+#define MSG_CONNECT_ERROR "Erreur %d se connectant à %s"
+#define MSG_CONN_CLOSED "%s(%d) ferm‚e"
+#define MSG_CONN_CREATED "Connexion %s cr‚e"
+#define MSG_CONN_DROPPED "Connexion %s supprim‚e"
+#define MSG_CONN_OPEN "%s(%d) ouverte (%s)"
+#define MSG_CONN_SUC_OPEN "%s(%d) ouverte avec succŠs"
+#define MSG_CONTROL_C_EXIT "Exit par Ctrl-C"
+#define MSG_COPY_BAD_PHASE "Copie de liste invalide en phase %d"
+#define MSG_COPY_INV_TYPE "Coparm: type non support‚ %d"
+#define MSG_CORREL_NO_QRY "Les sous-requˆtes corr‚l‚es ne peuvent pas ˆtre de type QRY"
+#define MSG_CREATED_PLUGDB " Cr‚‚ par PlugDB %s "
+#define MSG_CURSOR_SET "Curseur remis … %d"
+#define MSG_DATABASE_ACTIVE "Base de donn‚es %s activ‚e"
+#define MSG_DATABASE_LOADED "Base de donn‚es %s charg‚e"
+#define MSG_DATA_IS_NULL "ExecSpecialCmd: data est NULL"
+#define MSG_DATA_MISALIGN "Mauvais alignement pour ce type de donn‚es"
+#define MSG_DBASE_FILE "Fichier dBASE dbf: "
+#define MSG_DB_ALREADY_DEF "Base de donn‚es %s d‚j… d‚finie"
+#define MSG_DB_ALTERED "Base de donn‚es modifi‚e"
+#define MSG_DB_CREATED "Base de donn‚es %s cr‚‚e"
+#define MSG_DB_NOT_SPEC "Base de donn‚es non sp‚cifi‚e"
+#define MSG_DB_REMOVED "Base de donn‚es %s retir‚e de la liste"
+#define MSG_DB_SORT_ERROR "Erreur de tri DB"
+#define MSG_DB_STOPPED "Arrˆt de la base de donn‚es %s"
+#define MSG_DEBUG_NOT_ACTIV "Mode Debug inactif"
+#define MSG_DEBUG_SET_INV "Invalide pour Debug: %c"
+#define MSG_DEF_ALLOC_ERROR "Erreur d'allocation de la classe DEF %s"
+#define MSG_DELETING_ROWS "Suppression des lignes"
+#define MSG_DEL_FILE_ERR "Erreur … l'effacement de %s"
+#define MSG_DEL_READ_ERROR "Delete: erreur en lecture req=%d len=%d"
+#define MSG_DEL_WRITE_ERROR "Delete: erreur en ‚criture: %s"
+#define MSG_DEPREC_FLAG "Option Flag p‚rim‚e, utiliser Coltype"
+#define MSG_DICTIONARY "Dictionnaire "
+#define MSG_DIRECT_VARTOK "AccŠs direct aux rŠgles du Variable Token non impl‚ment‚"
+#define MSG_DISCONNECTED "D‚connect‚"
+#define MSG_DISTINCT_ERROR "Plus d'un ‚l‚ment fonctionel DISTINCT"
+#define MSG_DISTINCT_ROWS "S‚lection des lignes distinctes"
+#define MSG_DISTINCT_VALUES "Extraction des valeurs distinctes"
+#define MSG_DIS_NOHEAD_JOIN "Jointure distincte sur une table non en tˆte"
+#define MSG_DLL_LOAD_ERROR "Erreur %d au chargement du module %s"
+#define MSG_DOMAIN_EMPTY "Le domaine %s est vide"
+#define MSG_DOMAIN_ERROR "Colonne %s: disparit‚ domaine(%s)/valeur(%s)"
+#define MSG_DOMAIN_FULL "Le domaine %s est plein (max=%d)"
+#define MSG_DOM_FILE_ERROR "Fichier domain %s introuvable"
+#define MSG_DOM_NOT_SUPP "MS-DOM non support‚ par cette version"
+#define MSG_DOM_OPEN_ERROR "Erreur d'ouverture du domaine: %s"
+#define MSG_DOM_READ_ERROR "Erreur %d en lecture de domaine: %s"
+#define MSG_DOM_READ_ONLY "La table domaine %s est en lecture seulement"
+#define MSG_DOM_WRITE_ERROR "Erreur %d en ‚criture de domaine: %s"
+#define MSG_DONE "Effectu‚, rc=%d"
+#define MSG_DOSALMEM_NOMEM "Erreur d'allocation, pas assez de m‚moire"
+#define MSG_DROP_DB_ERR "Echec du Drop sur le base de donn‚es %s"
+#define MSG_DSORT_LOG_ERROR "Kindex: Erreur logique de tri distincte"
+#define MSG_DUMMY_NO_COLS "Les tables DUMMY ne peuvent pas avoir de colonne"
+#define MSG_DUPLICAT_COUNT "Count sur plus d'une colonne"
+#define MSG_DUP_COL_NAME "La colonne %s existe en double"
+#define MSG_DUP_PROJNUM "Non unique projnum %d pour la colonne %s"
+#define MSG_DVAL_NOTIN_LIST "Valeur %s non trouv‚e dans la liste des valeurs distinctes de la colonne %s"
+#define MSG_EMPTY_DOC "Document vide"
+#define MSG_EMPTY_FILE "%s du fichier vide %s: "
+#define MSG_ENDSTR_MISMATCH "Fins de chaŒne et de noeud ne correspondent pas"
+#define MSG_END_OF_DELETE "%d ligne(s) enlev‚e(s) en %.2lf sec"
+#define MSG_END_OF_INSERT "%d ligne(s) ins‚r‚e(s) en %.2lf sec"
+#define MSG_END_OF_QUERY "%d ligne(s) extraite(s) en %.2lf sec"
+#define MSG_END_OF_UPDATE "%d ligne(s) modifi‚e(s) en %.2lf sec"
+#define MSG_EOF_AFTER_LINE "Fin de fichier aprŠs la ligne %d"
+#define MSG_EOF_INDEX_FILE "EOF lisant le fichier index"
+#define MSG_ERASED " et effac‚e"
+#define MSG_ERASE_FAILED " (‚chec de l'effacement)"
+#define MSG_ERROR "Erreur"
+#define MSG_ERROR_IN_LSK "Erreur %d dans lseek64"
+#define MSG_ERROR_IN_SFP "Erreur %d dans SetFilePointer"
+#define MSG_ERROR_NO_PARM "ParamŠtre absent (valide seulement pour %.8s.1 et %.8s.5)"
+#define MSG_ERROR_OPENING "Erreur … l'ouverture de : "
+#define MSG_ERR_NUM_GT_MAX "Erreur: Numval (%d) plus grand que Maxnum (%d)"
+#define MSG_ERR_READING_REC "Erreur lisant l'enregistrement %d de %s"
+#define MSG_ERR_RET_RULE "Retour erreur, rŠgle=%u"
+#define MSG_ERR_RET_TYPE "Retour erreur, type=%d"
+#define MSG_EVAL_EXPIRED "Cette version d'évaluation est expir‚e"
+#define MSG_EVAL_ONLY "L'utilisation de cette Dll est pour ‚valuation seulement"
+#define MSG_EXECUTING "Ex‚cution"
+#define MSG_EXECUTION_ERROR "Erreur d'ex‚cution"
+#define MSG_EXEC_MODE_IS "Le mode d'ex‚cution est %s"
+#define MSG_EXEC_MODE_RESET ". Mode remis … Execute"
+#define MSG_EXEC_MODE_SET "Mode d'ex‚cution fix‚ … %s"
+#define MSG_EXIT_EVAL_ERR "Erreur pendant l'‚valuation de Exit"
+#define MSG_EXIT_FROM_LANG "Fin du langage %s version %d.%d"
+#define MSG_FAIL_ADD_NODE "L'ajout du noeud %s dans la table a ‚chou‚"
+#define MSG_FETCHING_DATA "Recherche des donn‚es"
+#define MSG_FETCHING_ROWS "Recherche des lignes"
+#define MSG_FETCH_NO_RES "Fetch: Pas de R‚sultats"
+#define MSG_FIELD_TOO_LONG "Valeur trop longue pour le champs %d ligne %d"
+#define MSG_FILELEN_ERROR "Erreur dans %s pour %s"
+#define MSG_FILE_CLOSE_ERR "Erreur %d … la fermeture du fichier"
+#define MSG_FILE_IS_EMPTY "Le fichier %s est vide"
+#define MSG_FILE_MAP_ERR "Erreur de File mapping"
+#define MSG_FILE_MAP_ERROR "CreateFileMapping %s erreur rc=%d"
+#define MSG_FILE_NOT_FOUND "Fichier %s introuvable"
+#define MSG_FILE_OPEN_YET "Fichier %s d‚j… ouvert"
+#define MSG_FILE_UNFOUND "Fichier %s non trouv‚"
+#define MSG_FILGRP_NO_TABLE "Table %d manquante pour groupe filtre"
+#define MSG_FILTER_ATTACH "Filtre pass‚ … Attach"
+#define MSG_FILTER_NO_TABLE "Filtre: premiŠre table manquante"
+#define MSG_FIND_BAD_TYPE "Recherche dans un tableau: type non conforme %s %s"
+#define MSG_FIX_OVFLW_ADD "D‚passement de capacit‚ en addition"
+#define MSG_FIX_OVFLW_TIMES "D‚passement de capacit‚ en mutiplication"
+#define MSG_FIX_UNFLW_ADD "Sous d‚passement de capacit‚ en addition"
+#define MSG_FIX_UNFLW_TIMES "Sous d‚passement de capacit‚ en multiplication"
+#define MSG_FLD_TOO_LNG_FOR "Champs %d trop long pour %s ligne %d de %s"
+#define MSG_FLTST_NO_CORREL "FilTest ne devrait ˆtre appel‚ que pour les sous-requˆtes corr‚l‚es"
+#define MSG_FLT_BAD_RESULT "Virgule flottante: r‚sultat inexacte"
+#define MSG_FLT_DENORMAL_OP "Op‚rande virgule flottante non normalis‚"
+#define MSG_FLT_INVALID_OP "Op‚ration virgule flottante invalide"
+#define MSG_FLT_OVERFLOW "D‚passement de capacit‚ virgule flottante"
+#define MSG_FLT_STACK_CHECK "Virgule flottante: Erreur de la pile"
+#define MSG_FLT_UNDERFLOW "Sous-d‚passement de capacit‚ virgule flottante"
+#define MSG_FLT_ZERO_DIVIDE "Virgule flottante: division par z‚ro"
+#define MSG_FMT_WRITE_NIY "L'‚criture des fichiers %s n'est pas encore impl‚ment‚e"
+#define MSG_FNC_NOTIN_SLIST "Fonction de tri absente de la liste de s‚lection"
+#define MSG_FORMAT_ERROR "Erreur de formattage"
+#define MSG_FOXPRO_FILE "Fichier FoxPro: "
+#define MSG_FPUTS_ERROR "Erreur dans fputs: %s"
+#define MSG_FSBPARP_NULL "PUTFON: fsbparp est nul"
+#define MSG_FSEEK_ERROR "Erreur dans fseek: %s"
+#define MSG_FSETPOS_ERROR "Erreur dans fseek pour i=%d"
+#define MSG_FTELL_ERROR "Erreur dans ftell enregistrement=%d: %s"
+#define MSG_FUNCTION_ERROR "Erreur dans %s: %d"
+#define MSG_FUNC_ERRNO "Erreur %d dans %s"
+#define MSG_FUNC_ERROR "Erreur dans %s"
+#define MSG_FUNC_ERR_S "Erreur dans %s: %s"
+#define MSG_FUNC_REF_DEL "R‚f‚rence … une fonction d‚finie (rŠgle %d) qui a ‚t‚ supprim‚e"
+#define MSG_FWRITE_ERROR "Erreur dans fwrite: %s"
+#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
+#define MSG_GETFILESIZE_ERR "Erreur %d dans GetFileSize"
+#define MSG_GET_DIST_VALS "R‚cup‚ration des valeurs distinctes de "
+#define MSG_GET_ERROR "Erreur dans %s (colonne %d)"
+#define MSG_GET_FUNC_ERR "Erreur en recherche de la fonction %s: %s"
+#define MSG_GET_NAME_ERR "Erreur en retrouvant le nom d'une table SYS"
+#define MSG_GLOBAL_ERROR "Erreur d'allocation de Global (taille=%d)\n"
+#define MSG_GRAM_ALLOC_ERR "Erreur d'allocation dans Grammar Up"
+#define MSG_GRAM_MISMATCH "Avertissement: version de GRAMMAR p‚rim‚e (sauv‚ sous GRAMMAR v%u)"
+#define MSG_GRAM_SUBSET_ERR "Erreur d'initialisation du dictionnaire de la grammaire"
+#define MSG_GRBY_TAB_NOTIMP "Group by avec tables jointes non impl‚ment‚"
+#define MSG_GROUPBY_NOT_ALL "Group By doit inclure toutes les s‚lections non-fonctionnelles"
+#define MSG_GROUP_ON_FUNC "Group by invalide sur colonne fonctionnelle"
+#define MSG_GRP_COL_MISM "Disparit‚ colonne des groupes"
+#define MSG_GRP_LIST_MISMAT "Le groupement ne couvre pas la liste de s‚lection"
+#define MSG_GUARD_PAGE "Violation de page de garde"
+#define MSG_GZOPEN_ERROR "gzopen %s: erreur %d sur %s"
+#define MSG_GZPUTS_ERROR "Erreur dans gzputs: %s"
+#define MSG_HANDLE_IS_NULL "%s est NULL: erreur code: %d"
+#define MSG_HARRY_COMP_NIY "Compute non impl‚ment‚ pour les chaŒnes cod‚es"
+#define MSG_HAVING_FILTER "Traitement du Filtre Having"
+#define MSG_HBUF_TOO_SMALL "Buffer(%d) trop petit pour entˆte(%d)"
+#define MSG_HEAD_OPEN_ERROR "Erreur … l'ouverture du fichier header"
+#define MSG_HEAD_READ_ERROR "Erreur en lecture du fichier header %s"
+#define MSG_HEAD_WRITE_ERR "Erreur en ‚criture du fichier header"
+#define MSG_HI_OFFSET_ERR "Offset sup‚rieur non nul"
+#define MSG_HUGE_DEFAULT "Huge est %d par d‚fault"
+#define MSG_HUGE_WARNING_1 "M‚moire Huge non compatible 16-bit pour %d\n"
+#define MSG_HUGE_WARNING_2 "R‚sultats impr‚visibles possibles\n"
+#define MSG_IDLE "Au repos"
+#define MSG_ILLEGAL_INSTR "Instruction ill‚gale"
+#define MSG_ILL_FILTER_CONV "Conversion implicite ill‚gale dans un filtre"
+#define MSG_INDEX_CREATED "Index %s cr‚‚ sur %s"
+#define MSG_INDEX_DEF_ERR "Erreur sauvegardant l'index d‚finition pour %s"
+#define MSG_INDEX_DROPPED "Index %s supprim‚ de %s"
+#define MSG_INDEX_INIT_ERR "Echec de l'initialisation de l'index %s"
+#define MSG_INDEX_NOT_DEF "Index %s non d‚fini"
+#define MSG_INDEX_NOT_UNIQ "L'index n'est pas Unique"
+#define MSG_INDEX_ONE_SAVE "Les index sont sauvegard‚s dans un fichier unique"
+#define MSG_INDEX_SEP_SAVE "Les index sont sauvegard‚s dans des fichiers s‚par‚s"
+#define MSG_INDEX_YET_ON "L'index %s existe d‚j… sur %s"
+#define MSG_INDX_ALL_DROP "Tous les index de %s supprim‚s"
+#define MSG_INDX_COL_NOTIN "La colonne index %s n'existe pas dans la table %s"
+#define MSG_INDX_EXIST_YET "L'entr‚e index existe d‚j…"
+#define MSG_INIT_ERROR "Erreur à l'initialisation de %s"
+#define MSG_INIT_FAILED "L'initialisation de %s a ‚chou‚"
+#define MSG_INPUT "Entr‚e: "
+#define MSG_INPUT_KEYBD_YET "L'entr‚e est d‚j… au clavier"
+#define MSG_INSERTING "Insertion: "
+#define MSG_INSERT_ERROR "Insert erreur: usage multiple du fichier %s"
+#define MSG_INSERT_MISMATCH "Les listes colonne et valeur ne correspondent pas"
+#define MSG_INTERNAL "interne"
+#define MSG_INT_COL_ERROR "Erreur interne sur la colonne index %s"
+#define MSG_INT_OVERFLOW "D‚passement de capacit‚ sur entier"
+#define MSG_INT_ZERO_DIVIDE "Division entiŠre par z‚ro"
+#define MSG_INVALID_BIP "Bip invalide .%d"
+#define MSG_INVALID_DISP "Disposition invalide"
+#define MSG_INVALID_FTYPE "SBV: Ftype %d invalide"
+#define MSG_INVALID_HANDLE "Poign‚e invalide"
+#define MSG_INVALID_OPER "Op‚rateur invalide %d pour %s"
+#define MSG_INVALID_OPTION "Option invalide %s"
+#define MSG_INV_COLUMN_TYPE "Type %d Invalide pour la colonne %s"
+#define MSG_INV_COL_DATATYP "Type de donn‚es %d invalide pour la colonne %d"
+#define MSG_INV_COL_NUM "Colonne invalide %d"
+#define MSG_INV_COL_TYPE "Type de colonne %s invalide"
+#define MSG_INV_CONC_BIP "Bip invalide (seuls valides: %.8s.0 .1 and .5)"
+#define MSG_INV_DATA_PATH "Chemin vers les donn‚es invalide"
+#define MSG_INV_DEF_READ "Lecture diff‚r‚e invalide rc=%d"
+#define MSG_INV_DIRCOL_OFST "Offset invalide pour une colonne DIR"
+#define MSG_INV_DOMAIN_TYPE "Type invalide %d"
+#define MSG_INV_FILTER "Filtre r‚siduel dans %s"
+#define MSG_INV_FNC_BUFTYPE "FNC: Type %d de l'argument invalide pour %s"
+#define MSG_INV_INFO_TYPE "Type d'info catalog invalide %d"
+#define MSG_INV_INIPATH "Inipath invalide "
+#define MSG_INV_MAP_POS "Position m‚moire invalide"
+#define MSG_INV_OPERATOR "op‚rateur invalide %d\n"
+#define MSG_INV_PARAMETER "ParamŠtre invalide %s"
+#define MSG_INV_PARM_TYPE "Type de paramŠtre invalide"
+#define MSG_INV_QUALIFIER "Qalificateur '%s' invalide"
+#define MSG_INV_QUERY_TYPE "Type de requˆte %d invalide"
+#define MSG_INV_RAND_ACC "L'accŠs al‚atoire d'une table non optimis‚e est impossible"
+#define MSG_INV_REC_POS "Position d'enregistrement invalide"
+#define MSG_INV_RESULT_TYPE "Type de r‚sultat invalide %s"
+#define MSG_INV_SET_SUBTYPE "Type de formattage %d invalide"
+#define MSG_INV_SPECIAL_CMD "%s: Commande sp‚ciale invalide"
+#define MSG_INV_SUBTYPE "Sous type invalide %s"
+#define MSG_INV_TOK_DOMAIN "Le domaine %s n'existe pas"
+#define MSG_INV_TOPSEM_CMD "Commande TopSem invalide %c"
+#define MSG_INV_TRANSF_USE "Usage invalide en rŠgle transformationnelle"
+#define MSG_INV_TYPE_SPEC "Sp‚cification de type invalide (%.8s.%d)"
+#define MSG_INV_UPDT_TABLE "Table %s invalide pour Update"
+#define MSG_INV_VALUE_LIST "Liste de valeurs invalide pour Insert"
+#define MSG_INV_WHERE_JOIN "Clause Where invalide dans une requˆte de jointure"
+#define MSG_INV_WORK_PATH "Chemin de travail invalide"
+#define MSG_IN_ARGTYPE_MISM "Arguments de types incompatibles pour une expression IN"
+#define MSG_IN_USE " et en activit‚"
+#define MSG_IN_WITHOUT_SUB "IN ou EXISTS sans tableau ou subquery"
+#define MSG_IS_NOT_CONN "%s n'est pas une connexion d‚finie"
+#define MSG_JCT_MISS_COLS "Colonnes manquantes pour une table JCT"
+#define MSG_JCT_MISS_TABLE "Table jointe manquante pour JCT"
+#define MSG_JCT_NO_FILTER "Filtrage impossible des tables virtuelles JCT"
+#define MSG_JCT_NO_KEY "Erreur logique JCT: cl‚ manquante"
+#define MSG_JOIN_KEY_NO_COL "La cl‚ de jointure n'est pas une colonne"
+#define MSG_KEY_ALLOC_ERR "Erreur d'allocation d'un bloc offset cl‚"
+#define MSG_KEY_ALLOC_ERROR "Erreur d'allocation m‚moire, Klen=%d n=%d"
+#define MSG_LANGUAGE_QUIT "%s lib‚r‚"
+#define MSG_LANG_ACTIVE "Langage %s actif"
+#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Lang"
+#define MSG_LANG_ALREADY_UP "Langage d‚j… en ‚dition"
+#define MSG_LANG_BAD_SAVE "Langage %s peut-ˆtre incorrectement sauvegard‚"
+#define MSG_LANG_NOT_FREED "Langage %s non lib‚rable (pas dans la chaŒne principale)"
+#define MSG_LANG_SAVED "Langage %s sauvegard‚"
+#define MSG_LANG_WR_LEN_ERR "Erreur de longueur … l'‚criture du bloc Lang"
+#define MSG_LDF_ALLOC_ERROR "Erreur d'allocation d'un LdfBlock"
+#define MSG_LDF_RN_MISMATCH "LDF: d‚calage des num‚ros de rŠgle"
+#define MSG_LDF_WLEN_ERROR "Erreur de longueur en ‚crivant LdfData"
+#define MSG_LDF_W_LEN_ERROR "Erreur de longueur pour LdfData en ‚criture"
+#define MSG_LIC_NO_MYSQL "Votre licence actuelle ne permet pas l'utilisation du type MYSQL"
+#define MSG_LINEAR_ERROR "Erreur de lin‚arisation"
+#define MSG_LINE_LENGTH "Largeur d'impression fix‚e … %d"
+#define MSG_LINE_MAXLIN "Nombre de lignes de travail plafonn‚ … %d"
+#define MSG_LINE_MAXRES "Nombre de lignes de r‚sultat plafonn‚ … %d"
+#define MSG_LINE_MAXTMP "Nombre de lignes interm‚diaires plafonn‚ … %d"
+#define MSG_LINE_TOO_LONG "La nouvelle ligne est trop longue"
+#define MSG_LINJOINDB_ERROR "Erreur systŠme: appel incorrecte … LinJoinDB"
+#define MSG_LIST "--Liste--"
+#define MSG_LNG_NOT_IN_LIST "Le langage %s n'est pas dans la liste"
+#define MSG_LOADING_DB "Chargement description de la BD"
+#define MSG_LOADING_FAILED "Le chargement de %s a ‚chou‚"
+#define MSG_LOAD_CDLL_ERROR "Erreur au chargement de ConnDll: rc=%d"
+#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n trop grand ? (%d)\n"
+#define MSG_LOGICAL_ERROR "%s: Erreur logique"
+#define MSG_LRECL_TOO_SMALL "Lrecl trop petit (longueur en-tˆte = %d)"
+#define MSG_MAC_NO_DELETE "Pas de suppression de lignes pour les tables MAC"
+#define MSG_MAC_NO_INDEX "Pas d'accŠs direct aux tables MAC"
+#define MSG_MAC_READ_ONLY "Les tables MAC sont en lecture seulement"
+#define MSG_MAC_WIN_ONLY "Les tables MAC sont seulement sous Windows"
+#define MSG_MAKE_EMPTY_FILE "G‚n‚ration du fichier vide %s: %s"
+#define MSG_MAKING "G‚n‚ration"
+#define MSG_MAKING_DISTINCT "Regroupement des valeures distinctes"
+#define MSG_MALLOC_ERROR "Allocation m‚moire impossible par %s"
+#define MSG_MALLOC_NULL "malloc retourne Null"
+#define MSG_MAP_NO_MORE "Le type %s n'est plus support‚"
+#define MSG_MAP_OBJ_ERR "Erreur %d … la fermeture du map objet"
+#define MSG_MAP_VEC_ONLY "MAP Insert permis seulement pour les tables VEC Estimate"
+#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s erreur rc=%d"
+#define MSG_MAXSIZE_ERROR "Maxsize incalculable sur table ouverte"
+#define MSG_MAXTMP_TRUNCATE "R‚sultats interm‚diaires tronqu‚s par maxtmp=%d"
+#define MSG_MAX_BITMAP "Taille maxi des bitmaps d'optimisation fix‚e … %d"
+#define MSG_MEMSIZE_TOO_BIG "Erreur: memsize (%d) trop grand pour Length (%d)"
+#define MSG_MEM_ALLOC_ERR "Erreur d'allocation m‚moire, taille %s = %d"
+#define MSG_MEM_ALLOC_ERROR "Erreur d'allocation m‚moire"
+#define MSG_MEM_ALLOC_YET "M‚moire d‚j… allou‚e"
+#define MSG_METAFILE_NOTFND "Fichier Meta introuvable"
+#define MSG_MISPLACED_QUOTE "Appostrophe mal plac‚e ligne %d"
+#define MSG_MISSING "Manquant: Value=%p Argval=%p Builtin=%d"
+#define MSG_MISSING_ARG "Argument manquant pour l'op‚rateur %d"
+#define MSG_MISSING_COL_DEF "D‚finition des colonnes manquante"
+#define MSG_MISSING_CONNECT "Connection #1 manquante"
+#define MSG_MISSING_EOL "Fin de ligne manquante dans %s"
+#define MSG_MISSING_FIELD "Champs %d manquant dans %s ligne %d"
+#define MSG_MISSING_FNAME "Nom du fichier manquant"
+#define MSG_MISSING_NODE "Noeud %s manquant dans %s"
+#define MSG_MISSING_POS "POS code manquant"
+#define MSG_MISSING_ROWNODE "Impossible de trouver le noeud de la ligne %d"
+#define MSG_MISSING_SERV_DB "Indication serveur et/ou base de donn‚es manquante"
+#define MSG_MISS_LEAD_COL "Colonne majeure %s manquante"
+#define MSG_MISS_NAME_LRECL "Nom du fichier et/ou LRECL manquant"
+#define MSG_MISS_TABLE_LIST "Liste des tables manquante"
+#define MSG_MISS_VCT_ELMT "Taille de bloc vectoriel manquante (Elements)"
+#define MSG_MIS_TAG_LIST "Liste des balises colonne manquante"
+#define MSG_MKEMPTY_NIY "MakeEmptyFile: pas encore implement‚ pour Huge et Unix"
+#define MSG_MOVE_INV_TYPE "MOVPARM: paramŠtre de type invalide %d"
+#define MSG_MULT_DISTINCT "Distinct utilis‚ plus d'une fois"
+#define MSG_MULT_KEY_ERROR "Erreur sur cl‚ multiple k=%d n=%d"
+#define MSG_MUL_MAKECOL_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_MYSQL_CNC_OFF "La connexion … MySQL est ferm‚e"
+#define MSG_MYSQL_CNC_ON "La connexion … MySQL est ‚tablie"
+#define MSG_MYSQL_NOT_SUP "Pas de support de MySQL dans cette version"
+#define MSG_MY_CNC_ALREADY "La connexion … MySQL est d‚j… active"
+#define MSG_NAME_CONV_ERR "Erreur de convertion du nom de noeud"
+#define MSG_NAME_IS_USED "Le nom %s est d‚j… utilis‚"
+#define MSG_NCOL_GT_MAXCOL "Trop de colonnes (%d > %d max)"
+#define MSG_NEW_CHAR_NULL "new char(%d) retourne Null"
+#define MSG_NEW_DOC_FAILED "Impossible de cr‚er le nouveau document"
+#define MSG_NEW_RETURN_NULL "NULL renvoy‚ par New dans PlugEvalLike"
+#define MSG_NEW_TABLE_ERR "La nouvelle table %s ne peut pas ˆtre charg‚e"
+#define MSG_NEXT_FILE_ERROR "Erreur en recherche du fichier suivant. rc=%s"
+#define MSG_NODEF_FROM_VIEW "Pas de d‚finition de table depuis une view"
+#define MSG_NODE_FOR_CHAR "Noeud %s trouve au lieu d'un caractŠre"
+#define MSG_NODE_SUBSET_ERR "Erreur d'initialisation de la zone Noeud %d"
+#define MSG_NONCONT_EXCEPT "Exception non-continuable"
+#define MSG_NON_DUP_HAVING "Clause Having dans une requˆte non fonctionelle"
+#define MSG_NON_EVAL_SEM "Sem non ‚valu‚e: p_no=%d"
+#define MSG_NOP_ZLIB_INDEX "L'indexage d'une table zlib non optimis‚e est impossible"
+#define MSG_NOT_A_DBF_FILE "Le fichier n'a pas le format dBASE dbf "
+#define MSG_NOT_ENOUGH_COLS "Pas assez de colonnes dans %s"
+#define MSG_NOT_ENOUGH_MEM "M‚moire insuffisante pour cette op‚ration"
+#define MSG_NOT_FIXED_LEN "Fichier %s non fixe, len=%d lrecl=%d"
+#define MSG_NOT_IMPLEMENTED "Non implement‚: %.8s"
+#define MSG_NOT_IMPL_JOIN "Pas impl‚ment‚ pour les jointures"
+#define MSG_NOT_IMPL_SET "Pas impl‚ment‚ pour les op‚rateurs d'ensembles"
+#define MSG_NOT_IMPL_YET "Pas encore implement‚"
+#define MSG_NOT_LINEARIZED "Arborescence des tables non lin‚aris‚e"
+#define MSG_NOT_MODIFIABLE " (non modifiable)"
+#define MSG_NO_0DH_HEAD "0DH manquant en fin d'en-tˆte (dbc=%d)"
+#define MSG_NO_ACTIVE_APPL "Pas d'application active"
+#define MSG_NO_ACTIVE_DB "Pas de base de donn‚es active"
+#define MSG_NO_ACTIVE_UDIC "Pas de dictionaire utilisateur actif"
+#define MSG_NO_AGGR_FUNC "Fonction aggr‚g‚e %d ill‚gale … cet endroit"
+#define MSG_NO_AREA_FILE "Fichier Area introuvable"
+#define MSG_NO_AVAIL_RESULT "Pas de r‚sultat disponible"
+#define MSG_NO_BIG_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les fichiers HUGE"
+#define MSG_NO_CHAR_FROM "Conversion de type %d en caractŠres impossible"
+#define MSG_NO_CLUSTER_COL "Pas de colonne optimisable"
+#define MSG_NO_COL_ADDING "Ajouter des colonnes dans une d‚finition existante est impossible"
+#define MSG_NO_COL_DEF_AS "La d‚finitions des colonnes est incompatible avec AS Select"
+#define MSG_NO_COL_FOUND "La section colonne %s est vide"
+#define MSG_NO_COL_IN_TABLE "La colonne %d n'est pas dans la table %s"
+#define MSG_NO_COL_SECTION "Section colonne manquante pour la table %s"
+#define MSG_NO_CONNECT_ADDR "Adresse de connection non sp‚cifi‚e"
+#define MSG_NO_CONST_FILTER "Filtres constants non implement‚s"
+#define MSG_NO_CURLY_BRKT "Pas d'accolade de fermeture"
+#define MSG_NO_DATABASE "Base de donn‚es %s introuvable"
+#define MSG_NO_DATE_FMT "Pas de format date pour le valblock de type %d"
+#define MSG_NO_DBF_INSERT "Insert pas encore impl‚ment‚ pour les fichier DBF"
+#define MSG_NO_DEF_FNCCOL "Colonne fonction par d‚faut introuvable"
+#define MSG_NO_DEF_PIVOTCOL "Colonne pivot par d‚faut introuvable"
+#define MSG_NO_DIR_INDX_RD "Pas d'accŠs directe des tables %s"
+#define MSG_NO_DMY_DIR_ACC "Pas d'accŠs direct aux tables virtuelles DUMMY"
+#define MSG_NO_DOM_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les domaines"
+#define MSG_NO_DOM_MATCH "ChaŒne %.8s... non touv‚e dans le domaine %s"
+#define MSG_NO_EDITED_LANG "Coparm: Pas de langage en ‚dition"
+#define MSG_NO_EXP_LINK "Liaison par expression invalide pour une table JCT"
+#define MSG_NO_EXT_FILTER "Le filtrage ne peut se r‚f‚rer … une autre table"
+#define MSG_NO_EXT_UPDATE "Pas de mise … jour en r‚f‚rence … une autre table"
+#define MSG_NO_FEAT_SUPPORT "%s non support‚ dans cette version"
+#define MSG_NO_FILE_LIST "La table %s n'a pas de liste de fichiers"
+#define MSG_NO_FLD_FORMAT "Format absent pour le champs %d de %s"
+#define MSG_NO_FORMAT_COL "Type COLUMN informattable"
+#define MSG_NO_FORMAT_TYPE "Le format ne peut pas ˆtre d‚fini … partir du type %d"
+#define MSG_NO_FULL_JOIN "Jointures autoris‚es seulement … ‚galit‚ sur cl‚(s)"
+#define MSG_NO_FUL_OUT_JOIN "Jointures externes complŠtes non support‚es"
+#define MSG_NO_FUNC_ORDER "Tri non support‚ sur ‚l‚ment fonctionnel"
+#define MSG_NO_HEAD_JOIN "Jointure sur une table non en tˆte"
+#define MSG_NO_HQL_CONV "Conversion en HQL non disponible"
+#define MSG_NO_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_INDEX_GBX "Pas ou mauvais index pour SQLGBX"
+#define MSG_NO_INDEX_IN "Pas d'index dans %s"
+#define MSG_NO_INDEX_READ "Pas d'accŠs directe des tables multiples"
+#define MSG_NO_INIT_LANG "Pas de langage initial"
+#define MSG_NO_JOIN_TO_EXP "Jointure vers une expression impossible"
+#define MSG_NO_JOIN_UPDEL "Pas de jointure avec Update/Delete"
+#define MSG_NO_KEY_COL "Pas de colonne cl‚ trouv‚e"
+#define MSG_NO_KEY_UPDATE "Le nom des cl‚s ne peut pas ˆtre modifi‚"
+#define MSG_NO_LANGUAGE "Pas de langage op‚rationnel\n"
+#define MSG_NO_LANG_TO_QUIT "Pas de langage … quitter"
+#define MSG_NO_LISTVAL_HERE "LSTBLK: Liste de valeurs utilis‚e hors contexte"
+#define MSG_NO_MAP_INSERT "MAP incompatible avec Insert"
+#define MSG_NO_MATCHING_COL "Pas de colonne correspondant … %s dans %s"
+#define MSG_NO_MATCH_COL "Colonne correspondante introuvable"
+#define MSG_NO_MEMORY "M‚moire pleine"
+#define MSG_NO_MEM_CORR_SUB "Subquery corr‚l‚e en m‚moire non encore impl‚ment‚e"
+#define MSG_NO_MODE_PADDED "Mode non support‚ pour les fichiers 'padded'"
+#define MSG_NO_MORE_COL "La colonne %s n'est plus dans la table pivot"
+#define MSG_NO_MORE_LANG "Plus de langage, exit de %s\n"
+#define MSG_NO_MORE_VAR "Les fichiers VAR ne sont plus support‚s"
+#define MSG_NO_MULCOL_JOIN "Jointure vers un index multi-colonne pas encore possible"
+#define MSG_NO_MULT_HAVING "Clauses Having multiples non impl‚ment‚es"
+#define MSG_NO_MUL_DIR_ACC "AccŠs direct des tables multiples pas encore impl‚ment‚"
+#define MSG_NO_MUL_VCT "Les tables VCT ne peuvent pas ˆtre multiples"
+#define MSG_NO_MYSQL_CONN "Aucune connexion MySQL ouverte"
+#define MSG_NO_MYSQL_DELETE "Pas de Delete pour les tables MySQL"
+#define MSG_NO_NBCOL "Pas de NBcol"
+#define MSG_NO_NBLIN "Pas de NBlin, MaxSize ou Continued"
+#define MSG_NO_NBLIN_CONT "Fetch: Pas de NBlin ou Continued"
+#define MSG_NO_NULL_CONST "Les constantes <null> ne sont pas prises en charge"
+#define MSG_NO_ODBC_COL "Colonnes ODBC automatiques non support‚es par cette version"
+#define MSG_NO_ODBC_DELETE "Delete ne devrait pas ˆtre appel‚ pour les tables ODBC"
+#define MSG_NO_ODBC_DIRECT "AccŠs directe des tables ODBC non encore impl‚ment‚"
+#define MSG_NO_ODBC_MUL "Multiple(2) non support‚ pour les tables ODBC"
+#define MSG_NO_ODBC_SPECOL "Pas de colonne sp‚ciale ODBC"
+#define MSG_NO_OPT_COLUMN "Pas optimisable ou pas de colonne optimis‚es"
+#define MSG_NO_OP_MODIF "Les modificateurs ne s'appliquent pas … %s"
+#define MSG_NO_PARAMETER "Pas de paramŠtre"
+#define MSG_NO_PART_DEL "Delete partiel des fichier %s impossible"
+#define MSG_NO_PART_MAP "Mapping partiel non impl‚ment‚ pour cet OS"
+#define MSG_NO_PAR_BLK_INS "Insertion de bloc partiel impossible"
+#define MSG_NO_PIV_DIR_ACC "Pas d'accŠs directe aux tables PIVOT"
+#define MSG_NO_POS_ADDED "Pos_code non ajout‚"
+#define MSG_NO_PROMPTING "Relance impossible pour les tables distribu‚es"
+#define MSG_NO_QRY_DELETE "Delete n'est pas utilisable pour les views QRY"
+#define MSG_NO_QUERY_ARRAY "Tableaux avec QUERY non encore impl‚ment‚s"
+#define MSG_NO_RCUR_DSK_YET "Usage r‚cursif de DISK non encore implement‚"
+#define MSG_NO_READ_32 "Lecture de 32 octets impossible"
+#define MSG_NO_RECOV_SPACE "Espace non recouvrable dans le fichier index"
+#define MSG_NO_REF_DELETE "Pas de suppression en r‚f‚rence … une autre table"
+#define MSG_NO_REF_UPDATE "Pas de mise … jour en r‚f‚rence … une autre table"
+#define MSG_NO_REMOTE_FNC "Certaines fonctions ne peuvent pas ˆtre ex‚cut‚es … distance"
+#define MSG_NO_ROWID_FOR_AM "AccŠs direct impossible de ROWID pour les tables de type %s"
+#define MSG_NO_ROW_NODE "Le nom du Rownode n'est pas d‚fini"
+#define MSG_NO_SECTION_NAME "Nom de section manquant"
+#define MSG_NO_SEC_UPDATE "Les noms de section ne peuvent pas ˆtre modifi‚s"
+#define MSG_NO_SELECTED_DB "Aucune base de donn‚es s‚lect‚e"
+#define MSG_NO_SELF_PIVOT "Une table ne peut se pivoter elle-mˆme !"
+#define MSG_NO_SERVER_FOUND "Serveur introuvable"
+#define MSG_NO_SETPOS_YET "SetPos pas encore impl‚ment‚ pour les fichier %s"
+#define MSG_NO_SFEXIT_UNIX "Fonction %s non disponible sur Unix"
+#define MSG_NO_SOURCE " (pas de source)"
+#define MSG_NO_SPEC_COL "Pas de colonne sp‚ciales MYSQL"
+#define MSG_NO_SQL_DELETE "Delete n'est pas utilisable actuellement pour les views SQL"
+#define MSG_NO_SUB_VAL "Pas de sous-value d'un tableau de type %d"
+#define MSG_NO_SUCH_INDEX "La table %s n'a pas l'index %s"
+#define MSG_NO_SUCH_SERVER "Serveur %s introuvable"
+#define MSG_NO_SUCH_TABLE "Table %s pas dans la base de donn‚es"
+#define MSG_NO_TABCOL_DATA "Pas de donn‚es pour la table %s colonne %s"
+#define MSG_NO_TABLE_COL "Aucune colonne trouv‚e pour %s"
+#define MSG_NO_TABLE_DEL "Delete non autoris‚ pour les tables %s "
+#define MSG_NO_TABLE_DESC "Pas de bloc descriptif de table"
+#define MSG_NO_TABLE_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_TABLE_LIST "Pas de liste de tables"
+#define MSG_NO_TAB_DATA "Pas de donn‚es pour la table %s"
+#define MSG_NO_TERM_IN_TOK "Les non-terminaux ne sont pas utilisables dans les rŠgles de Token"
+#define MSG_NO_TOKEN_DB "DB introuvable pour la colonne TOKEN %s"
+#define MSG_NO_UNIX_CATINFO "Pas d'info catalogue sous Unix"
+#define MSG_NO_UPDEL_JOIN "Pas de jointure de tables ODBC pour Update/Delete"
+#define MSG_NO_VCT_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les fichiers VCT"
+#define MSG_NO_VIEW_COLDEF "Colonne d‚finition impossible pour les views"
+#define MSG_NO_VIEW_SORT "La View fonctionnelle %s ne peut pas ˆtre tri‚e ou jointe"
+#define MSG_NO_ZIP_DELETE "Delete sur fichier Zip non encore implement‚"
+#define MSG_NO_ZIP_DIR_ACC "AccŠs directe des tables ZDOS non encore implement‚"
+#define MSG_NULL_COL_VALUE "La colonne n'a pas de valeur"
+#define MSG_NULL_ENTRY "InitLang, entr‚e nulle %d %s"
+#define MSG_NULL_QUERY "Requˆte vide"
+#define MSG_NUMVAL_NOMATCH "Disparit‚ de Numval pour %s"
+#define MSG_N_FULL_PARSES "%d significations"
+#define MSG_ODBC_READ_ONLY "ODBC est actuellement en lecture seulement"
+#define MSG_OFFSET_NOT_SUPP "Offset non support‚ pour ce type de sous requˆte"
+#define MSG_ONE_LANG_YET "Un langage est d‚j… en ‚dition"
+#define MSG_ONE_PARAM_ONLY "Un seul paramŠtre autoris‚"
+#define MSG_ONLY_LOG10_IMPL "Seul Log10 est implement‚"
+#define MSG_ON_LANGUAGE "Langage %.8s version %d niveau %d ‚ditable"
+#define MSG_OPENING "Ouverture"
+#define MSG_OPENING_QUERY "Ouverture de la requˆte"
+#define MSG_OPEN_EMPTY_FILE "Ouverture du fichier vide %s: %s"
+#define MSG_OPEN_ERROR "Erreur d'ouverture %d en mode %d sur %s: "
+#define MSG_OPEN_ERROR_IS "Erreur … l'ouverture de %s: %s"
+#define MSG_OPEN_ERROR_ON "Erreur d'ouverture sur %s"
+#define MSG_OPEN_MODE_ERROR "Erreur d'ouverture(%s) %d sur %s"
+#define MSG_OPEN_SORT_ERROR "Erreur logique de tri dans QUERY Open"
+#define MSG_OPEN_STRERROR "Erreur … l'ouverture: %s"
+#define MSG_OPEN_W_ERROR "Erreur … l'ouverture de %s en ‚criture"
+#define MSG_OPTBLK_RD_ERR "Erreur … la lecture d'un bloc optimisation: %s"
+#define MSG_OPTBLK_WR_ERR "Erreur … l'‚criture d'un bloc optimisation: %s"
+#define MSG_OPTIMIZING "Optimisation de "
+#define MSG_OPT_BMAP_RD_ERR "Erreur en lecture des bitmaps d'optimisation: %s"
+#define MSG_OPT_BMAP_WR_ERR "Erreur en ‚criture des bitmaps d'optimisation: %s"
+#define MSG_OPT_CANCELLED "Optimisation interrompue par l'utilisateur"
+#define MSG_OPT_DVAL_RD_ERR "Erreur en lecture des valeurs distinctes: %s"
+#define MSG_OPT_DVAL_WR_ERR "Erreur en ‚criture des valeurs distinctes: %s"
+#define MSG_OPT_HEAD_RD_ERR "Erreur en lecture de l'entˆte du fichier opt: %s"
+#define MSG_OPT_HEAD_WR_ERR "Erreur en ‚criture de l'entˆte du fichier opt: %s"
+#define MSG_OPT_INIT "Optimisation initialis‚e"
+#define MSG_OPT_LOGIC_ERR "Erreur logique dans SetBitmap, i=%d"
+#define MSG_OPT_MAX_RD_ERR "Erreur en lecture des valeurs maxi: %s"
+#define MSG_OPT_MAX_WR_ERR "Erreur en ‚criture des valeurs maxi: %s"
+#define MSG_OPT_MIN_RD_ERR "Erreur en lecture des valeurs mini: %s"
+#define MSG_OPT_MIN_WR_ERR "Erreur en ‚criture des valeurs mini: %s"
+#define MSG_OPT_NOT_MATCH "Le fichier opt %s n'est pas … jour"
+#define MSG_OP_RES_TOO_LONG "R‚sultat trop long pour l'op‚rateur=%d"
+#define MSG_ORDER_OUT_RANGE "Tri: Order %d hors limite"
+#define MSG_ORDER_TWICE "Un mˆme ‚l‚ment est tri‚ deux fois"
+#define MSG_PAGE_ERROR "Erreur de pagination"
+#define MSG_PARM_CNT_MISS "Disparit‚ du nombre de ParamŠtres"
+#define MSG_PARSE_NULL_SEM "S‚mantique nulle"
+#define MSG_PARSING_QUERY "Analyse de la requˆte"
+#define MSG_PIX_ERROR "Pix %s erreur rŠgle no=%u\n"
+#define MSG_PIX_TEST_ERROR "RŠgle=%u: pix-TEST pas dans le premier noeud\n"
+#define MSG_PLG_READ_ONLY "PLG est actuellement en lecture seulement"
+#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp est NULL"
+#define MSG_PLUG_NOT_INIT "Plug n'est pas initialis‚\n"
+#define MSG_PLUG_NOT_RUN "Plug n'est pas en marche"
+#define MSG_PNODE_RULE "(Noeud %d rŠgle %d) "
+#define MSG_POS_TOO_LONG "%s trop long (>%d)"
+#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp est NULL"
+#define MSG_PRIV_INSTR "Instruction privil‚gi‚e"
+#define MSG_PROCADD_ERROR "Erreur %d sur l'adresse de %s"
+#define MSG_PROCESS_SUBQRY "Sub-Query en cours de traitement"
+#define MSG_PROC_WOULD_LOOP "Bouclage du traitement (maxres=%d maxlin=%d)"
+#define MSG_PROGRESS_INFO "Informations sur le traitement en cours"
+#define MSG_PROMPT_CANCEL "Relance annul‚e"
+#define MSG_PROMPT_NIY "Prompt non impl‚ment‚ pour cette configuration"
+#define MSG_PTR_NOT_FOUND "Pointeur introuvable Num=%d ti1=%d"
+#define MSG_PXDEF_IS_NULL "Pxdef est NULL"
+#define MSG_QRY_READ_ONLY "Les views QRY sont en lecture seulement"
+#define MSG_QUERY_CANCELLED "Requˆte interrompue par l'utilisateur"
+#define MSG_QUERY_NOT_EXEC "Requˆte non ex‚cut‚e"
+#define MSG_QUERY_SAVED "Requˆte %s sauvegard‚e"
+#define MSG_QUOTE_IN_QUOTE "Appostrophe dans un champ entre appostrophe ligne %d"
+#define MSG_RANGE_NIY "Range pas encore impl‚ment‚ pour %s"
+#define MSG_RANGE_NO_JOIN "Range non compatible avec les index de jointure"
+#define MSG_RC_READING "rc=%d en lecture de la table %s"
+#define MSG_READB_BAD_INIT "%s ReadDB appel‚ avec Init=0"
+#define MSG_READCOL_ERROR "SQLCOL: erreur dans ReadColumn"
+#define MSG_READING "Lecture"
+#define MSG_READING_FROM "Lecture de %s"
+#define MSG_READING_RECORD "Erreur en lecture de l'enregistrement %d de %s"
+#define MSG_READY "Prˆt"
+#define MSG_READ_ERROR "Erreur en lecture sur %s: %s"
+#define MSG_READ_ERROR_RC "Erreur en lecture, rc=%d"
+#define MSG_READ_MEM_ERROR "Lecture m‚moire %d: taille=%d"
+#define MSG_READ_ONLY "Cette table prot‚g‚e en lecture seule ne peut ˆtre modifi‚e"
+#define MSG_READ_SEEK_ERROR "Erreur de recherche en lecture: %s"
+#define MSG_READ_SEG_ERROR "Lecture segment %d: taille=%d"
+#define MSG_RECEIVED "Re‡u %c\n"
+#define MSG_RECORD_ERROR "Erreur … la lecture de l'enregistrement %d de %s"
+#define MSG_RECORD_NO_SEP "Enregistrement sans s‚parateur"
+#define MSG_REC_SKIPPED " (%d lignes erronn‚es saut‚es par l'option MaxErr)"
+#define MSG_REDUCE_INDEX "Réduction de l'index"
+#define MSG_REGISTER_ERR "Enregistrement NS impossible, pr‚fix='%s' et href='%s'"
+#define MSG_REMOTE_CONN_ERR "La connection ‚loign‚e a ‚chou‚"
+#define MSG_REMOVE_ERROR "Erreur en supprimant %s: %s"
+#define MSG_REMOVE_NOT_IMPL "Remove non impl‚ment‚ pour TDB non Table"
+#define MSG_RENAME_ERROR "Erreur renommant %s en %s: %s"
+#define MSG_RENUM_RULES "Renum‚rotez les rŠgles et r‚entrez ADD (rŠgle sauvegard‚e dans la zone tampon)"
+#define MSG_REORDER_INDEX "Reclassement de l'index"
+#define MSG_REQU_ARG_NUM "La fonction %s doit avoir %d arguments"
+#define MSG_RESET_TO "%s remis … %d"
+#define MSG_RES_NOT_UNIQUE "Le r‚sultat n'est pas unique"
+#define MSG_RET_FROM_LANG "Retour au language %s version %d.%d du language %s version %d.%d"
+#define MSG_ROWID_NOT_IMPL "RowNumber non impl‚ment‚ pour les tables de type %s"
+#define MSG_ROWS_SELECTED "%d lignes s‚lectionn‚es en %.2lf sec"
+#define MSG_ROWS_TRUNCATED " (tronqu‚ par MAXRES, LIMIT, FREQ ou AreaSize)"
+#define MSG_ROW_ARGNB_ERR "ROW: disparit‚ du nombre d'arguments (%d,%d)"
+#define MSG_RPC_SERVER_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_RSC_ALLOC_ERROR "Erreur d'allocation m‚moire dans Rescol %s"
+#define MSG_RULE_ENTERED "RŠgle %d entr‚e"
+#define MSG_RULE_SUBSET_ERR "Erreur d'initialisation de la zone RŠgles"
+#define MSG_SAVING_INDEX "Sauvegarde du fichier index"
+#define MSG_SCAN_NOT_IMP "Scan non impl‚ment‚"
+#define MSG_SEC_KEY_FIRST "Les sections et cl‚s doivent ˆtre ins‚r‚es en premier"
+#define MSG_SEC_NAME_FIRST "Le nom de section doit ˆtre en tˆte de liste en insertion"
+#define MSG_SEC_NOT_FOUND "Section %s absente de %s"
+#define MSG_SEEK_ERROR "Seek erreur dans CopyHeader"
+#define MSG_SEMANTIC_TREE "Arbre s‚mantique"
+#define MSG_SEM_BAD_REF "Sem @%d r‚f‚rence un argument de type non 0 ou 1"
+#define MSG_SEM_UNKNOWN "inconnue, rc=%d"
+#define MSG_SEP_IN_FIELD "Le champ %d contient le caractŠre s‚parateur"
+#define MSG_SEQUENCE_ERROR "HSTMT: Allocation hors s‚quence"
+#define MSG_SETEOF_ERROR "Erreur %d dans SetEndOfFile"
+#define MSG_SETRECPOS_NIY "SetRecpos non impl‚ment‚ pour ce type de table"
+#define MSG_SET_LOCALE "Locale fix‚e … %s"
+#define MSG_SET_NULL_DOM "Valeur %d donn‚e … un domaine nul"
+#define MSG_SET_OP_NOT_IMPL "Op‚rateurs ensemblistes non impl‚ment‚s"
+#define MSG_SET_STR_TRUNC "SetValue: ChaŒne de caractŠres tronqu‚e"
+#define MSG_SEVERAL_TREES "Jointure non sp‚cifi‚e pour certaines tables"
+#define MSG_SFP_ERROR "Erreur sur SetFilePointer: %s"
+#define MSG_SFUNC_NOT_IMPL "Fonction scalaire %s non impl‚ment‚e"
+#define MSG_SHARED_LIB_ERR "Erreur au chargement de la librairie partag‚e %s: %s"
+#define MSG_SINGLE_STEP "Pas … pas"
+#define MSG_SLEEP "J'ai dormi %d milliseconds"
+#define MSG_SMART_SORTING "R‚cup‚ration des lignes tri‚es (passage %d de %d)"
+#define MSG_SMART_SORT_ERR "Erreur logique 1 dans Smart Sort"
+#define MSG_SORTING "Tri en cours"
+#define MSG_SORTING_INDEX "Tri de l'index"
+#define MSG_SORTING_VAL "Tri de %d valeurs"
+#define MSG_SORT_JOIN_INDEX "Tri de l'index de jointure"
+#define MSG_SPCOL_READONLY "La colonne sp‚ciale %s est en lecture seulement"
+#define MSG_SPEC_CMD_SEP "Les commandes sp‚ciales doivent ˆtre ex‚cut‚es s‚par‚ment"
+#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d non support‚"
+#define MSG_SQL_BLOCK_MISM "CheckColumn: bloc SQL courant non correspondant"
+#define MSG_SQL_CONF_ERROR "Erreur SQL: SQL_CONFORMANCE"
+#define MSG_SQL_READ_ONLY "Les views SQL sont actuellement en lecture seulement"
+#define MSG_SRCH_CLOSE_ERR "Erreur … la fermeture de l'Handle de recherche"
+#define MSG_SRC_TABLE_UNDEF "La table source n'est pas d‚finie"
+#define MSG_STACK_ERROR "Erreur sur la pile, i=%d\n"
+#define MSG_STACK_OVERFLOW "Parser: D‚bordement de la pile\n"
+#define MSG_STRG_NOT_FOUND "ChaŒne introuvable"
+#define MSG_STRING_INV_LIST "Liste invalide pour SemString"
+#define MSG_STRING_TOO_BIG "ChaŒne trop grande pour le domaine %s"
+#define MSG_SUBALLOC_ERROR "Pas assez de m‚moire en zone %p pour allouer %d (utilis‚=%d libre=%d)"
+#define MSG_SUBAL_HUGE_ERR "Pas assez de m‚moire en zone huge %p pour allouer %d"
+#define MSG_SUBARG_NOSEM "Argument @ ou sous-phrase de niveau %d pointe sur un noeud sans Sem"
+#define MSG_SUBARG_OUTRANGE "Argument @ ou sous-phrase de niveau %d hors limite"
+#define MSG_SUBQRY_ONEITEM "Une Sub-Query ne doit avoir qu'une s‚lection"
+#define MSG_SUBSET_ERROR "SubSet erreur dans LoadDB"
+#define MSG_SUB_OPEN_YET "Subquery d‚j… ouverte"
+#define MSG_SUB_RES_TOO_LNG "R‚sultat trop long pour SUBSTR"
+#define MSG_SYNTAX_ERROR "Erreur de syntaxe"
+#define MSG_SYSTEM_ERROR "Erreur systŠme %d"
+#define MSG_S_ACCESS_DENIED "%s: accŠs non autoris‚"
+#define MSG_S_ERROR "%s erreur"
+#define MSG_S_ERROR_NUM "%s: erreur=%d"
+#define MSG_S_INTRUPT_ERROR "%s: erreur interruption"
+#define MSG_S_INVALID_PARM "%s: paramŠtre invalide"
+#define MSG_S_INV_ADDRESS "%s: adresse invalide"
+#define MSG_S_UNKNOWN_ERROR "%s: erreur de code %u inconnu"
+#define MSG_TABDIR_READONLY "Les tables DIR sont en lecture seulement"
+#define MSG_TABLE_ALREADY "La table %s existe d‚j…"
+#define MSG_TABLE_ALTERED "Table %s %s alt‚r‚e"
+#define MSG_TABLE_CREATED "%s table %s cr‚‚e"
+#define MSG_TABLE_DROPPED "Table %s supprim‚e"
+#define MSG_TABLE_MULT_JOIN "Utilisation multiple de la table %s pour jointure"
+#define MSG_TABLE_NOT_IN_DB "La table %s n'existe pas dans %s"
+#define MSG_TABLE_NOT_OPT "Table non optimisable"
+#define MSG_TABLE_NO_INDEX "La table %s n'est pas indexable"
+#define MSG_TABLE_NO_OPT "La table %s n'existe pas ou de type non optimisable"
+#define MSG_TABLE_READ_ONLY "Les tables %s sont en lecture seulement "
+#define MSG_TABMUL_READONLY "Les tables multiples sont en lecture seulement"
+#define MSG_TAB_NOT_LOADED " (certaines tables n'ont put ˆtre charg‚es)"
+#define MSG_TAB_NOT_SPEC "Table non specifi‚e"
+#define MSG_TB_VW_NOTIN_DB "Table ou view %s pas dans la base de donn‚es"
+#define MSG_TDB_NXT_NOT_NUL "Tdb.Next non NULL"
+#define MSG_TDB_USE_ERROR "Erreur, Tdbp->Use=%d"
+#define MSG_TOO_MANY_COLS "Trop de colonnes"
+#define MSG_TOO_MANY_COLTAB "Trop de colonnes dans %s (%d)"
+#define MSG_TOO_MANY_FIELDS "Trop de champs ligne %d de %s"
+#define MSG_TOO_MANY_JUMPS "Trop de niveaux de saut"
+#define MSG_TOO_MANY_KEYS "Trop de cl‚s (%d)"
+#define MSG_TOO_MANY_POS "Trop de pos_codes"
+#define MSG_TOO_MANY_TABLES "Trop de tables (%d)"
+#define MSG_TOPSEM_ERROR "Erreur inconnue dans TopSem"
+#define MSG_TO_BLK_IS_NULL "To Blk est nul"
+#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr n'est pas nul"
+#define MSG_TO_PIX_NOT_NULL "Set.To_Pix n'est pas nul"
+#define MSG_TO_SEM_NOT_NULL "Set.To_Sem n'est pas nul"
+#define MSG_TRUNCATE_ERROR "Erreur en troncation: %s"
+#define MSG_TRUNC_BY_ESTIM "Tronqu‚ par l'option Estimate"
+#define MSG_TYPES_ERROR "Erreur sur Types(%d)"
+#define MSG_TYPE_CONV_ERROR "Type non convertible dans une expression"
+#define MSG_TYPE_DEF_MISM "Disparit‚ entre type et d‚finition"
+#define MSG_TYPE_MISMATCH "Cl‚ et source ne sont pas du mˆme type"
+#define MSG_TYPE_RECFM_MISM "Disparit‚ entre Type et Recfm"
+#define MSG_TYPE_TO_VERIFY "Type … v‚rifier: %d"
+#define MSG_TYPE_VALUE_ERR "Colonne %s: disparit‚ type(%s)/valeur(%s)"
+#define MSG_UNBALANCE_QUOTE "Appostrophe en trop ligne %d"
+#define MSG_UNDEFINED_AM "COLBLK %s: m‚thode d'accŠs ind‚finie"
+#define MSG_UNDEFINED_PATH "Chemin d'accŠs ind‚fini pour Plgcnx.ini"
+#define MSG_UNDEF_COL_COUNT "Count sur colonne non d‚finie"
+#define MSG_UNKNOWN_DOMAIN "Domaine inconnu %s"
+#define MSG_UNKNOWN_ERROR "Erreur inconnue"
+#define MSG_UNKNOWN_EXCPT "Exception non r‚pertori‚e"
+#define MSG_UNKNOWN_NAME "Nom inconnu: %.8s"
+#define MSG_UNKNOWN_PATH "Chemin d'accŠs inconnu pour Plgcnx.ini"
+#define MSG_UNKNOWN_POS "Nom pos_code inconnu: %s"
+#define MSG_UNKNOWN_SEM "Sem %.8s inconnue, rc=%d"
+#define MSG_UNKNOWN_SYNONYM "Synonyme inconnu"
+#define MSG_UNKNW_QRY_TYPE "ReadDB: type de requˆte inconnu"
+#define MSG_UNKN_ERR_CODE "Erreur de code %d inconnu"
+#define MSG_UNLOADABLE " inchargeable: "
+#define MSG_UNLOADABLE_PRM "%s inchargeable: %s"
+#define MSG_UNMATCH_FIL_ARG "Argument de filtre d‚pareill‚"
+#define MSG_UNQ_COL_SEV_TAB "La colonne %s non qualifi‚e est dans plusieurs tables"
+#define MSG_UNRESOLVED_ARG "?Argument manquant: %s non r‚solu en %d ligne %d"
+#define MSG_UPDATE_ERROR "Erreur en Update sur %s"
+#define MSG_UPDATING_ROWS "Mise … jour des lignes"
+#define MSG_UPD_ZIP_NOT_IMP "Mise … jour des tables ZDOS non encore implement‚"
+#define MSG_UP_LANGUAGE "Bloc langage %.8s version %d niveau %d charg‚"
+#define MSG_USED_FREE_MEM "Sarea: utilis‚ %d, libre %d"
+#define MSG_USETEMP_IS "Usetemp est : %s"
+#define MSG_USETEMP_RESET ". Usetemp remis … Auto"
+#define MSG_USETEMP_SET "Usetemp fix‚ … %s"
+#define MSG_USE_NO_MATCH "Use non correspondant : Use=%d, ti2=%d, ti3=%d"
+#define MSG_USING_INDEX " (Index‚ par"
+#define MSG_VALIST_MISMATCH "Disparit‚ des listes de valeurs"
+#define MSG_VALSTR_TOO_LONG "Valeur %s trop longue pour une chaŒne de longueur %d"
+#define MSG_VALTYPE_NOMATCH "Disparit‚ types de valeur"
+#define MSG_VALUE_ERROR "Colonne %s: bloc valeur nul"
+#define MSG_VALUE_NOT_ALLOC "Valeur non allou‚e pour la colonne R%d %s"
+#define MSG_VALUE_TOO_BIG "Valeur %lld trop grande pour la colonne %s"
+#define MSG_VALUE_TOO_LONG "Valeur %s trop longue pour la colonne %s de longueur %d"
+#define MSG_VAL_ALLOC_ERR "Allocation impossible du noeud valeur"
+#define MSG_VAL_TOO_LONG "Valeur %s trop longue pour le champ %s"
+#define MSG_VIEW_ALREADY "La VIEW %s existe d‚j…"
+#define MSG_VIEW_CREATED "%s view %s cr‚‚e"
+#define MSG_VIEW_DROPPED "View %s supprim‚e"
+#define MSG_VIEW_NOT_IN_DB "%s n'est pas une View de %s"
+#define MSG_VIR_NO_DELETE "Delete impossible sur les tables %s"
+#define MSG_VIR_READ_ONLY "Les tables virtuelles %s sont en lecture seulement"
+#define MSG_VM_LANG "Langage au format VM, non support‚"
+#define MSG_VOID_FIRST_ARG "Le premier argument ne doit pas ˆtre vide"
+#define MSG_VOID_IN_STRING "Erreur: chaŒne IN vide"
+#define MSG_VOID_ORDER_LIST "Liste de tri vide, erreur systŠme ?"
+#define MSG_VOID_POS_DICT "Dictionnaire interne du langage vide"
+#define MSG_VOID_QUERY "Requˆte vide %s"
+#define MSG_WORK_AREA "Espace de travail: %s"
+#define MSG_WORK_TOO_SMALL "Zone de travail trop petite, accroŒtre AreaSize"
+#define MSG_WRITE_ERROR "Erreur … l'‚criture de %s"
+#define MSG_WRITE_SEEK_ERR "Erreur de recherche en ‚criture: %s"
+#define MSG_WRITE_STRERROR "Erreur en ‚criture sur %s: %s"
+#define MSG_WRITING "Ecriture"
+#define MSG_WRITING_ERROR "Erreur … l'‚criture de %s: %s"
+#define MSG_WRITING_QUERY "Erreur … l'‚criture de la requˆte: "
+#define MSG_WRONG_ARG_NUM "La fonction %s ne prend pas %d arguments"
+#define MSG_WRONG_COL_NUM "Num‚ro de colonne %d trop grand pour %s"
+#define MSG_WRONG_DB_LIST "Liste des bases de donn‚es incorrecte ou vide"
+#define MSG_WRONG_FUNCTION "Mauvaise fonction %d"
+#define MSG_WRONG_OP_PARM "Mauvais op‚rateur ou paramŠtres pour %s"
+#define MSG_WRONG_PARMS "Mauvais paramŠtres pour %s"
+#define MSG_WRONG_PASSWORD "Mot de passe ill‚gal pour %s"
+#define MSG_WRONG_TYPE "type non support‚"
+#define MSG_WRONG_USERFILE "La Userfile a une mauvaise taille %d"
+#define MSG_WS_CONV_ERR "Erreur de convertion de %s en WS"
+#define MSG_XCOL_MISMATCH "La colonne %s ne correspond pas … l'index"
+#define MSG_XDB_DEL_ERROR "Erreur en supprimant des entr‚es du fichier XDB"
+#define MSG_XFILE_READERR "Erreur %d en lisant le fichier index"
+#define MSG_XFILE_TOO_SMALL "Le fichier index est plus petit que la taille de l'index"
+#define MSG_XFILE_WRITERR "Erreur en ‚crivant le fichier index: %s"
+#define MSG_XMLTAB_INIT_ERR "Erreur d'initialisation de la table XML"
+#define MSG_XML_INIT_ERROR "Erreur d'initialisation du nouveau fichier XML"
+#define MSG_XPATH_CNTX_ERR "Le nouveau contexte XPath ne peut ˆtre cr‚‚"
+#define MSG_XPATH_EVAL_ERR "Impossible d'‚valuer l'emplacement xpath '%s'"
+#define MSG_XPATH_NOT_SUPP "Xpath non support‚ colonne %s"
+#define MSG_X_ARG_ADDED "%d arguments ajout‚s"
+#define MSG_X_ARG_SET "%d arguments ont ‚t‚ initialis‚s"
+#define MSG_X_ON_TAB " %s sur %s("
+#define MSG_ZERO_DIVIDE "Division par z‚ro dans une expression"
diff --git a/storage/connect/global.h b/storage/connect/global.h
index 9b48a7fb0c3..4bc7b8f4e9f 100644
--- a/storage/connect/global.h
+++ b/storage/connect/global.h
@@ -1,251 +1,251 @@
-/***********************************************************************/
-/* 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(DOMDOC_SUPPORT) || defined(LIBXML2_SUPPORT)
-#define XML_SUPPORT 1
-#endif
-
-#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_BIGINT 5
-#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. */
-/***********************************************************************/
-#include "os.h"
-
-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 --------------------------*/
+/***********************************************************************/
+/* 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(DOMDOC_SUPPORT) || defined(LIBXML2_SUPPORT)
+#define XML_SUPPORT 1
+#endif
+
+#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_BIGINT 5
+#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. */
+/***********************************************************************/
+#include "os.h"
+
+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 --------------------------*/
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
index dbfa83a4ce7..ade617e3448 100644
--- a/storage/connect/ha_connect.cc
+++ b/storage/connect/ha_connect.cc
@@ -1,3777 +1,3777 @@
-/* Copyright (C) Olivier Bertrand 2004 - 2013
-
- 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.cc
-
- @brief
- The ha_connect engine is a stubbed storage engine that enables to create tables
- based on external data. Principally they are based on plain files of many
- different types, but also on collections of such files, collection of tables,
- ODBC tables retrieving data from other DBMS having an ODBC server, and even
- virtual tables.
-
- @details
- ha_connect will let you create/open/delete tables, the created table can be
- done specifying an already existing file, the drop table command will just
- suppress the table definition but not the eventual data file.
- Indexes are not yet supported but data can be inserted, updated or deleted.
-
- You can enable the CONNECT storage engine in your build by doing the
- following during your build process:<br> ./configure
- --with-connect-storage-engine (not implemented yet)
-
- You can install the CONNECT handler as all other storage handlers.
-
- Once this is done, MySQL will let you create tables with:<br>
- CREATE TABLE <table name> (...) ENGINE=CONNECT;
-
- The example storage engine does not use table locks. It
- implements an example "SHARE" that is inserted into a hash by table
- name. This is not used yet.
-
- Please read the object definition in ha_connect.h before reading the rest
- of this file.
-
- @note
- This MariaDB CONNECT handler is currently an adaptation of the XDB handler
- that was written for MySQL version 4.1.2-alpha. Its overall design should
- be enhanced in the future to meet MariaDB requirements.
-
- @note
- It was written also from the Brian's ha_example handler and contains parts
- of it that are there but not currently used, such as table variables.
-
- @note
- When you create an CONNECT table, the MySQL Server creates a table .frm
- (format) file in the database directory, using the table name as the file
- name as is customary with MySQL. No other files are created. To get an idea
- of what occurs, here is an example select that would do a scan of an entire
- table:
-
- @code
- ha-connect::open
- ha_connect::store_lock
- ha_connect::external_lock
- ha_connect::info
- ha_connect::rnd_init
- ha_connect::extra
- ENUM HA_EXTRA_CACHE Cache record in HA_rrnd()
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::rnd_next
- ha_connect::extra
- ENUM HA_EXTRA_NO_CACHE End caching of records (def)
- ha_connect::external_lock
- ha_connect::extra
- ENUM HA_EXTRA_RESET Reset database to after open
- @endcode
-
- Here you see that the connect storage engine has 9 rows called before
- rnd_next signals that it has reached the end of its data. Calls to
- ha_connect::extra() are hints as to what will be occuring to the request.
-
- Happy use!<br>
- -Olivier
-*/
-
-#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
-#define MYSQL_SERVER 1
-#define DONT_DEFINE_VOID
-//#include "sql_partition.h"
-#include "sql_class.h"
-#include "create_options.h"
-#include "mysql_com.h"
-#include "field.h"
-#undef OFFSET
-
-#define NOPARSE
-#if defined(UNIX)
-#include "osutil.h"
-#endif // UNIX
-#include "global.h"
-#include "plgdbsem.h"
-#include "reldef.h"
-#include "tabcol.h"
-#include "xindex.h"
-#include "connect.h"
-#include "user_connect.h"
-#include "ha_connect.h"
-#include "mycat.h"
-
-#define PLGINI "plugdb.ini" /* Configuration settings file */
-#define PLGXINI "plgcnx.ini" /* Configuration settings file */
-#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))
-
-#if defined (WIN32)
-typedef struct _WMIutil *PWMIUT; /* Used to call WMIColumns */
-#endif
-/****************************************************************************/
-/* CONNECT functions called externally. */
-/****************************************************************************/
-bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname);
-PTDB CntGetTDB(PGLOBAL g, const char *name, MODE xmod, PHC);
-bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE, char *, char *, bool, PHC);
-bool CntRewindTable(PGLOBAL g, PTDB tdbp);
-int CntCloseTable(PGLOBAL g, PTDB tdbp);
-int CntIndexInit(PGLOBAL g, PTDB tdbp, int id);
-RCODE CntReadNext(PGLOBAL g, PTDB tdbp);
-RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const void *k, int n);
-RCODE CntWriteRow(PGLOBAL g, PTDB tdbp);
-RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp);
-RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all);
-bool CntInfo(PGLOBAL g, PTDB tdbp, PXF info);
-int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len,
- bool *incl, key_part_map *kmap);
-#ifdef LIBXML2_SUPPORT
-void XmlInitParserLib(void);
-void XmlCleanupParserLib(void);
-#endif // LIBXML2_SUPPORT
-
-/****************************************************************************/
-/* Functions called externally by pre_parser. */
-/****************************************************************************/
-PQRYRES DBFColumns(PGLOBAL g, char *fn, BOOL info);
-PQRYRES CSVColumns(PGLOBAL g, char *fn, char sep, char q, int hdr, int mxr);
-#if defined(ODBC_SUPPORT)
-PQRYRES MyODBCCols(PGLOBAL g, char *tab, char *dsn);
-#endif // ODBC_SUPPORT
-#if defined(MYSQL_SUPPORT)
-PQRYRES MyColumns(PGLOBAL g, char *host, char *db, char *user, char *pwd,
- char *table, char *colpat, int port, bool key);
-#endif // MYSQL_SUPPORT
-enum enum_field_types PLGtoMYSQL(int type, bool gdf);
-#if defined(WIN32)
-PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *classname, PWMIUT wp= NULL);
-#endif // WIN32
-char GetTypeID(char *type);
-bool check_string_char_length(LEX_STRING *str, const char *err_msg,
- uint max_char_length, CHARSET_INFO *cs,
- bool no_error);
-
-/***********************************************************************/
-/* DB static variables. */
-/***********************************************************************/
-extern "C" char plgxini[];
-extern "C" char plgini[];
-extern "C" char nmfile[];
-extern "C" char pdebug[];
-
-extern "C" {
- char version[]= "Version 1.00.0005 October 03, 2012";
-
-#if defined(XMSG)
- char msglang[]; // Default message language
-#endif
- int trace= 0; // The general trace value
-} // extern "C"
-
-/****************************************************************************/
-/* Initialize the ha_connect static members. */
-/****************************************************************************/
-char connectini[_MAX_PATH]= "connect.ini";
-int xtrace= 0;
-ulong ha_connect::num= 0;
-//int DTVAL::Shift= 0;
-
-static handler *connect_create_handler(handlerton *hton,
- TABLE_SHARE *table,
- MEM_ROOT *mem_root);
-
-handlerton *connect_hton;
-
-/* Variables for connect share methods */
-
-/*
- Hash used to track the number of open tables; variable for connect share
- methods
-*/
-static HASH connect_open_tables;
-
-/* The mutex used to init the hash; variable for example share methods */
-mysql_mutex_t connect_mutex;
-
-
-/**
- structure for CREATE TABLE options (table options)
-
- These can be specified in the CREATE TABLE:
- CREATE TABLE ( ... ) {...here...}
-*/
-struct ha_table_option_struct {
- const char *type;
- const char *filename;
- const char *optname;
- const char *tabname;
- const char *tablist;
- const char *dbname;
- const char *separator;
-//const char *connect;
- const char *qchar;
- const char *module;
- const char *subtype;
- const char *oplist;
- int lrecl;
- int elements;
-//int estimate;
- int multiple;
- int header;
- int quoted;
- int ending;
- int compressed;
- bool mapped;
- bool huge;
- bool split;
- bool readonly;
- };
-
-#if defined(MARIADB)
-ha_create_table_option connect_table_option_list[]=
-{
- // These option are for stand alone Connect tables
- HA_TOPTION_STRING("TABLE_TYPE", type),
- HA_TOPTION_STRING("FILE_NAME", filename),
- HA_TOPTION_STRING("XFILE_NAME", optname),
-//HA_TOPTION_STRING("CONNECT_STRING", connect),
- HA_TOPTION_STRING("TABNAME", tabname),
- HA_TOPTION_STRING("TABLE_LIST", tablist),
- HA_TOPTION_STRING("DB_NAME", dbname),
- HA_TOPTION_STRING("SEP_CHAR", separator),
- HA_TOPTION_STRING("QCHAR", qchar),
- HA_TOPTION_STRING("MODULE", module),
- HA_TOPTION_STRING("SUBTYPE", subtype),
- HA_TOPTION_STRING("OPTION_LIST", oplist),
- HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1),
- HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1),
-//HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1),
- HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 2, 1),
- HA_TOPTION_NUMBER("HEADER", header, 0, 0, 3, 1),
- HA_TOPTION_NUMBER("QUOTED", quoted, -1, 0, 3, 1),
- HA_TOPTION_NUMBER("ENDING", ending, -1, 0, INT_MAX32, 1),
- HA_TOPTION_NUMBER("COMPRESS", compressed, 0, 0, 2, 1),
-//HA_TOPTION_BOOL("COMPRESS", compressed, 0),
- HA_TOPTION_BOOL("MAPPED", mapped, 0),
- HA_TOPTION_BOOL("HUGE", huge, 0),
- HA_TOPTION_BOOL("SPLIT", split, 0),
- HA_TOPTION_BOOL("READONLY", readonly, 0),
- HA_TOPTION_END
-};
-#endif // MARIADB
-
-
-/**
- structure for CREATE TABLE options (field options)
-
- These can be specified in the CREATE TABLE per field:
- CREATE TABLE ( field ... {...here...}, ... )
-*/
-struct ha_field_option_struct
-{
- int offset;
- int freq; // Not used by this version
- int opt; // Not used by this version
- int buflen;
- const char *dateformat;
- const char *fieldformat;
- char *special;
-};
-
-#if defined(MARIADB)
-ha_create_table_option connect_field_option_list[]=
-{
- HA_FOPTION_NUMBER("FLAG", offset, -1, 0, INT_MAX32, 1),
- HA_FOPTION_NUMBER("FREQUENCY", freq, 0, 0, INT_MAX32, 1), // not used
- HA_FOPTION_NUMBER("OPT_VALUE", opt, 0, 0, 2, 1), // used for indexing
- HA_FOPTION_NUMBER("BUF_LENGTH", buflen, 0, 0, INT_MAX32, 1),
- HA_FOPTION_STRING("DATE_FORMAT", dateformat),
- HA_FOPTION_STRING("FIELD_FORMAT", fieldformat),
- HA_FOPTION_STRING("SPECIAL", special),
- HA_FOPTION_END
-};
-#endif // MARIADB
-
-
-/**
- @brief
- Function we use in the creation of our hash to get key.
-*/
-static uchar* connect_get_key(CONNECT_SHARE *share, size_t *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=share->table_name_length;
- return (uchar*) share->table_name;
-}
-
-#ifdef HAVE_PSI_INTERFACE
-static PSI_mutex_key ex_key_mutex_connect, ex_key_mutex_CONNECT_SHARE_mutex;
-
-static PSI_mutex_info all_connect_mutexes[]=
-{
- { &ex_key_mutex_connect, "connect", PSI_FLAG_GLOBAL},
- { &ex_key_mutex_CONNECT_SHARE_mutex, "CONNECT_SHARE::mutex", 0}
-};
-
-/***********************************************************************/
-/* Push G->Message as a MySQL warning. */
-/***********************************************************************/
-bool PushWarning(PGLOBAL g, PTDBASE tdbp)
- {
- PHC phc;
- THD *thd;
- MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
-
- if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
- !(thd= (phc->GetTable())->in_use))
- return true;
-
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
- return false;
- } // end of PushWarning
-
-static void init_connect_psi_keys()
-{
- const char* category= "connect";
- int count;
-
- if (PSI_server == NULL)
- return;
-
- count= array_elements(all_connect_mutexes);
- PSI_server->register_mutex(category, all_connect_mutexes, count);
-}
-#endif
-
-static int connect_init_func(void *p)
-{
- DBUG_ENTER("connect_init_func");
-
-#ifdef HAVE_PSI_INTERFACE
- init_connect_psi_keys();
-#endif
-
- connect_hton= (handlerton *)p;
- mysql_mutex_init(ex_key_mutex_connect, &connect_mutex, MY_MUTEX_INIT_FAST);
-//VOID(mysql_mutex_init(&connect_mutex, MY_MUTEX_INIT_FAST));
- (void) my_hash_init(&connect_open_tables, system_charset_info, 32, 0, 0,
- (my_hash_get_key) connect_get_key, 0, 0);
-
-//connect_hton->name= "CONNECT";
- connect_hton->state= SHOW_OPTION_YES;
-//connect_hton->comment= "CONNECT handler";
- connect_hton->create= connect_create_handler;
- connect_hton->flags= HTON_TEMPORARY_NOT_SUPPORTED | HTON_NO_PARTITION;
-#if defined(MARIADB)
- connect_hton->db_type= DB_TYPE_AUTOASSIGN;
- connect_hton->table_options= connect_table_option_list;
- connect_hton->field_options= connect_field_option_list;
-#else // !MARIADB
-//connect_hton->system_database= connect_system_database;
-//connect_hton->is_supported_system_table= connect_is_supported_system_table;
-#endif // !MARIADB
-
- if (xtrace)
- printf("connect_init: hton=%p\n", p);
-
- DTVAL::SetTimeShift(); // Initialize time zone shift once for all
- DBUG_RETURN(0);
-}
-
-
-static int connect_done_func(void *p)
-{
- int error= 0;
- PCONNECT pc, pn;
- DBUG_ENTER("connect_done_func");
-
- if (connect_open_tables.records)
- error= 1;
-
- for (pc= user_connect::to_users; pc; pc= pn) {
- if (pc->g)
- PlugCleanup(pc->g, true);
-
- pn= pc->next;
- delete pc;
- } // endfor pc
-
- my_hash_free(&connect_open_tables);
- mysql_mutex_destroy(&connect_mutex);
-
- DBUG_RETURN(error);
-}
-
-
-/**
- @brief
- Example of simple lock controls. The "share" it creates is a
- structure we will pass to each example handler. Do you have to have
- one of these? Well, you have pieces that are used for locking, and
- they are needed to function.
-*/
-
-static CONNECT_SHARE *get_share(const char *table_name, TABLE *table)
-{
- CONNECT_SHARE *share;
- uint length;
- char *tmp_name;
-
- mysql_mutex_lock(&connect_mutex);
- length=(uint) strlen(table_name);
-
- if (!(share=(CONNECT_SHARE*)my_hash_search(&connect_open_tables,
- (uchar*) table_name, length))) {
- if (!(share=(CONNECT_SHARE *)my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &share, sizeof(*share), &tmp_name, length+1, NullS))) {
- mysql_mutex_unlock(&connect_mutex);
- return NULL;
- } // endif share
-
- share->use_count=0;
- share->table_name_length=length;
- share->table_name=tmp_name;
- strmov(share->table_name, table_name);
-
- if (my_hash_insert(&connect_open_tables, (uchar*) share))
- goto error;
-
- thr_lock_init(&share->lock);
- mysql_mutex_init(ex_key_mutex_CONNECT_SHARE_mutex,
- &share->mutex, MY_MUTEX_INIT_FAST);
- } // endif share
-
- share->use_count++;
- mysql_mutex_unlock(&connect_mutex);
- return share;
-
-error:
- mysql_mutex_destroy(&share->mutex);
- my_free(share);
- return NULL;
-}
-
-
-/**
- @brief
- Free lock controls. We call this whenever we close a table. If the table had
- the last reference to the share, then we free memory associated with it.
-*/
-
-static int free_share(CONNECT_SHARE *share)
-{
- mysql_mutex_lock(&connect_mutex);
-
- if (!--share->use_count) {
- my_hash_delete(&connect_open_tables, (uchar*) share);
- thr_lock_delete(&share->lock);
- mysql_mutex_destroy(&share->mutex);
-#if !defined(MARIADB)
- my_free(share->table_options);
- my_free(share->field_options);
-#endif // !MARIADB
- my_free(share);
- } // endif share
-
- mysql_mutex_unlock(&connect_mutex);
- return 0;
-}
-
-static handler* connect_create_handler(handlerton *hton,
- TABLE_SHARE *table,
- MEM_ROOT *mem_root)
-{
- handler *h= new (mem_root) ha_connect(hton, table);
-
- if (xtrace)
- printf("New CONNECT %p, table: %s\n",
- h, table ? table->table_name.str : "<null>");
-
- return h;
-} // end of connect_create_handler
-
-/****************************************************************************/
-/* ha_connect constructor. */
-/****************************************************************************/
-ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg)
- :handler(hton, table_arg)
-{
- hnum= ++num;
- xp= NULL; // Tested in next call
- xp= (table) ? GetUser(table->in_use) : NULL;
- tdbp= NULL;
- sdval= NULL;
- xmod= MODE_ANY;
- istable= false;
-//*tname= '\0';
- bzero((char*) &xinfo, sizeof(XINFO));
- valid_info= false;
- valid_query_id= 0;
- creat_query_id= (table && table->in_use) ? table->in_use->query_id : 0;
- stop= false;
-//hascond= false;
- indexing= -1;
- data_file_name= NULL;
- index_file_name= NULL;
- enable_activate_all_index= 0;
- int_table_flags= (HA_NO_TRANSACTIONS | HA_NO_PREFIX_CHAR_KEYS);
- ref_length= sizeof(int);
-#if !defined(MARIADB)
- share= NULL;
- table_options= NULL;
- field_options= NULL;
-#endif // !MARIADB
- tshp= NULL;
-} // end of ha_connect constructor
-
-
-/****************************************************************************/
-/* ha_connect destructor. */
-/****************************************************************************/
-ha_connect::~ha_connect(void)
-{
- if (xp) {
- PCONNECT p;
-
- xp->count--;
-
- for (p= user_connect::to_users; p; p= p->next)
- if (p == xp)
- break;
-
- if (p && !p->count) {
- if (p->next)
- p->next->previous= p->previous;
-
- if (p->previous)
- p->previous->next= p->next;
- else
- user_connect::to_users= p->next;
-
- } // endif p
-
- if (!xp->count) {
- PlugCleanup(xp->g, true);
- delete xp;
- } // endif count
-
- } // endif xp
-
-#if !defined(MARIADB)
- my_free(table_options);
- my_free(field_options);
-#endif // !MARIADB
-} // end of ha_connect destructor
-
-
-/****************************************************************************/
-/* Get a pointer to the user of this handler. */
-/****************************************************************************/
-PCONNECT ha_connect::GetUser(THD *thd)
-{
- const char *dbn= NULL;
-
- if (!thd)
- return NULL;
-
- if (xp && thd == xp->thdp)
- return xp;
-
- for (xp= user_connect::to_users; xp; xp= xp->next)
- if (thd == xp->thdp)
- break;
-
- if (!xp) {
- xp= new user_connect(thd, dbn);
-
- if (xp->user_init(this)) {
- delete xp;
- xp= NULL;
- } // endif user_init
-
- } else
- xp->count++;
-
- return xp;
-} // end of GetUser
-
-
-/****************************************************************************/
-/* Get the global pointer of the user of this handler. */
-/****************************************************************************/
-PGLOBAL ha_connect::GetPlug(THD *thd)
-{
- PCONNECT lxp= GetUser(thd);
- return (lxp) ? lxp->g : NULL;
-} // end of GetPlug
-
-
-/****************************************************************************/
-/* Return the value of an option specified in the option list. */
-/****************************************************************************/
-char *ha_connect::GetListOption(char *opname, const char *oplist, char *def)
-{
- char key[16], val[256];
- char *pk, *pv, *pn;
- char *opval= def;
- int n;
-
- for (pk= (char*)oplist; ; pk= ++pn) {
- pn= strchr(pk, ',');
- pv= strchr(pk, '=');
-
- if (pv && (!pn || pv < pn)) {
- n= pv - pk;
- memcpy(key, pk, n);
- key[n]= 0;
- pv++;
-
- if (pn) {
- n= pn - pv;
- memcpy(val, pv, n);
- val[n]= 0;
- } else
- strcpy(val, pv);
-
- } else {
- if (pn) {
- n= pn - pk;
- memcpy(key, pk, n);
- key[n]= 0;
- } else
- strcpy(key, pk);
-
- val[0]= 0;
- } // endif pv
-
- if (!stricmp(opname, key)) {
- opval= (char*)PlugSubAlloc(xp->g, NULL, strlen(val) + 1);
- strcpy(opval, val);
- break;
- } else if (!pn)
- break;
-
- } // endfor pk
-
- return opval;
-} // end of GetListOption
-
-/****************************************************************************/
-/* Return the table option structure. */
-/****************************************************************************/
-PTOS ha_connect::GetTableOptionStruct(TABLE *tab)
-{
-#if defined(MARIADB)
- return (tshp) ? tshp->option_struct : tab->s->option_struct;
-#else // !MARIADB
- if (share && share->table_options)
- return share->table_options;
- else if (table_options)
- return table_options;
-
- char *pk, *pv, *pn, *val;
- size_t len= sizeof(ha_table_option_struct) + tab->s->comment.length + 1;
- PTOS top= (PTOS)my_malloc(len, MYF(MY_FAE | MY_ZEROFILL));
-
- top->quoted= -1; // Default value
- top->ending= -1; // Default value
- pk= (char *)top + sizeof(ha_table_option_struct);
- memcpy(pk, tab->s->comment.str, tab->s->comment.length);
-
- for (; pk; pk= ++pn) {
- pn= strchr(pk, ',');
- pv= strchr(pk, '=');
-
- if (pn) *pn= 0;
-
- if (pv) *pv= 0;
-
- val= (pv && (!pn || pv < pn)) ? pv + 1 : "";
-
- if (!stricmp(pk, "type") || !stricmp(pk, "Table_Type")) {
- top->type= val;
- } else if (!stricmp(pk, "fn") || !stricmp(pk, "filename")
- || !stricmp(pk, "File_Name")) {
- top->filename= val;
- } else if (!stricmp(pk, "optfn") || !stricmp(pk, "optname")
- || !stricmp(pk, "Xfile_Name")) {
- top->optname= val;
- } else if (!stricmp(pk, "name") || !stricmp(pk, "tabname")) {
- top->tabname= val;
- } else if (!stricmp(pk, "tablist") || !stricmp(pk, "tablelist")
- || !stricmp(pk, "Table_list")) {
- top->tablist= val;
- } else if (!stricmp(pk, "sep") || !stricmp(pk, "separator")
- || !stricmp(pk, "Sep_Char")) {
- top->separator= val;
- } else if (!stricmp(pk, "db") || !stricmp(pk, "database")
- || !stricmp(pk, "DB_Name")) {
- top->dbname= val;
- } else if (!stricmp(pk, "qchar")) {
- top->qchar= val;
- } else if (!stricmp(pk, "module")) {
- top->module= val;
- } else if (!stricmp(pk, "subtype")) {
- top->subtype= val;
- } else if (!stricmp(pk, "lrecl")) {
- top->lrecl= atoi(val);
- } else if (!stricmp(pk, "elements")) {
- top->elements= atoi(val);
- } else if (!stricmp(pk, "multiple")) {
- top->multiple= atoi(val);
- } else if (!stricmp(pk, "header")) {
- top->header= atoi(val);
- } else if (!stricmp(pk, "quoted")) {
- top->quoted= atoi(val);
- } else if (!stricmp(pk, "ending")) {
- top->ending= atoi(val);
- } else if (!stricmp(pk, "compressed")) {
- top->compressed= atoi(val);
- } else if (!stricmp(pk, "mapped")) {
- top->mapped= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
- } else if (!stricmp(pk, "huge")) {
- top->huge= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
- } else if (!stricmp(pk, "split")) {
- top->split= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
- } else if (!stricmp(pk, "readonly") || !stricmp(pk, "protected")) {
- top->readonly= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
- } // endif's
-
- if (!pn)
- break;
-
- } // endfor pk
-
- // This to get all other options
- top->oplist= tab->s->comment.str;
-
- if (share)
- share->table_options= top;
- else
- table_options= top;
-
- return top;
-#endif // !MARIADB
-} // end of GetTableOptionStruct
-
-/****************************************************************************/
-/* Return the value of a string option or NULL if not specified. */
-/****************************************************************************/
-char *ha_connect::GetStringOption(char *opname, char *sdef)
-{
- char *opval= NULL;
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- ;
- else if (!stricmp(opname, "Type"))
- opval= (char*)options->type;
- else if (!stricmp(opname, "Filename"))
- opval= (char*)options->filename;
- else if (!stricmp(opname, "Optname"))
- opval= (char*)options->optname;
- else if (!stricmp(opname, "Tabname"))
- opval= (char*)options->tabname;
- else if (!stricmp(opname, "Tablist"))
- opval= (char*)options->tablist;
- else if (!stricmp(opname, "Database"))
- opval= (char*)options->dbname;
- else if (!stricmp(opname, "Separator"))
- opval= (char*)options->separator;
- else if (!stricmp(opname, "Connect"))
-// opval= (char*)options->connect;
- opval= table->s->connect_string.str;
- else if (!stricmp(opname, "Qchar"))
- opval= (char*)options->qchar;
- else if (!stricmp(opname, "Module"))
- opval= (char*)options->module;
- else if (!stricmp(opname, "Subtype"))
- opval= (char*)options->subtype;
-
- if (!opval && options->oplist)
- opval= GetListOption(opname, options->oplist);
-
- if (!opval) {
- if (sdef && !strcmp(sdef, "*")) {
- // Return the handler default value
- if (!stricmp(opname, "Database"))
- opval= (char*)GetDBName(NULL); // Current database
-
- } else
- opval= sdef; // Caller default
-
- } // endif !opval
-
- return opval;
-} // end of GetStringOption
-
-/****************************************************************************/
-/* Return the value of a Boolean option or bdef if not specified. */
-/****************************************************************************/
-bool ha_connect::GetBooleanOption(char *opname, bool bdef)
-{
- bool opval= bdef;
- char *pv;
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- ;
- else if (!stricmp(opname, "Mapped"))
- opval= options->mapped;
- else if (!stricmp(opname, "Huge"))
- opval= options->huge;
-//else if (!stricmp(opname, "Compressed"))
-// opval= options->compressed;
- else if (!stricmp(opname, "Split"))
- opval= options->split;
- else if (!stricmp(opname, "Readonly"))
- opval= options->readonly;
- else if (options->oplist)
- if ((pv= GetListOption(opname, options->oplist)))
- opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0);
-
- return opval;
-} // end of GetBooleanOption
-
-/****************************************************************************/
-/* Return the value of an integer option or NO_IVAL if not specified. */
-/****************************************************************************/
-int ha_connect::GetIntegerOption(char *opname)
-{
- int opval= NO_IVAL;
- char *pv;
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- ;
- else if (!stricmp(opname, "Lrecl"))
- opval= options->lrecl;
- else if (!stricmp(opname, "Elements"))
- opval= options->elements;
- else if (!stricmp(opname, "Estimate"))
-// opval= options->estimate;
- opval= (int)table->s->max_rows;
- else if (!stricmp(opname, "Avglen"))
- opval= (int)table->s->avg_row_length;
- else if (!stricmp(opname, "Multiple"))
- opval= options->multiple;
- else if (!stricmp(opname, "Header"))
- opval= options->header;
- else if (!stricmp(opname, "Quoted"))
- opval= options->quoted;
- else if (!stricmp(opname, "Ending"))
- opval= options->ending;
- else if (!stricmp(opname, "Compressed"))
- opval= (options->compressed);
-
- if (opval == NO_IVAL && options->oplist)
- if ((pv= GetListOption(opname, options->oplist)))
- opval= atoi(pv);
-
- return opval;
-} // end of GetIntegerOption
-
-/****************************************************************************/
-/* Set the value of the opname option (does not work for oplist options) */
-/* Currently used only to set the Lrecl value. */
-/****************************************************************************/
-bool ha_connect::SetIntegerOption(char *opname, int n)
-{
- PTOS options= GetTableOptionStruct(table);
-
- if (!options)
- return true;
-
- if (!stricmp(opname, "Lrecl"))
- options->lrecl= n;
- else if (!stricmp(opname, "Elements"))
- options->elements= n;
-//else if (!stricmp(opname, "Estimate"))
-// options->estimate= n;
- else if (!stricmp(opname, "Multiple"))
- options->multiple= n;
- else if (!stricmp(opname, "Header"))
- options->header= n;
- else if (!stricmp(opname, "Quoted"))
- options->quoted= n;
- else if (!stricmp(opname, "Ending"))
- options->ending= n;
- else if (!stricmp(opname, "Compressed"))
- options->compressed= n;
- else
- return true;
-//else if (options->oplist)
-// SetListOption(opname, options->oplist, n);
-
- return false;
-} // end of SetIntegerOption
-
-/****************************************************************************/
-/* Return a field option structure. */
-/****************************************************************************/
-PFOS ha_connect::GetFieldOptionStruct(Field *fdp)
-{
-#if defined(MARIADB)
- return fdp->option_struct;
-#else // !MARIADB
- if (share && share->field_options)
- return &share->field_options[fdp->field_index];
- else if (field_options)
- return &field_options[fdp->field_index];
-
- char *pc, *pk, *pv, *pn, *val;
- int i, k, n= table->s->fields;
- size_t len= n + n * sizeof(ha_field_option_struct);
- PFOS fp, fop;
-
- for (i= 0; i < n; i++)
- len+= table->s->field[i]->comment.length;
-
- fop= (PFOS)my_malloc(len, MYF(MY_FAE | MY_ZEROFILL));
- pc= (char*)fop + n * sizeof(ha_field_option_struct);
-
- for (i= k= 0; i < n; i++) {
- fp= &fop[i];
- fp->offset= -1; // Default value
-
- if (!table->s->field[i]->comment.length)
- continue;
-
- memcpy(pc, table->s->field[i]->comment.str,
- table->s->field[i]->comment.length);
-
- for (pk= pc; pk; pk= ++pn) {
- if ((pn= strchr(pk, ','))) *pn= 0;
- if ((pv= strchr(pk, '='))) *pv= 0;
- val= (pv && (!pn || pv < pn)) ? pv + 1 : "";
-
- if (!stricmp(pk, "datefmt") || !stricmp(pk, "date_format")) {
- fp->dateformat= val;
- } else if (!stricmp(pk, "fieldfmt") || !stricmp(pk, "field_format")) {
- fp->fieldformat= val;
- } else if (!stricmp(pk, "special")) {
- fp->special= val;
- } else if (!stricmp(pk, "offset") || !stricmp(pk, "flag")) {
- fp->offset= atoi(val);
- } else if (!stricmp(pk, "freq")) {
- fp->freq= atoi(val);
- } else if (!stricmp(pk, "opt")) {
- fp->opt= atoi(val);
- } else if (!stricmp(pk, "buflen")) {
- fp->buflen= atoi(val);
- } // endif's
-
- if (!pn)
- break;
-
- } // endfor pk
-
- pc+= table->s->field[i]->comment.length + 1;
- } // endfor i
-
- if (share)
- share->field_options= fop;
- else
- field_options= fop;
-
- return &fop[fdp->field_index];
-#endif // !MARIADB
-} // end of GetFildOptionStruct
-
-/****************************************************************************/
-/* Returns the column description structure used to make the column. */
-/****************************************************************************/
-void *ha_connect::GetColumnOption(void *field, PCOLINFO pcf)
-{
- const char *cp;
- int len;
- ha_field_option_struct *fop;
- Field* fp;
- Field* *fldp;
-
- // Double test to be on the safe side
- if (!table)
- return NULL;
-
- // Find the column to describe
- if (field) {
- fldp= (Field**)field;
- fldp++;
- } else
- fldp= (tshp) ? tshp->field : table->field;
-
- if (!(fp= *fldp))
- return NULL;
-
- // Get the CONNECT field options structure
- fop= GetFieldOptionStruct(fp);
- pcf->Flags= 0;
-
- // Now get column information
- if (fop && fop->special) {
- pcf->Name= "*";
- return fldp;
- } else
- pcf->Name= (char*)fp->field_name;
-
- pcf->Prec= 0;
- pcf->Opt= (fop) ? fop->opt : 0;
-
- if ((pcf->Length= fp->field_length) < 0)
- pcf->Length= 256; // BLOB?
-
- switch (fp->type()) {
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VARCHAR:
- pcf->Flags |= U_VAR;
- case MYSQL_TYPE_STRING:
- pcf->Type= TYPE_STRING;
-
- // Do something for case
- cp= fp->charset()->name;
-
- // Find if collation name ends by _ci
- if (!strcmp(cp + strlen(cp) - 3, "_ci")) {
- pcf->Prec= 1; // Case insensitive
- pcf->Opt= 0; // Prevent index opt until it is safe
- } // endif ci
-
- break;
- case MYSQL_TYPE_LONG:
- pcf->Type= TYPE_INT;
- break;
- case MYSQL_TYPE_SHORT:
- pcf->Type= TYPE_SHORT;
- break;
- case MYSQL_TYPE_DOUBLE:
- case MYSQL_TYPE_FLOAT:
- pcf->Type= TYPE_FLOAT;
- pcf->Prec= max(min(fp->decimals(), ((unsigned)pcf->Length - 2)), 0);
- break;
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- pcf->Type= TYPE_DATE;
- break;
- case MYSQL_TYPE_LONGLONG:
- pcf->Type= TYPE_BIGINT;
- break;
- default:
- pcf->Type=TYPE_ERROR;
- } // endswitch type
-
- // This is used to skip null bit
- if (fp->real_maybe_null())
- pcf->Flags |= U_NULLS;
-
-#if defined(MARIADB)
- // Mark virtual columns as such
- if (fp->vcol_info && !fp->stored_in_db)
- pcf->Flags |= U_VIRTUAL;
-#endif // MARIADB
-
- pcf->Key= 0; // Not used when called from MySQL
- pcf->Remark= fp->comment.str;
-
- if (fop) {
- pcf->Offset= fop->offset;
-// pcf->Freq= fop->freq;
- pcf->Datefmt= (char*)fop->dateformat;
- pcf->Fieldfmt= (char*)fop->fieldformat;
-
- // This is useful in particular for date columns
- if ((len= fop->buflen) > pcf->Length)
- pcf->Length= len;
-
- } else {
- pcf->Offset= -1;
-// pcf->Freq= 0;
- pcf->Datefmt= NULL;
- pcf->Fieldfmt= NULL;
- } // endif fop
-
- return fldp;
-} // end of GetColumnOption
-
-/****************************************************************************/
-/* Returns the index description structure used to make the index. */
-/****************************************************************************/
-PIXDEF ha_connect::GetIndexInfo(int n)
-{
- char *name, *pn;
- bool unique;
- PIXDEF xdp= NULL;
- PKPDEF kpp, pkp= NULL;
- PGLOBAL& g= xp->g;
- KEY kp;
-
- // Find the index to describe
- if ((unsigned)n < table->s->keynames.count)
-// kp= table->key_info[n]; which one ???
- kp= table->s->key_info[n];
- else
- return NULL;
-
- // Now get index information
- pn= (char*)table->s->keynames.type_names[n];
- name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1);
- strcpy(name, pn); // This is probably unuseful
- unique= (kp.flags & 1) != 0;
-
- // Allocate the index description block
- xdp= new(g) INDEXDEF(name, unique, n);
-
- // Get the the key parts info
- for (int k= 0; (unsigned)k < kp.key_parts; k++) {
- pn= (char*)kp.key_part[k].field->field_name;
- name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1);
- strcpy(name, pn); // This is probably unuseful
-
- // Allocate the key part description block
- kpp= new(g) KPARTDEF(name, k + 1);
- kpp->SetKlen(kp.key_part[k].length);
-
- // Index on auto increment column is an XXROW index
- if (kp.key_part[k].field->flags & AUTO_INCREMENT_FLAG && kp.key_parts == 1)
- xdp->SetAuto(true);
-
- if (pkp)
- pkp->SetNext(kpp);
- else
- xdp->SetToKeyParts(kpp);
-
- pkp= kpp;
- } // endfor k
-
- xdp->SetNParts(kp.key_parts);
- return xdp;
-} // end of GetIndexInfo
-
-const char *ha_connect::GetDBName(const char* name)
-{
- return (name) ? name : table->s->db.str;
-} // end of GetDBName
-
-const char *ha_connect::GetTableName(void)
-{
- return table->s->table_name.str;
-} // end of GetTableName
-
-/****************************************************************************/
-/* Returns the column real or special name length of a field. */
-/****************************************************************************/
-int ha_connect::GetColNameLen(Field *fp)
-{
- int n;
- PFOS fop= GetFieldOptionStruct(fp);
-
- // Now get the column name length
- if (fop && fop->special)
- n= strlen(fop->special) + 1;
- else
- n= strlen(fp->field_name);
-
- return n;
-} // end of GetColNameLen
-
-/****************************************************************************/
-/* Returns the column real or special name of a field. */
-/****************************************************************************/
-char *ha_connect::GetColName(Field *fp)
-{
- PFOS fop= GetFieldOptionStruct(fp);
-
- return (fop && fop->special) ? fop->special : (char*)fp->field_name;
-} // end of GetColName
-
-/****************************************************************************/
-/* Adds the column real or special name of a field to a string. */
-/****************************************************************************/
-void ha_connect::AddColName(char *cp, Field *fp)
-{
- PFOS fop= GetFieldOptionStruct(fp);
-
- // Now add the column name
- if (fop && fop->special)
- // The prefix * mark the column as "special"
- strcat(strcpy(cp, "*"), strupr(fop->special));
- else
- strcpy(cp, (char*)fp->field_name);
-
-} // end of AddColName
-
-/****************************************************************************/
-/* Get the table description block of a CONNECT table. */
-/****************************************************************************/
-PTDB ha_connect::GetTDB(PGLOBAL g)
-{
- const char *table_name;
- PTDB tp;
-
- // Double test to be on the safe side
- if (!g || !table)
- return NULL;
-
- table_name= GetTableName();
-
- if (tdbp && !stricmp(tdbp->GetName(), table_name)
- && tdbp->GetMode() == xmod && !xp->CheckQuery(valid_query_id)) {
- tp= tdbp;
- tp->SetMode(xmod);
- } else if ((tp= CntGetTDB(g, table_name, xmod, this)))
- valid_query_id= xp->last_query_id;
- else
- printf("GetTDB: %s\n", g->Message);
-
- return tp;
-} // end of GetTDB
-
-/****************************************************************************/
-/* Open a CONNECT table, restricting column list if cols is true. */
-/****************************************************************************/
-bool ha_connect::OpenTable(PGLOBAL g, bool del)
-{
- bool rc= false;
- char *c1= NULL, *c2=NULL;
-
- // Double test to be on the safe side
- if (!g || !table) {
- printf("OpenTable logical error; g=%p table=%p\n", g, table);
- return true;
- } // endif g
-
- if (!(tdbp= GetTDB(g)))
- return true;
-
- // Get the list of used fields (columns)
- char *p;
- unsigned int k1, k2, n1, n2;
- Field* *field;
- MY_BITMAP *map= (xmod != MODE_INSERT) ? table->read_set : table->write_set;
- MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL;
-
- k1= k2= 0;
- n1= n2= 1; // 1 is space for final null character
-
- for (field= table->field; *field; field++) {
- if (bitmap_is_set(map, (*field)->field_index)) {
- n1+= (GetColNameLen(*field) + 1);
- k1++;
- } // endif
-
- if (ump && bitmap_is_set(ump, (*field)->field_index)) {
- n2+= (GetColNameLen(*field) + 1);
- k2++;
- } // endif
-
- } // endfor field
-
- if (k1) {
- p= c1= (char*)PlugSubAlloc(g, NULL, n1);
-
- for (field= table->field; *field; field++)
- if (bitmap_is_set(map, (*field)->field_index)) {
- AddColName(p, *field);
- p+= (strlen(p) + 1);
- } // endif used field
-
- *p= '\0'; // mark end of list
- } // endif k1
-
- if (k2) {
- p= c2= (char*)PlugSubAlloc(g, NULL, n2);
-
- for (field= table->field; *field; field++)
- if (bitmap_is_set(ump, (*field)->field_index)) {
- AddColName(p, *field);
- p+= (strlen(p) + 1);
- } // endif used field
-
- *p= '\0'; // mark end of list
- } // endif k2
-
- // Open the table
- if (!(rc= CntOpenTable(g, tdbp, xmod, c1, c2, del, this))) {
- istable= true;
-// strmake(tname, table_name, sizeof(tname)-1);
-
- if (xmod == MODE_ANY && stop && *tdbp->GetName() != '#') {
- // We are in a create index query
- if (!((PTDBASE)tdbp)->GetDef()->Indexable()) {
- sprintf(g->Message, "Table %s cannot be indexed", tdbp->GetName());
- rc= true;
- } else if (xp) // xp can be null when called from create
- xp->tabp= (PTDBDOS)tdbp; // The table on which the index is created
-
- } // endif xmod
-
-// tdbp->SetOrig((PTBX)table); // used by CheckCond
- } else
- printf("OpenTable: %s\n", g->Message);
-
- if (rc) {
- tdbp= NULL;
- valid_info= false;
- } // endif rc
-
- return rc;
-} // end of OpenTable
-
-
-/****************************************************************************/
-/* IsOpened: returns true if the table is already opened. */
-/****************************************************************************/
-bool ha_connect::IsOpened(void)
-{
- return (!xp->CheckQuery(valid_query_id) && tdbp
- && tdbp->GetUse() == USE_OPEN);
-} // end of IsOpened
-
-
-/****************************************************************************/
-/* Close a CONNECT table. */
-/****************************************************************************/
-int ha_connect::CloseTable(PGLOBAL g)
-{
- int rc= CntCloseTable(g, tdbp);
- tdbp= NULL;
- sdval=NULL;
- valid_info= false;
- indexing= -1;
- return rc;
-} // end of CloseTable
-
-
-/***********************************************************************/
-/* Make a pseudo record from current row values. Specific to MySQL. */
-/***********************************************************************/
-int ha_connect::MakeRecord(char *buf)
-{
- char *p, *fmt, val[32];
- int rc= 0;
- Field* *field;
- Field *fp;
- my_bitmap_map *org_bitmap;
- CHARSET_INFO *charset;
- const MY_BITMAP *map;
- PVAL value;
- PCOL colp= NULL;
- DBUG_ENTER("ha_connect::MakeRecord");
-
- if (xtrace > 1)
-#if defined(MARIADB)
- printf("Maps: read=%p write=%p vcol=%p defr=%p defw=%p\n",
- *table->read_set->bitmap, *table->write_set->bitmap,
- *table->vcol_set->bitmap,
- *table->def_read_set.bitmap, *table->def_write_set.bitmap);
-#else // !MARIADB
- printf("Maps: read=%p write=%p defr=%p defw=%p\n",
- *table->read_set->bitmap, *table->write_set->bitmap,
- *table->def_read_set.bitmap, *table->def_write_set.bitmap);
-#endif // !MARIADB
-
- // Avoid asserts in field::store() for columns that are not updated
- org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
-
- // This is for variable_length rows
- memset(buf, 0, table->s->null_bytes);
-
- // store needs a charset, why not this one?
- charset= table->s->table_charset;
-
- // When sorting read_set selects all columns, so we use def_read_set
- map= (const MY_BITMAP *)&table->def_read_set;
-
- // Make the pseudo record from field values
- for (field= table->field; *field && !rc; field++) {
- fp= *field;
-
-#if defined(MARIADB)
- if (fp->vcol_info && !fp->stored_in_db)
- continue; // This is a virtual column
-#endif // MARIADB
-
- if (bitmap_is_set(map, fp->field_index)) {
- // This is a used field, fill the buffer with value
- for (colp= tdbp->GetColumns(); colp; colp= colp->GetNext())
- if (!stricmp(colp->GetName(), GetColName(fp)))
- break;
-
- if (!colp) {
- printf("Column %s not found\n", fp->field_name);
- dbug_tmp_restore_column_map(table->write_set, org_bitmap);
- DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
- } // endif colp
-
- value= colp->GetValue();
-
- // All this could be better optimized
- if (value->GetType() == TYPE_DATE) {
- if (!sdval)
- sdval= AllocateValue(xp->g, TYPE_STRING, 20);
-
- switch (fp->type()) {
- case MYSQL_TYPE_DATE:
- fmt= "%Y-%m-%d";
- break;
- case MYSQL_TYPE_TIME:
- fmt= "%H:%M:%S";
- break;
- default:
- fmt= "%Y-%m-%d %H:%M:%S";
- } // endswitch type
-
- // Get date in the format required by MySQL fields
- value->FormatValue(sdval, fmt);
- p= sdval->GetCharValue();
- } else if (value->GetType() == TYPE_FLOAT)
- p= NULL;
- else
- p= value->GetCharString(val);
-
- if (p) {
- if (fp->store(p, strlen(p), charset, CHECK_FIELD_WARN)) {
- // Avoid "error" on null fields
- if (value->GetIntValue())
- rc= HA_ERR_WRONG_IN_RECORD;
-
- DBUG_PRINT("MakeRecord", (p));
- } // endif store
-
- } else
- if (fp->store(value->GetFloatValue())) {
- rc= HA_ERR_WRONG_IN_RECORD;
- DBUG_PRINT("MakeRecord", (value->GetCharString(val)));
- } // endif store
-
- } // endif bitmap
-
- } // endfor field
-
- // This is copied from ha_tina and is necessary to avoid asserts
- dbug_tmp_restore_column_map(table->write_set, org_bitmap);
- DBUG_RETURN(rc);
-} // end of MakeRecord
-
-
-/***********************************************************************/
-/* Set row values from a MySQL pseudo record. Specific to MySQL. */
-/***********************************************************************/
-int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
-{
- char attr_buffer[1024];
- int rc= 0;
- PCOL colp;
- PVAL value;
- Field *fp;
- PTDBASE tp= (PTDBASE)tdbp;
- String attribute(attr_buffer, sizeof(attr_buffer),
- table->s->table_charset);
- my_bitmap_map *bmap= dbug_tmp_use_all_columns(table, table->read_set);
-
- // Scan the pseudo record for field values and set column values
- for (Field **field=table->field ; *field ; field++) {
- fp= *field;
-
-#if defined(MARIADB)
- if ((fp->vcol_info && !fp->stored_in_db) ||
- fp->option_struct->special)
- continue; // Is a virtual column possible here ???
-#endif // MARIADB
-
- if (bitmap_is_set(table->write_set, fp->field_index)) {
- for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
- if (!stricmp(colp->GetName(), fp->field_name))
- break;
-
- if (!colp) {
- printf("Column %s not found\n", fp->field_name);
- rc= HA_ERR_WRONG_IN_RECORD;
- goto err;
- } else
- value= colp->GetValue();
-
- // This is a used field, fill the value from the row buffer
- // All this could be better optimized
- switch (value->GetType()) {
- case TYPE_FLOAT:
- value->SetValue(fp->val_real());
- break;
- case TYPE_DATE:
- if (!sdval) {
- sdval= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
-
- // Get date in the format produced by MySQL fields
- ((DTVAL*)sdval)->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
- } // endif sdval
-
- fp->val_str(&attribute);
- sdval->SetValue_psz(attribute.c_ptr());
- value->SetValue_pval(sdval);
- break;
- default:
- fp->val_str(&attribute);
- value->SetValue_psz(attribute.c_ptr());
- } // endswitch Type
-
-#ifdef NEWCHANGE
- } else if (xmod == MODE_UPDATE) {
- PCOL cp;
-
- for (cp= tp->GetColumns(); cp; cp= cp->GetNext())
- if (!stricmp(colp->GetName(), cp->GetName()))
- break;
-
- if (!cp) {
- rc= HA_ERR_WRONG_IN_RECORD;
- goto err;
- } // endif cp
-
- value->SetValue_pval(cp->GetValue());
- } else // mode Insert
- value->Reset();
-#else
- } // endif bitmap_is_set
-#endif
-
- } // endfor field
-
- err:
- dbug_tmp_restore_column_map(table->read_set, bmap);
- return rc;
-} // end of ScanRecord
-
-
-/***********************************************************************/
-/* Check change in index column. Specific to MySQL. */
-/* Should be elaborated to check for real changes. */
-/***********************************************************************/
-int ha_connect::CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf)
-{
- return ScanRecord(g, newbuf);
-} // end of dummy CheckRecord
-
-
-/***********************************************************************/
-/* Return the string representing an operator. */
-/***********************************************************************/
-char *ha_connect::GetValStr(OPVAL vop, bool neg)
-{
- char *val;
-
- switch (vop) {
- case OP_EQ:
- val= " = ";
- break;
- case OP_NE:
- val= " <> ";
- break;
- case OP_GT:
- val= " > ";
- break;
- case OP_GE:
- val= " >= ";
- break;
- case OP_LT:
- val= " < ";
- break;
- case OP_LE:
- val= " <= ";
- break;
- case OP_IN:
- val= (neg) ? " NOT IN (" : " IN (";
- break;
- case OP_NULL:
- val= " IS NULL";
- break;
- case OP_LIKE:
- val= " LIKE ";
- break;
- case OP_XX:
- val= " BETWEEN ";
- break;
- case OP_EXIST:
- val= " EXISTS ";
- break;
- case OP_AND:
- val= " AND ";
- break;
- case OP_OR:
- val= " OR ";
- break;
- case OP_NOT:
- val= " NOT ";
- break;
- case OP_CNC:
- val= " || ";
- break;
- case OP_ADD:
- val= " + ";
- break;
- case OP_SUB:
- val= " - ";
- break;
- case OP_MULT:
- val= " * ";
- break;
- case OP_DIV:
- val= " / ";
- break;
- default:
- val= " ? ";
- } /* endswitch */
-
- return val;
-} // end of GetValStr
-
-
-/***********************************************************************/
-/* Check the WHERE condition and return an ODBC/WQL filter. */
-/***********************************************************************/
-PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
-{
- unsigned int i;
- bool ismul= false;
- PPARM pfirst= NULL, pprec= NULL, pp[2]= {NULL, NULL};
- OPVAL vop= OP_XX;
-
- if (!cond)
- return NULL;
-
- if (xtrace > 1)
- printf("Cond type=%d\n", cond->type());
-
- if (cond->type() == COND::COND_ITEM) {
- char *p1, *p2;
- Item_cond *cond_item= (Item_cond *)cond;
-
- if (xtrace > 1)
- printf("Cond: Ftype=%d name=%s\n", cond_item->functype(),
- cond_item->func_name());
-
- switch (cond_item->functype()) {
- case Item_func::COND_AND_FUNC: vop= OP_AND; break;
- case Item_func::COND_OR_FUNC: vop= OP_OR; break;
- default: return NULL;
- } // endswitch functype
-
- List<Item>* arglist= cond_item->argument_list();
- List_iterator<Item> li(*arglist);
- Item *subitem;
-
- p1= filp + strlen(filp);
- strcpy(p1, "(");
- p2= p1 + 1;
-
- for (i= 0; i < arglist->elements; i++)
- if ((subitem= li++)) {
- if (!CheckCond(g, filp, tty, subitem)) {
- if (vop == OP_OR)
- return NULL;
- else
- *p2= 0;
-
- } else {
- p1= p2 + strlen(p2);
- strcpy(p1, GetValStr(vop, FALSE));
- p2= p1 + strlen(p1);
- } // endif CheckCond
-
- } else
- return NULL;
-
- if (*p1 != '(')
- strcpy(p1, ")");
- else
- return NULL;
-
- } else if (cond->type() == COND::FUNC_ITEM) {
- unsigned int i;
-// int n;
- bool iscol, neg= FALSE;
- Item_func *condf= (Item_func *)cond;
- Item* *args= condf->arguments();
-
- if (xtrace > 1)
- printf("Func type=%d argnum=%d\n", condf->functype(),
- condf->argument_count());
-
-// neg= condf->
-
- switch (condf->functype()) {
- case Item_func::EQUAL_FUNC:
- case Item_func::EQ_FUNC: vop= OP_EQ; break;
- case Item_func::NE_FUNC: vop= OP_NE; break;
- case Item_func::LT_FUNC: vop= OP_LT; break;
- case Item_func::LE_FUNC: vop= OP_LE; break;
- case Item_func::GE_FUNC: vop= OP_GE; break;
- case Item_func::GT_FUNC: vop= OP_GT; break;
- case Item_func::IN_FUNC: vop= OP_IN;
- neg= ((Item_func_opt_neg *)condf)->negated;
- case Item_func::BETWEEN: ismul= true; break;
- default: return NULL;
- } // endswitch functype
-
- if (condf->argument_count() < 2)
- return NULL;
- else if (ismul && tty == TYPE_AM_WMI)
- return NULL; // Not supported by WQL
-
- for (i= 0; i < condf->argument_count(); i++) {
- if (xtrace > 1)
- printf("Argtype(%d)=%d\n", i, args[i]->type());
-
- if (i >= 2 && !ismul) {
- if (xtrace > 1)
- printf("Unexpected arg for vop=%d\n", vop);
-
- continue;
- } // endif i
-
- if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
- const char *fnm;
- ha_field_option_struct *fop;
- Item_field *pField= (Item_field *)args[i];
-
- if (pField->field->table != table)
- return NULL; // Field does not belong to this table
- else
- fop= GetFieldOptionStruct(pField->field);
-
- if (fop && fop->special) {
- if (tty == TYPE_AM_TBL && !stricmp(fop->special, "TABID"))
- fnm= "TABID";
- else
- return NULL;
-
- } else if (tty == TYPE_AM_TBL)
- return NULL;
- else
- fnm= pField->field->field_name;
-
- if (xtrace > 1) {
- printf("Field index=%d\n", pField->field->field_index);
- printf("Field name=%s\n", pField->field->field_name);
- } // endif xtrace
-
- // IN and BETWEEN clauses should be col VOP list
- if (i && ismul)
- return NULL;
-
- strcat(filp, fnm);
- } else {
- char buff[256];
- String *res, tmp(buff,sizeof(buff), &my_charset_bin);
- Item_basic_constant *pval= (Item_basic_constant *)args[i];
-
- if ((res= pval->val_str(&tmp)) == NULL)
- return NULL; // To be clarified
-
- if (xtrace > 1)
- printf("Value=%.*s\n", res->length(), res->ptr());
-
- // IN and BETWEEN clauses should be col VOP list
- if (!i && ismul)
- return NULL;
-
- // Append the value to the filter
- if (args[i]->type() == COND::STRING_ITEM)
- strcat(strcat(strcat(filp, "'"), res->ptr()), "'");
- else
- strncat(filp, res->ptr(), res->length());
-
- } // endif
-
- if (!i)
- strcat(filp, GetValStr(vop, neg));
- else if (vop == OP_XX && i == 1)
- strcat(filp, " AND ");
- else if (vop == OP_IN)
- strcat(filp, (i == condf->argument_count() - 1) ? ")" : ",");
-
- } // endfor i
-
- } else {
- if (xtrace > 1)
- printf("Unsupported condition\n");
-
- return NULL;
- } // endif's type
-
- return filp;
-} // end of CheckCond
-
-
- /**
- Push condition down to the table handler.
-
- @param cond Condition to be pushed. The condition tree must not be
- modified 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
- CONNECT handles the filtering only for table types that construct
- an SQL or WQL query, but still leaves it to MySQL because only some
- parts of the filter may be relevant.
- The first suballocate finds the position where the string will be
- constructed in the sarea. The second one does make the suballocation
- with the proper length.
- */
-const COND *ha_connect::cond_push(const COND *cond)
-{
- DBUG_ENTER("ha_connect::cond_push");
-
- if (tdbp) {
- AMT tty= tdbp->GetAmType();
-
- if (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
- tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL) {
- PGLOBAL& g= xp->g;
- PFIL filp= (PFIL)PlugSubAlloc(g, NULL, 0);
-
- *filp= 0;
-
- if (CheckCond(g, filp, tty, (Item *)cond)) {
- if (xtrace)
- puts(filp);
-
- tdbp->SetFilter(filp);
-// cond= NULL; // This does not work anyway
- PlugSubAlloc(g, NULL, strlen(filp) + 1);
- } // endif filp
-
- } // endif tty
-
- } // endif tdbp
-
- // Let MySQL do the filtering
- DBUG_RETURN(cond);
-} // end of cond_push
-
-/**
- Number of rows in table. It will only be called if
- (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
-*/
-ha_rows ha_connect::records()
-{
- if (!valid_info)
- info(HA_STATUS_VARIABLE);
-
- if (tdbp && tdbp->Cardinality(NULL))
- return stats.records;
- else
- return HA_POS_ERROR;
-
-} // end of records
-
-
-/**
- Return an error message specific to this handler.
-
- @param error error code previously returned by handler
- @param buf pointer to String where to add error message
-
- @return
- Returns true if this is a temporary error
-*/
-bool ha_connect::get_error_message(int error, String* buf)
-{
- DBUG_ENTER("ha_connect::get_error_message");
-
- if (xp && xp->g)
- buf->copy(xp->g->Message, (uint)strlen(xp->g->Message),
- system_charset_info);
-
- DBUG_RETURN(false);
-} // end of get_error_message
-
-
-/**
- @brief
- If frm_error() is called then we will use this to determine
- the file extensions that exist for the storage engine. This is also
- used by the default rename_table and delete_table method in
- handler.cc.
-
- For engines that have two file name extentions (separate meta/index file
- and data file), the order of elements is relevant. First element of engine
- file name extentions array should be meta/index file extention. Second
- element - data file extention. This order is assumed by
- prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
-
- @note: PlugDB will handle all file creation/deletion. When dropping
- a CONNECT table, we don't want the PlugDB table to be dropped or erased.
- Therefore we provide a void list of extensions.
-
- @see
- rename_table method in handler.cc and
- delete_table method in handler.cc
-*/
-static const char *ha_connect_exts[]= {
- NullS
-};
-
-
-const char **ha_connect::bas_ext() const
-{
- return ha_connect_exts; // a null list, see @note above
-} // end of bas_ext
-
-
-/**
- @brief
- Used for opening tables. The name will be the name of the file.
-
- @details
- A table is opened when it needs to be opened; e.g. when a request comes in
- for a SELECT on the table (tables are not open and closed for each request,
- they are cached).
-
- Called from handler.cc by handler::ha_open(). The server opens all tables by
- calling ha_open() which then calls the handler specific open().
-
- @note
- For CONNECT no open can be done here because field information is not yet
- updated. >>>>> TO BE CHECKED <<<<<
- (Thread information could be get by using 'ha_thd')
-
- @see
- handler::ha_open() in handler.cc
-*/
-int ha_connect::open(const char *name, int mode, uint test_if_locked)
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::open");
-
- if (xtrace)
- printf("open: name=%s mode=%d test=%ud\n", name, mode, test_if_locked);
-
- if (!(share= get_share(name, table)))
- DBUG_RETURN(1);
-
- thr_lock_data_init(&share->lock,&lock,NULL);
-
- // Try to get the user if possible
- if (table && table->in_use) {
- PGLOBAL g= GetPlug(table->in_use);
-
- // Try to set the database environment
- if (g)
- rc= (CntCheckDB(g, this, name)) ? (-2) : 0;
-
- } // endif table
-
- DBUG_RETURN(rc);
-} // end of open
-
-/**
- @brief
- Make the indexes for this table
-*/
-int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int rc= 0;
- PGLOBAL& g= xp->g;
- PDBUSER dup= PlgGetUser(g);
-
- // Ignore error on the opt file
- dup->Check &= ~CHK_OPT;
- tdbp= GetTDB(g);
- dup->Check |= CHK_OPT;
-
- if (tdbp || (tdbp= GetTDB(g))) {
- if (!((PTDBASE)tdbp)->GetDef()->Indexable()) {
- sprintf(g->Message, "Table %s is not indexable", tdbp->GetName());
- rc= RC_INFO;
- } else
- rc= ((PTDBASE)tdbp)->ResetTableOpt(g, true);
-
- } else
- rc= HA_ERR_INTERNAL_ERROR;
-
- return rc;
-} // end of optimize
-
-/**
- @brief
- Closes a table. We call the free_share() function to free any resources
- that we have allocated in the "shared" structure.
-
- @details
- Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
- only used to close up temporary tables or during the process where a
- temporary table is converted over to being a myisam table.
-
- For sql_base.cc look at close_data_tables().
-
- @see
- sql_base.cc, sql_select.cc and table.cc
-*/
-int ha_connect::close(void)
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::close");
-
- // If this is called by a later query, the table may have
- // been already closed and the tdbp is not valid anymore.
- if (tdbp && xp->last_query_id == valid_query_id)
- rc= CloseTable(xp->g);
-
- DBUG_RETURN(free_share(share) || rc);
-} // end of close
-
-
-/**
- @brief
- write_row() inserts a row. No extra() hint is given currently if a bulk load
- is happening. buf() is a byte array of data. You can use the field
- information to extract the data from the native byte array type.
-
- @details
- Example of this would be:
- @code
- for (Field **field=table->field ; *field ; field++)
- {
- ...
- }
- @endcode
-
- See ha_tina.cc for an example of extracting all of the data as strings.
- ha_berekly.cc has an example of how to store it intact by "packing" it
- for ha_berkeley's own native storage type.
-
- See the note for update_row() on auto_increments and timestamps. This
- case also applies to write_row().
-
- Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
- sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
-
- @see
- item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
- sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
-*/
-int ha_connect::write_row(uchar *buf)
-{
- int rc= 0;
- PGLOBAL& g= xp->g;
- DBUG_ENTER("ha_connect::write_row");
-
- // Open the table if it was not opened yet (possible ???)
- if (!IsOpened())
- if (OpenTable(g)) {
- if (strstr(g->Message, "read only"))
- rc= HA_ERR_TABLE_READONLY;
- else
- rc= HA_ERR_INITIALIZATION;
-
- DBUG_RETURN(rc);
- } // endif tdbp
-
- if (tdbp->GetMode() == MODE_ANY)
- DBUG_RETURN(0);
-
- // Set column values from the passed pseudo record
- if ((rc= ScanRecord(g, buf)))
- DBUG_RETURN(rc);
-
- // Return result code from write operation
- if (CntWriteRow(g, tdbp)) {
- DBUG_PRINT("write_row", (g->Message));
- printf("write_row: %s\n", g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } // endif RC
-
- DBUG_RETURN(rc);
-} // end of write_row
-
-
-/**
- @brief
- Yes, update_row() does what you expect, it updates a row. old_data will have
- the previous row record in it, while new_data will have the newest data in it.
- Keep in mind that the server can do updates based on ordering if an ORDER BY
- clause was used. Consecutive ordering is not guaranteed.
-
- @details
- Currently new_data will not have an updated auto_increament record, or
- and updated timestamp field. You can do these for example by doing:
- @code
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
- if (table->next_number_field && record == table->record[0])
- update_auto_increment();
- @endcode
-
- Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
-
- @see
- sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
-*/
-int ha_connect::update_row(const uchar *old_data, uchar *new_data)
-{
- int rc= 0;
- PGLOBAL& g= xp->g;
- DBUG_ENTER("ha_connect::update_row");
-
- if (xtrace > 1)
- printf("update_row: old=%s new=%s\n", old_data, new_data);
-
- // Check values for possible change in indexed column
- if ((rc= CheckRecord(g, old_data, new_data)))
- return rc;
-
- if (CntUpdateRow(g, tdbp)) {
- DBUG_PRINT("update_row", (g->Message));
- printf("update_row CONNECT: %s\n", g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } // endif RC
-
- DBUG_RETURN(rc);
-} // end of update_row
-
-
-/**
- @brief
- This will delete a row. buf will contain a copy of the row to be deleted.
- The server will call this right after the current row has been called (from
- either a previous rnd_nexT() or index call).
-
- @details
- If you keep a pointer to the last row or can access a primary key it will
- make doing the deletion quite a bit easier. Keep in mind that the server does
- not guarantee consecutive deletions. ORDER BY clauses can be used.
-
- Called in sql_acl.cc and sql_udf.cc to manage internal table
- information. Called in sql_delete.cc, sql_insert.cc, and
- sql_select.cc. In sql_select it is used for removing duplicates
- while in insert it is used for REPLACE calls.
-
- @see
- sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
-*/
-int ha_connect::delete_row(const uchar *buf)
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::delete_row");
-
- if (CntDeleteRow(xp->g, tdbp, false)) {
- rc= HA_ERR_INTERNAL_ERROR;
- printf("delete_row CONNECT: %s\n", xp->g->Message);
- } // endif DeleteRow
-
- DBUG_RETURN(rc);
-} // end of delete_row
-
-
-/****************************************************************************/
-/* We seem to come here at the begining of an index use. */
-/****************************************************************************/
-int ha_connect::index_init(uint idx, bool sorted)
-{
- int rc;
- PGLOBAL& g= xp->g;
- DBUG_ENTER("index_init");
-
- if ((rc= rnd_init(0)))
- return rc;
-
- indexing= CntIndexInit(g, tdbp, (signed)idx);
-
- if (indexing <= 0) {
- DBUG_PRINT("index_init", (g->Message));
- printf("index_init CONNECT: %s\n", g->Message);
- active_index= (uint)-1;
- rc= -1;
- } else {
- if (((PTDBDOX)tdbp)->To_Kindex->GetNum_K()) {
- if (((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
- ((PTDBDOX)tdbp)->GetTxfp()->ResetBuffer(g);
-
- active_index= idx;
- } else // Void table
- indexing= 0;
-
- rc= 0;
- } // endif indexing
-
- DBUG_RETURN(rc);
-} // end of index_init
-
-/****************************************************************************/
-/* We seem to come here at the end of an index use. */
-/****************************************************************************/
-int ha_connect::index_end()
-{
- DBUG_ENTER("index_end");
- active_index= -1;
- DBUG_RETURN(rnd_end());
-} // end of index_end
-
-
-/****************************************************************************/
-/* This is internally called by all indexed reading functions. */
-/****************************************************************************/
-int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const uchar *key, uint key_len)
-{
- int rc;
-
-//statistic_increment(ha_read_key_count, &LOCK_status);
-
- switch (CntIndexRead(xp->g, tdbp, op, key, (int)key_len)) {
- case RC_OK:
- xp->fnd++;
- rc= MakeRecord((char*)buf);
- break;
- case RC_EF: // End of file
- rc= HA_ERR_END_OF_FILE;
- break;
- case RC_NF: // Not found
- xp->nfd++;
- rc= (op == OP_SAME) ? HA_ERR_END_OF_FILE : HA_ERR_KEY_NOT_FOUND;
- break;
- default: // Read error
- DBUG_PRINT("ReadIndexed", (xp->g->Message));
- printf("ReadIndexed: %s\n", xp->g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } // endswitch RC
-
- if (xtrace > 1)
- printf("ReadIndexed: op=%d rc=%d\n", op, rc);
-
- table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND;
- return rc;
-} // end of ReadIndexed
-
-
-#ifdef NOT_USED
-/**
- @brief
- Positions an index cursor to the index specified in the handle. Fetches the
- row if available. If the key value is null, begin at the first key of the
- index.
-*/
-int ha_connect::index_read_map(uchar *buf, const uchar *key,
- key_part_map keypart_map __attribute__((unused)),
- enum ha_rkey_function find_flag
- __attribute__((unused)))
-{
- DBUG_ENTER("ha_connect::index_read");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-#endif // NOT_USED
-
-
-/****************************************************************************/
-/* This is called by handler::index_read_map. */
-/****************************************************************************/
-int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len,
- enum ha_rkey_function find_flag)
-{
- int rc;
- OPVAL op= OP_XX;
- DBUG_ENTER("ha_connect::index_read");
-
- switch(find_flag) {
- case HA_READ_KEY_EXACT: op= OP_EQ; break;
- case HA_READ_AFTER_KEY: op= OP_GT; break;
- case HA_READ_KEY_OR_NEXT: op= OP_GE; break;
- default: DBUG_RETURN(-1);
- } // endswitch find_flag
-
- if (xtrace > 1)
- printf("%p index_read: op=%d\n", this, op);
-
- if (indexing > 0)
- rc= ReadIndexed(buf, op, key, key_len);
- else
- rc= -1;
-
- DBUG_RETURN(rc);
-} // end of index_read
-
-
-/**
- @brief
- Used to read forward through the index.
-*/
-int ha_connect::index_next(uchar *buf)
-{
- int rc;
- DBUG_ENTER("ha_connect::index_next");
- //statistic_increment(ha_read_next_count, &LOCK_status);
-
- if (indexing > 0)
- rc= ReadIndexed(buf, OP_NEXT);
- else if (!indexing)
- rc= rnd_next(buf);
- else
- rc= -1;
-
- DBUG_RETURN(rc);
-} // end of index_next
-
-
-#ifdef NOT_USED
-/**
- @brief
- Used to read backwards through the index.
-*/
-int ha_connect::index_prev(uchar *buf)
-{
- DBUG_ENTER("ha_connect::index_prev");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-#endif // NOT_USED
-
-
-/**
- @brief
- index_first() asks for the first key in the index.
-
- @details
- Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
-
- @see
- opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
-*/
-int ha_connect::index_first(uchar *buf)
-{
- int rc;
- DBUG_ENTER("ha_connect::index_first");
-
- if (indexing > 0)
- rc= ReadIndexed(buf, OP_FIRST);
- else if (indexing < 0)
- rc= -1;
- else if (CntRewindTable(xp->g, tdbp)) {
- table->status= STATUS_NOT_FOUND;
- rc= -1;
- } else
- rc= rnd_next(buf);
-
- DBUG_RETURN(rc);
-} // end of index_first
-
-
-#ifdef NOT_USED
-/**
- @brief
- index_last() asks for the last key in the index.
-
- @details
- Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
-
- @see
- opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
-*/
-int ha_connect::index_last(uchar *buf)
-{
- DBUG_ENTER("ha_connect::index_last");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-#endif // NOT_USED
-
-
-/****************************************************************************/
-/* This is called to get more rows having the same index value. */
-/****************************************************************************/
-int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
-{
- int rc;
- DBUG_ENTER("ha_connect::index_next_same");
-//statistic_increment(ha_read_next_count, &LOCK_status);
-
- if (!indexing)
- rc= rnd_next(buf);
- else if (indexing > 0)
- rc= ReadIndexed(buf, OP_SAME);
- else
- rc= -1;
-
- DBUG_RETURN(rc);
-} // end of index_next_same
-
-
-/**
- @brief
- rnd_init() is called when the system wants the storage engine to do a table
- scan. See the example in the introduction at the top of this file to see when
- rnd_init() is called.
-
- @details
- Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
- and sql_update.cc.
-
- @note
- We always call open and extern_lock/start_stmt before comming here.
-
- @see
- filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
-*/
-int ha_connect::rnd_init(bool scan)
-{
- PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use) :
- (xp) ? xp->g : NULL);
- DBUG_ENTER("ha_connect::rnd_init");
-
- if (xtrace)
- printf("%p in rnd_init: scan=%d\n", this, scan);
-
- if (g) {
- // Open the table if it was not opened yet (possible ???)
- if (!IsOpened()) {
- if (!table || xmod == MODE_INSERT)
- DBUG_RETURN(HA_ERR_INITIALIZATION);
-
- if (OpenTable(g, xmod == MODE_DELETE))
-#if defined(MARIADB)
- DBUG_RETURN(HA_ERR_INITIALIZATION);
-#else // !MARIADB
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
-#endif // !MARIADB
-
- } else
- void(CntRewindTable(g, tdbp)); // Read from beginning
-
- } // endif g
-
- xp->nrd= xp->fnd= xp->nfd= 0;
- xp->tb1= my_interval_timer();
- DBUG_RETURN(0);
-} // end of rnd_init
-
-/**
- @brief
- Not described.
-
- @note
- The previous version said:
- Stop scanning of table. Note that this may be called several times during
- execution of a sub select.
- =====> This has been moved to external lock to avoid closing subselect tables.
-*/
-int ha_connect::rnd_end()
-{
- int rc= 0;
- DBUG_ENTER("ha_connect::rnd_end");
-
- // If this is called by a later query, the table may have
- // been already closed and the tdbp is not valid anymore.
-// if (tdbp && xp->last_query_id == valid_query_id)
-// rc= CloseTable(xp->g);
-
- DBUG_RETURN(rc);
-} // end of rnd_end
-
-
-/**
- @brief
- This is called for each row of the table scan. When you run out of records
- you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
- The Field structure for the table is the key to getting data into buf
- in a manner that will allow the server to understand it.
-
- @details
- Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
- and sql_update.cc.
-
- @see
- filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
-*/
-int ha_connect::rnd_next(uchar *buf)
-{
- int rc;
- DBUG_ENTER("ha_connect::rnd_next");
-//statistic_increment(ha_read_rnd_next_count, &LOCK_status);
-
-#if !defined(MARIADB)
- if (!tdbp) // MySQL ignores error from rnd_init
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
-#endif // !MARIADB
-
- if (tdbp->GetMode() == MODE_ANY) {
- // We will stop on next read
- if (!stop) {
- stop= true;
- DBUG_RETURN(RC_OK);
- } else
- DBUG_RETURN(HA_ERR_END_OF_FILE);
-
- } // endif Mode
-
- switch (CntReadNext(xp->g, tdbp)) {
- case RC_OK:
- rc= MakeRecord((char*)buf);
- break;
- case RC_EF: // End of file
- rc= HA_ERR_END_OF_FILE;
- break;
- case RC_NF: // Not found
- rc= HA_ERR_RECORD_DELETED;
- break;
- default: // Read error
- printf("rnd_next CONNECT: %s\n", xp->g->Message);
- rc= (records()) ? HA_ERR_INTERNAL_ERROR : HA_ERR_END_OF_FILE;
- break;
- } // endswitch RC
-
-#ifndef DBUG_OFF
- if (rc || !(xp->nrd++ % 16384)) {
- ulonglong tb2= my_interval_timer();
- double elapsed= (double) (tb2 - xp->tb1) / 1000000000ULL;
- DBUG_PRINT("rnd_next", ("rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
- rc, xp->nrd, xp->fnd, xp->nfd, elapsed));
- xp->tb1= tb2;
- xp->fnd= xp->nfd= 0;
- } // endif nrd
-#endif
-
- table->status= (!rc) ? 0 : STATUS_NOT_FOUND;
- DBUG_RETURN(rc);
-} // end of rnd_next
-
-
-/**
- @brief
- position() is called after each call to rnd_next() if the data needs
- to be ordered. You can do something like the following to store
- the position:
- @code
- my_store_ptr(ref, ref_length, current_position);
- @endcode
-
- @details
- The server uses ref to store data. ref_length in the above case is
- the size needed to store current_position. ref is just a byte array
- that the server will maintain. If you are using offsets to mark rows, then
- current_position should be the offset. If it is a primary key like in
- BDB, then it needs to be a primary key.
-
- Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
-
- @see
- filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
-*/
-void ha_connect::position(const uchar *record)
-{
- DBUG_ENTER("ha_connect::position");
- if (((PTDBASE)tdbp)->GetDef()->Indexable())
- my_store_ptr(ref, ref_length, (my_off_t)((PTDBASE)tdbp)->GetRecpos());
- DBUG_VOID_RETURN;
-} // end of position
-
-
-/**
- @brief
- This is like rnd_next, but you are given a position to use
- to determine the row. The position will be of the type that you stored in
- ref. You can use my_get_ptr(pos,ref_length) to retrieve whatever key
- or position you saved when position() was called.
-
- @details
- Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and sql_update.cc.
-
- @note
- Is this really useful? It was never called even when sorting.
-
- @see
- filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
-*/
-int ha_connect::rnd_pos(uchar *buf, uchar *pos)
-{
- int rc;
- PTDBASE tp= (PTDBASE)tdbp;
- DBUG_ENTER("ha_connect::rnd_pos");
-
- if (!tp->SetRecpos(xp->g, (int)my_get_ptr(pos, ref_length)))
- rc= rnd_next(buf);
- else
- rc= HA_ERR_KEY_NOT_FOUND;
-
- DBUG_RETURN(rc);
-} // end of rnd_pos
-
-
-/**
- @brief
- ::info() is used to return information to the optimizer. See my_base.h for
- the complete description.
-
- @details
- Currently this table handler doesn't implement most of the fields really needed.
- SHOW also makes use of this data.
-
- You will probably want to have the following in your code:
- @code
- if (records < 2)
- records= 2;
- @endcode
- The reason is that the server will optimize for cases of only a single
- record. If, in a table scan, you don't know the number of records, it
- will probably be better to set records to two so you can return as many
- records as you need. Along with records, a few more variables you may wish
- to set are:
- records
- deleted
- data_file_length
- index_file_length
- delete_length
- check_time
- Take a look at the public variables in handler.h for more information.
-
- Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
- sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
- sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc,
- sql_table.cc, sql_union.cc, and sql_update.cc.
-
- @see
- filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc,
- sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc,
- sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_table.cc,
- sql_union.cc and sql_update.cc
-*/
-int ha_connect::info(uint flag)
-{
- bool pure= false;
- PGLOBAL g= GetPlug((table) ? table->in_use : NULL);
-
- DBUG_ENTER("ha_connect::info");
-
- if (xtrace)
- printf("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info);
-
- if (!valid_info) {
- // tdbp must be available to get updated info
- if (!tdbp || xp->CheckQuery(valid_query_id)) {
- if (xmod == MODE_ANY) { // Pure info, not a query
- pure= true;
-// xmod= MODE_READ;
- } // endif xmod
-
-// tdbp= OpenTable(g, xmod == MODE_DELETE);
- tdbp= GetTDB(g);
- } // endif tdbp
-
- valid_info= CntInfo(g, tdbp, &xinfo);
- } // endif valid_info
-
- if (flag & HA_STATUS_VARIABLE) {
- stats.records= xinfo.records;
- stats.deleted= 0;
- stats.data_file_length= xinfo.data_file_length;
- stats.index_file_length= 0;
- stats.delete_length= 0;
- stats.check_time= 0;
- stats.mean_rec_length= xinfo.mean_rec_length;
- } // endif HA_STATUS_VARIABLE
-
- if (flag & HA_STATUS_CONST) {
- // This is imported from the previous handler and must be reconsidered
- stats.max_data_file_length= LL(4294967295);
- stats.max_index_file_length= LL(4398046510080);
- stats.create_time= 0;
- data_file_name= xinfo.data_file_name;
- index_file_name= NULL;
-// sortkey= (uint) - 1; // Table is not sorted
- ref_length= sizeof(int); // Pointer size to row
- table->s->db_options_in_use= 03;
- stats.block_size= 1024;
- table->s->keys_in_use.set_prefix(table->s->keys);
- table->s->keys_for_keyread= table->s->keys_in_use;
-// table->s->keys_for_keyread.subtract(table->s->read_only_keys);
- table->s->db_record_offset= 0;
- } // endif HA_STATUS_CONST
-
- if (flag & HA_STATUS_ERRKEY) {
- errkey= 0;
- } // endif HA_STATUS_ERRKEY
-
- if (flag & HA_STATUS_TIME)
- stats.update_time= 0;
-
- if (flag & HA_STATUS_AUTO)
- stats.auto_increment_value= 1;
-
- if (tdbp && pure)
- CloseTable(g); // Not used anymore
-
- DBUG_RETURN(0);
-} // end of info
-
-
-/**
- @brief
- extra() is called whenever the server wishes to send a hint to
- the storage engine. The myisam engine implements the most hints.
- ha_innodb.cc has the most exhaustive list of these hints.
-
- @note
- This is not yet implemented for CONNECT.
-
- @see
- ha_innodb.cc
-*/
-int ha_connect::extra(enum ha_extra_function operation)
-{
- DBUG_ENTER("ha_connect::extra");
- DBUG_RETURN(0);
-} // end of extra
-
-
-/**
- @brief
- Used to delete all rows in a table, including cases of truncate and cases where
- the optimizer realizes that all rows will be removed as a result of an SQL statement.
-
- @details
- Called from item_sum.cc by Item_func_group_concat::clear(),
- Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
- Called from sql_delete.cc by mysql_delete().
- Called from sql_select.cc by JOIN::reinit().
- Called from sql_union.cc by st_select_lex_unit::exec().
-
- @see
- Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
- Item_func_group_concat::clear() in item_sum.cc;
- mysql_delete() in sql_delete.cc;
- JOIN::reinit() in sql_select.cc and
- st_select_lex_unit::exec() in sql_union.cc.
-*/
-int ha_connect::delete_all_rows()
-{
- int rc= 0;
- PGLOBAL g= xp->g;
- DBUG_ENTER("ha_connect::delete_all_rows");
-
- // Close and reopen the table so it will be deleted
- rc= CloseTable(g);
-
- if (!(OpenTable(g))) {
- if (CntDeleteRow(g, tdbp, true)) {
- printf("%s\n", g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } // endif
-
- } else
- rc= HA_ERR_INITIALIZATION;
-
- DBUG_RETURN(rc);
-} // end of delete_all_rows
-
-/**
- @brief
- This create a lock on the table. If you are implementing a storage engine
- that can handle transacations look at ha_berkely.cc to see how you will
- want to go about doing this. Otherwise you should consider calling flock()
- here. Hint: Read the section "locking functions for mysql" in lock.cc to understand
- this.
-
- @details
- Called from lock.cc by lock_external() and unlock_external(). Also called
- from sql_table.cc by copy_data_between_tables().
-
- @note
- Following what we did in the MySQL XDB handler, we use this call to actually
- physically open the table. This could be reconsider when finalizing this handler
- design, which means we have a better understanding of what MariaDB does.
-
- @see
- lock.cc by lock_external() and unlock_external() in lock.cc;
- the section "locking functions for mysql" in lock.cc;
- copy_data_between_tables() in sql_table.cc.
-*/
-int ha_connect::external_lock(THD *thd, int lock_type)
-{
- int rc= 0;
- bool del= false;
- MODE newmode;
- PGLOBAL g= GetPlug(thd);
- DBUG_ENTER("ha_connect::external_lock");
-
- if (xtrace)
- printf("%p external_lock: lock_type=%d\n", this, lock_type);
-
- if (!g)
- DBUG_RETURN(-99);
-
- // Action will depend on lock_type
- switch (lock_type) {
- case F_WRLCK:
- newmode= MODE_WRITE;
- break;
- case F_RDLCK:
- newmode= MODE_READ;
- break;
- case F_UNLCK:
- default:
- newmode= MODE_ANY;
- } // endswitch mode
-
- if (newmode == MODE_ANY) {
- // This is unlocking, do it by closing the table
- if (xp->CheckQueryID())
- rc= 2; // Logical error ???
- else if (tdbp) {
- if (tdbp->GetMode() == MODE_ANY && *tdbp->GetName() == '#'
- && xp->tabp) {
- PDOSDEF defp1= (PDOSDEF)((PTDBASE)tdbp)->GetDef();
- PDOSDEF defp2= (PDOSDEF)xp->tabp->GetDef();
- PIXDEF xp1, xp2, sxp;
-
- // Look for new created indexes
- for (xp1= defp1->GetIndx(); xp1; xp1= xp1->GetNext()) {
- for (xp2= defp2->GetIndx(); xp2; xp2= xp2->GetNext())
- if (!stricmp(xp1->GetName(), xp2->GetName()))
- break; // Index already made
-
- if (!xp2) {
- // Here we do make the index on tabp
- sxp= xp1->GetNext();
- xp1->SetNext(NULL);
- xp->tabp->MakeIndex(g, xp1, true);
- xp1->SetNext(sxp);
- } // endif xp2
-
- } // endfor xp1
-
- // Look for dropped indexes
- for (xp2= defp2->GetIndx(); xp2; xp2= xp2->GetNext()) {
- for (xp1= defp1->GetIndx(); xp1; xp1= xp1->GetNext())
- if (!stricmp(xp1->GetName(), xp2->GetName()))
- break; // Index not to drop
-
- if (!xp1) {
- // Here we erase the index file
- sxp= xp2->GetNext();
- xp2->SetNext(NULL);
- defp2->DeleteIndexFile(g, xp2);
- xp2->SetNext(sxp);
- } // endif xp1
-
- } // endfor xp2
-
- } // endif Mode
-
- rc= CloseTable(g);
- } // endif tdbp
-
- DBUG_RETURN(rc);
- } // endif MODE_ANY
-
- if (xtrace) {
- printf("%p external_lock: cmdtype=%d\n", this, thd->lex->sql_command);
- printf("Cmd=%s\n", thd->query_string);
- } // endif xtrace
-
- // Next code is temporarily replaced until sql_command is set
- stop= false;
-
- if (newmode == MODE_WRITE) {
- switch (thd->lex->sql_command) {
- case SQLCOM_INSERT:
- case SQLCOM_CREATE_TABLE:
- case SQLCOM_LOAD:
- case SQLCOM_INSERT_SELECT:
- newmode= MODE_INSERT;
- break;
-// case SQLCOM_REPLACE:
-// case SQLCOM_REPLACE_SELECT:
-// newmode= MODE_UPDATE; // To be checked
-// break;
- case SQLCOM_DELETE:
- case SQLCOM_DELETE_MULTI:
- del= true;
- case SQLCOM_TRUNCATE:
- newmode= MODE_DELETE;
- break;
- case SQLCOM_UPDATE:
- case SQLCOM_UPDATE_MULTI:
- newmode= MODE_UPDATE;
- break;
- case SQLCOM_SELECT:
- case SQLCOM_OPTIMIZE:
- newmode= MODE_READ;
- break;
- case SQLCOM_DROP_TABLE:
- case SQLCOM_RENAME_TABLE:
- case SQLCOM_ALTER_TABLE:
- newmode= MODE_ANY;
- break;
- case SQLCOM_DROP_INDEX:
- case SQLCOM_CREATE_INDEX:
- newmode= MODE_ANY;
- stop= true;
- break;
- default:
- printf("Unsupported sql_command=%d", thd->lex->sql_command);
- sprintf(g->Message, "Unsupported sql_command=%d", thd->lex->sql_command);
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endswitch newmode
-
- } else if (newmode == MODE_READ) {
- switch (thd->lex->sql_command) {
- case SQLCOM_INSERT:
- case SQLCOM_CREATE_TABLE:
- case SQLCOM_LOAD:
- case SQLCOM_INSERT_SELECT:
-// case SQLCOM_REPLACE:
-// case SQLCOM_REPLACE_SELECT:
- case SQLCOM_DELETE:
- case SQLCOM_DELETE_MULTI:
- case SQLCOM_TRUNCATE:
- case SQLCOM_UPDATE:
- case SQLCOM_UPDATE_MULTI:
- case SQLCOM_SELECT:
- case SQLCOM_OPTIMIZE:
- break;
- case SQLCOM_DROP_INDEX:
- case SQLCOM_CREATE_INDEX:
- stop= true;
- case SQLCOM_DROP_TABLE:
- case SQLCOM_RENAME_TABLE:
- case SQLCOM_ALTER_TABLE:
- newmode= MODE_ANY;
- break;
- default:
- printf("Unsupported sql_command=%d", thd->lex->sql_command);
- sprintf(g->Message, "Unsupported sql_command=%d", thd->lex->sql_command);
- DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
- } // endswitch newmode
-
- } // endif's newmode
-
-
- if (xtrace)
- printf("New mode=%d\n", newmode);
-
- // If this is the start of a new query, cleanup the previous one
- if (xp->CheckCleanup()) {
- tdbp= NULL;
- valid_info= false;
- } // endif CheckCleanup
-
- if (xtrace)
- printf("Calling CntCheckDB db=%s\n", GetDBName(NULL));
-
- // Set or reset the good database environment
- if (CntCheckDB(g, this, GetDBName(NULL))) {
- printf("%p external_lock: %s\n", this, g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- // This can NOT be called without open called first, but
- // the table can have been closed since then
- } else if (!tdbp || xp->CheckQuery(valid_query_id) || xmod != newmode) {
- if (tdbp)
- CloseTable(g);
-
- xmod= newmode;
-
- if (!table)
- rc= 3; // Logical error
-
- // Delay open until used fields are known
- } // endif tdbp
-
- if (xtrace)
- printf("external_lock: rc=%d\n", rc);
-
- DBUG_RETURN(rc);
-} // end of external_lock
-
-
-/**
- @brief
- The idea with handler::store_lock() is: The statement decides which locks
- should be needed for the table. For updates/deletes/inserts we get WRITE
- locks, for SELECT... we get read locks.
-
- @details
- Before adding the lock into the table lock handler (see thr_lock.c),
- mysqld calls store lock with the requested locks. Store lock can now
- modify a write lock to a read lock (or some other lock), ignore the
- lock (if we don't want to use MySQL table locks at all), or add locks
- for many tables (like we do when we are using a MERGE handler).
-
- Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
- (which signals that we are doing WRITES, but are still allowing other
- readers and writers).
-
- When releasing locks, store_lock() is also called. In this case one
- usually doesn't have to do anything.
-
- In some exceptional cases MySQL may send a request for a TL_IGNORE;
- This means that we are requesting the same lock as last time and this
- should also be ignored. (This may happen when someone does a flush
- table when we have opened a part of the tables, in which case mysqld
- closes and reopens the tables and tries to get the same locks at last
- time). In the future we will probably try to remove this.
-
- Called from lock.cc by get_lock_data().
-
- @note
- In this method one should NEVER rely on table->in_use, it may, in fact,
- refer to a different thread! (this happens if get_lock_data() is called
- from mysql_lock_abort_for_thread() function)
-
- @see
- get_lock_data() in lock.cc
-*/
-THR_LOCK_DATA **ha_connect::store_lock(THD *thd,
- THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)
-{
- if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
- lock.type=lock_type;
- *to++ = &lock;
- return to;
-}
-
-
-/**
- @brief
- Used to delete a table. By the time delete_table() has been called all
- opened references to this table will have been closed (and your globally
- shared references released). The variable name will just be the name of
- the table. You will need to remove any files you have created at this point.
-
- @details
- If you do not implement this, the default delete_table() is called from
- handler.cc and it will delete all files with the file extensions returned
- by bas_ext().
-
- Called from handler.cc by delete_table and ha_create_table(). Only used
- during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
- the storage engine.
-
- @see
- delete_table and ha_create_table() in handler.cc
-*/
-int ha_connect::delete_table(const char *name)
-{
- DBUG_ENTER("ha_connect::delete_table");
- /* This is not implemented but we want someone to be able that it works. */
- DBUG_RETURN(0);
-}
-
-
-/**
- @brief
- Given a starting key and an ending key, estimate the number of rows that
- will exist between the two keys.
-
- @details
- end_key may be empty, in which case determine if start_key matches any rows.
-
- Called from opt_range.cc by check_quick_keys().
-
- @see
- check_quick_keys() in opt_range.cc
-*/
-ha_rows ha_connect::records_in_range(uint inx, key_range *min_key,
- key_range *max_key)
-{
- ha_rows rows;
- DBUG_ENTER("ha_connect::records_in_range");
-
- if (indexing < 0 || inx != active_index)
- index_init(inx, false);
-
- if (xtrace)
- printf("records_in_range: inx=%d indexing=%d\n", inx, indexing);
-
- if (indexing > 0) {
- int nval;
- uint len[2];
- const uchar *key[2];
- bool incl[2];
- key_part_map kmap[2];
-
- key[0]= (min_key) ? min_key->key : NULL;
- key[1]= (max_key) ? max_key->key : NULL;
- len[0]= (min_key) ? min_key->length : 0;
- len[1]= (max_key) ? max_key->length : 0;
- incl[0]= (min_key) ? (min_key->flag == HA_READ_KEY_EXACT) : false;
- incl[1]= (max_key) ? (max_key->flag == HA_READ_AFTER_KEY) : false;
- kmap[0]= (min_key) ? min_key->keypart_map : 0;
- kmap[1]= (max_key) ? max_key->keypart_map : 0;
-
- if ((nval= CntIndexRange(xp->g, tdbp, key, len, incl, kmap)) < 0)
- rows= HA_POS_ERROR;
- else
- rows= (ha_rows)nval;
-
- } else if (indexing < 0)
- rows= HA_POS_ERROR;
- else
- rows= 100000000; // Don't use missing index
-
- DBUG_RETURN(rows);
-} // end of records_in_range
-
-/**
- Convert an ISO-8859-1 column name to UTF-8
-*/
-char *ha_connect::encode(PGLOBAL g, char *cnm)
- {
- char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) * 3);
- uint dummy_errors;
- uint32 len= copy_and_convert(buf, strlen(cnm) * 3,
- &my_charset_utf8_general_ci,
- cnm, strlen(cnm),
- &my_charset_latin1,
- &dummy_errors);
- buf[len]= '\0';
- return buf;
- } // end of Encode
-
-/**
- Store field definition for create.
-
- @return
- Return 0 if ok
-*/
-
-bool ha_connect::add_fields(THD *thd, void *alt_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 *vcolinfo,
- engine_option_value *create_options)
-{
- register Create_field *new_field;
- LEX *lex= thd->lex;
- Alter_info *alter_info= (Alter_info*)alt_info;
- Virtual_column_info *vcol_info= (Virtual_column_info *)vcolinfo;
-
- DBUG_ENTER("ha_connect::add_fields");
-
- if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
- system_charset_info, 1))
- {
- my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
- }
-#if 0
- if (type_modifier & PRI_KEY_FLAG)
- {
- Key *key;
- lex->col_list.push_back(new Key_part_spec(*field_name, 0));
- key= new Key(Key::PRIMARY, null_lex_str,
- &default_key_create_info,
- 0, lex->col_list, NULL);
- alter_info->key_list.push_back(key);
- lex->col_list.empty();
- }
- if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
- {
- Key *key;
- lex->col_list.push_back(new Key_part_spec(*field_name, 0));
- key= new Key(Key::UNIQUE, null_lex_str,
- &default_key_create_info, 0,
- lex->col_list, NULL);
- alter_info->key_list.push_back(key);
- lex->col_list.empty();
- }
-
- if (default_value)
- {
- /*
- Default value should be literal => basic constants =>
- no need fix_fields()
-
- We allow only one function as part of default value -
- NOW() as default for TIMESTAMP type.
- */
- if (default_value->type() == Item::FUNC_ITEM &&
- !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
- type == MYSQL_TYPE_TIMESTAMP))
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
- DBUG_RETURN(1);
- }
- else if (default_value->type() == Item::NULL_ITEM)
- {
- default_value= 0;
- if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
- NOT_NULL_FLAG)
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
- DBUG_RETURN(1);
- }
- }
- else if (type_modifier & AUTO_INCREMENT_FLAG)
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
- DBUG_RETURN(1);
- }
- }
-
- if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
- {
- my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
- DBUG_RETURN(1);
- }
-#endif // 0
-
- if (!(new_field= new Create_field()) ||
- new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
- NULL, NULL, comment, NULL,
- NULL, cs, 0, vcol_info,
- create_options))
- DBUG_RETURN(1);
-
- alter_info->create_list.push_back(new_field);
-//lex->last_field=new_field;
- DBUG_RETURN(0);
-}
-
-/**
- @brief
- pre_create() is called when creating a table with no columns.
-
- @details
- When pre_create() is called the .frm file have not already been
- created. You can overwrite some definitions at this point but the
- main purpose of it is to define the columns for some table types.
-
- @note
- Not really implemented yet.
-*/
-bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
-{
- char ttp= '?', spc= ',', qch= 0, *typn= "DOS";
- char *fn, *dsn, *tab, *db, *host, *user, *pwd, *prt, *sep, *inf;
-#if defined(WIN32)
- char *nsp= NULL, *cls= NULL;
-#endif // WIN32
- int port= MYSQL_PORT, hdr= 0, mxr= 0;
- bool b= false, ok= false, info= false;
- LEX *lex= thd->lex;
- LEX_STRING *comment, *name;
- HA_CREATE_INFO *create_info= (HA_CREATE_INFO *)crt_info;
- engine_option_value *pov;
- PQRYRES qrp;
- PCOLRES crp;
- PGLOBAL g= GetPlug(thd);
-
- fn= dsn= tab= db= host= user= pwd= prt= sep= inf= NULL;
-
- if (g) {
- // Set default values
- tab= (char*)create_info->alias;
- db= thd->db;
- } else
- return true;
-
- // Get the useful create options
- for (pov= create_info->option_list; pov; pov= pov->next)
- if (!stricmp(pov->name.str, "table_type")) {
- typn= pov->value.str;
- ttp= GetTypeID(typn);
- } else if (!stricmp(pov->name.str, "file_name")) {
- fn= pov->value.str;
- } else if (!stricmp(pov->name.str, "tabname")) {
- tab= pov->value.str;
- } else if (!stricmp(pov->name.str, "db_name")) {
- db= pov->value.str;
- } else if (!stricmp(pov->name.str, "sep_char")) {
- sep= pov->value.str;
- spc= (!strcmp(sep, "\\t")) ? '\t' : *sep;
- } else if (!stricmp(pov->name.str, "qchar")) {
- qch= *pov->value.str;
- } else if (!stricmp(pov->name.str, "quoted")) {
- if (!qch)
- qch= '"';
-
- } else if (!stricmp(pov->name.str, "header")) {
- hdr= atoi(pov->value.str);
- } else if (!stricmp(pov->name.str, "option_list")) {
- host= GetListOption("host", pov->value.str, "localhost");
- user= GetListOption("user", pov->value.str, "root");
- pwd= GetListOption("password", pov->value.str);
- prt= GetListOption("port", pov->value.str);
- port= (prt) ? atoi(prt) : MYSQL_PORT;
-#if defined(WIN32)
- nsp= GetListOption("namespace", pov->value.str);
- cls= GetListOption("class", pov->value.str);
-#endif // WIN32
- mxr= atoi(GetListOption("maxerr", pov->value.str, "0"));
- inf= GetListOption("info", pov->value.str);
- } // endelse option_list
-
- switch (ttp) {
-#if defined(ODBC_SUPPORT)
- case 'O': // ODBC
- info= !!strchr("1yYoO", *inf);
-
- if (!(dsn= create_info->connect_string.str) && !info)
- sprintf(g->Message, "Missing %s connection string", typn);
- else
- ok= !info;
-
- break;
-#endif // ODBC_SUPPORT
- case 'A': // DBF
- case 'C': // CSV
- if (!fn)
- sprintf(g->Message, "Missing %s file name", typn);
- else
- ok= true;
-
- break;
-#if defined(MYSQL_SUPPORT)
- case 'Y': // MYSQL
- if (!user)
- user= "root"; // Avoid crash
-
- ok= true;
- break;
-#endif // MYSQL_SUPPORT
-#if defined(WIN32)
- case 'W': // WMI
- ok= true;
- break;
-#endif // WIN32
- default:
- sprintf(g->Message, "Cannot get column info for table type %s", typn);
- } // endif ttp
-
- if (ok) {
- char *length, *decimals, *cnm, *rem;
- int i, len, dec;
- enum_field_types type;
- PDBUSER dup= PlgGetUser(g);
- PCATLG cat= (dup) ? dup->Catalog : NULL;
-
- if (cat)
- cat->SetDataPath(g, thd->db);
- else
- return true; // Should never happen
-
- switch (ttp) {
- case 'A':
- qrp= DBFColumns(g, fn, false);
- break;
-#if defined(ODBC_SUPPORT)
- case 'O':
- qrp= MyODBCCols(g, tab, dsn);
- break;
-#endif // ODBC_SUPPORT
-#if defined(MYSQL_SUPPORT)
- case 'Y':
- qrp= MyColumns(g, host, db, user, pwd, tab, NULL, port, false);
- break;
-#endif // MYSQL_SUPPORT
- case 'C':
- qrp= CSVColumns(g, fn, spc, qch, hdr, mxr);
- break;
-#if defined(WIN32)
- case 'W':
- qrp= WMIColumns(g, nsp, cls);
- break;
-#endif // WIN32
- } // endswitch ttp
-
- if (!qrp) {
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
- return true;
- } // endif qrp
-
- for (i= 0; !b && i < qrp->Nblin; i++) {
- crp= qrp->Colresp; // Column Name
- cnm= encode(g, crp->Kdata->GetCharValue(i));
- name= thd->make_lex_string(NULL, cnm, strlen(cnm), true);
- crp= crp->Next; // Data Type
- type= PLGtoMYSQL(crp->Kdata->GetIntValue(i), true);
- crp= crp->Next; // Type Name
- crp= crp->Next; // Precision (length)
- len= crp->Kdata->GetIntValue(i);
- length= (char*)PlugSubAlloc(g, NULL, 8);
- sprintf(length, "%d", len);
- crp= crp->Next; // Length
- crp= crp->Next; // Scale (precision)
-
- if ((dec= crp->Kdata->GetIntValue(i))) {
- decimals= (char*)PlugSubAlloc(g, NULL, 8);
- sprintf(decimals, "%d", dec);
- } else
- decimals= NULL;
-
- if ((crp= crp->Next) && // Remark (comment)
- (rem= crp->Kdata->GetCharValue(i)))
- comment= thd->make_lex_string(NULL, rem, strlen(rem), true);
- else
- comment= thd->make_lex_string(NULL, "", 0, true);
-
- // Now add the field
-// b= add_field_to_list(thd, &name, type, length, decimals,
-// 0, NULL, NULL, comment, NULL, NULL, NULL, 0, NULL, NULL);
- b= add_fields(thd, alt_info, name, type, length, decimals,
- 0, comment, NULL, NULL, NULL);
- } // endfor i
-
- return b;
- } else if (info) { // ODBC Data Sources
- comment= thd->make_lex_string(NULL, "", 0, true);
- name= thd->make_lex_string(NULL, "Name", 4, true);
- b= add_fields(thd, alt_info, name, MYSQL_TYPE_VARCHAR, "256", 0,
- 0, comment, NULL, NULL, NULL);
- name= thd->make_lex_string(NULL, "Description", 11, true);
- b= add_fields(thd, alt_info, name, MYSQL_TYPE_VARCHAR, "256", 0,
- 0, comment, NULL, NULL, NULL);
- return b;
- } // endif info
-
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
- return true;
-} // end of pre_create
-
-/**
- @brief
- create() is called to create a database. The variable name will have the name
- of the table.
-
- @details
- When create() is called you do not need to worry about
- opening the table. Also, the .frm file will have already been
- created so adjusting create_info is not necessary. You can overwrite
- the .frm file at this point if you wish to change the table
- definition, but there are no methods currently provided for doing
- so.
-
- Called from handle.cc by ha_create_table().
-
- @note
- Currently we do nothing here because we suppose that the PlugDB matching
- table already exists. At least we should check that the table definition
- for MariaDB exactly match the PlugDB one. Later we should make possible
- to entirely create a table from MariaDB.
-
- @see
- ha_create_table() in handle.cc
-*/
-
-int ha_connect::create(const char *name, TABLE *table_arg,
- HA_CREATE_INFO *create_info)
-{
- int rc= RC_OK;
- bool dbf;
- Field* *field;
- Field *fp;
- TABLE *st= table; // Probably unuseful
- PIXDEF xdp, pxd= NULL, toidx= NULL;
- PGLOBAL g= GetPlug(table_arg->in_use);
-
- DBUG_ENTER("ha_connect::create");
- PTOS options= GetTableOptionStruct(table_arg);
-
- // CONNECT engine specific table options:
- DBUG_ASSERT(options);
-
- if (!g) {
- rc= HA_ERR_INTERNAL_ERROR;
- DBUG_RETURN(rc);
- } // endif g
-
- // Check column types
- dbf= (options->type && !stricmp(options->type, "DBF"));
-
- for (field= table_arg->field; *field; field++) {
- fp= *field;
-
-#if defined(MARIADB)
- if (fp->vcol_info && !fp->stored_in_db)
- continue; // This is a virtual column
-#endif // MARIADB
-
- switch (fp->type()) {
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_LONGLONG:
- break; // Ok
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- case MYSQL_TYPE_INT24:
- break; // To be checked
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_BIT:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_GEOMETRY:
- default:
-// fprintf(stderr, "Unsupported type column %s\n", fp->field_name);
- sprintf(g->Message, "Unsupported type for column %s",
- fp->field_name);
- rc= HA_ERR_INTERNAL_ERROR;
- my_printf_error(ER_UNKNOWN_ERROR,
- "Unsupported type for column '%s'",
- MYF(0), fp->field_name);
- DBUG_RETURN(rc);
- } // endswitch type
-
-
- if (dbf) {
- bool b= false;
-
- if ((b= strlen(fp->field_name) > 11))
- sprintf(g->Message, "DBF: Column name '%s' is too long (max=11)",
- fp->field_name);
- else if ((b= fp->field_length > 255))
- sprintf(g->Message, "DBF: Column length too big for '%s' (max=255)",
- fp->field_name);
-
- if (b) {
- my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
- rc= HA_ERR_INTERNAL_ERROR;
- DBUG_RETURN(rc);
- } // endif b
-
- } // endif dbf
-
- } // endfor field
-
- // Check whether indexes were specified
- table= table_arg; // Used by called functions
-
- // Get the index definitions
- for (int n= 0; (unsigned)n < table->s->keynames.count; n++) {
- if (xtrace)
- printf("Getting created index %d info\n", n + 1);
-
- xdp= GetIndexInfo(n);
-
- if (pxd)
- pxd->SetNext(xdp);
- else
- toidx= xdp;
-
- pxd= xdp;
- } // endfor n
-
- if (toidx) {
- PDBUSER dup= PlgGetUser(g);
- PCATLG cat= (dup) ? dup->Catalog : NULL;
-
- DBUG_ASSERT(cat);
-
- if (cat)
- cat->SetDataPath(g, table_arg->in_use->db);
-
- if ((rc= optimize(NULL, NULL))) {
- printf("Create rc=%d %s\n", rc, g->Message);
- rc= HA_ERR_INTERNAL_ERROR;
- } else
- CloseTable(g);
-
- } // endif toidx
-
- table= st;
- DBUG_RETURN(rc);
-} // end of create
-
-
-/**
- check_if_incompatible_data() called if ALTER TABLE can't detect otherwise
- if new and old definition are compatible
-
- @details If there are no other explicit signs like changed number of
- fields this function will be called by compare_tables()
- (sql/sql_tables.cc) to decide should we rewrite whole table or only .frm
- file.
-
-*/
-
-bool ha_connect::check_if_incompatible_data(HA_CREATE_INFO *info,
- uint table_changes)
-{
-//ha_table_option_struct *param_old, *param_new;
- DBUG_ENTER("ha_connect::check_if_incompatible_data");
- // TO DO: implement it.
- DBUG_RETURN(COMPATIBLE_DATA_YES);
-}
-
-
-struct st_mysql_storage_engine connect_storage_engine=
-{ MYSQL_HANDLERTON_INTERFACE_VERSION };
-
-struct st_mysql_daemon unusable_connect=
-{ MYSQL_DAEMON_INTERFACE_VERSION };
-
-mysql_declare_plugin(connect)
-{
- MYSQL_STORAGE_ENGINE_PLUGIN,
- &connect_storage_engine,
- "CONNECT",
- "Olivier Bertrand",
- "Direct access to external data, including many file formats",
- PLUGIN_LICENSE_GPL,
- connect_init_func, /* Plugin Init */
- connect_done_func, /* Plugin Deinit */
- 0x0001 /* 0.1 */,
- NULL, /* status variables */
- NULL, /* system variables */
- NULL, /* config options */
- 0, /* flags */
-}
-mysql_declare_plugin_end;
-
-#if defined(MARIADB)
-maria_declare_plugin(connect)
-{
- MYSQL_STORAGE_ENGINE_PLUGIN,
- &connect_storage_engine,
- "CONNECT",
- "Olivier Bertrand",
- "Direct access to external data, including many file formats",
- PLUGIN_LICENSE_GPL,
- connect_init_func, /* Plugin Init */
- connect_done_func, /* Plugin Deinit */
- 0x0001, /* version number (0.1) */
- NULL, /* status variables */
- NULL, /* system variables */
- "0.1", /* string version */
- MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
-},
-{
- MYSQL_DAEMON_PLUGIN,
- &unusable_connect,
- "UNUSABLE",
- "Olivier Bertrand",
- "Unusable Daemon",
- PLUGIN_LICENSE_PROPRIETARY,
- NULL, /* Plugin Init */
- NULL, /* Plugin Deinit */
- 0x0101, /* version number (1.1) */
- NULL, /* status variables */
- NULL, /* system variables */
- "1.01.00.000" , /* version, as a string */
- MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
-}
-maria_declare_plugin_end;
-#endif // MARIADB
-
-#if defined(WIN32)
-/**************************************************************************/
-/* DllMain */
-/**************************************************************************/
-bool APIENTRY DllMain(HINSTANCE hInst, ULONG ulReason, PCONTEXT pctx)
- {
- switch (ulReason) {
- case DLL_PROCESS_ATTACH:
- printf("CONNECT Engine loaded...\n");
- GetCurrentDirectory(sizeof(connectini), connectini);
- strcat(connectini, "\\connect.ini");
-
- if ((xtrace= GetPrivateProfileInt("CONNECT", "Trace", 0, connectini))) {
- printf("connectini=%s xtrace=%d\n", connectini, xtrace);
- printf("plgini=%s\n", plgini);
- printf("plgxini=%s\n", plgxini);
- printf("nmfile=%s\n", nmfile);
- printf("pdebug=%s\n", pdebug);
- printf("version=%s\n", version);
- trace= xtrace;
- } // endif xtrace
-#ifdef LIBXML2_SUPPORT
- XmlInitParserLib();
-#endif // LIBXML2_SUPPORT
- break;
- case DLL_PROCESS_DETACH:
-#ifdef LIBXML2_SUPPORT
- XmlCleanupParserLib();
-#endif // LIBXML2_SUPPORT
- break;
- case DLL_THREAD_ATTACH:
- break;
- case DLL_THREAD_DETACH:
- break;
- default:
- break;
- } // endswitch ulReason
-
- return true;
- } // end of DllMain
-#else // !WIN32
-/**************************************************************************/
-/* Library's initialization function. */
-/**************************************************************************/
-void __attribute__((constructor)) init()
- {
- printf("CONNECT Engine loaded...\n");
- getcwd(connectini, sizeof(connectini));
- strcat(connectini, "/connect.ini");
- printf("connectini=%s\n", connectini);
-
- if ((xtrace= GetPrivateProfileInt("CONNECT", "Trace", 0, connectini))) {
- printf("connectini=%s xtrace=%d\n", connectini, xtrace);
- printf("plgini=%s\n", plgini);
- printf("plgxini=%s\n", plgxini);
- printf("nmfile=%s\n", nmfile);
- printf("pdebug=%s\n", pdebug);
- printf("version=%s\n", version);
- trace= xtrace;
- } // endif xtrace
-
-#ifdef LIBXML2_SUPPORT
- XmlInitParserLib();
-#endif // LIBXML2_SUPPORT
- } // end of init
-
-/**************************************************************************/
-/* Library's cleanup function */
-/**************************************************************************/
-void __attribute__((destructor)) fini()
- {
-#ifdef LIBXML2_SUPPORT
- XmlCleanupParserLib();
-#endif // LIBXML2_SUPPORT
- } // end of fini
-#endif // !WIN32
-
+/* Copyright (C) Olivier Bertrand 2004 - 2013
+
+ 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.cc
+
+ @brief
+ The ha_connect engine is a stubbed storage engine that enables to create tables
+ based on external data. Principally they are based on plain files of many
+ different types, but also on collections of such files, collection of tables,
+ ODBC tables retrieving data from other DBMS having an ODBC server, and even
+ virtual tables.
+
+ @details
+ ha_connect will let you create/open/delete tables, the created table can be
+ done specifying an already existing file, the drop table command will just
+ suppress the table definition but not the eventual data file.
+ Indexes are not yet supported but data can be inserted, updated or deleted.
+
+ You can enable the CONNECT storage engine in your build by doing the
+ following during your build process:<br> ./configure
+ --with-connect-storage-engine (not implemented yet)
+
+ You can install the CONNECT handler as all other storage handlers.
+
+ Once this is done, MySQL will let you create tables with:<br>
+ CREATE TABLE <table name> (...) ENGINE=CONNECT;
+
+ The example storage engine does not use table locks. It
+ implements an example "SHARE" that is inserted into a hash by table
+ name. This is not used yet.
+
+ Please read the object definition in ha_connect.h before reading the rest
+ of this file.
+
+ @note
+ This MariaDB CONNECT handler is currently an adaptation of the XDB handler
+ that was written for MySQL version 4.1.2-alpha. Its overall design should
+ be enhanced in the future to meet MariaDB requirements.
+
+ @note
+ It was written also from the Brian's ha_example handler and contains parts
+ of it that are there but not currently used, such as table variables.
+
+ @note
+ When you create an CONNECT table, the MySQL Server creates a table .frm
+ (format) file in the database directory, using the table name as the file
+ name as is customary with MySQL. No other files are created. To get an idea
+ of what occurs, here is an example select that would do a scan of an entire
+ table:
+
+ @code
+ ha-connect::open
+ ha_connect::store_lock
+ ha_connect::external_lock
+ ha_connect::info
+ ha_connect::rnd_init
+ ha_connect::extra
+ ENUM HA_EXTRA_CACHE Cache record in HA_rrnd()
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::extra
+ ENUM HA_EXTRA_NO_CACHE End caching of records (def)
+ ha_connect::external_lock
+ ha_connect::extra
+ ENUM HA_EXTRA_RESET Reset database to after open
+ @endcode
+
+ Here you see that the connect storage engine has 9 rows called before
+ rnd_next signals that it has reached the end of its data. Calls to
+ ha_connect::extra() are hints as to what will be occuring to the request.
+
+ Happy use!<br>
+ -Olivier
+*/
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#define MYSQL_SERVER 1
+#define DONT_DEFINE_VOID
+//#include "sql_partition.h"
+#include "sql_class.h"
+#include "create_options.h"
+#include "mysql_com.h"
+#include "field.h"
+#undef OFFSET
+
+#define NOPARSE
+#if defined(UNIX)
+#include "osutil.h"
+#endif // UNIX
+#include "global.h"
+#include "plgdbsem.h"
+#include "reldef.h"
+#include "tabcol.h"
+#include "xindex.h"
+#include "connect.h"
+#include "user_connect.h"
+#include "ha_connect.h"
+#include "mycat.h"
+
+#define PLGINI "plugdb.ini" /* Configuration settings file */
+#define PLGXINI "plgcnx.ini" /* Configuration settings file */
+#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))
+
+#if defined (WIN32)
+typedef struct _WMIutil *PWMIUT; /* Used to call WMIColumns */
+#endif
+/****************************************************************************/
+/* CONNECT functions called externally. */
+/****************************************************************************/
+bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname);
+PTDB CntGetTDB(PGLOBAL g, const char *name, MODE xmod, PHC);
+bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE, char *, char *, bool, PHC);
+bool CntRewindTable(PGLOBAL g, PTDB tdbp);
+int CntCloseTable(PGLOBAL g, PTDB tdbp);
+int CntIndexInit(PGLOBAL g, PTDB tdbp, int id);
+RCODE CntReadNext(PGLOBAL g, PTDB tdbp);
+RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const void *k, int n);
+RCODE CntWriteRow(PGLOBAL g, PTDB tdbp);
+RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp);
+RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all);
+bool CntInfo(PGLOBAL g, PTDB tdbp, PXF info);
+int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len,
+ bool *incl, key_part_map *kmap);
+#ifdef LIBXML2_SUPPORT
+void XmlInitParserLib(void);
+void XmlCleanupParserLib(void);
+#endif // LIBXML2_SUPPORT
+
+/****************************************************************************/
+/* Functions called externally by pre_parser. */
+/****************************************************************************/
+PQRYRES DBFColumns(PGLOBAL g, char *fn, BOOL info);
+PQRYRES CSVColumns(PGLOBAL g, char *fn, char sep, char q, int hdr, int mxr);
+#if defined(ODBC_SUPPORT)
+PQRYRES MyODBCCols(PGLOBAL g, char *tab, char *dsn);
+#endif // ODBC_SUPPORT
+#if defined(MYSQL_SUPPORT)
+PQRYRES MyColumns(PGLOBAL g, char *host, char *db, char *user, char *pwd,
+ char *table, char *colpat, int port, bool key);
+#endif // MYSQL_SUPPORT
+enum enum_field_types PLGtoMYSQL(int type, bool gdf);
+#if defined(WIN32)
+PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *classname, PWMIUT wp= NULL);
+#endif // WIN32
+char GetTypeID(char *type);
+bool check_string_char_length(LEX_STRING *str, const char *err_msg,
+ uint max_char_length, CHARSET_INFO *cs,
+ bool no_error);
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+extern "C" char plgxini[];
+extern "C" char plgini[];
+extern "C" char nmfile[];
+extern "C" char pdebug[];
+
+extern "C" {
+ char version[]= "Version 1.00.0005 October 03, 2012";
+
+#if defined(XMSG)
+ char msglang[]; // Default message language
+#endif
+ int trace= 0; // The general trace value
+} // extern "C"
+
+/****************************************************************************/
+/* Initialize the ha_connect static members. */
+/****************************************************************************/
+char connectini[_MAX_PATH]= "connect.ini";
+int xtrace= 0;
+ulong ha_connect::num= 0;
+//int DTVAL::Shift= 0;
+
+static handler *connect_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
+
+handlerton *connect_hton;
+
+/* Variables for connect share methods */
+
+/*
+ Hash used to track the number of open tables; variable for connect share
+ methods
+*/
+static HASH connect_open_tables;
+
+/* The mutex used to init the hash; variable for example share methods */
+mysql_mutex_t connect_mutex;
+
+
+/**
+ structure for CREATE TABLE options (table options)
+
+ These can be specified in the CREATE TABLE:
+ CREATE TABLE ( ... ) {...here...}
+*/
+struct ha_table_option_struct {
+ const char *type;
+ const char *filename;
+ const char *optname;
+ const char *tabname;
+ const char *tablist;
+ const char *dbname;
+ const char *separator;
+//const char *connect;
+ const char *qchar;
+ const char *module;
+ const char *subtype;
+ const char *oplist;
+ int lrecl;
+ int elements;
+//int estimate;
+ int multiple;
+ int header;
+ int quoted;
+ int ending;
+ int compressed;
+ bool mapped;
+ bool huge;
+ bool split;
+ bool readonly;
+ };
+
+#if defined(MARIADB)
+ha_create_table_option connect_table_option_list[]=
+{
+ // These option are for stand alone Connect tables
+ HA_TOPTION_STRING("TABLE_TYPE", type),
+ HA_TOPTION_STRING("FILE_NAME", filename),
+ HA_TOPTION_STRING("XFILE_NAME", optname),
+//HA_TOPTION_STRING("CONNECT_STRING", connect),
+ HA_TOPTION_STRING("TABNAME", tabname),
+ HA_TOPTION_STRING("TABLE_LIST", tablist),
+ HA_TOPTION_STRING("DB_NAME", dbname),
+ HA_TOPTION_STRING("SEP_CHAR", separator),
+ HA_TOPTION_STRING("QCHAR", qchar),
+ HA_TOPTION_STRING("MODULE", module),
+ HA_TOPTION_STRING("SUBTYPE", subtype),
+ HA_TOPTION_STRING("OPTION_LIST", oplist),
+ HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1),
+//HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 2, 1),
+ HA_TOPTION_NUMBER("HEADER", header, 0, 0, 3, 1),
+ HA_TOPTION_NUMBER("QUOTED", quoted, -1, 0, 3, 1),
+ HA_TOPTION_NUMBER("ENDING", ending, -1, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("COMPRESS", compressed, 0, 0, 2, 1),
+//HA_TOPTION_BOOL("COMPRESS", compressed, 0),
+ HA_TOPTION_BOOL("MAPPED", mapped, 0),
+ HA_TOPTION_BOOL("HUGE", huge, 0),
+ HA_TOPTION_BOOL("SPLIT", split, 0),
+ HA_TOPTION_BOOL("READONLY", readonly, 0),
+ HA_TOPTION_END
+};
+#endif // MARIADB
+
+
+/**
+ structure for CREATE TABLE options (field options)
+
+ These can be specified in the CREATE TABLE per field:
+ CREATE TABLE ( field ... {...here...}, ... )
+*/
+struct ha_field_option_struct
+{
+ int offset;
+ int freq; // Not used by this version
+ int opt; // Not used by this version
+ int buflen;
+ const char *dateformat;
+ const char *fieldformat;
+ char *special;
+};
+
+#if defined(MARIADB)
+ha_create_table_option connect_field_option_list[]=
+{
+ HA_FOPTION_NUMBER("FLAG", offset, -1, 0, INT_MAX32, 1),
+ HA_FOPTION_NUMBER("FREQUENCY", freq, 0, 0, INT_MAX32, 1), // not used
+ HA_FOPTION_NUMBER("OPT_VALUE", opt, 0, 0, 2, 1), // used for indexing
+ HA_FOPTION_NUMBER("BUF_LENGTH", buflen, 0, 0, INT_MAX32, 1),
+ HA_FOPTION_STRING("DATE_FORMAT", dateformat),
+ HA_FOPTION_STRING("FIELD_FORMAT", fieldformat),
+ HA_FOPTION_STRING("SPECIAL", special),
+ HA_FOPTION_END
+};
+#endif // MARIADB
+
+
+/**
+ @brief
+ Function we use in the creation of our hash to get key.
+*/
+static uchar* connect_get_key(CONNECT_SHARE *share, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=share->table_name_length;
+ return (uchar*) share->table_name;
+}
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key ex_key_mutex_connect, ex_key_mutex_CONNECT_SHARE_mutex;
+
+static PSI_mutex_info all_connect_mutexes[]=
+{
+ { &ex_key_mutex_connect, "connect", PSI_FLAG_GLOBAL},
+ { &ex_key_mutex_CONNECT_SHARE_mutex, "CONNECT_SHARE::mutex", 0}
+};
+
+/***********************************************************************/
+/* Push G->Message as a MySQL warning. */
+/***********************************************************************/
+bool PushWarning(PGLOBAL g, PTDBASE tdbp)
+ {
+ PHC phc;
+ THD *thd;
+ MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
+
+ if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
+ !(thd= (phc->GetTable())->in_use))
+ return true;
+
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
+ return false;
+ } // end of PushWarning
+
+static void init_connect_psi_keys()
+{
+ const char* category= "connect";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_connect_mutexes);
+ PSI_server->register_mutex(category, all_connect_mutexes, count);
+}
+#endif
+
+static int connect_init_func(void *p)
+{
+ DBUG_ENTER("connect_init_func");
+
+#ifdef HAVE_PSI_INTERFACE
+ init_connect_psi_keys();
+#endif
+
+ connect_hton= (handlerton *)p;
+ mysql_mutex_init(ex_key_mutex_connect, &connect_mutex, MY_MUTEX_INIT_FAST);
+//VOID(mysql_mutex_init(&connect_mutex, MY_MUTEX_INIT_FAST));
+ (void) my_hash_init(&connect_open_tables, system_charset_info, 32, 0, 0,
+ (my_hash_get_key) connect_get_key, 0, 0);
+
+//connect_hton->name= "CONNECT";
+ connect_hton->state= SHOW_OPTION_YES;
+//connect_hton->comment= "CONNECT handler";
+ connect_hton->create= connect_create_handler;
+ connect_hton->flags= HTON_TEMPORARY_NOT_SUPPORTED | HTON_NO_PARTITION;
+#if defined(MARIADB)
+ connect_hton->db_type= DB_TYPE_AUTOASSIGN;
+ connect_hton->table_options= connect_table_option_list;
+ connect_hton->field_options= connect_field_option_list;
+#else // !MARIADB
+//connect_hton->system_database= connect_system_database;
+//connect_hton->is_supported_system_table= connect_is_supported_system_table;
+#endif // !MARIADB
+
+ if (xtrace)
+ printf("connect_init: hton=%p\n", p);
+
+ DTVAL::SetTimeShift(); // Initialize time zone shift once for all
+ DBUG_RETURN(0);
+}
+
+
+static int connect_done_func(void *p)
+{
+ int error= 0;
+ PCONNECT pc, pn;
+ DBUG_ENTER("connect_done_func");
+
+ if (connect_open_tables.records)
+ error= 1;
+
+ for (pc= user_connect::to_users; pc; pc= pn) {
+ if (pc->g)
+ PlugCleanup(pc->g, true);
+
+ pn= pc->next;
+ delete pc;
+ } // endfor pc
+
+ my_hash_free(&connect_open_tables);
+ mysql_mutex_destroy(&connect_mutex);
+
+ DBUG_RETURN(error);
+}
+
+
+/**
+ @brief
+ Example of simple lock controls. The "share" it creates is a
+ structure we will pass to each example handler. Do you have to have
+ one of these? Well, you have pieces that are used for locking, and
+ they are needed to function.
+*/
+
+static CONNECT_SHARE *get_share(const char *table_name, TABLE *table)
+{
+ CONNECT_SHARE *share;
+ uint length;
+ char *tmp_name;
+
+ mysql_mutex_lock(&connect_mutex);
+ length=(uint) strlen(table_name);
+
+ if (!(share=(CONNECT_SHARE*)my_hash_search(&connect_open_tables,
+ (uchar*) table_name, length))) {
+ if (!(share=(CONNECT_SHARE *)my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &share, sizeof(*share), &tmp_name, length+1, NullS))) {
+ mysql_mutex_unlock(&connect_mutex);
+ return NULL;
+ } // endif share
+
+ share->use_count=0;
+ share->table_name_length=length;
+ share->table_name=tmp_name;
+ strmov(share->table_name, table_name);
+
+ if (my_hash_insert(&connect_open_tables, (uchar*) share))
+ goto error;
+
+ thr_lock_init(&share->lock);
+ mysql_mutex_init(ex_key_mutex_CONNECT_SHARE_mutex,
+ &share->mutex, MY_MUTEX_INIT_FAST);
+ } // endif share
+
+ share->use_count++;
+ mysql_mutex_unlock(&connect_mutex);
+ return share;
+
+error:
+ mysql_mutex_destroy(&share->mutex);
+ my_free(share);
+ return NULL;
+}
+
+
+/**
+ @brief
+ Free lock controls. We call this whenever we close a table. If the table had
+ the last reference to the share, then we free memory associated with it.
+*/
+
+static int free_share(CONNECT_SHARE *share)
+{
+ mysql_mutex_lock(&connect_mutex);
+
+ if (!--share->use_count) {
+ my_hash_delete(&connect_open_tables, (uchar*) share);
+ thr_lock_delete(&share->lock);
+ mysql_mutex_destroy(&share->mutex);
+#if !defined(MARIADB)
+ my_free(share->table_options);
+ my_free(share->field_options);
+#endif // !MARIADB
+ my_free(share);
+ } // endif share
+
+ mysql_mutex_unlock(&connect_mutex);
+ return 0;
+}
+
+static handler* connect_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
+{
+ handler *h= new (mem_root) ha_connect(hton, table);
+
+ if (xtrace)
+ printf("New CONNECT %p, table: %s\n",
+ h, table ? table->table_name.str : "<null>");
+
+ return h;
+} // end of connect_create_handler
+
+/****************************************************************************/
+/* ha_connect constructor. */
+/****************************************************************************/
+ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg)
+ :handler(hton, table_arg)
+{
+ hnum= ++num;
+ xp= NULL; // Tested in next call
+ xp= (table) ? GetUser(table->in_use) : NULL;
+ tdbp= NULL;
+ sdval= NULL;
+ xmod= MODE_ANY;
+ istable= false;
+//*tname= '\0';
+ bzero((char*) &xinfo, sizeof(XINFO));
+ valid_info= false;
+ valid_query_id= 0;
+ creat_query_id= (table && table->in_use) ? table->in_use->query_id : 0;
+ stop= false;
+//hascond= false;
+ indexing= -1;
+ data_file_name= NULL;
+ index_file_name= NULL;
+ enable_activate_all_index= 0;
+ int_table_flags= (HA_NO_TRANSACTIONS | HA_NO_PREFIX_CHAR_KEYS);
+ ref_length= sizeof(int);
+#if !defined(MARIADB)
+ share= NULL;
+ table_options= NULL;
+ field_options= NULL;
+#endif // !MARIADB
+ tshp= NULL;
+} // end of ha_connect constructor
+
+
+/****************************************************************************/
+/* ha_connect destructor. */
+/****************************************************************************/
+ha_connect::~ha_connect(void)
+{
+ if (xp) {
+ PCONNECT p;
+
+ xp->count--;
+
+ for (p= user_connect::to_users; p; p= p->next)
+ if (p == xp)
+ break;
+
+ if (p && !p->count) {
+ if (p->next)
+ p->next->previous= p->previous;
+
+ if (p->previous)
+ p->previous->next= p->next;
+ else
+ user_connect::to_users= p->next;
+
+ } // endif p
+
+ if (!xp->count) {
+ PlugCleanup(xp->g, true);
+ delete xp;
+ } // endif count
+
+ } // endif xp
+
+#if !defined(MARIADB)
+ my_free(table_options);
+ my_free(field_options);
+#endif // !MARIADB
+} // end of ha_connect destructor
+
+
+/****************************************************************************/
+/* Get a pointer to the user of this handler. */
+/****************************************************************************/
+PCONNECT ha_connect::GetUser(THD *thd)
+{
+ const char *dbn= NULL;
+
+ if (!thd)
+ return NULL;
+
+ if (xp && thd == xp->thdp)
+ return xp;
+
+ for (xp= user_connect::to_users; xp; xp= xp->next)
+ if (thd == xp->thdp)
+ break;
+
+ if (!xp) {
+ xp= new user_connect(thd, dbn);
+
+ if (xp->user_init(this)) {
+ delete xp;
+ xp= NULL;
+ } // endif user_init
+
+ } else
+ xp->count++;
+
+ return xp;
+} // end of GetUser
+
+
+/****************************************************************************/
+/* Get the global pointer of the user of this handler. */
+/****************************************************************************/
+PGLOBAL ha_connect::GetPlug(THD *thd)
+{
+ PCONNECT lxp= GetUser(thd);
+ return (lxp) ? lxp->g : NULL;
+} // end of GetPlug
+
+
+/****************************************************************************/
+/* Return the value of an option specified in the option list. */
+/****************************************************************************/
+char *ha_connect::GetListOption(char *opname, const char *oplist, char *def)
+{
+ char key[16], val[256];
+ char *pk, *pv, *pn;
+ char *opval= def;
+ int n;
+
+ for (pk= (char*)oplist; ; pk= ++pn) {
+ pn= strchr(pk, ',');
+ pv= strchr(pk, '=');
+
+ if (pv && (!pn || pv < pn)) {
+ n= pv - pk;
+ memcpy(key, pk, n);
+ key[n]= 0;
+ pv++;
+
+ if (pn) {
+ n= pn - pv;
+ memcpy(val, pv, n);
+ val[n]= 0;
+ } else
+ strcpy(val, pv);
+
+ } else {
+ if (pn) {
+ n= pn - pk;
+ memcpy(key, pk, n);
+ key[n]= 0;
+ } else
+ strcpy(key, pk);
+
+ val[0]= 0;
+ } // endif pv
+
+ if (!stricmp(opname, key)) {
+ opval= (char*)PlugSubAlloc(xp->g, NULL, strlen(val) + 1);
+ strcpy(opval, val);
+ break;
+ } else if (!pn)
+ break;
+
+ } // endfor pk
+
+ return opval;
+} // end of GetListOption
+
+/****************************************************************************/
+/* Return the table option structure. */
+/****************************************************************************/
+PTOS ha_connect::GetTableOptionStruct(TABLE *tab)
+{
+#if defined(MARIADB)
+ return (tshp) ? tshp->option_struct : tab->s->option_struct;
+#else // !MARIADB
+ if (share && share->table_options)
+ return share->table_options;
+ else if (table_options)
+ return table_options;
+
+ char *pk, *pv, *pn, *val;
+ size_t len= sizeof(ha_table_option_struct) + tab->s->comment.length + 1;
+ PTOS top= (PTOS)my_malloc(len, MYF(MY_FAE | MY_ZEROFILL));
+
+ top->quoted= -1; // Default value
+ top->ending= -1; // Default value
+ pk= (char *)top + sizeof(ha_table_option_struct);
+ memcpy(pk, tab->s->comment.str, tab->s->comment.length);
+
+ for (; pk; pk= ++pn) {
+ pn= strchr(pk, ',');
+ pv= strchr(pk, '=');
+
+ if (pn) *pn= 0;
+
+ if (pv) *pv= 0;
+
+ val= (pv && (!pn || pv < pn)) ? pv + 1 : "";
+
+ if (!stricmp(pk, "type") || !stricmp(pk, "Table_Type")) {
+ top->type= val;
+ } else if (!stricmp(pk, "fn") || !stricmp(pk, "filename")
+ || !stricmp(pk, "File_Name")) {
+ top->filename= val;
+ } else if (!stricmp(pk, "optfn") || !stricmp(pk, "optname")
+ || !stricmp(pk, "Xfile_Name")) {
+ top->optname= val;
+ } else if (!stricmp(pk, "name") || !stricmp(pk, "tabname")) {
+ top->tabname= val;
+ } else if (!stricmp(pk, "tablist") || !stricmp(pk, "tablelist")
+ || !stricmp(pk, "Table_list")) {
+ top->tablist= val;
+ } else if (!stricmp(pk, "sep") || !stricmp(pk, "separator")
+ || !stricmp(pk, "Sep_Char")) {
+ top->separator= val;
+ } else if (!stricmp(pk, "db") || !stricmp(pk, "database")
+ || !stricmp(pk, "DB_Name")) {
+ top->dbname= val;
+ } else if (!stricmp(pk, "qchar")) {
+ top->qchar= val;
+ } else if (!stricmp(pk, "module")) {
+ top->module= val;
+ } else if (!stricmp(pk, "subtype")) {
+ top->subtype= val;
+ } else if (!stricmp(pk, "lrecl")) {
+ top->lrecl= atoi(val);
+ } else if (!stricmp(pk, "elements")) {
+ top->elements= atoi(val);
+ } else if (!stricmp(pk, "multiple")) {
+ top->multiple= atoi(val);
+ } else if (!stricmp(pk, "header")) {
+ top->header= atoi(val);
+ } else if (!stricmp(pk, "quoted")) {
+ top->quoted= atoi(val);
+ } else if (!stricmp(pk, "ending")) {
+ top->ending= atoi(val);
+ } else if (!stricmp(pk, "compressed")) {
+ top->compressed= atoi(val);
+ } else if (!stricmp(pk, "mapped")) {
+ top->mapped= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
+ } else if (!stricmp(pk, "huge")) {
+ top->huge= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
+ } else if (!stricmp(pk, "split")) {
+ top->split= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
+ } else if (!stricmp(pk, "readonly") || !stricmp(pk, "protected")) {
+ top->readonly= (!*val || *val == 'y' || *val == 'Y' || atoi(val) != 0);
+ } // endif's
+
+ if (!pn)
+ break;
+
+ } // endfor pk
+
+ // This to get all other options
+ top->oplist= tab->s->comment.str;
+
+ if (share)
+ share->table_options= top;
+ else
+ table_options= top;
+
+ return top;
+#endif // !MARIADB
+} // end of GetTableOptionStruct
+
+/****************************************************************************/
+/* Return the value of a string option or NULL if not specified. */
+/****************************************************************************/
+char *ha_connect::GetStringOption(char *opname, char *sdef)
+{
+ char *opval= NULL;
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ ;
+ else if (!stricmp(opname, "Type"))
+ opval= (char*)options->type;
+ else if (!stricmp(opname, "Filename"))
+ opval= (char*)options->filename;
+ else if (!stricmp(opname, "Optname"))
+ opval= (char*)options->optname;
+ else if (!stricmp(opname, "Tabname"))
+ opval= (char*)options->tabname;
+ else if (!stricmp(opname, "Tablist"))
+ opval= (char*)options->tablist;
+ else if (!stricmp(opname, "Database"))
+ opval= (char*)options->dbname;
+ else if (!stricmp(opname, "Separator"))
+ opval= (char*)options->separator;
+ else if (!stricmp(opname, "Connect"))
+// opval= (char*)options->connect;
+ opval= table->s->connect_string.str;
+ else if (!stricmp(opname, "Qchar"))
+ opval= (char*)options->qchar;
+ else if (!stricmp(opname, "Module"))
+ opval= (char*)options->module;
+ else if (!stricmp(opname, "Subtype"))
+ opval= (char*)options->subtype;
+
+ if (!opval && options->oplist)
+ opval= GetListOption(opname, options->oplist);
+
+ if (!opval) {
+ if (sdef && !strcmp(sdef, "*")) {
+ // Return the handler default value
+ if (!stricmp(opname, "Database"))
+ opval= (char*)GetDBName(NULL); // Current database
+
+ } else
+ opval= sdef; // Caller default
+
+ } // endif !opval
+
+ return opval;
+} // end of GetStringOption
+
+/****************************************************************************/
+/* Return the value of a Boolean option or bdef if not specified. */
+/****************************************************************************/
+bool ha_connect::GetBooleanOption(char *opname, bool bdef)
+{
+ bool opval= bdef;
+ char *pv;
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ ;
+ else if (!stricmp(opname, "Mapped"))
+ opval= options->mapped;
+ else if (!stricmp(opname, "Huge"))
+ opval= options->huge;
+//else if (!stricmp(opname, "Compressed"))
+// opval= options->compressed;
+ else if (!stricmp(opname, "Split"))
+ opval= options->split;
+ else if (!stricmp(opname, "Readonly"))
+ opval= options->readonly;
+ else if (options->oplist)
+ if ((pv= GetListOption(opname, options->oplist)))
+ opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0);
+
+ return opval;
+} // end of GetBooleanOption
+
+/****************************************************************************/
+/* Return the value of an integer option or NO_IVAL if not specified. */
+/****************************************************************************/
+int ha_connect::GetIntegerOption(char *opname)
+{
+ int opval= NO_IVAL;
+ char *pv;
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ ;
+ else if (!stricmp(opname, "Lrecl"))
+ opval= options->lrecl;
+ else if (!stricmp(opname, "Elements"))
+ opval= options->elements;
+ else if (!stricmp(opname, "Estimate"))
+// opval= options->estimate;
+ opval= (int)table->s->max_rows;
+ else if (!stricmp(opname, "Avglen"))
+ opval= (int)table->s->avg_row_length;
+ else if (!stricmp(opname, "Multiple"))
+ opval= options->multiple;
+ else if (!stricmp(opname, "Header"))
+ opval= options->header;
+ else if (!stricmp(opname, "Quoted"))
+ opval= options->quoted;
+ else if (!stricmp(opname, "Ending"))
+ opval= options->ending;
+ else if (!stricmp(opname, "Compressed"))
+ opval= (options->compressed);
+
+ if (opval == NO_IVAL && options->oplist)
+ if ((pv= GetListOption(opname, options->oplist)))
+ opval= atoi(pv);
+
+ return opval;
+} // end of GetIntegerOption
+
+/****************************************************************************/
+/* Set the value of the opname option (does not work for oplist options) */
+/* Currently used only to set the Lrecl value. */
+/****************************************************************************/
+bool ha_connect::SetIntegerOption(char *opname, int n)
+{
+ PTOS options= GetTableOptionStruct(table);
+
+ if (!options)
+ return true;
+
+ if (!stricmp(opname, "Lrecl"))
+ options->lrecl= n;
+ else if (!stricmp(opname, "Elements"))
+ options->elements= n;
+//else if (!stricmp(opname, "Estimate"))
+// options->estimate= n;
+ else if (!stricmp(opname, "Multiple"))
+ options->multiple= n;
+ else if (!stricmp(opname, "Header"))
+ options->header= n;
+ else if (!stricmp(opname, "Quoted"))
+ options->quoted= n;
+ else if (!stricmp(opname, "Ending"))
+ options->ending= n;
+ else if (!stricmp(opname, "Compressed"))
+ options->compressed= n;
+ else
+ return true;
+//else if (options->oplist)
+// SetListOption(opname, options->oplist, n);
+
+ return false;
+} // end of SetIntegerOption
+
+/****************************************************************************/
+/* Return a field option structure. */
+/****************************************************************************/
+PFOS ha_connect::GetFieldOptionStruct(Field *fdp)
+{
+#if defined(MARIADB)
+ return fdp->option_struct;
+#else // !MARIADB
+ if (share && share->field_options)
+ return &share->field_options[fdp->field_index];
+ else if (field_options)
+ return &field_options[fdp->field_index];
+
+ char *pc, *pk, *pv, *pn, *val;
+ int i, k, n= table->s->fields;
+ size_t len= n + n * sizeof(ha_field_option_struct);
+ PFOS fp, fop;
+
+ for (i= 0; i < n; i++)
+ len+= table->s->field[i]->comment.length;
+
+ fop= (PFOS)my_malloc(len, MYF(MY_FAE | MY_ZEROFILL));
+ pc= (char*)fop + n * sizeof(ha_field_option_struct);
+
+ for (i= k= 0; i < n; i++) {
+ fp= &fop[i];
+ fp->offset= -1; // Default value
+
+ if (!table->s->field[i]->comment.length)
+ continue;
+
+ memcpy(pc, table->s->field[i]->comment.str,
+ table->s->field[i]->comment.length);
+
+ for (pk= pc; pk; pk= ++pn) {
+ if ((pn= strchr(pk, ','))) *pn= 0;
+ if ((pv= strchr(pk, '='))) *pv= 0;
+ val= (pv && (!pn || pv < pn)) ? pv + 1 : "";
+
+ if (!stricmp(pk, "datefmt") || !stricmp(pk, "date_format")) {
+ fp->dateformat= val;
+ } else if (!stricmp(pk, "fieldfmt") || !stricmp(pk, "field_format")) {
+ fp->fieldformat= val;
+ } else if (!stricmp(pk, "special")) {
+ fp->special= val;
+ } else if (!stricmp(pk, "offset") || !stricmp(pk, "flag")) {
+ fp->offset= atoi(val);
+ } else if (!stricmp(pk, "freq")) {
+ fp->freq= atoi(val);
+ } else if (!stricmp(pk, "opt")) {
+ fp->opt= atoi(val);
+ } else if (!stricmp(pk, "buflen")) {
+ fp->buflen= atoi(val);
+ } // endif's
+
+ if (!pn)
+ break;
+
+ } // endfor pk
+
+ pc+= table->s->field[i]->comment.length + 1;
+ } // endfor i
+
+ if (share)
+ share->field_options= fop;
+ else
+ field_options= fop;
+
+ return &fop[fdp->field_index];
+#endif // !MARIADB
+} // end of GetFildOptionStruct
+
+/****************************************************************************/
+/* Returns the column description structure used to make the column. */
+/****************************************************************************/
+void *ha_connect::GetColumnOption(void *field, PCOLINFO pcf)
+{
+ const char *cp;
+ int len;
+ ha_field_option_struct *fop;
+ Field* fp;
+ Field* *fldp;
+
+ // Double test to be on the safe side
+ if (!table)
+ return NULL;
+
+ // Find the column to describe
+ if (field) {
+ fldp= (Field**)field;
+ fldp++;
+ } else
+ fldp= (tshp) ? tshp->field : table->field;
+
+ if (!(fp= *fldp))
+ return NULL;
+
+ // Get the CONNECT field options structure
+ fop= GetFieldOptionStruct(fp);
+ pcf->Flags= 0;
+
+ // Now get column information
+ if (fop && fop->special) {
+ pcf->Name= "*";
+ return fldp;
+ } else
+ pcf->Name= (char*)fp->field_name;
+
+ pcf->Prec= 0;
+ pcf->Opt= (fop) ? fop->opt : 0;
+
+ if ((pcf->Length= fp->field_length) < 0)
+ pcf->Length= 256; // BLOB?
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VARCHAR:
+ pcf->Flags |= U_VAR;
+ case MYSQL_TYPE_STRING:
+ pcf->Type= TYPE_STRING;
+
+ // Do something for case
+ cp= fp->charset()->name;
+
+ // Find if collation name ends by _ci
+ if (!strcmp(cp + strlen(cp) - 3, "_ci")) {
+ pcf->Prec= 1; // Case insensitive
+ pcf->Opt= 0; // Prevent index opt until it is safe
+ } // endif ci
+
+ break;
+ case MYSQL_TYPE_LONG:
+ pcf->Type= TYPE_INT;
+ break;
+ case MYSQL_TYPE_SHORT:
+ pcf->Type= TYPE_SHORT;
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_FLOAT:
+ pcf->Type= TYPE_FLOAT;
+ pcf->Prec= max(min(fp->decimals(), ((unsigned)pcf->Length - 2)), 0);
+ break;
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ pcf->Type= TYPE_DATE;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ pcf->Type= TYPE_BIGINT;
+ break;
+ default:
+ pcf->Type=TYPE_ERROR;
+ } // endswitch type
+
+ // This is used to skip null bit
+ if (fp->real_maybe_null())
+ pcf->Flags |= U_NULLS;
+
+#if defined(MARIADB)
+ // Mark virtual columns as such
+ if (fp->vcol_info && !fp->stored_in_db)
+ pcf->Flags |= U_VIRTUAL;
+#endif // MARIADB
+
+ pcf->Key= 0; // Not used when called from MySQL
+ pcf->Remark= fp->comment.str;
+
+ if (fop) {
+ pcf->Offset= fop->offset;
+// pcf->Freq= fop->freq;
+ pcf->Datefmt= (char*)fop->dateformat;
+ pcf->Fieldfmt= (char*)fop->fieldformat;
+
+ // This is useful in particular for date columns
+ if ((len= fop->buflen) > pcf->Length)
+ pcf->Length= len;
+
+ } else {
+ pcf->Offset= -1;
+// pcf->Freq= 0;
+ pcf->Datefmt= NULL;
+ pcf->Fieldfmt= NULL;
+ } // endif fop
+
+ return fldp;
+} // end of GetColumnOption
+
+/****************************************************************************/
+/* Returns the index description structure used to make the index. */
+/****************************************************************************/
+PIXDEF ha_connect::GetIndexInfo(int n)
+{
+ char *name, *pn;
+ bool unique;
+ PIXDEF xdp= NULL;
+ PKPDEF kpp, pkp= NULL;
+ PGLOBAL& g= xp->g;
+ KEY kp;
+
+ // Find the index to describe
+ if ((unsigned)n < table->s->keynames.count)
+// kp= table->key_info[n]; which one ???
+ kp= table->s->key_info[n];
+ else
+ return NULL;
+
+ // Now get index information
+ pn= (char*)table->s->keynames.type_names[n];
+ name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1);
+ strcpy(name, pn); // This is probably unuseful
+ unique= (kp.flags & 1) != 0;
+
+ // Allocate the index description block
+ xdp= new(g) INDEXDEF(name, unique, n);
+
+ // Get the the key parts info
+ for (int k= 0; (unsigned)k < kp.key_parts; k++) {
+ pn= (char*)kp.key_part[k].field->field_name;
+ name= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1);
+ strcpy(name, pn); // This is probably unuseful
+
+ // Allocate the key part description block
+ kpp= new(g) KPARTDEF(name, k + 1);
+ kpp->SetKlen(kp.key_part[k].length);
+
+ // Index on auto increment column is an XXROW index
+ if (kp.key_part[k].field->flags & AUTO_INCREMENT_FLAG && kp.key_parts == 1)
+ xdp->SetAuto(true);
+
+ if (pkp)
+ pkp->SetNext(kpp);
+ else
+ xdp->SetToKeyParts(kpp);
+
+ pkp= kpp;
+ } // endfor k
+
+ xdp->SetNParts(kp.key_parts);
+ return xdp;
+} // end of GetIndexInfo
+
+const char *ha_connect::GetDBName(const char* name)
+{
+ return (name) ? name : table->s->db.str;
+} // end of GetDBName
+
+const char *ha_connect::GetTableName(void)
+{
+ return table->s->table_name.str;
+} // end of GetTableName
+
+/****************************************************************************/
+/* Returns the column real or special name length of a field. */
+/****************************************************************************/
+int ha_connect::GetColNameLen(Field *fp)
+{
+ int n;
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ // Now get the column name length
+ if (fop && fop->special)
+ n= strlen(fop->special) + 1;
+ else
+ n= strlen(fp->field_name);
+
+ return n;
+} // end of GetColNameLen
+
+/****************************************************************************/
+/* Returns the column real or special name of a field. */
+/****************************************************************************/
+char *ha_connect::GetColName(Field *fp)
+{
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ return (fop && fop->special) ? fop->special : (char*)fp->field_name;
+} // end of GetColName
+
+/****************************************************************************/
+/* Adds the column real or special name of a field to a string. */
+/****************************************************************************/
+void ha_connect::AddColName(char *cp, Field *fp)
+{
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ // Now add the column name
+ if (fop && fop->special)
+ // The prefix * mark the column as "special"
+ strcat(strcpy(cp, "*"), strupr(fop->special));
+ else
+ strcpy(cp, (char*)fp->field_name);
+
+} // end of AddColName
+
+/****************************************************************************/
+/* Get the table description block of a CONNECT table. */
+/****************************************************************************/
+PTDB ha_connect::GetTDB(PGLOBAL g)
+{
+ const char *table_name;
+ PTDB tp;
+
+ // Double test to be on the safe side
+ if (!g || !table)
+ return NULL;
+
+ table_name= GetTableName();
+
+ if (tdbp && !stricmp(tdbp->GetName(), table_name)
+ && tdbp->GetMode() == xmod && !xp->CheckQuery(valid_query_id)) {
+ tp= tdbp;
+ tp->SetMode(xmod);
+ } else if ((tp= CntGetTDB(g, table_name, xmod, this)))
+ valid_query_id= xp->last_query_id;
+ else
+ printf("GetTDB: %s\n", g->Message);
+
+ return tp;
+} // end of GetTDB
+
+/****************************************************************************/
+/* Open a CONNECT table, restricting column list if cols is true. */
+/****************************************************************************/
+bool ha_connect::OpenTable(PGLOBAL g, bool del)
+{
+ bool rc= false;
+ char *c1= NULL, *c2=NULL;
+
+ // Double test to be on the safe side
+ if (!g || !table) {
+ printf("OpenTable logical error; g=%p table=%p\n", g, table);
+ return true;
+ } // endif g
+
+ if (!(tdbp= GetTDB(g)))
+ return true;
+
+ // Get the list of used fields (columns)
+ char *p;
+ unsigned int k1, k2, n1, n2;
+ Field* *field;
+ MY_BITMAP *map= (xmod != MODE_INSERT) ? table->read_set : table->write_set;
+ MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL;
+
+ k1= k2= 0;
+ n1= n2= 1; // 1 is space for final null character
+
+ for (field= table->field; *field; field++) {
+ if (bitmap_is_set(map, (*field)->field_index)) {
+ n1+= (GetColNameLen(*field) + 1);
+ k1++;
+ } // endif
+
+ if (ump && bitmap_is_set(ump, (*field)->field_index)) {
+ n2+= (GetColNameLen(*field) + 1);
+ k2++;
+ } // endif
+
+ } // endfor field
+
+ if (k1) {
+ p= c1= (char*)PlugSubAlloc(g, NULL, n1);
+
+ for (field= table->field; *field; field++)
+ if (bitmap_is_set(map, (*field)->field_index)) {
+ AddColName(p, *field);
+ p+= (strlen(p) + 1);
+ } // endif used field
+
+ *p= '\0'; // mark end of list
+ } // endif k1
+
+ if (k2) {
+ p= c2= (char*)PlugSubAlloc(g, NULL, n2);
+
+ for (field= table->field; *field; field++)
+ if (bitmap_is_set(ump, (*field)->field_index)) {
+ AddColName(p, *field);
+ p+= (strlen(p) + 1);
+ } // endif used field
+
+ *p= '\0'; // mark end of list
+ } // endif k2
+
+ // Open the table
+ if (!(rc= CntOpenTable(g, tdbp, xmod, c1, c2, del, this))) {
+ istable= true;
+// strmake(tname, table_name, sizeof(tname)-1);
+
+ if (xmod == MODE_ANY && stop && *tdbp->GetName() != '#') {
+ // We are in a create index query
+ if (!((PTDBASE)tdbp)->GetDef()->Indexable()) {
+ sprintf(g->Message, "Table %s cannot be indexed", tdbp->GetName());
+ rc= true;
+ } else if (xp) // xp can be null when called from create
+ xp->tabp= (PTDBDOS)tdbp; // The table on which the index is created
+
+ } // endif xmod
+
+// tdbp->SetOrig((PTBX)table); // used by CheckCond
+ } else
+ printf("OpenTable: %s\n", g->Message);
+
+ if (rc) {
+ tdbp= NULL;
+ valid_info= false;
+ } // endif rc
+
+ return rc;
+} // end of OpenTable
+
+
+/****************************************************************************/
+/* IsOpened: returns true if the table is already opened. */
+/****************************************************************************/
+bool ha_connect::IsOpened(void)
+{
+ return (!xp->CheckQuery(valid_query_id) && tdbp
+ && tdbp->GetUse() == USE_OPEN);
+} // end of IsOpened
+
+
+/****************************************************************************/
+/* Close a CONNECT table. */
+/****************************************************************************/
+int ha_connect::CloseTable(PGLOBAL g)
+{
+ int rc= CntCloseTable(g, tdbp);
+ tdbp= NULL;
+ sdval=NULL;
+ valid_info= false;
+ indexing= -1;
+ return rc;
+} // end of CloseTable
+
+
+/***********************************************************************/
+/* Make a pseudo record from current row values. Specific to MySQL. */
+/***********************************************************************/
+int ha_connect::MakeRecord(char *buf)
+{
+ char *p, *fmt, val[32];
+ int rc= 0;
+ Field* *field;
+ Field *fp;
+ my_bitmap_map *org_bitmap;
+ CHARSET_INFO *charset;
+ const MY_BITMAP *map;
+ PVAL value;
+ PCOL colp= NULL;
+ DBUG_ENTER("ha_connect::MakeRecord");
+
+ if (xtrace > 1)
+#if defined(MARIADB)
+ printf("Maps: read=%p write=%p vcol=%p defr=%p defw=%p\n",
+ *table->read_set->bitmap, *table->write_set->bitmap,
+ *table->vcol_set->bitmap,
+ *table->def_read_set.bitmap, *table->def_write_set.bitmap);
+#else // !MARIADB
+ printf("Maps: read=%p write=%p defr=%p defw=%p\n",
+ *table->read_set->bitmap, *table->write_set->bitmap,
+ *table->def_read_set.bitmap, *table->def_write_set.bitmap);
+#endif // !MARIADB
+
+ // Avoid asserts in field::store() for columns that are not updated
+ org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
+
+ // This is for variable_length rows
+ memset(buf, 0, table->s->null_bytes);
+
+ // store needs a charset, why not this one?
+ charset= table->s->table_charset;
+
+ // When sorting read_set selects all columns, so we use def_read_set
+ map= (const MY_BITMAP *)&table->def_read_set;
+
+ // Make the pseudo record from field values
+ for (field= table->field; *field && !rc; field++) {
+ fp= *field;
+
+#if defined(MARIADB)
+ if (fp->vcol_info && !fp->stored_in_db)
+ continue; // This is a virtual column
+#endif // MARIADB
+
+ if (bitmap_is_set(map, fp->field_index)) {
+ // This is a used field, fill the buffer with value
+ for (colp= tdbp->GetColumns(); colp; colp= colp->GetNext())
+ if (!stricmp(colp->GetName(), GetColName(fp)))
+ break;
+
+ if (!colp) {
+ printf("Column %s not found\n", fp->field_name);
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
+ DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
+ } // endif colp
+
+ value= colp->GetValue();
+
+ // All this could be better optimized
+ if (value->GetType() == TYPE_DATE) {
+ if (!sdval)
+ sdval= AllocateValue(xp->g, TYPE_STRING, 20);
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_DATE:
+ fmt= "%Y-%m-%d";
+ break;
+ case MYSQL_TYPE_TIME:
+ fmt= "%H:%M:%S";
+ break;
+ default:
+ fmt= "%Y-%m-%d %H:%M:%S";
+ } // endswitch type
+
+ // Get date in the format required by MySQL fields
+ value->FormatValue(sdval, fmt);
+ p= sdval->GetCharValue();
+ } else if (value->GetType() == TYPE_FLOAT)
+ p= NULL;
+ else
+ p= value->GetCharString(val);
+
+ if (p) {
+ if (fp->store(p, strlen(p), charset, CHECK_FIELD_WARN)) {
+ // Avoid "error" on null fields
+ if (value->GetIntValue())
+ rc= HA_ERR_WRONG_IN_RECORD;
+
+ DBUG_PRINT("MakeRecord", (p));
+ } // endif store
+
+ } else
+ if (fp->store(value->GetFloatValue())) {
+ rc= HA_ERR_WRONG_IN_RECORD;
+ DBUG_PRINT("MakeRecord", (value->GetCharString(val)));
+ } // endif store
+
+ } // endif bitmap
+
+ } // endfor field
+
+ // This is copied from ha_tina and is necessary to avoid asserts
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
+ DBUG_RETURN(rc);
+} // end of MakeRecord
+
+
+/***********************************************************************/
+/* Set row values from a MySQL pseudo record. Specific to MySQL. */
+/***********************************************************************/
+int ha_connect::ScanRecord(PGLOBAL g, uchar *buf)
+{
+ char attr_buffer[1024];
+ int rc= 0;
+ PCOL colp;
+ PVAL value;
+ Field *fp;
+ PTDBASE tp= (PTDBASE)tdbp;
+ String attribute(attr_buffer, sizeof(attr_buffer),
+ table->s->table_charset);
+ my_bitmap_map *bmap= dbug_tmp_use_all_columns(table, table->read_set);
+
+ // Scan the pseudo record for field values and set column values
+ for (Field **field=table->field ; *field ; field++) {
+ fp= *field;
+
+#if defined(MARIADB)
+ if ((fp->vcol_info && !fp->stored_in_db) ||
+ fp->option_struct->special)
+ continue; // Is a virtual column possible here ???
+#endif // MARIADB
+
+ if (bitmap_is_set(table->write_set, fp->field_index)) {
+ for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
+ if (!stricmp(colp->GetName(), fp->field_name))
+ break;
+
+ if (!colp) {
+ printf("Column %s not found\n", fp->field_name);
+ rc= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ } else
+ value= colp->GetValue();
+
+ // This is a used field, fill the value from the row buffer
+ // All this could be better optimized
+ switch (value->GetType()) {
+ case TYPE_FLOAT:
+ value->SetValue(fp->val_real());
+ break;
+ case TYPE_DATE:
+ if (!sdval) {
+ sdval= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
+
+ // Get date in the format produced by MySQL fields
+ ((DTVAL*)sdval)->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
+ } // endif sdval
+
+ fp->val_str(&attribute);
+ sdval->SetValue_psz(attribute.c_ptr());
+ value->SetValue_pval(sdval);
+ break;
+ default:
+ fp->val_str(&attribute);
+ value->SetValue_psz(attribute.c_ptr());
+ } // endswitch Type
+
+#ifdef NEWCHANGE
+ } else if (xmod == MODE_UPDATE) {
+ PCOL cp;
+
+ for (cp= tp->GetColumns(); cp; cp= cp->GetNext())
+ if (!stricmp(colp->GetName(), cp->GetName()))
+ break;
+
+ if (!cp) {
+ rc= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ } // endif cp
+
+ value->SetValue_pval(cp->GetValue());
+ } else // mode Insert
+ value->Reset();
+#else
+ } // endif bitmap_is_set
+#endif
+
+ } // endfor field
+
+ err:
+ dbug_tmp_restore_column_map(table->read_set, bmap);
+ return rc;
+} // end of ScanRecord
+
+
+/***********************************************************************/
+/* Check change in index column. Specific to MySQL. */
+/* Should be elaborated to check for real changes. */
+/***********************************************************************/
+int ha_connect::CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf)
+{
+ return ScanRecord(g, newbuf);
+} // end of dummy CheckRecord
+
+
+/***********************************************************************/
+/* Return the string representing an operator. */
+/***********************************************************************/
+char *ha_connect::GetValStr(OPVAL vop, bool neg)
+{
+ char *val;
+
+ switch (vop) {
+ case OP_EQ:
+ val= " = ";
+ break;
+ case OP_NE:
+ val= " <> ";
+ break;
+ case OP_GT:
+ val= " > ";
+ break;
+ case OP_GE:
+ val= " >= ";
+ break;
+ case OP_LT:
+ val= " < ";
+ break;
+ case OP_LE:
+ val= " <= ";
+ break;
+ case OP_IN:
+ val= (neg) ? " NOT IN (" : " IN (";
+ break;
+ case OP_NULL:
+ val= " IS NULL";
+ break;
+ case OP_LIKE:
+ val= " LIKE ";
+ break;
+ case OP_XX:
+ val= " BETWEEN ";
+ break;
+ case OP_EXIST:
+ val= " EXISTS ";
+ break;
+ case OP_AND:
+ val= " AND ";
+ break;
+ case OP_OR:
+ val= " OR ";
+ break;
+ case OP_NOT:
+ val= " NOT ";
+ break;
+ case OP_CNC:
+ val= " || ";
+ break;
+ case OP_ADD:
+ val= " + ";
+ break;
+ case OP_SUB:
+ val= " - ";
+ break;
+ case OP_MULT:
+ val= " * ";
+ break;
+ case OP_DIV:
+ val= " / ";
+ break;
+ default:
+ val= " ? ";
+ } /* endswitch */
+
+ return val;
+} // end of GetValStr
+
+
+/***********************************************************************/
+/* Check the WHERE condition and return an ODBC/WQL filter. */
+/***********************************************************************/
+PFIL ha_connect::CheckCond(PGLOBAL g, PFIL filp, AMT tty, Item *cond)
+{
+ unsigned int i;
+ bool ismul= false;
+ PPARM pfirst= NULL, pprec= NULL, pp[2]= {NULL, NULL};
+ OPVAL vop= OP_XX;
+
+ if (!cond)
+ return NULL;
+
+ if (xtrace > 1)
+ printf("Cond type=%d\n", cond->type());
+
+ if (cond->type() == COND::COND_ITEM) {
+ char *p1, *p2;
+ Item_cond *cond_item= (Item_cond *)cond;
+
+ if (xtrace > 1)
+ printf("Cond: Ftype=%d name=%s\n", cond_item->functype(),
+ cond_item->func_name());
+
+ switch (cond_item->functype()) {
+ case Item_func::COND_AND_FUNC: vop= OP_AND; break;
+ case Item_func::COND_OR_FUNC: vop= OP_OR; break;
+ default: return NULL;
+ } // endswitch functype
+
+ List<Item>* arglist= cond_item->argument_list();
+ List_iterator<Item> li(*arglist);
+ Item *subitem;
+
+ p1= filp + strlen(filp);
+ strcpy(p1, "(");
+ p2= p1 + 1;
+
+ for (i= 0; i < arglist->elements; i++)
+ if ((subitem= li++)) {
+ if (!CheckCond(g, filp, tty, subitem)) {
+ if (vop == OP_OR)
+ return NULL;
+ else
+ *p2= 0;
+
+ } else {
+ p1= p2 + strlen(p2);
+ strcpy(p1, GetValStr(vop, FALSE));
+ p2= p1 + strlen(p1);
+ } // endif CheckCond
+
+ } else
+ return NULL;
+
+ if (*p1 != '(')
+ strcpy(p1, ")");
+ else
+ return NULL;
+
+ } else if (cond->type() == COND::FUNC_ITEM) {
+ unsigned int i;
+// int n;
+ bool iscol, neg= FALSE;
+ Item_func *condf= (Item_func *)cond;
+ Item* *args= condf->arguments();
+
+ if (xtrace > 1)
+ printf("Func type=%d argnum=%d\n", condf->functype(),
+ condf->argument_count());
+
+// neg= condf->
+
+ switch (condf->functype()) {
+ case Item_func::EQUAL_FUNC:
+ case Item_func::EQ_FUNC: vop= OP_EQ; break;
+ case Item_func::NE_FUNC: vop= OP_NE; break;
+ case Item_func::LT_FUNC: vop= OP_LT; break;
+ case Item_func::LE_FUNC: vop= OP_LE; break;
+ case Item_func::GE_FUNC: vop= OP_GE; break;
+ case Item_func::GT_FUNC: vop= OP_GT; break;
+ case Item_func::IN_FUNC: vop= OP_IN;
+ neg= ((Item_func_opt_neg *)condf)->negated;
+ case Item_func::BETWEEN: ismul= true; break;
+ default: return NULL;
+ } // endswitch functype
+
+ if (condf->argument_count() < 2)
+ return NULL;
+ else if (ismul && tty == TYPE_AM_WMI)
+ return NULL; // Not supported by WQL
+
+ for (i= 0; i < condf->argument_count(); i++) {
+ if (xtrace > 1)
+ printf("Argtype(%d)=%d\n", i, args[i]->type());
+
+ if (i >= 2 && !ismul) {
+ if (xtrace > 1)
+ printf("Unexpected arg for vop=%d\n", vop);
+
+ continue;
+ } // endif i
+
+ if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
+ const char *fnm;
+ ha_field_option_struct *fop;
+ Item_field *pField= (Item_field *)args[i];
+
+ if (pField->field->table != table)
+ return NULL; // Field does not belong to this table
+ else
+ fop= GetFieldOptionStruct(pField->field);
+
+ if (fop && fop->special) {
+ if (tty == TYPE_AM_TBL && !stricmp(fop->special, "TABID"))
+ fnm= "TABID";
+ else
+ return NULL;
+
+ } else if (tty == TYPE_AM_TBL)
+ return NULL;
+ else
+ fnm= pField->field->field_name;
+
+ if (xtrace > 1) {
+ printf("Field index=%d\n", pField->field->field_index);
+ printf("Field name=%s\n", pField->field->field_name);
+ } // endif xtrace
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (i && ismul)
+ return NULL;
+
+ strcat(filp, fnm);
+ } else {
+ char buff[256];
+ String *res, tmp(buff,sizeof(buff), &my_charset_bin);
+ Item_basic_constant *pval= (Item_basic_constant *)args[i];
+
+ if ((res= pval->val_str(&tmp)) == NULL)
+ return NULL; // To be clarified
+
+ if (xtrace > 1)
+ printf("Value=%.*s\n", res->length(), res->ptr());
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (!i && ismul)
+ return NULL;
+
+ // Append the value to the filter
+ if (args[i]->type() == COND::STRING_ITEM)
+ strcat(strcat(strcat(filp, "'"), res->ptr()), "'");
+ else
+ strncat(filp, res->ptr(), res->length());
+
+ } // endif
+
+ if (!i)
+ strcat(filp, GetValStr(vop, neg));
+ else if (vop == OP_XX && i == 1)
+ strcat(filp, " AND ");
+ else if (vop == OP_IN)
+ strcat(filp, (i == condf->argument_count() - 1) ? ")" : ",");
+
+ } // endfor i
+
+ } else {
+ if (xtrace > 1)
+ printf("Unsupported condition\n");
+
+ return NULL;
+ } // endif's type
+
+ return filp;
+} // end of CheckCond
+
+
+ /**
+ Push condition down to the table handler.
+
+ @param cond Condition to be pushed. The condition tree must not be
+ modified 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
+ CONNECT handles the filtering only for table types that construct
+ an SQL or WQL query, but still leaves it to MySQL because only some
+ parts of the filter may be relevant.
+ The first suballocate finds the position where the string will be
+ constructed in the sarea. The second one does make the suballocation
+ with the proper length.
+ */
+const COND *ha_connect::cond_push(const COND *cond)
+{
+ DBUG_ENTER("ha_connect::cond_push");
+
+ if (tdbp) {
+ AMT tty= tdbp->GetAmType();
+
+ if (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
+ tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL) {
+ PGLOBAL& g= xp->g;
+ PFIL filp= (PFIL)PlugSubAlloc(g, NULL, 0);
+
+ *filp= 0;
+
+ if (CheckCond(g, filp, tty, (Item *)cond)) {
+ if (xtrace)
+ puts(filp);
+
+ tdbp->SetFilter(filp);
+// cond= NULL; // This does not work anyway
+ PlugSubAlloc(g, NULL, strlen(filp) + 1);
+ } // endif filp
+
+ } // endif tty
+
+ } // endif tdbp
+
+ // Let MySQL do the filtering
+ DBUG_RETURN(cond);
+} // end of cond_push
+
+/**
+ Number of rows in table. It will only be called if
+ (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
+*/
+ha_rows ha_connect::records()
+{
+ if (!valid_info)
+ info(HA_STATUS_VARIABLE);
+
+ if (tdbp && tdbp->Cardinality(NULL))
+ return stats.records;
+ else
+ return HA_POS_ERROR;
+
+} // end of records
+
+
+/**
+ Return an error message specific to this handler.
+
+ @param error error code previously returned by handler
+ @param buf pointer to String where to add error message
+
+ @return
+ Returns true if this is a temporary error
+*/
+bool ha_connect::get_error_message(int error, String* buf)
+{
+ DBUG_ENTER("ha_connect::get_error_message");
+
+ if (xp && xp->g)
+ buf->copy(xp->g->Message, (uint)strlen(xp->g->Message),
+ system_charset_info);
+
+ DBUG_RETURN(false);
+} // end of get_error_message
+
+
+/**
+ @brief
+ If frm_error() is called then we will use this to determine
+ the file extensions that exist for the storage engine. This is also
+ used by the default rename_table and delete_table method in
+ handler.cc.
+
+ For engines that have two file name extentions (separate meta/index file
+ and data file), the order of elements is relevant. First element of engine
+ file name extentions array should be meta/index file extention. Second
+ element - data file extention. This order is assumed by
+ prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
+
+ @note: PlugDB will handle all file creation/deletion. When dropping
+ a CONNECT table, we don't want the PlugDB table to be dropped or erased.
+ Therefore we provide a void list of extensions.
+
+ @see
+ rename_table method in handler.cc and
+ delete_table method in handler.cc
+*/
+static const char *ha_connect_exts[]= {
+ NullS
+};
+
+
+const char **ha_connect::bas_ext() const
+{
+ return ha_connect_exts; // a null list, see @note above
+} // end of bas_ext
+
+
+/**
+ @brief
+ Used for opening tables. The name will be the name of the file.
+
+ @details
+ A table is opened when it needs to be opened; e.g. when a request comes in
+ for a SELECT on the table (tables are not open and closed for each request,
+ they are cached).
+
+ Called from handler.cc by handler::ha_open(). The server opens all tables by
+ calling ha_open() which then calls the handler specific open().
+
+ @note
+ For CONNECT no open can be done here because field information is not yet
+ updated. >>>>> TO BE CHECKED <<<<<
+ (Thread information could be get by using 'ha_thd')
+
+ @see
+ handler::ha_open() in handler.cc
+*/
+int ha_connect::open(const char *name, int mode, uint test_if_locked)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::open");
+
+ if (xtrace)
+ printf("open: name=%s mode=%d test=%ud\n", name, mode, test_if_locked);
+
+ if (!(share= get_share(name, table)))
+ DBUG_RETURN(1);
+
+ thr_lock_data_init(&share->lock,&lock,NULL);
+
+ // Try to get the user if possible
+ if (table && table->in_use) {
+ PGLOBAL g= GetPlug(table->in_use);
+
+ // Try to set the database environment
+ if (g)
+ rc= (CntCheckDB(g, this, name)) ? (-2) : 0;
+
+ } // endif table
+
+ DBUG_RETURN(rc);
+} // end of open
+
+/**
+ @brief
+ Make the indexes for this table
+*/
+int ha_connect::optimize(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ PDBUSER dup= PlgGetUser(g);
+
+ // Ignore error on the opt file
+ dup->Check &= ~CHK_OPT;
+ tdbp= GetTDB(g);
+ dup->Check |= CHK_OPT;
+
+ if (tdbp || (tdbp= GetTDB(g))) {
+ if (!((PTDBASE)tdbp)->GetDef()->Indexable()) {
+ sprintf(g->Message, "Table %s is not indexable", tdbp->GetName());
+ rc= RC_INFO;
+ } else
+ rc= ((PTDBASE)tdbp)->ResetTableOpt(g, true);
+
+ } else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ return rc;
+} // end of optimize
+
+/**
+ @brief
+ Closes a table. We call the free_share() function to free any resources
+ that we have allocated in the "shared" structure.
+
+ @details
+ Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
+ only used to close up temporary tables or during the process where a
+ temporary table is converted over to being a myisam table.
+
+ For sql_base.cc look at close_data_tables().
+
+ @see
+ sql_base.cc, sql_select.cc and table.cc
+*/
+int ha_connect::close(void)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::close");
+
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+ if (tdbp && xp->last_query_id == valid_query_id)
+ rc= CloseTable(xp->g);
+
+ DBUG_RETURN(free_share(share) || rc);
+} // end of close
+
+
+/**
+ @brief
+ write_row() inserts a row. No extra() hint is given currently if a bulk load
+ is happening. buf() is a byte array of data. You can use the field
+ information to extract the data from the native byte array type.
+
+ @details
+ Example of this would be:
+ @code
+ for (Field **field=table->field ; *field ; field++)
+ {
+ ...
+ }
+ @endcode
+
+ See ha_tina.cc for an example of extracting all of the data as strings.
+ ha_berekly.cc has an example of how to store it intact by "packing" it
+ for ha_berkeley's own native storage type.
+
+ See the note for update_row() on auto_increments and timestamps. This
+ case also applies to write_row().
+
+ Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
+ sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
+
+ @see
+ item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
+ sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
+*/
+int ha_connect::write_row(uchar *buf)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("ha_connect::write_row");
+
+ // Open the table if it was not opened yet (possible ???)
+ if (!IsOpened())
+ if (OpenTable(g)) {
+ if (strstr(g->Message, "read only"))
+ rc= HA_ERR_TABLE_READONLY;
+ else
+ rc= HA_ERR_INITIALIZATION;
+
+ DBUG_RETURN(rc);
+ } // endif tdbp
+
+ if (tdbp->GetMode() == MODE_ANY)
+ DBUG_RETURN(0);
+
+ // Set column values from the passed pseudo record
+ if ((rc= ScanRecord(g, buf)))
+ DBUG_RETURN(rc);
+
+ // Return result code from write operation
+ if (CntWriteRow(g, tdbp)) {
+ DBUG_PRINT("write_row", (g->Message));
+ printf("write_row: %s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endif RC
+
+ DBUG_RETURN(rc);
+} // end of write_row
+
+
+/**
+ @brief
+ Yes, update_row() does what you expect, it updates a row. old_data will have
+ the previous row record in it, while new_data will have the newest data in it.
+ Keep in mind that the server can do updates based on ordering if an ORDER BY
+ clause was used. Consecutive ordering is not guaranteed.
+
+ @details
+ Currently new_data will not have an updated auto_increament record, or
+ and updated timestamp field. You can do these for example by doing:
+ @code
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
+ table->timestamp_field->set_time();
+ if (table->next_number_field && record == table->record[0])
+ update_auto_increment();
+ @endcode
+
+ Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
+
+ @see
+ sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
+*/
+int ha_connect::update_row(const uchar *old_data, uchar *new_data)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("ha_connect::update_row");
+
+ if (xtrace > 1)
+ printf("update_row: old=%s new=%s\n", old_data, new_data);
+
+ // Check values for possible change in indexed column
+ if ((rc= CheckRecord(g, old_data, new_data)))
+ return rc;
+
+ if (CntUpdateRow(g, tdbp)) {
+ DBUG_PRINT("update_row", (g->Message));
+ printf("update_row CONNECT: %s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endif RC
+
+ DBUG_RETURN(rc);
+} // end of update_row
+
+
+/**
+ @brief
+ This will delete a row. buf will contain a copy of the row to be deleted.
+ The server will call this right after the current row has been called (from
+ either a previous rnd_nexT() or index call).
+
+ @details
+ If you keep a pointer to the last row or can access a primary key it will
+ make doing the deletion quite a bit easier. Keep in mind that the server does
+ not guarantee consecutive deletions. ORDER BY clauses can be used.
+
+ Called in sql_acl.cc and sql_udf.cc to manage internal table
+ information. Called in sql_delete.cc, sql_insert.cc, and
+ sql_select.cc. In sql_select it is used for removing duplicates
+ while in insert it is used for REPLACE calls.
+
+ @see
+ sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
+*/
+int ha_connect::delete_row(const uchar *buf)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::delete_row");
+
+ if (CntDeleteRow(xp->g, tdbp, false)) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ printf("delete_row CONNECT: %s\n", xp->g->Message);
+ } // endif DeleteRow
+
+ DBUG_RETURN(rc);
+} // end of delete_row
+
+
+/****************************************************************************/
+/* We seem to come here at the begining of an index use. */
+/****************************************************************************/
+int ha_connect::index_init(uint idx, bool sorted)
+{
+ int rc;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("index_init");
+
+ if ((rc= rnd_init(0)))
+ return rc;
+
+ indexing= CntIndexInit(g, tdbp, (signed)idx);
+
+ if (indexing <= 0) {
+ DBUG_PRINT("index_init", (g->Message));
+ printf("index_init CONNECT: %s\n", g->Message);
+ active_index= (uint)-1;
+ rc= -1;
+ } else {
+ if (((PTDBDOX)tdbp)->To_Kindex->GetNum_K()) {
+ if (((PTDBASE)tdbp)->GetFtype() != RECFM_NAF)
+ ((PTDBDOX)tdbp)->GetTxfp()->ResetBuffer(g);
+
+ active_index= idx;
+ } else // Void table
+ indexing= 0;
+
+ rc= 0;
+ } // endif indexing
+
+ DBUG_RETURN(rc);
+} // end of index_init
+
+/****************************************************************************/
+/* We seem to come here at the end of an index use. */
+/****************************************************************************/
+int ha_connect::index_end()
+{
+ DBUG_ENTER("index_end");
+ active_index= -1;
+ DBUG_RETURN(rnd_end());
+} // end of index_end
+
+
+/****************************************************************************/
+/* This is internally called by all indexed reading functions. */
+/****************************************************************************/
+int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const uchar *key, uint key_len)
+{
+ int rc;
+
+//statistic_increment(ha_read_key_count, &LOCK_status);
+
+ switch (CntIndexRead(xp->g, tdbp, op, key, (int)key_len)) {
+ case RC_OK:
+ xp->fnd++;
+ rc= MakeRecord((char*)buf);
+ break;
+ case RC_EF: // End of file
+ rc= HA_ERR_END_OF_FILE;
+ break;
+ case RC_NF: // Not found
+ xp->nfd++;
+ rc= (op == OP_SAME) ? HA_ERR_END_OF_FILE : HA_ERR_KEY_NOT_FOUND;
+ break;
+ default: // Read error
+ DBUG_PRINT("ReadIndexed", (xp->g->Message));
+ printf("ReadIndexed: %s\n", xp->g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endswitch RC
+
+ if (xtrace > 1)
+ printf("ReadIndexed: op=%d rc=%d\n", op, rc);
+
+ table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND;
+ return rc;
+} // end of ReadIndexed
+
+
+#ifdef NOT_USED
+/**
+ @brief
+ Positions an index cursor to the index specified in the handle. Fetches the
+ row if available. If the key value is null, begin at the first key of the
+ index.
+*/
+int ha_connect::index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map __attribute__((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__((unused)))
+{
+ DBUG_ENTER("ha_connect::index_read");
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+#endif // NOT_USED
+
+
+/****************************************************************************/
+/* This is called by handler::index_read_map. */
+/****************************************************************************/
+int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len,
+ enum ha_rkey_function find_flag)
+{
+ int rc;
+ OPVAL op= OP_XX;
+ DBUG_ENTER("ha_connect::index_read");
+
+ switch(find_flag) {
+ case HA_READ_KEY_EXACT: op= OP_EQ; break;
+ case HA_READ_AFTER_KEY: op= OP_GT; break;
+ case HA_READ_KEY_OR_NEXT: op= OP_GE; break;
+ default: DBUG_RETURN(-1);
+ } // endswitch find_flag
+
+ if (xtrace > 1)
+ printf("%p index_read: op=%d\n", this, op);
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, op, key, key_len);
+ else
+ rc= -1;
+
+ DBUG_RETURN(rc);
+} // end of index_read
+
+
+/**
+ @brief
+ Used to read forward through the index.
+*/
+int ha_connect::index_next(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_next");
+ //statistic_increment(ha_read_next_count, &LOCK_status);
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, OP_NEXT);
+ else if (!indexing)
+ rc= rnd_next(buf);
+ else
+ rc= -1;
+
+ DBUG_RETURN(rc);
+} // end of index_next
+
+
+#ifdef NOT_USED
+/**
+ @brief
+ Used to read backwards through the index.
+*/
+int ha_connect::index_prev(uchar *buf)
+{
+ DBUG_ENTER("ha_connect::index_prev");
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+#endif // NOT_USED
+
+
+/**
+ @brief
+ index_first() asks for the first key in the index.
+
+ @details
+ Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
+
+ @see
+ opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
+*/
+int ha_connect::index_first(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_first");
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, OP_FIRST);
+ else if (indexing < 0)
+ rc= -1;
+ else if (CntRewindTable(xp->g, tdbp)) {
+ table->status= STATUS_NOT_FOUND;
+ rc= -1;
+ } else
+ rc= rnd_next(buf);
+
+ DBUG_RETURN(rc);
+} // end of index_first
+
+
+#ifdef NOT_USED
+/**
+ @brief
+ index_last() asks for the last key in the index.
+
+ @details
+ Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
+
+ @see
+ opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
+*/
+int ha_connect::index_last(uchar *buf)
+{
+ DBUG_ENTER("ha_connect::index_last");
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+#endif // NOT_USED
+
+
+/****************************************************************************/
+/* This is called to get more rows having the same index value. */
+/****************************************************************************/
+int ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_next_same");
+//statistic_increment(ha_read_next_count, &LOCK_status);
+
+ if (!indexing)
+ rc= rnd_next(buf);
+ else if (indexing > 0)
+ rc= ReadIndexed(buf, OP_SAME);
+ else
+ rc= -1;
+
+ DBUG_RETURN(rc);
+} // end of index_next_same
+
+
+/**
+ @brief
+ rnd_init() is called when the system wants the storage engine to do a table
+ scan. See the example in the introduction at the top of this file to see when
+ rnd_init() is called.
+
+ @details
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+ and sql_update.cc.
+
+ @note
+ We always call open and extern_lock/start_stmt before comming here.
+
+ @see
+ filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
+*/
+int ha_connect::rnd_init(bool scan)
+{
+ PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use) :
+ (xp) ? xp->g : NULL);
+ DBUG_ENTER("ha_connect::rnd_init");
+
+ if (xtrace)
+ printf("%p in rnd_init: scan=%d\n", this, scan);
+
+ if (g) {
+ // Open the table if it was not opened yet (possible ???)
+ if (!IsOpened()) {
+ if (!table || xmod == MODE_INSERT)
+ DBUG_RETURN(HA_ERR_INITIALIZATION);
+
+ if (OpenTable(g, xmod == MODE_DELETE))
+#if defined(MARIADB)
+ DBUG_RETURN(HA_ERR_INITIALIZATION);
+#else // !MARIADB
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+#endif // !MARIADB
+
+ } else
+ void(CntRewindTable(g, tdbp)); // Read from beginning
+
+ } // endif g
+
+ xp->nrd= xp->fnd= xp->nfd= 0;
+ xp->tb1= my_interval_timer();
+ DBUG_RETURN(0);
+} // end of rnd_init
+
+/**
+ @brief
+ Not described.
+
+ @note
+ The previous version said:
+ Stop scanning of table. Note that this may be called several times during
+ execution of a sub select.
+ =====> This has been moved to external lock to avoid closing subselect tables.
+*/
+int ha_connect::rnd_end()
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::rnd_end");
+
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+// if (tdbp && xp->last_query_id == valid_query_id)
+// rc= CloseTable(xp->g);
+
+ DBUG_RETURN(rc);
+} // end of rnd_end
+
+
+/**
+ @brief
+ This is called for each row of the table scan. When you run out of records
+ you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
+ The Field structure for the table is the key to getting data into buf
+ in a manner that will allow the server to understand it.
+
+ @details
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+ and sql_update.cc.
+
+ @see
+ filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
+*/
+int ha_connect::rnd_next(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::rnd_next");
+//statistic_increment(ha_read_rnd_next_count, &LOCK_status);
+
+#if !defined(MARIADB)
+ if (!tdbp) // MySQL ignores error from rnd_init
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+#endif // !MARIADB
+
+ if (tdbp->GetMode() == MODE_ANY) {
+ // We will stop on next read
+ if (!stop) {
+ stop= true;
+ DBUG_RETURN(RC_OK);
+ } else
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ } // endif Mode
+
+ switch (CntReadNext(xp->g, tdbp)) {
+ case RC_OK:
+ rc= MakeRecord((char*)buf);
+ break;
+ case RC_EF: // End of file
+ rc= HA_ERR_END_OF_FILE;
+ break;
+ case RC_NF: // Not found
+ rc= HA_ERR_RECORD_DELETED;
+ break;
+ default: // Read error
+ printf("rnd_next CONNECT: %s\n", xp->g->Message);
+ rc= (records()) ? HA_ERR_INTERNAL_ERROR : HA_ERR_END_OF_FILE;
+ break;
+ } // endswitch RC
+
+#ifndef DBUG_OFF
+ if (rc || !(xp->nrd++ % 16384)) {
+ ulonglong tb2= my_interval_timer();
+ double elapsed= (double) (tb2 - xp->tb1) / 1000000000ULL;
+ DBUG_PRINT("rnd_next", ("rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
+ rc, xp->nrd, xp->fnd, xp->nfd, elapsed));
+ xp->tb1= tb2;
+ xp->fnd= xp->nfd= 0;
+ } // endif nrd
+#endif
+
+ table->status= (!rc) ? 0 : STATUS_NOT_FOUND;
+ DBUG_RETURN(rc);
+} // end of rnd_next
+
+
+/**
+ @brief
+ position() is called after each call to rnd_next() if the data needs
+ to be ordered. You can do something like the following to store
+ the position:
+ @code
+ my_store_ptr(ref, ref_length, current_position);
+ @endcode
+
+ @details
+ The server uses ref to store data. ref_length in the above case is
+ the size needed to store current_position. ref is just a byte array
+ that the server will maintain. If you are using offsets to mark rows, then
+ current_position should be the offset. If it is a primary key like in
+ BDB, then it needs to be a primary key.
+
+ Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
+
+ @see
+ filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
+*/
+void ha_connect::position(const uchar *record)
+{
+ DBUG_ENTER("ha_connect::position");
+ if (((PTDBASE)tdbp)->GetDef()->Indexable())
+ my_store_ptr(ref, ref_length, (my_off_t)((PTDBASE)tdbp)->GetRecpos());
+ DBUG_VOID_RETURN;
+} // end of position
+
+
+/**
+ @brief
+ This is like rnd_next, but you are given a position to use
+ to determine the row. The position will be of the type that you stored in
+ ref. You can use my_get_ptr(pos,ref_length) to retrieve whatever key
+ or position you saved when position() was called.
+
+ @details
+ Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and sql_update.cc.
+
+ @note
+ Is this really useful? It was never called even when sorting.
+
+ @see
+ filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
+*/
+int ha_connect::rnd_pos(uchar *buf, uchar *pos)
+{
+ int rc;
+ PTDBASE tp= (PTDBASE)tdbp;
+ DBUG_ENTER("ha_connect::rnd_pos");
+
+ if (!tp->SetRecpos(xp->g, (int)my_get_ptr(pos, ref_length)))
+ rc= rnd_next(buf);
+ else
+ rc= HA_ERR_KEY_NOT_FOUND;
+
+ DBUG_RETURN(rc);
+} // end of rnd_pos
+
+
+/**
+ @brief
+ ::info() is used to return information to the optimizer. See my_base.h for
+ the complete description.
+
+ @details
+ Currently this table handler doesn't implement most of the fields really needed.
+ SHOW also makes use of this data.
+
+ You will probably want to have the following in your code:
+ @code
+ if (records < 2)
+ records= 2;
+ @endcode
+ The reason is that the server will optimize for cases of only a single
+ record. If, in a table scan, you don't know the number of records, it
+ will probably be better to set records to two so you can return as many
+ records as you need. Along with records, a few more variables you may wish
+ to set are:
+ records
+ deleted
+ data_file_length
+ index_file_length
+ delete_length
+ check_time
+ Take a look at the public variables in handler.h for more information.
+
+ Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
+ sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
+ sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc,
+ sql_table.cc, sql_union.cc, and sql_update.cc.
+
+ @see
+ filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc,
+ sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc,
+ sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_table.cc,
+ sql_union.cc and sql_update.cc
+*/
+int ha_connect::info(uint flag)
+{
+ bool pure= false;
+ PGLOBAL g= GetPlug((table) ? table->in_use : NULL);
+
+ DBUG_ENTER("ha_connect::info");
+
+ if (xtrace)
+ printf("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info);
+
+ if (!valid_info) {
+ // tdbp must be available to get updated info
+ if (!tdbp || xp->CheckQuery(valid_query_id)) {
+ if (xmod == MODE_ANY) { // Pure info, not a query
+ pure= true;
+// xmod= MODE_READ;
+ } // endif xmod
+
+// tdbp= OpenTable(g, xmod == MODE_DELETE);
+ tdbp= GetTDB(g);
+ } // endif tdbp
+
+ valid_info= CntInfo(g, tdbp, &xinfo);
+ } // endif valid_info
+
+ if (flag & HA_STATUS_VARIABLE) {
+ stats.records= xinfo.records;
+ stats.deleted= 0;
+ stats.data_file_length= xinfo.data_file_length;
+ stats.index_file_length= 0;
+ stats.delete_length= 0;
+ stats.check_time= 0;
+ stats.mean_rec_length= xinfo.mean_rec_length;
+ } // endif HA_STATUS_VARIABLE
+
+ if (flag & HA_STATUS_CONST) {
+ // This is imported from the previous handler and must be reconsidered
+ stats.max_data_file_length= LL(4294967295);
+ stats.max_index_file_length= LL(4398046510080);
+ stats.create_time= 0;
+ data_file_name= xinfo.data_file_name;
+ index_file_name= NULL;
+// sortkey= (uint) - 1; // Table is not sorted
+ ref_length= sizeof(int); // Pointer size to row
+ table->s->db_options_in_use= 03;
+ stats.block_size= 1024;
+ table->s->keys_in_use.set_prefix(table->s->keys);
+ table->s->keys_for_keyread= table->s->keys_in_use;
+// table->s->keys_for_keyread.subtract(table->s->read_only_keys);
+ table->s->db_record_offset= 0;
+ } // endif HA_STATUS_CONST
+
+ if (flag & HA_STATUS_ERRKEY) {
+ errkey= 0;
+ } // endif HA_STATUS_ERRKEY
+
+ if (flag & HA_STATUS_TIME)
+ stats.update_time= 0;
+
+ if (flag & HA_STATUS_AUTO)
+ stats.auto_increment_value= 1;
+
+ if (tdbp && pure)
+ CloseTable(g); // Not used anymore
+
+ DBUG_RETURN(0);
+} // end of info
+
+
+/**
+ @brief
+ extra() is called whenever the server wishes to send a hint to
+ the storage engine. The myisam engine implements the most hints.
+ ha_innodb.cc has the most exhaustive list of these hints.
+
+ @note
+ This is not yet implemented for CONNECT.
+
+ @see
+ ha_innodb.cc
+*/
+int ha_connect::extra(enum ha_extra_function operation)
+{
+ DBUG_ENTER("ha_connect::extra");
+ DBUG_RETURN(0);
+} // end of extra
+
+
+/**
+ @brief
+ Used to delete all rows in a table, including cases of truncate and cases where
+ the optimizer realizes that all rows will be removed as a result of an SQL statement.
+
+ @details
+ Called from item_sum.cc by Item_func_group_concat::clear(),
+ Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
+ Called from sql_delete.cc by mysql_delete().
+ Called from sql_select.cc by JOIN::reinit().
+ Called from sql_union.cc by st_select_lex_unit::exec().
+
+ @see
+ Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
+ Item_func_group_concat::clear() in item_sum.cc;
+ mysql_delete() in sql_delete.cc;
+ JOIN::reinit() in sql_select.cc and
+ st_select_lex_unit::exec() in sql_union.cc.
+*/
+int ha_connect::delete_all_rows()
+{
+ int rc= 0;
+ PGLOBAL g= xp->g;
+ DBUG_ENTER("ha_connect::delete_all_rows");
+
+ // Close and reopen the table so it will be deleted
+ rc= CloseTable(g);
+
+ if (!(OpenTable(g))) {
+ if (CntDeleteRow(g, tdbp, true)) {
+ printf("%s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endif
+
+ } else
+ rc= HA_ERR_INITIALIZATION;
+
+ DBUG_RETURN(rc);
+} // end of delete_all_rows
+
+/**
+ @brief
+ This create a lock on the table. If you are implementing a storage engine
+ that can handle transacations look at ha_berkely.cc to see how you will
+ want to go about doing this. Otherwise you should consider calling flock()
+ here. Hint: Read the section "locking functions for mysql" in lock.cc to understand
+ this.
+
+ @details
+ Called from lock.cc by lock_external() and unlock_external(). Also called
+ from sql_table.cc by copy_data_between_tables().
+
+ @note
+ Following what we did in the MySQL XDB handler, we use this call to actually
+ physically open the table. This could be reconsider when finalizing this handler
+ design, which means we have a better understanding of what MariaDB does.
+
+ @see
+ lock.cc by lock_external() and unlock_external() in lock.cc;
+ the section "locking functions for mysql" in lock.cc;
+ copy_data_between_tables() in sql_table.cc.
+*/
+int ha_connect::external_lock(THD *thd, int lock_type)
+{
+ int rc= 0;
+ bool del= false;
+ MODE newmode;
+ PGLOBAL g= GetPlug(thd);
+ DBUG_ENTER("ha_connect::external_lock");
+
+ if (xtrace)
+ printf("%p external_lock: lock_type=%d\n", this, lock_type);
+
+ if (!g)
+ DBUG_RETURN(-99);
+
+ // Action will depend on lock_type
+ switch (lock_type) {
+ case F_WRLCK:
+ newmode= MODE_WRITE;
+ break;
+ case F_RDLCK:
+ newmode= MODE_READ;
+ break;
+ case F_UNLCK:
+ default:
+ newmode= MODE_ANY;
+ } // endswitch mode
+
+ if (newmode == MODE_ANY) {
+ // This is unlocking, do it by closing the table
+ if (xp->CheckQueryID())
+ rc= 2; // Logical error ???
+ else if (tdbp) {
+ if (tdbp->GetMode() == MODE_ANY && *tdbp->GetName() == '#'
+ && xp->tabp) {
+ PDOSDEF defp1= (PDOSDEF)((PTDBASE)tdbp)->GetDef();
+ PDOSDEF defp2= (PDOSDEF)xp->tabp->GetDef();
+ PIXDEF xp1, xp2, sxp;
+
+ // Look for new created indexes
+ for (xp1= defp1->GetIndx(); xp1; xp1= xp1->GetNext()) {
+ for (xp2= defp2->GetIndx(); xp2; xp2= xp2->GetNext())
+ if (!stricmp(xp1->GetName(), xp2->GetName()))
+ break; // Index already made
+
+ if (!xp2) {
+ // Here we do make the index on tabp
+ sxp= xp1->GetNext();
+ xp1->SetNext(NULL);
+ xp->tabp->MakeIndex(g, xp1, true);
+ xp1->SetNext(sxp);
+ } // endif xp2
+
+ } // endfor xp1
+
+ // Look for dropped indexes
+ for (xp2= defp2->GetIndx(); xp2; xp2= xp2->GetNext()) {
+ for (xp1= defp1->GetIndx(); xp1; xp1= xp1->GetNext())
+ if (!stricmp(xp1->GetName(), xp2->GetName()))
+ break; // Index not to drop
+
+ if (!xp1) {
+ // Here we erase the index file
+ sxp= xp2->GetNext();
+ xp2->SetNext(NULL);
+ defp2->DeleteIndexFile(g, xp2);
+ xp2->SetNext(sxp);
+ } // endif xp1
+
+ } // endfor xp2
+
+ } // endif Mode
+
+ rc= CloseTable(g);
+ } // endif tdbp
+
+ DBUG_RETURN(rc);
+ } // endif MODE_ANY
+
+ if (xtrace) {
+ printf("%p external_lock: cmdtype=%d\n", this, thd->lex->sql_command);
+ printf("Cmd=%s\n", thd->query_string);
+ } // endif xtrace
+
+ // Next code is temporarily replaced until sql_command is set
+ stop= false;
+
+ if (newmode == MODE_WRITE) {
+ switch (thd->lex->sql_command) {
+ case SQLCOM_INSERT:
+ case SQLCOM_CREATE_TABLE:
+ case SQLCOM_LOAD:
+ case SQLCOM_INSERT_SELECT:
+ newmode= MODE_INSERT;
+ break;
+// case SQLCOM_REPLACE:
+// case SQLCOM_REPLACE_SELECT:
+// newmode= MODE_UPDATE; // To be checked
+// break;
+ case SQLCOM_DELETE:
+ case SQLCOM_DELETE_MULTI:
+ del= true;
+ case SQLCOM_TRUNCATE:
+ newmode= MODE_DELETE;
+ break;
+ case SQLCOM_UPDATE:
+ case SQLCOM_UPDATE_MULTI:
+ newmode= MODE_UPDATE;
+ break;
+ case SQLCOM_SELECT:
+ case SQLCOM_OPTIMIZE:
+ newmode= MODE_READ;
+ break;
+ case SQLCOM_DROP_TABLE:
+ case SQLCOM_RENAME_TABLE:
+ case SQLCOM_ALTER_TABLE:
+ newmode= MODE_ANY;
+ break;
+ case SQLCOM_DROP_INDEX:
+ case SQLCOM_CREATE_INDEX:
+ newmode= MODE_ANY;
+ stop= true;
+ break;
+ default:
+ printf("Unsupported sql_command=%d", thd->lex->sql_command);
+ sprintf(g->Message, "Unsupported sql_command=%d", thd->lex->sql_command);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endswitch newmode
+
+ } else if (newmode == MODE_READ) {
+ switch (thd->lex->sql_command) {
+ case SQLCOM_INSERT:
+ case SQLCOM_CREATE_TABLE:
+ case SQLCOM_LOAD:
+ case SQLCOM_INSERT_SELECT:
+// case SQLCOM_REPLACE:
+// case SQLCOM_REPLACE_SELECT:
+ case SQLCOM_DELETE:
+ case SQLCOM_DELETE_MULTI:
+ case SQLCOM_TRUNCATE:
+ case SQLCOM_UPDATE:
+ case SQLCOM_UPDATE_MULTI:
+ case SQLCOM_SELECT:
+ case SQLCOM_OPTIMIZE:
+ break;
+ case SQLCOM_DROP_INDEX:
+ case SQLCOM_CREATE_INDEX:
+ stop= true;
+ case SQLCOM_DROP_TABLE:
+ case SQLCOM_RENAME_TABLE:
+ case SQLCOM_ALTER_TABLE:
+ newmode= MODE_ANY;
+ break;
+ default:
+ printf("Unsupported sql_command=%d", thd->lex->sql_command);
+ sprintf(g->Message, "Unsupported sql_command=%d", thd->lex->sql_command);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endswitch newmode
+
+ } // endif's newmode
+
+
+ if (xtrace)
+ printf("New mode=%d\n", newmode);
+
+ // If this is the start of a new query, cleanup the previous one
+ if (xp->CheckCleanup()) {
+ tdbp= NULL;
+ valid_info= false;
+ } // endif CheckCleanup
+
+ if (xtrace)
+ printf("Calling CntCheckDB db=%s\n", GetDBName(NULL));
+
+ // Set or reset the good database environment
+ if (CntCheckDB(g, this, GetDBName(NULL))) {
+ printf("%p external_lock: %s\n", this, g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ // This can NOT be called without open called first, but
+ // the table can have been closed since then
+ } else if (!tdbp || xp->CheckQuery(valid_query_id) || xmod != newmode) {
+ if (tdbp)
+ CloseTable(g);
+
+ xmod= newmode;
+
+ if (!table)
+ rc= 3; // Logical error
+
+ // Delay open until used fields are known
+ } // endif tdbp
+
+ if (xtrace)
+ printf("external_lock: rc=%d\n", rc);
+
+ DBUG_RETURN(rc);
+} // end of external_lock
+
+
+/**
+ @brief
+ The idea with handler::store_lock() is: The statement decides which locks
+ should be needed for the table. For updates/deletes/inserts we get WRITE
+ locks, for SELECT... we get read locks.
+
+ @details
+ Before adding the lock into the table lock handler (see thr_lock.c),
+ mysqld calls store lock with the requested locks. Store lock can now
+ modify a write lock to a read lock (or some other lock), ignore the
+ lock (if we don't want to use MySQL table locks at all), or add locks
+ for many tables (like we do when we are using a MERGE handler).
+
+ Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
+ (which signals that we are doing WRITES, but are still allowing other
+ readers and writers).
+
+ When releasing locks, store_lock() is also called. In this case one
+ usually doesn't have to do anything.
+
+ In some exceptional cases MySQL may send a request for a TL_IGNORE;
+ This means that we are requesting the same lock as last time and this
+ should also be ignored. (This may happen when someone does a flush
+ table when we have opened a part of the tables, in which case mysqld
+ closes and reopens the tables and tries to get the same locks at last
+ time). In the future we will probably try to remove this.
+
+ Called from lock.cc by get_lock_data().
+
+ @note
+ In this method one should NEVER rely on table->in_use, it may, in fact,
+ refer to a different thread! (this happens if get_lock_data() is called
+ from mysql_lock_abort_for_thread() function)
+
+ @see
+ get_lock_data() in lock.cc
+*/
+THR_LOCK_DATA **ha_connect::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+ lock.type=lock_type;
+ *to++ = &lock;
+ return to;
+}
+
+
+/**
+ @brief
+ Used to delete a table. By the time delete_table() has been called all
+ opened references to this table will have been closed (and your globally
+ shared references released). The variable name will just be the name of
+ the table. You will need to remove any files you have created at this point.
+
+ @details
+ If you do not implement this, the default delete_table() is called from
+ handler.cc and it will delete all files with the file extensions returned
+ by bas_ext().
+
+ Called from handler.cc by delete_table and ha_create_table(). Only used
+ during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
+ the storage engine.
+
+ @see
+ delete_table and ha_create_table() in handler.cc
+*/
+int ha_connect::delete_table(const char *name)
+{
+ DBUG_ENTER("ha_connect::delete_table");
+ /* This is not implemented but we want someone to be able that it works. */
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief
+ Given a starting key and an ending key, estimate the number of rows that
+ will exist between the two keys.
+
+ @details
+ end_key may be empty, in which case determine if start_key matches any rows.
+
+ Called from opt_range.cc by check_quick_keys().
+
+ @see
+ check_quick_keys() in opt_range.cc
+*/
+ha_rows ha_connect::records_in_range(uint inx, key_range *min_key,
+ key_range *max_key)
+{
+ ha_rows rows;
+ DBUG_ENTER("ha_connect::records_in_range");
+
+ if (indexing < 0 || inx != active_index)
+ index_init(inx, false);
+
+ if (xtrace)
+ printf("records_in_range: inx=%d indexing=%d\n", inx, indexing);
+
+ if (indexing > 0) {
+ int nval;
+ uint len[2];
+ const uchar *key[2];
+ bool incl[2];
+ key_part_map kmap[2];
+
+ key[0]= (min_key) ? min_key->key : NULL;
+ key[1]= (max_key) ? max_key->key : NULL;
+ len[0]= (min_key) ? min_key->length : 0;
+ len[1]= (max_key) ? max_key->length : 0;
+ incl[0]= (min_key) ? (min_key->flag == HA_READ_KEY_EXACT) : false;
+ incl[1]= (max_key) ? (max_key->flag == HA_READ_AFTER_KEY) : false;
+ kmap[0]= (min_key) ? min_key->keypart_map : 0;
+ kmap[1]= (max_key) ? max_key->keypart_map : 0;
+
+ if ((nval= CntIndexRange(xp->g, tdbp, key, len, incl, kmap)) < 0)
+ rows= HA_POS_ERROR;
+ else
+ rows= (ha_rows)nval;
+
+ } else if (indexing < 0)
+ rows= HA_POS_ERROR;
+ else
+ rows= 100000000; // Don't use missing index
+
+ DBUG_RETURN(rows);
+} // end of records_in_range
+
+/**
+ Convert an ISO-8859-1 column name to UTF-8
+*/
+char *ha_connect::encode(PGLOBAL g, char *cnm)
+ {
+ char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) * 3);
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, strlen(cnm) * 3,
+ &my_charset_utf8_general_ci,
+ cnm, strlen(cnm),
+ &my_charset_latin1,
+ &dummy_errors);
+ buf[len]= '\0';
+ return buf;
+ } // end of Encode
+
+/**
+ Store field definition for create.
+
+ @return
+ Return 0 if ok
+*/
+
+bool ha_connect::add_fields(THD *thd, void *alt_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 *vcolinfo,
+ engine_option_value *create_options)
+{
+ register Create_field *new_field;
+ LEX *lex= thd->lex;
+ Alter_info *alter_info= (Alter_info*)alt_info;
+ Virtual_column_info *vcol_info= (Virtual_column_info *)vcolinfo;
+
+ DBUG_ENTER("ha_connect::add_fields");
+
+ if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
+ system_charset_info, 1))
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+#if 0
+ if (type_modifier & PRI_KEY_FLAG)
+ {
+ Key *key;
+ lex->col_list.push_back(new Key_part_spec(*field_name, 0));
+ key= new Key(Key::PRIMARY, null_lex_str,
+ &default_key_create_info,
+ 0, lex->col_list, NULL);
+ alter_info->key_list.push_back(key);
+ lex->col_list.empty();
+ }
+ if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
+ {
+ Key *key;
+ lex->col_list.push_back(new Key_part_spec(*field_name, 0));
+ key= new Key(Key::UNIQUE, null_lex_str,
+ &default_key_create_info, 0,
+ lex->col_list, NULL);
+ alter_info->key_list.push_back(key);
+ lex->col_list.empty();
+ }
+
+ if (default_value)
+ {
+ /*
+ Default value should be literal => basic constants =>
+ no need fix_fields()
+
+ We allow only one function as part of default value -
+ NOW() as default for TIMESTAMP type.
+ */
+ if (default_value->type() == Item::FUNC_ITEM &&
+ !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
+ type == MYSQL_TYPE_TIMESTAMP))
+ {
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
+ DBUG_RETURN(1);
+ }
+ else if (default_value->type() == Item::NULL_ITEM)
+ {
+ default_value= 0;
+ if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
+ NOT_NULL_FLAG)
+ {
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
+ DBUG_RETURN(1);
+ }
+ }
+ else if (type_modifier & AUTO_INCREMENT_FLAG)
+ {
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
+ DBUG_RETURN(1);
+ }
+ }
+
+ if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
+ {
+ my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
+ DBUG_RETURN(1);
+ }
+#endif // 0
+
+ if (!(new_field= new Create_field()) ||
+ new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
+ NULL, NULL, comment, NULL,
+ NULL, cs, 0, vcol_info,
+ create_options))
+ DBUG_RETURN(1);
+
+ alter_info->create_list.push_back(new_field);
+//lex->last_field=new_field;
+ DBUG_RETURN(0);
+}
+
+/**
+ @brief
+ pre_create() is called when creating a table with no columns.
+
+ @details
+ When pre_create() is called the .frm file have not already been
+ created. You can overwrite some definitions at this point but the
+ main purpose of it is to define the columns for some table types.
+
+ @note
+ Not really implemented yet.
+*/
+bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
+{
+ char ttp= '?', spc= ',', qch= 0, *typn= "DOS";
+ char *fn, *dsn, *tab, *db, *host, *user, *pwd, *prt, *sep, *inf;
+#if defined(WIN32)
+ char *nsp= NULL, *cls= NULL;
+#endif // WIN32
+ int port= MYSQL_PORT, hdr= 0, mxr= 0;
+ bool b= false, ok= false, info= false;
+ LEX *lex= thd->lex;
+ LEX_STRING *comment, *name;
+ HA_CREATE_INFO *create_info= (HA_CREATE_INFO *)crt_info;
+ engine_option_value *pov;
+ PQRYRES qrp;
+ PCOLRES crp;
+ PGLOBAL g= GetPlug(thd);
+
+ fn= dsn= tab= db= host= user= pwd= prt= sep= inf= NULL;
+
+ if (g) {
+ // Set default values
+ tab= (char*)create_info->alias;
+ db= thd->db;
+ } else
+ return true;
+
+ // Get the useful create options
+ for (pov= create_info->option_list; pov; pov= pov->next)
+ if (!stricmp(pov->name.str, "table_type")) {
+ typn= pov->value.str;
+ ttp= GetTypeID(typn);
+ } else if (!stricmp(pov->name.str, "file_name")) {
+ fn= pov->value.str;
+ } else if (!stricmp(pov->name.str, "tabname")) {
+ tab= pov->value.str;
+ } else if (!stricmp(pov->name.str, "db_name")) {
+ db= pov->value.str;
+ } else if (!stricmp(pov->name.str, "sep_char")) {
+ sep= pov->value.str;
+ spc= (!strcmp(sep, "\\t")) ? '\t' : *sep;
+ } else if (!stricmp(pov->name.str, "qchar")) {
+ qch= *pov->value.str;
+ } else if (!stricmp(pov->name.str, "quoted")) {
+ if (!qch)
+ qch= '"';
+
+ } else if (!stricmp(pov->name.str, "header")) {
+ hdr= atoi(pov->value.str);
+ } else if (!stricmp(pov->name.str, "option_list")) {
+ host= GetListOption("host", pov->value.str, "localhost");
+ user= GetListOption("user", pov->value.str, "root");
+ pwd= GetListOption("password", pov->value.str);
+ prt= GetListOption("port", pov->value.str);
+ port= (prt) ? atoi(prt) : MYSQL_PORT;
+#if defined(WIN32)
+ nsp= GetListOption("namespace", pov->value.str);
+ cls= GetListOption("class", pov->value.str);
+#endif // WIN32
+ mxr= atoi(GetListOption("maxerr", pov->value.str, "0"));
+ inf= GetListOption("info", pov->value.str);
+ } // endelse option_list
+
+ switch (ttp) {
+#if defined(ODBC_SUPPORT)
+ case 'O': // ODBC
+ info= !!strchr("1yYoO", *inf);
+
+ if (!(dsn= create_info->connect_string.str) && !info)
+ sprintf(g->Message, "Missing %s connection string", typn);
+ else
+ ok= !info;
+
+ break;
+#endif // ODBC_SUPPORT
+ case 'A': // DBF
+ case 'C': // CSV
+ if (!fn)
+ sprintf(g->Message, "Missing %s file name", typn);
+ else
+ ok= true;
+
+ break;
+#if defined(MYSQL_SUPPORT)
+ case 'Y': // MYSQL
+ if (!user)
+ user= "root"; // Avoid crash
+
+ ok= true;
+ break;
+#endif // MYSQL_SUPPORT
+#if defined(WIN32)
+ case 'W': // WMI
+ ok= true;
+ break;
+#endif // WIN32
+ default:
+ sprintf(g->Message, "Cannot get column info for table type %s", typn);
+ } // endif ttp
+
+ if (ok) {
+ char *length, *decimals, *cnm, *rem;
+ int i, len, dec;
+ enum_field_types type;
+ PDBUSER dup= PlgGetUser(g);
+ PCATLG cat= (dup) ? dup->Catalog : NULL;
+
+ if (cat)
+ cat->SetDataPath(g, thd->db);
+ else
+ return true; // Should never happen
+
+ switch (ttp) {
+ case 'A':
+ qrp= DBFColumns(g, fn, false);
+ break;
+#if defined(ODBC_SUPPORT)
+ case 'O':
+ qrp= MyODBCCols(g, tab, dsn);
+ break;
+#endif // ODBC_SUPPORT
+#if defined(MYSQL_SUPPORT)
+ case 'Y':
+ qrp= MyColumns(g, host, db, user, pwd, tab, NULL, port, false);
+ break;
+#endif // MYSQL_SUPPORT
+ case 'C':
+ qrp= CSVColumns(g, fn, spc, qch, hdr, mxr);
+ break;
+#if defined(WIN32)
+ case 'W':
+ qrp= WMIColumns(g, nsp, cls);
+ break;
+#endif // WIN32
+ } // endswitch ttp
+
+ if (!qrp) {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
+ return true;
+ } // endif qrp
+
+ for (i= 0; !b && i < qrp->Nblin; i++) {
+ crp= qrp->Colresp; // Column Name
+ cnm= encode(g, crp->Kdata->GetCharValue(i));
+ name= thd->make_lex_string(NULL, cnm, strlen(cnm), true);
+ crp= crp->Next; // Data Type
+ type= PLGtoMYSQL(crp->Kdata->GetIntValue(i), true);
+ crp= crp->Next; // Type Name
+ crp= crp->Next; // Precision (length)
+ len= crp->Kdata->GetIntValue(i);
+ length= (char*)PlugSubAlloc(g, NULL, 8);
+ sprintf(length, "%d", len);
+ crp= crp->Next; // Length
+ crp= crp->Next; // Scale (precision)
+
+ if ((dec= crp->Kdata->GetIntValue(i))) {
+ decimals= (char*)PlugSubAlloc(g, NULL, 8);
+ sprintf(decimals, "%d", dec);
+ } else
+ decimals= NULL;
+
+ if ((crp= crp->Next) && // Remark (comment)
+ (rem= crp->Kdata->GetCharValue(i)))
+ comment= thd->make_lex_string(NULL, rem, strlen(rem), true);
+ else
+ comment= thd->make_lex_string(NULL, "", 0, true);
+
+ // Now add the field
+// b= add_field_to_list(thd, &name, type, length, decimals,
+// 0, NULL, NULL, comment, NULL, NULL, NULL, 0, NULL, NULL);
+ b= add_fields(thd, alt_info, name, type, length, decimals,
+ 0, comment, NULL, NULL, NULL);
+ } // endfor i
+
+ return b;
+ } else if (info) { // ODBC Data Sources
+ comment= thd->make_lex_string(NULL, "", 0, true);
+ name= thd->make_lex_string(NULL, "Name", 4, true);
+ b= add_fields(thd, alt_info, name, MYSQL_TYPE_VARCHAR, "256", 0,
+ 0, comment, NULL, NULL, NULL);
+ name= thd->make_lex_string(NULL, "Description", 11, true);
+ b= add_fields(thd, alt_info, name, MYSQL_TYPE_VARCHAR, "256", 0,
+ 0, comment, NULL, NULL, NULL);
+ return b;
+ } // endif info
+
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
+ return true;
+} // end of pre_create
+
+/**
+ @brief
+ create() is called to create a database. The variable name will have the name
+ of the table.
+
+ @details
+ When create() is called you do not need to worry about
+ opening the table. Also, the .frm file will have already been
+ created so adjusting create_info is not necessary. You can overwrite
+ the .frm file at this point if you wish to change the table
+ definition, but there are no methods currently provided for doing
+ so.
+
+ Called from handle.cc by ha_create_table().
+
+ @note
+ Currently we do nothing here because we suppose that the PlugDB matching
+ table already exists. At least we should check that the table definition
+ for MariaDB exactly match the PlugDB one. Later we should make possible
+ to entirely create a table from MariaDB.
+
+ @see
+ ha_create_table() in handle.cc
+*/
+
+int ha_connect::create(const char *name, TABLE *table_arg,
+ HA_CREATE_INFO *create_info)
+{
+ int rc= RC_OK;
+ bool dbf;
+ Field* *field;
+ Field *fp;
+ TABLE *st= table; // Probably unuseful
+ PIXDEF xdp, pxd= NULL, toidx= NULL;
+ PGLOBAL g= GetPlug(table_arg->in_use);
+
+ DBUG_ENTER("ha_connect::create");
+ PTOS options= GetTableOptionStruct(table_arg);
+
+ // CONNECT engine specific table options:
+ DBUG_ASSERT(options);
+
+ if (!g) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif g
+
+ // Check column types
+ dbf= (options->type && !stricmp(options->type, "DBF"));
+
+ for (field= table_arg->field; *field; field++) {
+ fp= *field;
+
+#if defined(MARIADB)
+ if (fp->vcol_info && !fp->stored_in_db)
+ continue; // This is a virtual column
+#endif // MARIADB
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_LONGLONG:
+ break; // Ok
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_INT24:
+ break; // To be checked
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ default:
+// fprintf(stderr, "Unsupported type column %s\n", fp->field_name);
+ sprintf(g->Message, "Unsupported type for column %s",
+ fp->field_name);
+ rc= HA_ERR_INTERNAL_ERROR;
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unsupported type for column '%s'",
+ MYF(0), fp->field_name);
+ DBUG_RETURN(rc);
+ } // endswitch type
+
+
+ if (dbf) {
+ bool b= false;
+
+ if ((b= strlen(fp->field_name) > 11))
+ sprintf(g->Message, "DBF: Column name '%s' is too long (max=11)",
+ fp->field_name);
+ else if ((b= fp->field_length > 255))
+ sprintf(g->Message, "DBF: Column length too big for '%s' (max=255)",
+ fp->field_name);
+
+ if (b) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif b
+
+ } // endif dbf
+
+ } // endfor field
+
+ // Check whether indexes were specified
+ table= table_arg; // Used by called functions
+
+ // Get the index definitions
+ for (int n= 0; (unsigned)n < table->s->keynames.count; n++) {
+ if (xtrace)
+ printf("Getting created index %d info\n", n + 1);
+
+ xdp= GetIndexInfo(n);
+
+ if (pxd)
+ pxd->SetNext(xdp);
+ else
+ toidx= xdp;
+
+ pxd= xdp;
+ } // endfor n
+
+ if (toidx) {
+ PDBUSER dup= PlgGetUser(g);
+ PCATLG cat= (dup) ? dup->Catalog : NULL;
+
+ DBUG_ASSERT(cat);
+
+ if (cat)
+ cat->SetDataPath(g, table_arg->in_use->db);
+
+ if ((rc= optimize(NULL, NULL))) {
+ printf("Create rc=%d %s\n", rc, g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ CloseTable(g);
+
+ } // endif toidx
+
+ table= st;
+ DBUG_RETURN(rc);
+} // end of create
+
+
+/**
+ check_if_incompatible_data() called if ALTER TABLE can't detect otherwise
+ if new and old definition are compatible
+
+ @details If there are no other explicit signs like changed number of
+ fields this function will be called by compare_tables()
+ (sql/sql_tables.cc) to decide should we rewrite whole table or only .frm
+ file.
+
+*/
+
+bool ha_connect::check_if_incompatible_data(HA_CREATE_INFO *info,
+ uint table_changes)
+{
+//ha_table_option_struct *param_old, *param_new;
+ DBUG_ENTER("ha_connect::check_if_incompatible_data");
+ // TO DO: implement it.
+ DBUG_RETURN(COMPATIBLE_DATA_YES);
+}
+
+
+struct st_mysql_storage_engine connect_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+struct st_mysql_daemon unusable_connect=
+{ MYSQL_DAEMON_INTERFACE_VERSION };
+
+mysql_declare_plugin(connect)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &connect_storage_engine,
+ "CONNECT",
+ "Olivier Bertrand",
+ "Direct access to external data, including many file formats",
+ PLUGIN_LICENSE_GPL,
+ connect_init_func, /* Plugin Init */
+ connect_done_func, /* Plugin Deinit */
+ 0x0001 /* 0.1 */,
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL, /* config options */
+ 0, /* flags */
+}
+mysql_declare_plugin_end;
+
+#if defined(MARIADB)
+maria_declare_plugin(connect)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &connect_storage_engine,
+ "CONNECT",
+ "Olivier Bertrand",
+ "Direct access to external data, including many file formats",
+ PLUGIN_LICENSE_GPL,
+ connect_init_func, /* Plugin Init */
+ connect_done_func, /* Plugin Deinit */
+ 0x0001, /* version number (0.1) */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "0.1", /* string version */
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
+},
+{
+ MYSQL_DAEMON_PLUGIN,
+ &unusable_connect,
+ "UNUSABLE",
+ "Olivier Bertrand",
+ "Unusable Daemon",
+ PLUGIN_LICENSE_PROPRIETARY,
+ NULL, /* Plugin Init */
+ NULL, /* Plugin Deinit */
+ 0x0101, /* version number (1.1) */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.01.00.000" , /* version, as a string */
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
+}
+maria_declare_plugin_end;
+#endif // MARIADB
+
+#if defined(WIN32)
+/**************************************************************************/
+/* DllMain */
+/**************************************************************************/
+bool APIENTRY DllMain(HINSTANCE hInst, ULONG ulReason, PCONTEXT pctx)
+ {
+ switch (ulReason) {
+ case DLL_PROCESS_ATTACH:
+ printf("CONNECT Engine loaded...\n");
+ GetCurrentDirectory(sizeof(connectini), connectini);
+ strcat(connectini, "\\connect.ini");
+
+ if ((xtrace= GetPrivateProfileInt("CONNECT", "Trace", 0, connectini))) {
+ printf("connectini=%s xtrace=%d\n", connectini, xtrace);
+ printf("plgini=%s\n", plgini);
+ printf("plgxini=%s\n", plgxini);
+ printf("nmfile=%s\n", nmfile);
+ printf("pdebug=%s\n", pdebug);
+ printf("version=%s\n", version);
+ trace= xtrace;
+ } // endif xtrace
+#ifdef LIBXML2_SUPPORT
+ XmlInitParserLib();
+#endif // LIBXML2_SUPPORT
+ break;
+ case DLL_PROCESS_DETACH:
+#ifdef LIBXML2_SUPPORT
+ XmlCleanupParserLib();
+#endif // LIBXML2_SUPPORT
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ default:
+ break;
+ } // endswitch ulReason
+
+ return true;
+ } // end of DllMain
+#else // !WIN32
+/**************************************************************************/
+/* Library's initialization function. */
+/**************************************************************************/
+void __attribute__((constructor)) init()
+ {
+ printf("CONNECT Engine loaded...\n");
+ getcwd(connectini, sizeof(connectini));
+ strcat(connectini, "/connect.ini");
+ printf("connectini=%s\n", connectini);
+
+ if ((xtrace= GetPrivateProfileInt("CONNECT", "Trace", 0, connectini))) {
+ printf("connectini=%s xtrace=%d\n", connectini, xtrace);
+ printf("plgini=%s\n", plgini);
+ printf("plgxini=%s\n", plgxini);
+ printf("nmfile=%s\n", nmfile);
+ printf("pdebug=%s\n", pdebug);
+ printf("version=%s\n", version);
+ trace= xtrace;
+ } // endif xtrace
+
+#ifdef LIBXML2_SUPPORT
+ XmlInitParserLib();
+#endif // LIBXML2_SUPPORT
+ } // end of init
+
+/**************************************************************************/
+/* Library's cleanup function */
+/**************************************************************************/
+void __attribute__((destructor)) fini()
+ {
+#ifdef LIBXML2_SUPPORT
+ XmlCleanupParserLib();
+#endif // LIBXML2_SUPPORT
+ } // end of fini
+#endif // !WIN32
+
diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h
index bf0ca2797b4..c33807f232b 100644
--- a/storage/connect/ha_connect.h
+++ b/storage/connect/ha_connect.h
@@ -1,393 +1,393 @@
-/* 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 *crt_info, void *alt_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, char *def= NULL);
- char *encode(PGLOBAL g, char *cnm);
- 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
+/* 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 *crt_info, void *alt_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, char *def= NULL);
+ char *encode(PGLOBAL g, char *cnm);
+ 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
diff --git a/storage/connect/inihandl.c b/storage/connect/inihandl.c
index 91fb95a2df9..6c13faf58c8 100644
--- a/storage/connect/inihandl.c
+++ b/storage/connect/inihandl.c
@@ -1,1325 +1,1325 @@
-/*
- * Profile functions
- *
- * Copyright 1993 Miguel de Icaza
- * Copyright 1996 Alexandre Julliard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <ctype.h>
-//#include <errno.h>
-#include <fcntl.h>
-//#include <io.h> commented this line out to compile for solaris
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/stat.h>
-//#include <sys/types.h>
-//#include <memory.h>
-#include "my_global.h"
-//#include "osutil.h"
-#include "global.h"
-
-
-// The types and variables used locally
-//typedef int bool;
-typedef unsigned int uint;
-#define DWORD int
-#define TRUE 1
-#define FALSE 0
-#define SVP(S) ((S) ? S : "<null>")
-#define _strlwr(P) strlwr(P) //OB: changed this line
-#define MAX_PATHNAME_LEN 256
-#define N_CACHED_PROFILES 10
-#ifndef WIN32
-#define stricmp strcasecmp
-#define _strnicmp strncasecmp
-#endif // !WIN32
-#define EnterCriticalSection(x)
-#define LeaveCriticalSection(x)
-
-#if defined(TEST_MODULE)
-// Stand alone test program
-#include <stdarg.h>
- int trace = 0;
-void htrc(char const *fmt, ...)
-{
- va_list ap;
- va_start (ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end (ap);
-} /* end of htrc */
-#else // !TEST_MODULE
-// Normal included functions
-extern int trace;
-void htrc(char const *fmt, ...);
-#endif // !TEST MODULE
-
-
-typedef struct tagPROFILEKEY {
- char *value;
- struct tagPROFILEKEY *next;
- char name[1];
- } PROFILEKEY;
-
-typedef struct tagPROFILESECTION {
- struct tagPROFILEKEY *key;
- struct tagPROFILESECTION *next;
- char name[1];
- } PROFILESECTION;
-
-typedef struct {
- bool changed;
- PROFILESECTION *section;
-//char *dos_name;
-//char *unix_name;
- char *filename;
- time_t mtime;
- } PROFILE;
-
-#define memfree(P) if (P) free(P)
-
-/* Cached profile files */
-static PROFILE *MRUProfile[N_CACHED_PROFILES] = {NULL};
-
-#define CurProfile (MRUProfile[0])
-
-/* wine.ini config file registry root */
-//static HKEY wine_profile_key;
-
-#define PROFILE_MAX_LINE_LEN 1024
-
-/* Wine profile name in $HOME directory; must begin with slash */
-static const char PROFILE_WineIniName[] = "/.winerc";
-
-/* Wine profile: the profile file being used */
-static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
-
-/* Check for comments in profile */
-#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
-
-//static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
-
-//static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
-
-static const char hex[16] = "0123456789ABCDEF";
-
-bool WritePrivateProfileString(LPCSTR section, LPCSTR entry,
- LPCSTR string, LPCSTR filename );
-/***********************************************************************
- * PROFILE_CopyEntry
- *
- * Copy the content of an entry into a buffer, removing quotes,
- * and possibly translating environment variables.
- ***********************************************************************/
-static void PROFILE_CopyEntry( char *buffer, const char *value, uint len,
- int handle_env )
-{
- const char *p;
- char quote = '\0';
-
- if (!buffer)
- return;
-
- if ((*value == '\'') || (*value == '\"'))
- if (value[1] && (value[strlen(value)-1] == *value))
- quote = *value++;
-
- if (!handle_env) {
- strncpy(buffer, value, len);
-
- if (quote && (len >= strlen(value)))
- buffer[strlen(buffer)-1] = '\0';
-
- return;
- } // endif handle
-
- for (p = value; (*p && (len > 1)); *buffer++ = *p++, len--) {
- if ((*p == '$') && (p[1] == '{')) {
- char env_val[1024];
- const char *env_p;
- const char *p2 = strchr(p, '}');
-
- if (!p2)
- continue; /* ignore it */
-
- strncpy(env_val, p + 2, min(sizeof(env_val), (int)(p2-p)-1));
-
- if ((env_p = getenv(env_val)) != NULL) {
- int buffer_len;
-
- strncpy( buffer, env_p, len );
- buffer_len = strlen( buffer );
- buffer += buffer_len;
- len -= buffer_len;
- } // endif env_p
-
- p = p2 + 1;
- } // endif p
-
- } // endfor p
-
- if (quote && (len > 1))
- buffer--;
-
- *buffer = '\0';
-} // end of PROFILE_CopyEntry
-
-
-/***********************************************************************
- * PROFILE_Save
- *
- * Save a profile tree to a file.
- ***********************************************************************/
-static void PROFILE_Save( FILE *file, PROFILESECTION *section )
-{
- PROFILEKEY *key;
-
- for (; section; section = section->next) {
- if (section->name[0])
- fprintf(file, "\n[%s]\n", SVP(section->name));
-
- for (key = section->key; key; key = key->next)
- if (key->name && key->name[0]) {
- fprintf(file, "%s", SVP(key->name));
-
- if (key->value)
- fprintf(file, "=%s", SVP(key->value));
-
- fprintf(file, "\n");
- } // endif key->name
-
- } // endfor section
-
-} // end of PROFILE_Save
-
-
-/***********************************************************************
- * PROFILE_Free
- *
- * Free a profile tree.
- ***********************************************************************/
-static void PROFILE_Free( PROFILESECTION *section )
-{
- PROFILESECTION *next_section;
- PROFILEKEY *key, *next_key;
-
- for (; section; section = next_section) {
- for (key = section->key; key; key = next_key) {
- next_key = key->next;
- memfree(key->value);
- free(key);
- } // endfor key
-
- next_section = section->next;
- free(section);
- } // endfor section
-
-} // end of PROFILE_Free
-
-static int PROFILE_isspace(char c)
-{
- /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
- if (isspace(c) || c=='\r' || c==0x1a)
- return 1;
-
- return 0;
-} // end of PROFILE_isspace
-
-
-/***********************************************************************
- * PROFILE_Load
- *
- * Load a profile tree from a file.
- ***********************************************************************/
-static PROFILESECTION *PROFILE_Load( FILE *file )
-{
- char buffer[PROFILE_MAX_LINE_LEN];
- char *p, *p2;
- int line = 0;
- PROFILESECTION *section, *first_section;
- PROFILESECTION* *next_section;
- PROFILEKEY *key, *prev_key, **next_key;
-
- first_section = malloc(sizeof(*section));
-
- if (first_section == NULL)
- return NULL;
-
- first_section->name[0] = 0;
- first_section->key = NULL;
- first_section->next = NULL;
- next_section = &first_section->next;
- next_key = &first_section->key;
- prev_key = NULL;
-
- while (fgets(buffer, PROFILE_MAX_LINE_LEN, file)) {
- line++;
- p = buffer;
-
- while (*p && PROFILE_isspace(*p))
- p++;
-
- if (*p == '[') { /* section start */
- if (!(p2 = strrchr( p, ']'))) {
- fprintf(stderr, "Invalid section header at line %d: '%s'\n",
- line, p);
- } else {
- *p2 = '\0';
- p++;
-
- if (!(section = malloc(sizeof(*section) + strlen(p))))
- break;
-
- strcpy(section->name, p);
- section->key = NULL;
- section->next = NULL;
- *next_section = section;
- next_section = &section->next;
- next_key = &section->key;
- prev_key = NULL;
-
- if (trace > 1)
- htrc("New section: '%s'\n",section->name);
-
- continue;
- } // endif p2
-
- } // endif p
-
- p2 = p + strlen(p) - 1;
-
- while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2)))
- *p2-- = '\0';
-
- if ((p2 = strchr(p, '=')) != NULL) {
- char *p3 = p2 - 1;
-
- while ((p3 > p) && PROFILE_isspace(*p3))
- *p3-- = '\0';
-
- *p2++ = '\0';
-
- while (*p2 && PROFILE_isspace(*p2))
- p2++;
-
- } // endif p2
-
- if (*p || !prev_key || *prev_key->name) {
- if (!(key = malloc(sizeof(*key) + strlen(p))))
- break;
-
- strcpy(key->name, p);
-
- if (p2) {
- key->value = malloc(strlen(p2)+1);
- strcpy(key->value, p2);
- } else
- key->value = NULL;
-
- key->next = NULL;
- *next_key = key;
- next_key = &key->next;
- prev_key = key;
-
- if (trace > 1)
- htrc("New key: name='%s', value='%s'\n",
- key->name,key->value?key->value:"(none)");
-
- } // endif p || prev_key
-
- } // endif *p
-
- return first_section;
-} // end of PROFILE_Load
-
-/***********************************************************************
- * PROFILE_FlushFile
- *
- * Flush the current profile to disk if changed.
- ***********************************************************************/
-static bool PROFILE_FlushFile(void)
-{
-//char *p, buffer[MAX_PATHNAME_LEN];
-//const char *unix_name;
- FILE *file = NULL;
- struct stat buf;
-
- if (trace > 1)
- htrc("PROFILE_FlushFile: CurProfile=%p\n", CurProfile);
-
- if (!CurProfile) {
- fprintf(stderr, "No current profile!\n");
- return FALSE;
- } // endif !CurProfile
-
- if (!CurProfile->changed || !CurProfile->filename)
- return TRUE;
-
-#if 0
- if (!(file = fopen(unix_name, "w"))) {
- /* Try to create it in $HOME/.wine */
- /* FIXME: this will need a more general solution */
- //strcpy( buffer, get_config_dir() );
- //p = buffer + strlen(buffer);
- //*p++ = '/';
- char *p1 = strrchr(CurProfile->filename, '\\');
-
- p = buffer; // OB: To be elaborate
-
- if (p1)
- p1++;
- else
- p1 = CurProfile->dos_name;
-
- strcpy(p, p1);
- _strlwr(p);
- file = fopen(buffer, "w");
- unix_name = buffer;
- } // endif !unix_name
-#endif // 0
-
- if (!(file = fopen(CurProfile->filename, "w"))) {
- fprintf(stderr, "could not save profile file %s\n", CurProfile->filename);
- return FALSE;
- } // endif !file
-
- if (trace > 1)
- htrc("Saving '%s'\n", CurProfile->filename);
-
- PROFILE_Save(file, CurProfile->section);
- fclose(file);
- CurProfile->changed = FALSE;
-
- if (!stat(CurProfile->filename, &buf))
- CurProfile->mtime = buf.st_mtime;
-
- return TRUE;
-} // end of PROFILE_FlushFile
-
-
-/***********************************************************************
- * PROFILE_ReleaseFile
- *
- * Flush the current profile to disk and remove it from the cache.
- ***********************************************************************/
-static void PROFILE_ReleaseFile(void)
-{
- PROFILE_FlushFile();
- PROFILE_Free(CurProfile->section);
-//memfree(CurProfile->dos_name);
-//memfree(CurProfile->unix_name);
- memfree(CurProfile->filename);
- CurProfile->changed = FALSE;
- CurProfile->section = NULL;
-//CurProfile->dos_name = NULL;
-//CurProfile->unix_name = NULL;
- CurProfile->filename = NULL;
- CurProfile->mtime = 0;
-} // end of PROFILE_ReleaseFile
-
-
-/***********************************************************************
- * PROFILE_Open
- *
- * Open a profile file, checking the cached file first.
- ***********************************************************************/
-static bool PROFILE_Open(LPCSTR filename)
-{
-//char buffer[MAX_PATHNAME_LEN];
-//char *p;
- FILE *file = NULL;
- int i, j;
- struct stat buf;
- PROFILE *tempProfile;
-
- if (trace > 1)
- htrc("PROFILE_Open: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
-
- /* First time around */
- if (!CurProfile)
- for (i = 0; i < N_CACHED_PROFILES; i++) {
- MRUProfile[i] = malloc(sizeof(PROFILE));
-
- if (MRUProfile[i] == NULL)
- break;
-
- MRUProfile[i]->changed=FALSE;
- MRUProfile[i]->section=NULL;
-// MRUProfile[i]->dos_name=NULL;
-// MRUProfile[i]->unix_name=NULL;
- MRUProfile[i]->filename=NULL;
- MRUProfile[i]->mtime=0;
- } // endfor i
-
- /* Check for a match */
- for (i = 0; i < N_CACHED_PROFILES; i++) {
- if (trace > 1)
- htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
-
- if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) {
- if (i) {
- PROFILE_FlushFile();
- tempProfile = MRUProfile[i];
-
- for (j = i; j > 0; j--)
- MRUProfile[j] = MRUProfile[j-1];
-
- CurProfile=tempProfile;
- } // endif i
-
- if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) {
- if (trace > 1)
- htrc("(%s): already opened (mru=%d)\n", filename, i);
-
- } else {
- if (trace > 1)
- htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i);
-
- } // endif stat
-
- return TRUE;
- } // endif filename
-
- } // endfor i
-
- /* Flush the old current profile */
- PROFILE_FlushFile();
-
- /* Make the oldest profile the current one only in order to get rid of it */
- if (i == N_CACHED_PROFILES) {
- tempProfile = MRUProfile[N_CACHED_PROFILES-1];
-
- for(i = N_CACHED_PROFILES-1; i > 0; i--)
- MRUProfile[i] = MRUProfile[i-1];
-
- CurProfile = tempProfile;
- } // endif i
-
- if (CurProfile->filename)
- PROFILE_ReleaseFile();
-
- /* OK, now that CurProfile is definitely free we assign it our new file */
-// newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
-// strcpy( newdos_name, full_name.short_name );
-
-// newdos_name = malloc(strlen(filename)+1);
-// strcpy(newdos_name, filename);
-
-// CurProfile->dos_name = newdos_name;
- CurProfile->filename = malloc(strlen(filename) + 1);
- strcpy(CurProfile->filename, filename);
-
- /* Try to open the profile file, first in $HOME/.wine */
-
- /* FIXME: this will need a more general solution */
-// strcpy( buffer, get_config_dir() );
-// p = buffer + strlen(buffer);
-// *p++ = '/';
-// strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
-// p = buffer;
-// strcpy(p, filename);
-// _strlwr(p);
-
- if (trace > 1)
- htrc("Opening %s\n", filename);
-
- if ((file = fopen(filename, "r"))) {
- if (trace > 1)
- htrc("(%s): found it\n", filename);
-
-// CurProfile->unix_name = malloc(strlen(buffer)+1);
-// strcpy(CurProfile->unix_name, buffer);
- } /* endif file */
-
- if (file) {
- CurProfile->section = PROFILE_Load(file);
- fclose(file);
-
- if (!stat(CurProfile->filename, &buf))
- CurProfile->mtime = buf.st_mtime;
-
- } else {
- /* Does not exist yet, we will create it in PROFILE_FlushFile */
- fprintf(stderr, "profile file %s not found\n", filename);
- } /* endif file */
-
- return TRUE;
-}
-
-
-/***********************************************************************
- * PROFILE_DeleteSection
- *
- * Delete a section from a profile tree.
- ***********************************************************************/
-static bool PROFILE_DeleteSection(PROFILESECTION* *section, LPCSTR name)
-{
- while (*section) {
- if ((*section)->name[0] && !stricmp((*section)->name, name)) {
- PROFILESECTION *to_del = *section;
-
- *section = to_del->next;
- to_del->next = NULL;
- PROFILE_Free(to_del);
- return TRUE;
- } // endif section
-
- section = &(*section)->next;
- } // endwhile section
-
- return FALSE;
-} // end of PROFILE_DeleteSection
-
-
-/***********************************************************************
- * PROFILE_DeleteKey
- *
- * Delete a key from a profile tree.
- ***********************************************************************/
-static bool PROFILE_DeleteKey(PROFILESECTION* *section,
- LPCSTR section_name, LPCSTR key_name)
-{
- while (*section) {
- if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
- PROFILEKEY* *key = &(*section)->key;
-
- while (*key) {
- if (!stricmp((*key)->name, key_name)) {
- PROFILEKEY *to_del = *key;
-
- *key = to_del->next;
- memfree(to_del->value);
- free(to_del);
- return TRUE;
- } // endif name
-
- key = &(*key)->next;
- } // endwhile *key
-
- } // endif section->name
-
- section = &(*section)->next;
- } // endwhile *section
-
- return FALSE;
-} // end of PROFILE_DeleteKey
-
-
-/***********************************************************************
- * PROFILE_DeleteAllKeys
- *
- * Delete all keys from a profile tree.
- ***********************************************************************/
-void PROFILE_DeleteAllKeys(LPCSTR section_name)
-{
- PROFILESECTION* *section= &CurProfile->section;
-
- while (*section) {
- if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
- PROFILEKEY* *key = &(*section)->key;
-
- while (*key) {
- PROFILEKEY *to_del = *key;
-
- *key = to_del->next;
- memfree(to_del->value);
- free(to_del);
- CurProfile->changed = TRUE;
- } // endwhile *key
-
- } // endif section->name
-
- section = &(*section)->next;
- } // endwhile *section
-
-} // end of PROFILE_DeleteAllKeys
-
-
-/***********************************************************************
- * PROFILE_Find
- *
- * Find a key in a profile tree, optionally creating it.
- ***********************************************************************/
-static PROFILEKEY *PROFILE_Find(PROFILESECTION* *section,
- const char *section_name,
- const char *key_name,
- bool create, bool create_always)
-{
- const char *p;
- int seclen, keylen;
-
- while (PROFILE_isspace(*section_name))
- section_name++;
-
- p = section_name + strlen(section_name) - 1;
-
- while ((p > section_name) && PROFILE_isspace(*p))
- p--;
-
- seclen = p - section_name + 1;
-
- while (PROFILE_isspace(*key_name))
- key_name++;
-
- p = key_name + strlen(key_name) - 1;
-
- while ((p > key_name) && PROFILE_isspace(*p))
- p--;
-
- keylen = p - key_name + 1;
-
- while (*section) {
- if (((*section)->name[0])
- && (!(_strnicmp((*section)->name, section_name, seclen )))
- && (((*section)->name)[seclen] == '\0')) {
- PROFILEKEY* *key = &(*section)->key;
-
- while (*key) {
- /* If create_always is FALSE then we check if the keyname already exists.
- * Otherwise we add it regardless of its existence, to allow
- * keys to be added more then once in some cases.
- */
- if (!create_always) {
- if ((!(_strnicmp( (*key)->name, key_name, keylen )))
- && (((*key)->name)[keylen] == '\0'))
- return *key;
-
- } // endif !create_always
-
- key = &(*key)->next;
- } // endwhile *key
-
- if (!create)
- return NULL;
-
- if (!(*key = malloc(sizeof(PROFILEKEY) + strlen(key_name))))
- return NULL;
-
- strcpy((*key)->name, key_name);
- (*key)->value = NULL;
- (*key)->next = NULL;
- return *key;
- } // endifsection->name
-
- section = &(*section)->next;
- } // endwhile *section
-
- if (!create)
- return NULL;
-
- *section = malloc(sizeof(PROFILESECTION) + strlen(section_name));
-
- if (*section == NULL)
- return NULL;
-
- strcpy((*section)->name, section_name);
- (*section)->next = NULL;
-
- if (!((*section)->key = malloc(sizeof(PROFILEKEY) + strlen(key_name)))) {
- free(*section);
- return NULL;
- } // endif malloc
-
- strcpy((*section)->key->name, key_name);
- (*section)->key->value = NULL;
- (*section)->key->next = NULL;
- return (*section)->key;
-} // end of PROFILE_Find
-
-
-/***********************************************************************
- * PROFILE_GetSection
- *
- * Returns all keys of a section.
- * If return_values is TRUE, also include the corresponding values.
- ***********************************************************************/
-static int PROFILE_GetSection(PROFILESECTION *section, LPCSTR section_name,
- LPSTR buffer, uint len, bool handle_env,
- bool return_values)
-{
- PROFILEKEY *key;
-
- if(!buffer)
- return 0;
-
- while (section) {
- if (section->name[0] && !stricmp(section->name, section_name)) {
- uint oldlen = len;
-
- for (key = section->key; key; key = key->next) {
- if (len <= 2)
- break;
-
- if (!*key->name)
- continue; /* Skip empty lines */
-
- if (IS_ENTRY_COMMENT(key->name))
- continue; /* Skip comments */
-
- PROFILE_CopyEntry(buffer, key->name, len - 1, handle_env);
- len -= strlen(buffer) + 1;
- buffer += strlen(buffer) + 1;
-
- if (len < 2)
- break;
-
- if (return_values && key->value) {
- buffer[-1] = '=';
- PROFILE_CopyEntry(buffer, key->value, len - 1, handle_env);
- len -= strlen(buffer) + 1;
- buffer += strlen(buffer) + 1;
- } // endif return_values
-
- } // endfor key
-
- *buffer = '\0';
-
- if (len <= 1) {
- /*If either lpszSection or lpszKey is NULL and the supplied
- destination buffer is too small to hold all the strings,
- the last string is truncated and followed by two null characters.
- In this case, the return value is equal to cchReturnBuffer
- minus two. */
- buffer[-1] = '\0';
- return oldlen - 2;
- } // endif len
-
- return oldlen - len;
- } // endif section->name
-
- section = section->next;
- } // endwhile section
-
- buffer[0] = buffer[1] = '\0';
- return 0;
-} // end of PROFILE_GetSection
-
-
-/* See GetPrivateProfileSectionNamesA for documentation */
-static int PROFILE_GetSectionNames(LPSTR buffer, uint len)
-{
- LPSTR buf;
- uint f,l;
- PROFILESECTION *section;
-
- if (trace > 1)
- htrc("GetSectionNames: buffer=%p len=%u\n", buffer, len);
-
- if (!buffer || !len)
- return 0;
-
- if (len == 1) {
- *buffer='\0';
- return 0;
- } // endif len
-
- f = len - 1;
- buf = buffer;
- section = CurProfile->section;
-
- if (trace > 1)
- htrc("GetSectionNames: section=%p\n", section);
-
- while (section != NULL) {
- if (trace > 1)
- htrc("section=%s\n", section->name);
-
- if (section->name[0]) {
- l = strlen(section->name) + 1;
-
- if (trace > 1)
- htrc("l=%u f=%u\n", l, f);
-
- if (l > f) {
- if (f > 0) {
- strncpy(buf, section->name, f-1);
- buf += f-1;
- *buf++='\0';
- } // endif f
-
- *buf = '\0';
- return len - 2;
- } // endif l
-
- strcpy(buf, section->name);
- buf += l;
- f -= l;
- } // endif section->name
-
- section = section->next;
- } // endwhile section
-
- *buf='\0';
- return buf-buffer;
-} // end of PROFILE_GetSectionNames
-
-
-/***********************************************************************
- * PROFILE_GetString
- *
- * Get a profile string.
- *
- * Tests with GetPrivateProfileString16, W95a,
- * with filled buffer ("****...") and section "set1" and key_name "1" valid:
- * section key_name def_val res buffer
- * "set1" "1" "x" 43 [data]
- * "set1" "1 " "x" 43 [data] (!)
- * "set1" " 1 "' "x" 43 [data] (!)
- * "set1" "" "x" 1 "x"
- * "set1" "" "x " 1 "x" (!)
- * "set1" "" " x " 3 " x" (!)
- * "set1" NULL "x" 6 "1\02\03\0\0"
- * "set1" "" "x" 1 "x"
- * NULL "1" "x" 0 "" (!)
- * "" "1" "x" 1 "x"
- * NULL NULL "" 0 ""
- *
- *************************************************************************/
-static int PROFILE_GetString(LPCSTR section, LPCSTR key_name,
- LPCSTR def_val, LPSTR buffer, uint len)
-{
- PROFILEKEY *key = NULL;
-
- if(!buffer)
- return 0;
-
- if (!def_val)
- def_val = "";
-
- if (key_name && key_name[0]) {
- key = PROFILE_Find(&CurProfile->section, section, key_name, FALSE, FALSE);
- PROFILE_CopyEntry(buffer, (key && key->value) ? key->value : def_val, len, FALSE);
-
- if (trace > 1)
- htrc("('%s','%s','%s'): returning '%s'\n",
- section, key_name, def_val, buffer );
-
- return strlen(buffer);
- } // endif key_name
-
- if (key_name && !(key_name[0]))
- /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
- return 0;
-
- if (section && section[0])
- return PROFILE_GetSection(CurProfile->section, section, buffer, len,
- FALSE, FALSE);
- buffer[0] = '\0';
- return 0;
-} // end of PROFILE_GetString
-
-
-/***********************************************************************
- * PROFILE_SetString
- *
- * Set a profile string.
- ***********************************************************************/
-static bool PROFILE_SetString(LPCSTR section_name, LPCSTR key_name,
- LPCSTR value, bool create_always)
-{
- if (!key_name) { /* Delete a whole section */
- if (trace > 1)
- htrc("Deleting('%s')\n", section_name);
-
- CurProfile->changed |= PROFILE_DeleteSection(&CurProfile->section,
- section_name);
- return TRUE; /* Even if PROFILE_DeleteSection() has failed,
- this is not an error on application's level.*/
- } else if (!value) { /* Delete a key */
- if (trace > 1)
- htrc("Deleting('%s','%s')\n", section_name, key_name);
-
- CurProfile->changed |= PROFILE_DeleteKey(&CurProfile->section,
- section_name, key_name);
- return TRUE; /* same error handling as above */
- } else { /* Set the key value */
- PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
- key_name, TRUE, create_always);
- if (trace > 1)
- htrc("Setting('%s','%s','%s')\n", section_name, key_name, value);
-
- if (!key)
- return FALSE;
-
- if (key->value) {
- /* strip the leading spaces. We can safely strip \n\r and
- * friends too, they should not happen here anyway. */
- while (PROFILE_isspace(*value))
- value++;
-
- if (!strcmp(key->value, value)) {
- if (trace > 1)
- htrc(" no change needed\n" );
-
- return TRUE; /* No change needed */
- } // endif value
-
- if (trace > 1)
- htrc(" replacing '%s'\n", key->value);
-
- free(key->value);
- } else if (trace > 1)
- htrc(" creating key\n" );
-
- key->value = malloc(strlen(value) + 1);
- strcpy(key->value, value);
- CurProfile->changed = TRUE;
- } // endelse
-
- return TRUE;
-} // end of PROFILE_SetString
-
-
-/***********************************************************************
- * PROFILE_GetStringItem
- *
- * Convenience function that turns a string 'xxx, yyy, zzz' into
- * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
- ***********************************************************************/
-char *PROFILE_GetStringItem(char* start)
-{
- char *lpchX, *lpch;
-
- for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++) {
- if (*lpchX == ',') {
- if (lpch)
- *lpch = '\0';
- else
- *lpchX = '\0';
-
- while(*(++lpchX))
- if (!PROFILE_isspace(*lpchX))
- return lpchX;
-
- } else if (PROFILE_isspace(*lpchX) && !lpch) {
- lpch = lpchX;
- } else
- lpch = NULL;
-
- } // endfor lpchX
-
- if (lpch)
- *lpch = '\0';
-
- return NULL;
-} // end of PROFILE_GetStringItem
-
-/**********************************************************************
- * if allow_section_name_copy is TRUE, allow the copying :
- * - of Section names if 'section' is NULL
- * - of Keys in a Section if 'entry' is NULL
- * (see MSDN doc for GetPrivateProfileString)
- **********************************************************************/
-static int PROFILE_GetPrivateProfileString(LPCSTR section, LPCSTR entry,
- LPCSTR def_val, LPSTR buffer,
- uint len, LPCSTR filename,
- bool allow_section_name_copy)
-{
- int ret;
- LPSTR pDefVal = NULL;
-
- if (!filename)
- filename = "win.ini";
-
- /* strip any trailing ' ' of def_val. */
- if (def_val) {
- LPSTR p = (LPSTR)&def_val[strlen(def_val)]; // even "" works !
-
- while (p > def_val)
- if ((*(--p)) != ' ')
- break;
-
- if (*p == ' ') { /* ouch, contained trailing ' ' */
- int len = p - (LPSTR)def_val;
-
- pDefVal = malloc(len + 1);
- strncpy(pDefVal, def_val, len);
- pDefVal[len] = '\0';
- } // endif *p
-
- } // endif def_val
-
- if (!pDefVal)
- pDefVal = (LPSTR)def_val;
-
- EnterCriticalSection(&PROFILE_CritSect);
-
- if (PROFILE_Open(filename)) {
- if ((allow_section_name_copy) && (section == NULL))
- ret = PROFILE_GetSectionNames(buffer, len);
- else
- /* PROFILE_GetString already handles the 'entry == NULL' case */
- ret = PROFILE_GetString(section, entry, pDefVal, buffer, len);
-
- } else {
- strncpy(buffer, pDefVal, len);
- ret = strlen(buffer);
- } // endif Open
-
- LeaveCriticalSection(&PROFILE_CritSect);
-
- if (pDefVal != def_val) /* allocated */
- memfree(pDefVal);
-
- return ret;
-} // end of PROFILE_GetPrivateProfileString
-
-/********************** API functions **********************************/
-
-/***********************************************************************
- * GetPrivateProfileStringA (KERNEL32.@)
- ***********************************************************************/
-int GetPrivateProfileString(LPCSTR section, LPCSTR entry, LPCSTR def_val,
- LPSTR buffer, uint len, LPCSTR filename)
-{
- return PROFILE_GetPrivateProfileString(section, entry, def_val,
- buffer, len, filename, TRUE);
-} // end of GetPrivateProfileString
-
-
-/***********************************************************************
- * GetPrivateProfileIntA (KERNEL32.@)
- ***********************************************************************/
-uint GetPrivateProfileInt(LPCSTR section, LPCSTR entry,
- int def_val, LPCSTR filename)
-{
- char buffer[20];
- int result;
-
- if (!PROFILE_GetPrivateProfileString(section, entry, "", buffer,
- sizeof(buffer), filename, FALSE))
- return def_val;
-
- /* FIXME: if entry can be found but it's empty, then Win16 is
- * supposed to return 0 instead of def_val ! Difficult/problematic
- * to implement (every other failure also returns zero buffer),
- * thus wait until testing framework avail for making sure nothing
- * else gets broken that way. */
- if (!buffer[0])
- return (uint)def_val;
-
- /* Don't use strtol() here !
- * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
- YES, scan for unsigned format ! (otherwise compatibility error) */
- if (!sscanf(buffer, "%u", &result))
- return 0;
-
- return (uint)result;
-} // end of GetPrivateProfileInt
-
-
-/***********************************************************************
- * GetPrivateProfileSectionA (KERNEL32.@)
- ***********************************************************************/
-int GetPrivateProfileSection(LPCSTR section, LPSTR buffer,
- DWORD len, LPCSTR filename)
-{
- int ret = 0;
-
- EnterCriticalSection( &PROFILE_CritSect );
-
- if (PROFILE_Open(filename))
- ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
- FALSE, TRUE);
-
- LeaveCriticalSection( &PROFILE_CritSect );
- return ret;
-} // end of GetPrivateProfileSection
-
-
-/***********************************************************************
- * WritePrivateProfileStringA (KERNEL32.@)
- ***********************************************************************/
-bool WritePrivateProfileString(LPCSTR section, LPCSTR entry,
- LPCSTR string, LPCSTR filename)
-{
- bool ret = FALSE;
-
- EnterCriticalSection( &PROFILE_CritSect );
-
- if (PROFILE_Open(filename)) {
- if (!section && !entry && !string) /* documented "file flush" case */
- PROFILE_ReleaseFile(); /* always return FALSE in this case */
- else {
- if (!section) {
- //FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
- } else {
- ret = PROFILE_SetString(section, entry, string, FALSE);
-
- if (ret)
- ret = PROFILE_FlushFile();
-
- } // endif section
-
- } // endif section || entry|| string
-
- } // endif Open
-
- LeaveCriticalSection( &PROFILE_CritSect );
- return ret;
-} // end of WritePrivateProfileString
-
-
-/***********************************************************************
- * WritePrivateProfileSectionA (KERNEL32.@)
- ***********************************************************************/
-bool WritePrivateProfileSection(LPCSTR section,
- LPCSTR string, LPCSTR filename )
-{
- bool ret = FALSE;
- LPSTR p ;
-
- EnterCriticalSection(&PROFILE_CritSect);
-
- if (PROFILE_Open(filename)) {
- if (!section && !string)
- PROFILE_ReleaseFile(); /* always return FALSE in this case */
- else if (!string) { /* delete the named section*/
- ret = PROFILE_SetString(section, NULL, NULL, FALSE);
-
- if (ret)
- ret = PROFILE_FlushFile();
- } else {
- PROFILE_DeleteAllKeys(section);
- ret = TRUE;
-
- while (*string) {
- LPSTR buf = malloc(strlen(string) + 1);
- strcpy(buf, string);
-
- if ((p = strchr(buf, '='))) {
- *p='\0';
- ret = PROFILE_SetString(section, buf, p+1, TRUE);
- } // endif p
-
- free(buf);
- string += strlen(string) + 1;
-
- if (ret)
- ret = PROFILE_FlushFile();
-
- } // endwhile *string
-
- } // endelse
-
- } // endif Open
-
- LeaveCriticalSection(&PROFILE_CritSect);
- return ret;
-} // end of WritePrivateProfileSection
-
-
-/***********************************************************************
- * GetPrivateProfileSectionNamesA (KERNEL32.@)
- *
- * Returns the section names contained in the specified file.
- * FIXME: Where do we find this file when the path is relative?
- * The section names are returned as a list of strings with an extra
- * '\0' to mark the end of the list. Except for that the behavior
- * depends on the Windows version.
- *
- * Win95:
- * - if the buffer is 0 or 1 character long then it is as if it was of
- * infinite length.
- * - otherwise, if the buffer is to small only the section names that fit
- * are returned.
- * - note that this means if the buffer was to small to return even just
- * the first section name then a single '\0' will be returned.
- * - the return value is the number of characters written in the buffer,
- * except if the buffer was too smal in which case len-2 is returned
- *
- * Win2000:
- * - if the buffer is 0, 1 or 2 characters long then it is filled with
- * '\0' and the return value is 0
- * - otherwise if the buffer is too small then the first section name that
- * does not fit is truncated so that the string list can be terminated
- * correctly (double '\0')
- * - the return value is the number of characters written in the buffer
- * except for the trailing '\0'. If the buffer is too small, then the
- * return value is len-2
- * - Win2000 has a bug that triggers when the section names and the
- * trailing '\0' fit exactly in the buffer. In that case the trailing
- * '\0' is missing.
- *
- * Wine implements the observed Win2000 behavior (except for the bug).
- *
- * Note that when the buffer is big enough then the return value may be any
- * value between 1 and len-1 (or len in Win95), including len-2.
- */
-DWORD GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename)
-{
- DWORD ret = 0;
-
- if (trace > 1)
- htrc("GPPSN: filename=%s\n", filename);
-
- EnterCriticalSection(&PROFILE_CritSect);
-
- if (PROFILE_Open(filename))
- ret = PROFILE_GetSectionNames(buffer, size);
-
- LeaveCriticalSection(&PROFILE_CritSect);
- return ret;
-} // end of GetPrivateProfileSectionNames
-
-
-/************************************************************************
- * Program to test the above
- ************************************************************************/
-#ifdef TEST_MODULE
-int main(int argc, char**argv) {
- char buff[128];
- char *p, *inifile = "D:\\Plug\\Data\\contact.ini";
- DWORD n;
-
- n = GetPrivateProfileSectionNames(buff, 128, inifile);
- printf("Sections: n=%d\n", n);
-
- for (p = buff; *p; p += (strlen(p) + 1))
- printf("section=[%s]\n", p);
-
- GetPrivateProfileString("BER", "name", "?", buff, 128, inifile);
- printf("[BER](name) = %s\n", buff);
-
- WritePrivateProfileString("FOO", "city", NULL, inifile);
- GetPrivateProfileString("FOO", "city", "?", buff, 128, inifile);
- printf("[FOO](city) = %s\n", buff);
-
- printf("FOO city: ");
- fgets(buff, sizeof(buff), stdin);
- if (buff[strlen(buff) - 1] == '\n')
- buff[strlen(buff) - 1] = '\0';
- WritePrivateProfileString("FOO", "city", buff, inifile);
- GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
- printf("After write, [FOO](City) = %s\n", buff);
-
- printf("New city: ");
- fgets(buff, sizeof(buff), stdin);
- if (buff[strlen(buff) - 1] == '\n')
- buff[strlen(buff) - 1] = '\0';
- WritePrivateProfileString("FOO", "city", buff, inifile);
- GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
- printf("After update, [FOO](City) = %s\n", buff);
-
- printf("FOO name: ");
- fgets(buff, sizeof(buff), stdin);
- if (buff[strlen(buff) - 1] == '\n')
- buff[strlen(buff) - 1] = '\0';
- WritePrivateProfileString("FOO", "name", buff, inifile);
- GetPrivateProfileString("FOO", "name", "X", buff, 128, inifile);
- printf("[FOO](name) = %s\n", buff);
-} // end of main
-#endif // TEST_MODULE
+/*
+ * Profile functions
+ *
+ * Copyright 1993 Miguel de Icaza
+ * Copyright 1996 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <ctype.h>
+//#include <errno.h>
+#include <fcntl.h>
+//#include <io.h> commented this line out to compile for solaris
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+//#include <sys/types.h>
+//#include <memory.h>
+#include "my_global.h"
+//#include "osutil.h"
+#include "global.h"
+
+
+// The types and variables used locally
+//typedef int bool;
+typedef unsigned int uint;
+#define DWORD int
+#define TRUE 1
+#define FALSE 0
+#define SVP(S) ((S) ? S : "<null>")
+#define _strlwr(P) strlwr(P) //OB: changed this line
+#define MAX_PATHNAME_LEN 256
+#define N_CACHED_PROFILES 10
+#ifndef WIN32
+#define stricmp strcasecmp
+#define _strnicmp strncasecmp
+#endif // !WIN32
+#define EnterCriticalSection(x)
+#define LeaveCriticalSection(x)
+
+#if defined(TEST_MODULE)
+// Stand alone test program
+#include <stdarg.h>
+ int trace = 0;
+void htrc(char const *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end (ap);
+} /* end of htrc */
+#else // !TEST_MODULE
+// Normal included functions
+extern int trace;
+void htrc(char const *fmt, ...);
+#endif // !TEST MODULE
+
+
+typedef struct tagPROFILEKEY {
+ char *value;
+ struct tagPROFILEKEY *next;
+ char name[1];
+ } PROFILEKEY;
+
+typedef struct tagPROFILESECTION {
+ struct tagPROFILEKEY *key;
+ struct tagPROFILESECTION *next;
+ char name[1];
+ } PROFILESECTION;
+
+typedef struct {
+ bool changed;
+ PROFILESECTION *section;
+//char *dos_name;
+//char *unix_name;
+ char *filename;
+ time_t mtime;
+ } PROFILE;
+
+#define memfree(P) if (P) free(P)
+
+/* Cached profile files */
+static PROFILE *MRUProfile[N_CACHED_PROFILES] = {NULL};
+
+#define CurProfile (MRUProfile[0])
+
+/* wine.ini config file registry root */
+//static HKEY wine_profile_key;
+
+#define PROFILE_MAX_LINE_LEN 1024
+
+/* Wine profile name in $HOME directory; must begin with slash */
+static const char PROFILE_WineIniName[] = "/.winerc";
+
+/* Wine profile: the profile file being used */
+static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
+
+/* Check for comments in profile */
+#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
+
+//static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
+
+//static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
+
+static const char hex[16] = "0123456789ABCDEF";
+
+bool WritePrivateProfileString(LPCSTR section, LPCSTR entry,
+ LPCSTR string, LPCSTR filename );
+/***********************************************************************
+ * PROFILE_CopyEntry
+ *
+ * Copy the content of an entry into a buffer, removing quotes,
+ * and possibly translating environment variables.
+ ***********************************************************************/
+static void PROFILE_CopyEntry( char *buffer, const char *value, uint len,
+ int handle_env )
+{
+ const char *p;
+ char quote = '\0';
+
+ if (!buffer)
+ return;
+
+ if ((*value == '\'') || (*value == '\"'))
+ if (value[1] && (value[strlen(value)-1] == *value))
+ quote = *value++;
+
+ if (!handle_env) {
+ strncpy(buffer, value, len);
+
+ if (quote && (len >= strlen(value)))
+ buffer[strlen(buffer)-1] = '\0';
+
+ return;
+ } // endif handle
+
+ for (p = value; (*p && (len > 1)); *buffer++ = *p++, len--) {
+ if ((*p == '$') && (p[1] == '{')) {
+ char env_val[1024];
+ const char *env_p;
+ const char *p2 = strchr(p, '}');
+
+ if (!p2)
+ continue; /* ignore it */
+
+ strncpy(env_val, p + 2, min(sizeof(env_val), (int)(p2-p)-1));
+
+ if ((env_p = getenv(env_val)) != NULL) {
+ int buffer_len;
+
+ strncpy( buffer, env_p, len );
+ buffer_len = strlen( buffer );
+ buffer += buffer_len;
+ len -= buffer_len;
+ } // endif env_p
+
+ p = p2 + 1;
+ } // endif p
+
+ } // endfor p
+
+ if (quote && (len > 1))
+ buffer--;
+
+ *buffer = '\0';
+} // end of PROFILE_CopyEntry
+
+
+/***********************************************************************
+ * PROFILE_Save
+ *
+ * Save a profile tree to a file.
+ ***********************************************************************/
+static void PROFILE_Save( FILE *file, PROFILESECTION *section )
+{
+ PROFILEKEY *key;
+
+ for (; section; section = section->next) {
+ if (section->name[0])
+ fprintf(file, "\n[%s]\n", SVP(section->name));
+
+ for (key = section->key; key; key = key->next)
+ if (key->name && key->name[0]) {
+ fprintf(file, "%s", SVP(key->name));
+
+ if (key->value)
+ fprintf(file, "=%s", SVP(key->value));
+
+ fprintf(file, "\n");
+ } // endif key->name
+
+ } // endfor section
+
+} // end of PROFILE_Save
+
+
+/***********************************************************************
+ * PROFILE_Free
+ *
+ * Free a profile tree.
+ ***********************************************************************/
+static void PROFILE_Free( PROFILESECTION *section )
+{
+ PROFILESECTION *next_section;
+ PROFILEKEY *key, *next_key;
+
+ for (; section; section = next_section) {
+ for (key = section->key; key; key = next_key) {
+ next_key = key->next;
+ memfree(key->value);
+ free(key);
+ } // endfor key
+
+ next_section = section->next;
+ free(section);
+ } // endfor section
+
+} // end of PROFILE_Free
+
+static int PROFILE_isspace(char c)
+{
+ /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
+ if (isspace(c) || c=='\r' || c==0x1a)
+ return 1;
+
+ return 0;
+} // end of PROFILE_isspace
+
+
+/***********************************************************************
+ * PROFILE_Load
+ *
+ * Load a profile tree from a file.
+ ***********************************************************************/
+static PROFILESECTION *PROFILE_Load( FILE *file )
+{
+ char buffer[PROFILE_MAX_LINE_LEN];
+ char *p, *p2;
+ int line = 0;
+ PROFILESECTION *section, *first_section;
+ PROFILESECTION* *next_section;
+ PROFILEKEY *key, *prev_key, **next_key;
+
+ first_section = malloc(sizeof(*section));
+
+ if (first_section == NULL)
+ return NULL;
+
+ first_section->name[0] = 0;
+ first_section->key = NULL;
+ first_section->next = NULL;
+ next_section = &first_section->next;
+ next_key = &first_section->key;
+ prev_key = NULL;
+
+ while (fgets(buffer, PROFILE_MAX_LINE_LEN, file)) {
+ line++;
+ p = buffer;
+
+ while (*p && PROFILE_isspace(*p))
+ p++;
+
+ if (*p == '[') { /* section start */
+ if (!(p2 = strrchr( p, ']'))) {
+ fprintf(stderr, "Invalid section header at line %d: '%s'\n",
+ line, p);
+ } else {
+ *p2 = '\0';
+ p++;
+
+ if (!(section = malloc(sizeof(*section) + strlen(p))))
+ break;
+
+ strcpy(section->name, p);
+ section->key = NULL;
+ section->next = NULL;
+ *next_section = section;
+ next_section = &section->next;
+ next_key = &section->key;
+ prev_key = NULL;
+
+ if (trace > 1)
+ htrc("New section: '%s'\n",section->name);
+
+ continue;
+ } // endif p2
+
+ } // endif p
+
+ p2 = p + strlen(p) - 1;
+
+ while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2)))
+ *p2-- = '\0';
+
+ if ((p2 = strchr(p, '=')) != NULL) {
+ char *p3 = p2 - 1;
+
+ while ((p3 > p) && PROFILE_isspace(*p3))
+ *p3-- = '\0';
+
+ *p2++ = '\0';
+
+ while (*p2 && PROFILE_isspace(*p2))
+ p2++;
+
+ } // endif p2
+
+ if (*p || !prev_key || *prev_key->name) {
+ if (!(key = malloc(sizeof(*key) + strlen(p))))
+ break;
+
+ strcpy(key->name, p);
+
+ if (p2) {
+ key->value = malloc(strlen(p2)+1);
+ strcpy(key->value, p2);
+ } else
+ key->value = NULL;
+
+ key->next = NULL;
+ *next_key = key;
+ next_key = &key->next;
+ prev_key = key;
+
+ if (trace > 1)
+ htrc("New key: name='%s', value='%s'\n",
+ key->name,key->value?key->value:"(none)");
+
+ } // endif p || prev_key
+
+ } // endif *p
+
+ return first_section;
+} // end of PROFILE_Load
+
+/***********************************************************************
+ * PROFILE_FlushFile
+ *
+ * Flush the current profile to disk if changed.
+ ***********************************************************************/
+static bool PROFILE_FlushFile(void)
+{
+//char *p, buffer[MAX_PATHNAME_LEN];
+//const char *unix_name;
+ FILE *file = NULL;
+ struct stat buf;
+
+ if (trace > 1)
+ htrc("PROFILE_FlushFile: CurProfile=%p\n", CurProfile);
+
+ if (!CurProfile) {
+ fprintf(stderr, "No current profile!\n");
+ return FALSE;
+ } // endif !CurProfile
+
+ if (!CurProfile->changed || !CurProfile->filename)
+ return TRUE;
+
+#if 0
+ if (!(file = fopen(unix_name, "w"))) {
+ /* Try to create it in $HOME/.wine */
+ /* FIXME: this will need a more general solution */
+ //strcpy( buffer, get_config_dir() );
+ //p = buffer + strlen(buffer);
+ //*p++ = '/';
+ char *p1 = strrchr(CurProfile->filename, '\\');
+
+ p = buffer; // OB: To be elaborate
+
+ if (p1)
+ p1++;
+ else
+ p1 = CurProfile->dos_name;
+
+ strcpy(p, p1);
+ _strlwr(p);
+ file = fopen(buffer, "w");
+ unix_name = buffer;
+ } // endif !unix_name
+#endif // 0
+
+ if (!(file = fopen(CurProfile->filename, "w"))) {
+ fprintf(stderr, "could not save profile file %s\n", CurProfile->filename);
+ return FALSE;
+ } // endif !file
+
+ if (trace > 1)
+ htrc("Saving '%s'\n", CurProfile->filename);
+
+ PROFILE_Save(file, CurProfile->section);
+ fclose(file);
+ CurProfile->changed = FALSE;
+
+ if (!stat(CurProfile->filename, &buf))
+ CurProfile->mtime = buf.st_mtime;
+
+ return TRUE;
+} // end of PROFILE_FlushFile
+
+
+/***********************************************************************
+ * PROFILE_ReleaseFile
+ *
+ * Flush the current profile to disk and remove it from the cache.
+ ***********************************************************************/
+static void PROFILE_ReleaseFile(void)
+{
+ PROFILE_FlushFile();
+ PROFILE_Free(CurProfile->section);
+//memfree(CurProfile->dos_name);
+//memfree(CurProfile->unix_name);
+ memfree(CurProfile->filename);
+ CurProfile->changed = FALSE;
+ CurProfile->section = NULL;
+//CurProfile->dos_name = NULL;
+//CurProfile->unix_name = NULL;
+ CurProfile->filename = NULL;
+ CurProfile->mtime = 0;
+} // end of PROFILE_ReleaseFile
+
+
+/***********************************************************************
+ * PROFILE_Open
+ *
+ * Open a profile file, checking the cached file first.
+ ***********************************************************************/
+static bool PROFILE_Open(LPCSTR filename)
+{
+//char buffer[MAX_PATHNAME_LEN];
+//char *p;
+ FILE *file = NULL;
+ int i, j;
+ struct stat buf;
+ PROFILE *tempProfile;
+
+ if (trace > 1)
+ htrc("PROFILE_Open: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
+
+ /* First time around */
+ if (!CurProfile)
+ for (i = 0; i < N_CACHED_PROFILES; i++) {
+ MRUProfile[i] = malloc(sizeof(PROFILE));
+
+ if (MRUProfile[i] == NULL)
+ break;
+
+ MRUProfile[i]->changed=FALSE;
+ MRUProfile[i]->section=NULL;
+// MRUProfile[i]->dos_name=NULL;
+// MRUProfile[i]->unix_name=NULL;
+ MRUProfile[i]->filename=NULL;
+ MRUProfile[i]->mtime=0;
+ } // endfor i
+
+ /* Check for a match */
+ for (i = 0; i < N_CACHED_PROFILES; i++) {
+ if (trace > 1)
+ htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
+
+ if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) {
+ if (i) {
+ PROFILE_FlushFile();
+ tempProfile = MRUProfile[i];
+
+ for (j = i; j > 0; j--)
+ MRUProfile[j] = MRUProfile[j-1];
+
+ CurProfile=tempProfile;
+ } // endif i
+
+ if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) {
+ if (trace > 1)
+ htrc("(%s): already opened (mru=%d)\n", filename, i);
+
+ } else {
+ if (trace > 1)
+ htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i);
+
+ } // endif stat
+
+ return TRUE;
+ } // endif filename
+
+ } // endfor i
+
+ /* Flush the old current profile */
+ PROFILE_FlushFile();
+
+ /* Make the oldest profile the current one only in order to get rid of it */
+ if (i == N_CACHED_PROFILES) {
+ tempProfile = MRUProfile[N_CACHED_PROFILES-1];
+
+ for(i = N_CACHED_PROFILES-1; i > 0; i--)
+ MRUProfile[i] = MRUProfile[i-1];
+
+ CurProfile = tempProfile;
+ } // endif i
+
+ if (CurProfile->filename)
+ PROFILE_ReleaseFile();
+
+ /* OK, now that CurProfile is definitely free we assign it our new file */
+// newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
+// strcpy( newdos_name, full_name.short_name );
+
+// newdos_name = malloc(strlen(filename)+1);
+// strcpy(newdos_name, filename);
+
+// CurProfile->dos_name = newdos_name;
+ CurProfile->filename = malloc(strlen(filename) + 1);
+ strcpy(CurProfile->filename, filename);
+
+ /* Try to open the profile file, first in $HOME/.wine */
+
+ /* FIXME: this will need a more general solution */
+// strcpy( buffer, get_config_dir() );
+// p = buffer + strlen(buffer);
+// *p++ = '/';
+// strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
+// p = buffer;
+// strcpy(p, filename);
+// _strlwr(p);
+
+ if (trace > 1)
+ htrc("Opening %s\n", filename);
+
+ if ((file = fopen(filename, "r"))) {
+ if (trace > 1)
+ htrc("(%s): found it\n", filename);
+
+// CurProfile->unix_name = malloc(strlen(buffer)+1);
+// strcpy(CurProfile->unix_name, buffer);
+ } /* endif file */
+
+ if (file) {
+ CurProfile->section = PROFILE_Load(file);
+ fclose(file);
+
+ if (!stat(CurProfile->filename, &buf))
+ CurProfile->mtime = buf.st_mtime;
+
+ } else {
+ /* Does not exist yet, we will create it in PROFILE_FlushFile */
+ fprintf(stderr, "profile file %s not found\n", filename);
+ } /* endif file */
+
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * PROFILE_DeleteSection
+ *
+ * Delete a section from a profile tree.
+ ***********************************************************************/
+static bool PROFILE_DeleteSection(PROFILESECTION* *section, LPCSTR name)
+{
+ while (*section) {
+ if ((*section)->name[0] && !stricmp((*section)->name, name)) {
+ PROFILESECTION *to_del = *section;
+
+ *section = to_del->next;
+ to_del->next = NULL;
+ PROFILE_Free(to_del);
+ return TRUE;
+ } // endif section
+
+ section = &(*section)->next;
+ } // endwhile section
+
+ return FALSE;
+} // end of PROFILE_DeleteSection
+
+
+/***********************************************************************
+ * PROFILE_DeleteKey
+ *
+ * Delete a key from a profile tree.
+ ***********************************************************************/
+static bool PROFILE_DeleteKey(PROFILESECTION* *section,
+ LPCSTR section_name, LPCSTR key_name)
+{
+ while (*section) {
+ if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
+ PROFILEKEY* *key = &(*section)->key;
+
+ while (*key) {
+ if (!stricmp((*key)->name, key_name)) {
+ PROFILEKEY *to_del = *key;
+
+ *key = to_del->next;
+ memfree(to_del->value);
+ free(to_del);
+ return TRUE;
+ } // endif name
+
+ key = &(*key)->next;
+ } // endwhile *key
+
+ } // endif section->name
+
+ section = &(*section)->next;
+ } // endwhile *section
+
+ return FALSE;
+} // end of PROFILE_DeleteKey
+
+
+/***********************************************************************
+ * PROFILE_DeleteAllKeys
+ *
+ * Delete all keys from a profile tree.
+ ***********************************************************************/
+void PROFILE_DeleteAllKeys(LPCSTR section_name)
+{
+ PROFILESECTION* *section= &CurProfile->section;
+
+ while (*section) {
+ if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
+ PROFILEKEY* *key = &(*section)->key;
+
+ while (*key) {
+ PROFILEKEY *to_del = *key;
+
+ *key = to_del->next;
+ memfree(to_del->value);
+ free(to_del);
+ CurProfile->changed = TRUE;
+ } // endwhile *key
+
+ } // endif section->name
+
+ section = &(*section)->next;
+ } // endwhile *section
+
+} // end of PROFILE_DeleteAllKeys
+
+
+/***********************************************************************
+ * PROFILE_Find
+ *
+ * Find a key in a profile tree, optionally creating it.
+ ***********************************************************************/
+static PROFILEKEY *PROFILE_Find(PROFILESECTION* *section,
+ const char *section_name,
+ const char *key_name,
+ bool create, bool create_always)
+{
+ const char *p;
+ int seclen, keylen;
+
+ while (PROFILE_isspace(*section_name))
+ section_name++;
+
+ p = section_name + strlen(section_name) - 1;
+
+ while ((p > section_name) && PROFILE_isspace(*p))
+ p--;
+
+ seclen = p - section_name + 1;
+
+ while (PROFILE_isspace(*key_name))
+ key_name++;
+
+ p = key_name + strlen(key_name) - 1;
+
+ while ((p > key_name) && PROFILE_isspace(*p))
+ p--;
+
+ keylen = p - key_name + 1;
+
+ while (*section) {
+ if (((*section)->name[0])
+ && (!(_strnicmp((*section)->name, section_name, seclen )))
+ && (((*section)->name)[seclen] == '\0')) {
+ PROFILEKEY* *key = &(*section)->key;
+
+ while (*key) {
+ /* If create_always is FALSE then we check if the keyname already exists.
+ * Otherwise we add it regardless of its existence, to allow
+ * keys to be added more then once in some cases.
+ */
+ if (!create_always) {
+ if ((!(_strnicmp( (*key)->name, key_name, keylen )))
+ && (((*key)->name)[keylen] == '\0'))
+ return *key;
+
+ } // endif !create_always
+
+ key = &(*key)->next;
+ } // endwhile *key
+
+ if (!create)
+ return NULL;
+
+ if (!(*key = malloc(sizeof(PROFILEKEY) + strlen(key_name))))
+ return NULL;
+
+ strcpy((*key)->name, key_name);
+ (*key)->value = NULL;
+ (*key)->next = NULL;
+ return *key;
+ } // endifsection->name
+
+ section = &(*section)->next;
+ } // endwhile *section
+
+ if (!create)
+ return NULL;
+
+ *section = malloc(sizeof(PROFILESECTION) + strlen(section_name));
+
+ if (*section == NULL)
+ return NULL;
+
+ strcpy((*section)->name, section_name);
+ (*section)->next = NULL;
+
+ if (!((*section)->key = malloc(sizeof(PROFILEKEY) + strlen(key_name)))) {
+ free(*section);
+ return NULL;
+ } // endif malloc
+
+ strcpy((*section)->key->name, key_name);
+ (*section)->key->value = NULL;
+ (*section)->key->next = NULL;
+ return (*section)->key;
+} // end of PROFILE_Find
+
+
+/***********************************************************************
+ * PROFILE_GetSection
+ *
+ * Returns all keys of a section.
+ * If return_values is TRUE, also include the corresponding values.
+ ***********************************************************************/
+static int PROFILE_GetSection(PROFILESECTION *section, LPCSTR section_name,
+ LPSTR buffer, uint len, bool handle_env,
+ bool return_values)
+{
+ PROFILEKEY *key;
+
+ if(!buffer)
+ return 0;
+
+ while (section) {
+ if (section->name[0] && !stricmp(section->name, section_name)) {
+ uint oldlen = len;
+
+ for (key = section->key; key; key = key->next) {
+ if (len <= 2)
+ break;
+
+ if (!*key->name)
+ continue; /* Skip empty lines */
+
+ if (IS_ENTRY_COMMENT(key->name))
+ continue; /* Skip comments */
+
+ PROFILE_CopyEntry(buffer, key->name, len - 1, handle_env);
+ len -= strlen(buffer) + 1;
+ buffer += strlen(buffer) + 1;
+
+ if (len < 2)
+ break;
+
+ if (return_values && key->value) {
+ buffer[-1] = '=';
+ PROFILE_CopyEntry(buffer, key->value, len - 1, handle_env);
+ len -= strlen(buffer) + 1;
+ buffer += strlen(buffer) + 1;
+ } // endif return_values
+
+ } // endfor key
+
+ *buffer = '\0';
+
+ if (len <= 1) {
+ /*If either lpszSection or lpszKey is NULL and the supplied
+ destination buffer is too small to hold all the strings,
+ the last string is truncated and followed by two null characters.
+ In this case, the return value is equal to cchReturnBuffer
+ minus two. */
+ buffer[-1] = '\0';
+ return oldlen - 2;
+ } // endif len
+
+ return oldlen - len;
+ } // endif section->name
+
+ section = section->next;
+ } // endwhile section
+
+ buffer[0] = buffer[1] = '\0';
+ return 0;
+} // end of PROFILE_GetSection
+
+
+/* See GetPrivateProfileSectionNamesA for documentation */
+static int PROFILE_GetSectionNames(LPSTR buffer, uint len)
+{
+ LPSTR buf;
+ uint f,l;
+ PROFILESECTION *section;
+
+ if (trace > 1)
+ htrc("GetSectionNames: buffer=%p len=%u\n", buffer, len);
+
+ if (!buffer || !len)
+ return 0;
+
+ if (len == 1) {
+ *buffer='\0';
+ return 0;
+ } // endif len
+
+ f = len - 1;
+ buf = buffer;
+ section = CurProfile->section;
+
+ if (trace > 1)
+ htrc("GetSectionNames: section=%p\n", section);
+
+ while (section != NULL) {
+ if (trace > 1)
+ htrc("section=%s\n", section->name);
+
+ if (section->name[0]) {
+ l = strlen(section->name) + 1;
+
+ if (trace > 1)
+ htrc("l=%u f=%u\n", l, f);
+
+ if (l > f) {
+ if (f > 0) {
+ strncpy(buf, section->name, f-1);
+ buf += f-1;
+ *buf++='\0';
+ } // endif f
+
+ *buf = '\0';
+ return len - 2;
+ } // endif l
+
+ strcpy(buf, section->name);
+ buf += l;
+ f -= l;
+ } // endif section->name
+
+ section = section->next;
+ } // endwhile section
+
+ *buf='\0';
+ return buf-buffer;
+} // end of PROFILE_GetSectionNames
+
+
+/***********************************************************************
+ * PROFILE_GetString
+ *
+ * Get a profile string.
+ *
+ * Tests with GetPrivateProfileString16, W95a,
+ * with filled buffer ("****...") and section "set1" and key_name "1" valid:
+ * section key_name def_val res buffer
+ * "set1" "1" "x" 43 [data]
+ * "set1" "1 " "x" 43 [data] (!)
+ * "set1" " 1 "' "x" 43 [data] (!)
+ * "set1" "" "x" 1 "x"
+ * "set1" "" "x " 1 "x" (!)
+ * "set1" "" " x " 3 " x" (!)
+ * "set1" NULL "x" 6 "1\02\03\0\0"
+ * "set1" "" "x" 1 "x"
+ * NULL "1" "x" 0 "" (!)
+ * "" "1" "x" 1 "x"
+ * NULL NULL "" 0 ""
+ *
+ *************************************************************************/
+static int PROFILE_GetString(LPCSTR section, LPCSTR key_name,
+ LPCSTR def_val, LPSTR buffer, uint len)
+{
+ PROFILEKEY *key = NULL;
+
+ if(!buffer)
+ return 0;
+
+ if (!def_val)
+ def_val = "";
+
+ if (key_name && key_name[0]) {
+ key = PROFILE_Find(&CurProfile->section, section, key_name, FALSE, FALSE);
+ PROFILE_CopyEntry(buffer, (key && key->value) ? key->value : def_val, len, FALSE);
+
+ if (trace > 1)
+ htrc("('%s','%s','%s'): returning '%s'\n",
+ section, key_name, def_val, buffer );
+
+ return strlen(buffer);
+ } // endif key_name
+
+ if (key_name && !(key_name[0]))
+ /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
+ return 0;
+
+ if (section && section[0])
+ return PROFILE_GetSection(CurProfile->section, section, buffer, len,
+ FALSE, FALSE);
+ buffer[0] = '\0';
+ return 0;
+} // end of PROFILE_GetString
+
+
+/***********************************************************************
+ * PROFILE_SetString
+ *
+ * Set a profile string.
+ ***********************************************************************/
+static bool PROFILE_SetString(LPCSTR section_name, LPCSTR key_name,
+ LPCSTR value, bool create_always)
+{
+ if (!key_name) { /* Delete a whole section */
+ if (trace > 1)
+ htrc("Deleting('%s')\n", section_name);
+
+ CurProfile->changed |= PROFILE_DeleteSection(&CurProfile->section,
+ section_name);
+ return TRUE; /* Even if PROFILE_DeleteSection() has failed,
+ this is not an error on application's level.*/
+ } else if (!value) { /* Delete a key */
+ if (trace > 1)
+ htrc("Deleting('%s','%s')\n", section_name, key_name);
+
+ CurProfile->changed |= PROFILE_DeleteKey(&CurProfile->section,
+ section_name, key_name);
+ return TRUE; /* same error handling as above */
+ } else { /* Set the key value */
+ PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
+ key_name, TRUE, create_always);
+ if (trace > 1)
+ htrc("Setting('%s','%s','%s')\n", section_name, key_name, value);
+
+ if (!key)
+ return FALSE;
+
+ if (key->value) {
+ /* strip the leading spaces. We can safely strip \n\r and
+ * friends too, they should not happen here anyway. */
+ while (PROFILE_isspace(*value))
+ value++;
+
+ if (!strcmp(key->value, value)) {
+ if (trace > 1)
+ htrc(" no change needed\n" );
+
+ return TRUE; /* No change needed */
+ } // endif value
+
+ if (trace > 1)
+ htrc(" replacing '%s'\n", key->value);
+
+ free(key->value);
+ } else if (trace > 1)
+ htrc(" creating key\n" );
+
+ key->value = malloc(strlen(value) + 1);
+ strcpy(key->value, value);
+ CurProfile->changed = TRUE;
+ } // endelse
+
+ return TRUE;
+} // end of PROFILE_SetString
+
+
+/***********************************************************************
+ * PROFILE_GetStringItem
+ *
+ * Convenience function that turns a string 'xxx, yyy, zzz' into
+ * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
+ ***********************************************************************/
+char *PROFILE_GetStringItem(char* start)
+{
+ char *lpchX, *lpch;
+
+ for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++) {
+ if (*lpchX == ',') {
+ if (lpch)
+ *lpch = '\0';
+ else
+ *lpchX = '\0';
+
+ while(*(++lpchX))
+ if (!PROFILE_isspace(*lpchX))
+ return lpchX;
+
+ } else if (PROFILE_isspace(*lpchX) && !lpch) {
+ lpch = lpchX;
+ } else
+ lpch = NULL;
+
+ } // endfor lpchX
+
+ if (lpch)
+ *lpch = '\0';
+
+ return NULL;
+} // end of PROFILE_GetStringItem
+
+/**********************************************************************
+ * if allow_section_name_copy is TRUE, allow the copying :
+ * - of Section names if 'section' is NULL
+ * - of Keys in a Section if 'entry' is NULL
+ * (see MSDN doc for GetPrivateProfileString)
+ **********************************************************************/
+static int PROFILE_GetPrivateProfileString(LPCSTR section, LPCSTR entry,
+ LPCSTR def_val, LPSTR buffer,
+ uint len, LPCSTR filename,
+ bool allow_section_name_copy)
+{
+ int ret;
+ LPSTR pDefVal = NULL;
+
+ if (!filename)
+ filename = "win.ini";
+
+ /* strip any trailing ' ' of def_val. */
+ if (def_val) {
+ LPSTR p = (LPSTR)&def_val[strlen(def_val)]; // even "" works !
+
+ while (p > def_val)
+ if ((*(--p)) != ' ')
+ break;
+
+ if (*p == ' ') { /* ouch, contained trailing ' ' */
+ int len = p - (LPSTR)def_val;
+
+ pDefVal = malloc(len + 1);
+ strncpy(pDefVal, def_val, len);
+ pDefVal[len] = '\0';
+ } // endif *p
+
+ } // endif def_val
+
+ if (!pDefVal)
+ pDefVal = (LPSTR)def_val;
+
+ EnterCriticalSection(&PROFILE_CritSect);
+
+ if (PROFILE_Open(filename)) {
+ if ((allow_section_name_copy) && (section == NULL))
+ ret = PROFILE_GetSectionNames(buffer, len);
+ else
+ /* PROFILE_GetString already handles the 'entry == NULL' case */
+ ret = PROFILE_GetString(section, entry, pDefVal, buffer, len);
+
+ } else {
+ strncpy(buffer, pDefVal, len);
+ ret = strlen(buffer);
+ } // endif Open
+
+ LeaveCriticalSection(&PROFILE_CritSect);
+
+ if (pDefVal != def_val) /* allocated */
+ memfree(pDefVal);
+
+ return ret;
+} // end of PROFILE_GetPrivateProfileString
+
+/********************** API functions **********************************/
+
+/***********************************************************************
+ * GetPrivateProfileStringA (KERNEL32.@)
+ ***********************************************************************/
+int GetPrivateProfileString(LPCSTR section, LPCSTR entry, LPCSTR def_val,
+ LPSTR buffer, uint len, LPCSTR filename)
+{
+ return PROFILE_GetPrivateProfileString(section, entry, def_val,
+ buffer, len, filename, TRUE);
+} // end of GetPrivateProfileString
+
+
+/***********************************************************************
+ * GetPrivateProfileIntA (KERNEL32.@)
+ ***********************************************************************/
+uint GetPrivateProfileInt(LPCSTR section, LPCSTR entry,
+ int def_val, LPCSTR filename)
+{
+ char buffer[20];
+ int result;
+
+ if (!PROFILE_GetPrivateProfileString(section, entry, "", buffer,
+ sizeof(buffer), filename, FALSE))
+ return def_val;
+
+ /* FIXME: if entry can be found but it's empty, then Win16 is
+ * supposed to return 0 instead of def_val ! Difficult/problematic
+ * to implement (every other failure also returns zero buffer),
+ * thus wait until testing framework avail for making sure nothing
+ * else gets broken that way. */
+ if (!buffer[0])
+ return (uint)def_val;
+
+ /* Don't use strtol() here !
+ * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
+ YES, scan for unsigned format ! (otherwise compatibility error) */
+ if (!sscanf(buffer, "%u", &result))
+ return 0;
+
+ return (uint)result;
+} // end of GetPrivateProfileInt
+
+
+/***********************************************************************
+ * GetPrivateProfileSectionA (KERNEL32.@)
+ ***********************************************************************/
+int GetPrivateProfileSection(LPCSTR section, LPSTR buffer,
+ DWORD len, LPCSTR filename)
+{
+ int ret = 0;
+
+ EnterCriticalSection( &PROFILE_CritSect );
+
+ if (PROFILE_Open(filename))
+ ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
+ FALSE, TRUE);
+
+ LeaveCriticalSection( &PROFILE_CritSect );
+ return ret;
+} // end of GetPrivateProfileSection
+
+
+/***********************************************************************
+ * WritePrivateProfileStringA (KERNEL32.@)
+ ***********************************************************************/
+bool WritePrivateProfileString(LPCSTR section, LPCSTR entry,
+ LPCSTR string, LPCSTR filename)
+{
+ bool ret = FALSE;
+
+ EnterCriticalSection( &PROFILE_CritSect );
+
+ if (PROFILE_Open(filename)) {
+ if (!section && !entry && !string) /* documented "file flush" case */
+ PROFILE_ReleaseFile(); /* always return FALSE in this case */
+ else {
+ if (!section) {
+ //FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
+ } else {
+ ret = PROFILE_SetString(section, entry, string, FALSE);
+
+ if (ret)
+ ret = PROFILE_FlushFile();
+
+ } // endif section
+
+ } // endif section || entry|| string
+
+ } // endif Open
+
+ LeaveCriticalSection( &PROFILE_CritSect );
+ return ret;
+} // end of WritePrivateProfileString
+
+
+/***********************************************************************
+ * WritePrivateProfileSectionA (KERNEL32.@)
+ ***********************************************************************/
+bool WritePrivateProfileSection(LPCSTR section,
+ LPCSTR string, LPCSTR filename )
+{
+ bool ret = FALSE;
+ LPSTR p ;
+
+ EnterCriticalSection(&PROFILE_CritSect);
+
+ if (PROFILE_Open(filename)) {
+ if (!section && !string)
+ PROFILE_ReleaseFile(); /* always return FALSE in this case */
+ else if (!string) { /* delete the named section*/
+ ret = PROFILE_SetString(section, NULL, NULL, FALSE);
+
+ if (ret)
+ ret = PROFILE_FlushFile();
+ } else {
+ PROFILE_DeleteAllKeys(section);
+ ret = TRUE;
+
+ while (*string) {
+ LPSTR buf = malloc(strlen(string) + 1);
+ strcpy(buf, string);
+
+ if ((p = strchr(buf, '='))) {
+ *p='\0';
+ ret = PROFILE_SetString(section, buf, p+1, TRUE);
+ } // endif p
+
+ free(buf);
+ string += strlen(string) + 1;
+
+ if (ret)
+ ret = PROFILE_FlushFile();
+
+ } // endwhile *string
+
+ } // endelse
+
+ } // endif Open
+
+ LeaveCriticalSection(&PROFILE_CritSect);
+ return ret;
+} // end of WritePrivateProfileSection
+
+
+/***********************************************************************
+ * GetPrivateProfileSectionNamesA (KERNEL32.@)
+ *
+ * Returns the section names contained in the specified file.
+ * FIXME: Where do we find this file when the path is relative?
+ * The section names are returned as a list of strings with an extra
+ * '\0' to mark the end of the list. Except for that the behavior
+ * depends on the Windows version.
+ *
+ * Win95:
+ * - if the buffer is 0 or 1 character long then it is as if it was of
+ * infinite length.
+ * - otherwise, if the buffer is to small only the section names that fit
+ * are returned.
+ * - note that this means if the buffer was to small to return even just
+ * the first section name then a single '\0' will be returned.
+ * - the return value is the number of characters written in the buffer,
+ * except if the buffer was too smal in which case len-2 is returned
+ *
+ * Win2000:
+ * - if the buffer is 0, 1 or 2 characters long then it is filled with
+ * '\0' and the return value is 0
+ * - otherwise if the buffer is too small then the first section name that
+ * does not fit is truncated so that the string list can be terminated
+ * correctly (double '\0')
+ * - the return value is the number of characters written in the buffer
+ * except for the trailing '\0'. If the buffer is too small, then the
+ * return value is len-2
+ * - Win2000 has a bug that triggers when the section names and the
+ * trailing '\0' fit exactly in the buffer. In that case the trailing
+ * '\0' is missing.
+ *
+ * Wine implements the observed Win2000 behavior (except for the bug).
+ *
+ * Note that when the buffer is big enough then the return value may be any
+ * value between 1 and len-1 (or len in Win95), including len-2.
+ */
+DWORD GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename)
+{
+ DWORD ret = 0;
+
+ if (trace > 1)
+ htrc("GPPSN: filename=%s\n", filename);
+
+ EnterCriticalSection(&PROFILE_CritSect);
+
+ if (PROFILE_Open(filename))
+ ret = PROFILE_GetSectionNames(buffer, size);
+
+ LeaveCriticalSection(&PROFILE_CritSect);
+ return ret;
+} // end of GetPrivateProfileSectionNames
+
+
+/************************************************************************
+ * Program to test the above
+ ************************************************************************/
+#ifdef TEST_MODULE
+int main(int argc, char**argv) {
+ char buff[128];
+ char *p, *inifile = "D:\\Plug\\Data\\contact.ini";
+ DWORD n;
+
+ n = GetPrivateProfileSectionNames(buff, 128, inifile);
+ printf("Sections: n=%d\n", n);
+
+ for (p = buff; *p; p += (strlen(p) + 1))
+ printf("section=[%s]\n", p);
+
+ GetPrivateProfileString("BER", "name", "?", buff, 128, inifile);
+ printf("[BER](name) = %s\n", buff);
+
+ WritePrivateProfileString("FOO", "city", NULL, inifile);
+ GetPrivateProfileString("FOO", "city", "?", buff, 128, inifile);
+ printf("[FOO](city) = %s\n", buff);
+
+ printf("FOO city: ");
+ fgets(buff, sizeof(buff), stdin);
+ if (buff[strlen(buff) - 1] == '\n')
+ buff[strlen(buff) - 1] = '\0';
+ WritePrivateProfileString("FOO", "city", buff, inifile);
+ GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
+ printf("After write, [FOO](City) = %s\n", buff);
+
+ printf("New city: ");
+ fgets(buff, sizeof(buff), stdin);
+ if (buff[strlen(buff) - 1] == '\n')
+ buff[strlen(buff) - 1] = '\0';
+ WritePrivateProfileString("FOO", "city", buff, inifile);
+ GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
+ printf("After update, [FOO](City) = %s\n", buff);
+
+ printf("FOO name: ");
+ fgets(buff, sizeof(buff), stdin);
+ if (buff[strlen(buff) - 1] == '\n')
+ buff[strlen(buff) - 1] = '\0';
+ WritePrivateProfileString("FOO", "name", buff, inifile);
+ GetPrivateProfileString("FOO", "name", "X", buff, 128, inifile);
+ printf("[FOO](name) = %s\n", buff);
+} // end of main
+#endif // TEST_MODULE
diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp
index dedee068ca0..36e920540aa 100644
--- a/storage/connect/libdoc.cpp
+++ b/storage/connect/libdoc.cpp
@@ -1,751 +1,751 @@
-/******************************************************************/
-/* 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"
-
-#include "sql_string.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) {
- 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;
- } // end of LIBXMLDOC constructor
-
-/******************************************************************/
-/* Initialize XML parser and check library compatibility. */
-/******************************************************************/
-bool LIBXMLDOC::Initialize(PGLOBAL g)
- {
-//int n = xmlKeepBlanksDefault(0);
- 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;
-
- // 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= global_fopen(g, MSGID_CANNOT_OPEN, 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)
- {
- const char *txt = (const char *)cnt;
- uint dummy_errors;
- uint32 len= copy_and_convert(buf, n, &my_charset_latin1, txt,
- strlen(txt), &my_charset_utf8_general_ci,
- &dummy_errors);
- buf[len]= '\0';
- return 0;
- } // end of Decode
-
-/******************************************************************/
-/* Convert node or attribute content to latin characters. */
-/******************************************************************/
-xmlChar *LIBXMLDOC::Encode(PGLOBAL g, char *txt)
- {
- const CHARSET_INFO *ics= &my_charset_latin1; // TODO: Field->charset()
- const CHARSET_INFO *ocs= &my_charset_utf8_general_ci;
- size_t i = strlen(txt);
- size_t o = i * ocs->mbmaxlen / ics->mbmaxlen + 1;
- char *buf;
- if (g) {
- buf = (char*)PlugSubAlloc(g, NULL, o);
- } else {
- o = 1024;
- buf = Buf;
- } // endif g
- uint dummy_errors;
- uint32 len= copy_and_convert(buf, o, ocs,
- txt, i, ics,
- &dummy_errors);
- buf[len]= '\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
+/******************************************************************/
+/* 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"
+
+#include "sql_string.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) {
+ 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;
+ } // end of LIBXMLDOC constructor
+
+/******************************************************************/
+/* Initialize XML parser and check library compatibility. */
+/******************************************************************/
+bool LIBXMLDOC::Initialize(PGLOBAL g)
+ {
+//int n = xmlKeepBlanksDefault(0);
+ 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;
+
+ // 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= global_fopen(g, MSGID_CANNOT_OPEN, 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)
+ {
+ const char *txt = (const char *)cnt;
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, n, &my_charset_latin1, txt,
+ strlen(txt), &my_charset_utf8_general_ci,
+ &dummy_errors);
+ buf[len]= '\0';
+ return 0;
+ } // end of Decode
+
+/******************************************************************/
+/* Convert node or attribute content to latin characters. */
+/******************************************************************/
+xmlChar *LIBXMLDOC::Encode(PGLOBAL g, char *txt)
+ {
+ const CHARSET_INFO *ics= &my_charset_latin1; // TODO: Field->charset()
+ const CHARSET_INFO *ocs= &my_charset_utf8_general_ci;
+ size_t i = strlen(txt);
+ size_t o = i * ocs->mbmaxlen / ics->mbmaxlen + 1;
+ char *buf;
+ if (g) {
+ buf = (char*)PlugSubAlloc(g, NULL, o);
+ } else {
+ o = 1024;
+ buf = Buf;
+ } // endif g
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, o, ocs,
+ txt, i, ics,
+ &dummy_errors);
+ buf[len]= '\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
diff --git a/storage/connect/libdoc.h b/storage/connect/libdoc.h
index 6da45d613f1..7f6e0b5c291 100644
--- a/storage/connect/libdoc.h
+++ b/storage/connect/libdoc.h
@@ -1,144 +1,144 @@
-/******************************************************************/
-/* 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;
- } 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;
- 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
+/******************************************************************/
+/* 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;
+ } 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;
+ 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
diff --git a/storage/connect/macutil.cpp b/storage/connect/macutil.cpp
index 25b832078f3..44382cdafb4 100644
--- a/storage/connect/macutil.cpp
+++ b/storage/connect/macutil.cpp
@@ -1,318 +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
+/***********************************************************************/
+/* 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
diff --git a/storage/connect/macutil.h b/storage/connect/macutil.h
index 063daf44167..8a3e97e12e1 100644
--- a/storage/connect/macutil.h
+++ b/storage/connect/macutil.h
@@ -1,36 +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
+// 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
diff --git a/storage/connect/maputil.cpp b/storage/connect/maputil.cpp
index d7389d26032..c068c09b364 100644
--- a/storage/connect/maputil.cpp
+++ b/storage/connect/maputil.cpp
@@ -1,172 +1,172 @@
-#include "my_global.h"
-#ifdef UNIX
-#include "osutil.h"
-#include <errno.h>
-#include <stddef.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= global_open(g, MSGID_NONE, 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
+#include "my_global.h"
+#ifdef UNIX
+#include "osutil.h"
+#include <errno.h>
+#include <stddef.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= global_open(g, MSGID_NONE, 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
diff --git a/storage/connect/maputil.h b/storage/connect/maputil.h
index 4fbba23c23a..8ab41487a63 100644
--- a/storage/connect/maputil.h
+++ b/storage/connect/maputil.h
@@ -1,22 +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__ */
+#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__ */
diff --git a/storage/connect/messages.h b/storage/connect/messages.h
index 872d41ad49a..b55ec39b235 100644
--- a/storage/connect/messages.h
+++ b/storage/connect/messages.h
@@ -1,13 +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 */
-/* ---------------------------------------------------------------------- */
+/**************************************************************************/
+/* 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 */
+/* ---------------------------------------------------------------------- */
diff --git a/storage/connect/msgid.h b/storage/connect/msgid.h
index 36b47378d46..7a9f9438472 100644
--- a/storage/connect/msgid.h
+++ b/storage/connect/msgid.h
@@ -1,1013 +1,1013 @@
-#define MSG_BAD_ARRAY_VAL 239
-#define MSG_BAD_SET_CASE 240
-#define MSG_MISSING_ARG 241
-#define MSG_NO_SUB_VAL 242
-#define MSG_PREC_VBLP_NULL 243
-#define MSG_X_ON_TAB 244
-#define MSG_BAD_COLCRT_ARG 245
-#define MSG_BAD_COLSIZE 246
-#define MSG_BAD_COL_ENTRY 247
-#define MSG_BAD_COL_TYPE 248
-#define MSG_BAD_FILE_LIST 249
-#define MSG_BAD_GETVIEW_RET 250
-#define MSG_BAD_OFFSET_VAL 251
-#define MSG_BAD_TABLE_LINE 252
-#define MSG_BAD_TABLE_TYPE 253
-#define MSG_COLSEC_TOO_BIG 254
-#define MSG_COL_HAS_NO_DEF 255
-#define MSG_COL_NOT_CODED 256
-#define MSG_ERASED 257
-#define MSG_ERASE_FAILED 258
-#define MSG_INDEX_DROPPED 259
-#define MSG_INDX_ALL_DROP 260
-#define MSG_INV_QUALIFIER 261
-#define MSG_LOADING_DB 262
-#define MSG_NO_COL_FOUND 263
-#define MSG_NO_COL_SECTION 264
-#define MSG_NO_FEAT_SUPPORT 265
-#define MSG_NO_FILE_LIST 266
-#define MSG_NO_INDEX 267
-#define MSG_NO_MORE_VAR 268
-#define MSG_NO_MUL_VCT 269
-#define MSG_NO_OPT_COLUMN 270
-#define MSG_NO_SUCH_INDEX 271
-#define MSG_NO_SUCH_TABLE 272
-#define MSG_NO_TABLE_INDEX 273
-#define MSG_OPEN_ERROR_ON 274
-#define MSG_RECORD_ERROR 275
-#define MSG_SUBSET_ERROR 276
-#define MSG_TABLE_ALREADY 277
-#define MSG_TABLE_NOT_IN_DB 278
-#define MSG_TABLE_NO_OPT 279
-#define MSG_TAB_NOT_LOADED 280
-#define MSG_TAB_NOT_SPEC 281
-#define MSG_TB_VW_NOTIN_DB 282
-#define MSG_TOO_MANY_COLTAB 283
-#define MSG_TOO_MANY_JUMPS 284
-#define MSG_TOO_MANY_TABLES 285
-#define MSG_VIEW_ALREADY 286
-#define MSG_VIEW_NOT_IN_DB 287
-#define MSG_WRITE_ERROR 288
-#define MSG_XDB_DEL_ERROR 289
-#define MSG_COL_NOTIN_GRPBY 290
-#define MSG_DOMAIN_ERROR 291
-#define MSG_NO_TOKEN_DB 292
-#define MSG_SPCOL_READONLY 293
-#define MSG_TYPE_VALUE_ERR 294
-#define MSG_UNDEFINED_AM 295
-#define MSG_VALUE_ERROR 296
-#define MSG_SORTING_VAL 297
-#define MSG_NAME_CONV_ERR 298
-#define MSG_WS_CONV_ERR 299
-#define MSG_BAD_COMPARE_OP 300
-#define MSG_BAD_EXP_ARGTYPE 301
-#define MSG_BAD_IN_ARGTYPE 302
-#define MSG_BAD_SUBSEL_IN_X 303
-#define MSG_IN_ARGTYPE_MISM 304
-#define MSG_ROW_ARGNB_ERR 305
-#define MSG_TYPE_CONV_ERROR 306
-#define MSG_NO_MAP_INSERT 307
-#define MSG_SEEK_ERROR 308
-#define MSG_BAD_DBF_FILE 309
-#define MSG_BAD_DBF_REC 310
-#define MSG_BAD_DBF_TYPE 311
-#define MSG_BAD_HEADER 312
-#define MSG_BAD_HEAD_END 313
-#define MSG_BAD_LRECL 314
-#define MSG_BIN_MODE_FAIL 315
-#define MSG_DBASE_FILE 316
-#define MSG_FOXPRO_FILE 317
-#define MSG_NOT_A_DBF_FILE 318
-#define MSG_NO_0DH_HEAD 319
-#define MSG_NO_DBF_INSERT 320
-#define MSG_NO_READ_32 321
-#define MSG_NO_MODE_PADDED 322
-#define MSG_SETEOF_ERROR 323
-#define MSG_REMOVE_ERROR 324
-#define MSG_RENAME_ERROR 325
-#define MSG_BAD_HEADER_VAL 326
-#define MSG_BAD_MAX_NREC 327
-#define MSG_HEAD_OPEN_ERROR 328
-#define MSG_HEAD_READ_ERROR 329
-#define MSG_HEAD_WRITE_ERR 330
-#define MSG_MAP_VEC_ONLY 331
-#define MSG_MKEMPTY_NIY 332
-#define MSG_BAD_BLK_SIZE 333
-#define MSG_BAD_LINE_LEN 334
-#define MSG_FUNC_ERR_S 335
-#define MSG_INV_RAND_ACC 336
-#define MSG_NOP_ZLIB_INDEX 337
-#define MSG_NO_PART_DEL 338
-#define MSG_NO_PAR_BLK_INS 339
-#define MSG_NO_SETPOS_YET 340
-#define MSG_BAD_ARRAY_OPER 341
-#define MSG_BAD_FILTER 342
-#define MSG_BAD_FILTER_CONV 343
-#define MSG_BAD_HAV_FILTYPE 344
-#define MSG_BAD_TYPE_LIKE 345
-#define MSG_ILL_FILTER_CONV 346
-#define MSG_IN_WITHOUT_SUB 347
-#define MSG_UNMATCH_FIL_ARG 348
-#define MSG_VALUE_NOT_ALLOC 349
-#define MSG_VOID_FIRST_ARG 350
-#define MSG_DISTINCT_ERROR 351
-#define MSG_INV_FNC_BUFTYPE 352
-#define MSG_INV_SET_SUBTYPE 353
-#define MSG_NO_AGGR_FUNC 354
-#define MSG_APP_STILL_ACTIV 355
-#define MSG_AREAFILE_NOTFND 356
-#define MSG_BAD_LANG_SIZE 357
-#define MSG_BAD_PARAMETERS 358
-#define MSG_BAD_PARAM_TYPE 359
-#define MSG_GRAM_ALLOC_ERR 360
-#define MSG_GRAM_MISMATCH 361
-#define MSG_GRAM_SUBSET_ERR 362
-#define MSG_INVALID_BIP 363
-#define MSG_LANGUAGE_QUIT 364
-#define MSG_LANG_ALREADY_UP 365
-#define MSG_LANG_BAD_SAVE 366
-#define MSG_LANG_NOT_FREED 367
-#define MSG_LANG_SAVED 368
-#define MSG_LANG_WR_LEN_ERR 369
-#define MSG_LDF_ALLOC_ERROR 370
-#define MSG_LDF_W_LEN_ERROR 371
-#define MSG_LNG_NOT_IN_LIST 372
-#define MSG_METAFILE_NOTFND 373
-#define MSG_NODE_SUBSET_ERR 374
-#define MSG_NO_LANG_TO_QUIT 375
-#define MSG_NO_MORE_LANG 376
-#define MSG_ONE_LANG_YET 377
-#define MSG_ON_LANGUAGE 378
-#define MSG_OPEN_W_ERROR 379
-#define MSG_RULE_SUBSET_ERR 380
-#define MSG_UP_LANGUAGE 381
-#define MSG_VM_LANG 382
-#define MSG_BUILD_INDEX 383
-#define MSG_CD_ORDER_ERROR 384
-#define MSG_DSORT_LOG_ERROR 385
-#define MSG_JOIN_KEY_NO_COL 386
-#define MSG_KEY_ALLOC_ERROR 387
-#define MSG_LOGICAL_ERROR 388
-#define MSG_MEM_ALLOC_ERR 389
-#define MSG_QUERY_CANCELLED 390
-#define MSG_RC_READING 391
-#define MSG_REORDER_INDEX 392
-#define MSG_SORTING_INDEX 393
-#define MSG_SORT_JOIN_INDEX 394
-#define MSG_TOO_MANY_KEYS 395
-#define MSG_TYPE_MISMATCH 396
-#define MSG_REGISTER_ERR 397
-#define MSG_XPATH_CNTX_ERR 398
-#define MSG_XPATH_EVAL_ERR 399
-#define MSG_API_CONF_ERROR 400
-#define MSG_BAD_HANDLE_VAL 401
-#define MSG_COL_NUM_MISM 402
-#define MSG_CONNECT_CANCEL 403
-#define MSG_INV_COLUMN_TYPE 404
-#define MSG_NO_CONNECT_ADDR 405
-#define MSG_NO_TABCOL_DATA 406
-#define MSG_NO_TAB_DATA 407
-#define MSG_SEQUENCE_ERROR 408
-#define MSG_SQL_CONF_ERROR 409
-#define MSG_CONNECTED 410
-#define MSG_CONN_CLOSED 411
-#define MSG_CONN_CREATED 412
-#define MSG_CONN_DROPPED 413
-#define MSG_CONN_OPEN 414
-#define MSG_CONN_SUC_OPEN 415
-#define MSG_DISCONNECTED 416
-#define MSG_IS_NOT_CONN 417
-#define MSG_NAME_IS_USED 418
-#define MSG_NO_SUCH_SERVER 419
-#define MSG_BAD_COLIST_ITEM 420
-#define MSG_BAD_COLIST_TYPE 421
-#define MSG_BAD_COL_IN_FILT 422
-#define MSG_BAD_FUNC_ARG 423
-#define MSG_BAD_FUNC_ARGTYP 424
-#define MSG_BAD_OPERATOR 425
-#define MSG_BAD_PROJNUM 426
-#define MSG_BAD_SEM_DOMAIN 427
-#define MSG_CLN_NOT_IN_JOIN 428
-#define MSG_COLIST_BAD_TYPE 429
-#define MSG_COLUMN_ERROR 430
-#define MSG_COL_NOT_EXIST 431
-#define MSG_COL_NOT_FOUND 432
-#define MSG_COL_NOT_IN_JOIN 433
-#define MSG_DUPLICAT_COUNT 434
-#define MSG_DUP_PROJNUM 435
-#define MSG_FILTER_ATTACH 436
-#define MSG_GRBY_TAB_NOTIMP 437
-#define MSG_NON_DUP_HAVING 438
-#define MSG_NOT_IMPL_JOIN 439
-#define MSG_NOT_IMPL_SET 440
-#define MSG_NO_COL_IN_TABLE 441
-#define MSG_NO_MULT_HAVING 442
-#define MSG_NO_TABLE_DESC 443
-#define MSG_REMOVE_NOT_IMPL 444
-#define MSG_TYPE_TO_VERIFY 445
-#define MSG_UNDEF_COL_COUNT 446
-#define MSG_UNKNOWN_NAME 447
-#define MSG_WRONG_COL_NUM 448
-#define MSG_ALL_DELETED 449
-#define MSG_BAD_LOCALE 450
-#define MSG_BAD_QUERY_TYPE 451
-#define MSG_BUFSIZE_ERROR 452
-#define MSG_END_OF_DELETE 453
-#define MSG_END_OF_INSERT 454
-#define MSG_END_OF_QUERY 455
-#define MSG_END_OF_UPDATE 456
-#define MSG_NCOL_GT_MAXCOL 457
-#define MSG_OPEN_ERROR_IS 458
-#define MSG_SET_LOCALE 459
-#define MSG_X_ARG_ADDED 460
-#define MSG_ALG_CHOICE_AUTO 461
-#define MSG_ALG_CHOICE_BAD 462
-#define MSG_ALG_CHOICE_QRY 463
-#define MSG_ALG_CURLY_BRK 464
-#define MSG_ALTER_DB_ERR 465
-#define MSG_APPL_IS_ACTIVE 466
-#define MSG_APPL_NOT_INIT 467
-#define MSG_AVGLEN_ERROR 468
-#define MSG_BAD_DEF_TYPE 469
-#define MSG_BAD_DIST_JN_FIL 470
-#define MSG_BAD_DIST_JOIN 471
-#define MSG_BAD_DOM_COL_DEF 472
-#define MSG_BAD_FIELD_FMT 473
-#define MSG_BAD_OUTER_JOIN 474
-#define MSG_BAD_SETTINGS 475
-#define MSG_BAD_XMODE_VAL 476
-#define MSG_DATABASE_ACTIVE 477
-#define MSG_DATABASE_LOADED 478
-#define MSG_DB_ALREADY_DEF 479
-#define MSG_DB_ALTERED 480
-#define MSG_DB_CREATED 481
-#define MSG_DB_REMOVED 482
-#define MSG_DB_STOPPED 483
-#define MSG_DIS_NOHEAD_JOIN 484
-#define MSG_DROP_DB_ERR 485
-#define MSG_DUP_COL_NAME 486
-#define MSG_EXECUTING 487
-#define MSG_EXEC_MODE_SET 488
-#define MSG_INDEX_CREATED 489
-#define MSG_INV_DATA_PATH 490
-#define MSG_INV_WORK_PATH 491
-#define MSG_IN_USE 492
-#define MSG_LIC_NO_MYSQL 493
-#define MSG_LINE_LENGTH 494
-#define MSG_LINE_MAXLIN 495
-#define MSG_LINE_MAXRES 496
-#define MSG_LINE_MAXTMP 497
-#define MSG_MAC_WIN_ONLY 498
-#define MSG_MALLOC_NULL 499
-#define MSG_MAP_NO_MORE 500
-#define MSG_MISSING_COL_DEF 501
-#define MSG_MISSING_CONNECT 502
-#define MSG_MISSING_SERV_DB 503
-#define MSG_MISS_NAME_LRECL 504
-#define MSG_MISS_TABLE_LIST 505
-#define MSG_MISS_VCT_ELMT 506
-#define MSG_NEW_CHAR_NULL 507
-#define MSG_NODEF_FROM_VIEW 508
-#define MSG_NO_COL_ADDING 509
-#define MSG_NO_COL_DEF_AS 510
-#define MSG_NO_DATABASE 511
-#define MSG_NO_FULL_JOIN 512
-#define MSG_NO_FUL_OUT_JOIN 513
-#define MSG_NO_HEAD_JOIN 514
-#define MSG_NO_ODBC_COL 515
-#define MSG_NO_SELECTED_DB 516
-#define MSG_NO_SELF_PIVOT 517
-#define MSG_NULL_QUERY 518
-#define MSG_READY 519
-#define MSG_SEC_NOT_FOUND 520
-#define MSG_SET_OP_NOT_IMPL 521
-#define MSG_TABLE_ALTERED 522
-#define MSG_TABLE_CREATED 523
-#define MSG_TABLE_DROPPED 524
-#define MSG_TDB_NXT_NOT_NUL 525
-#define MSG_TYPE_DEF_MISM 526
-#define MSG_TYPE_RECFM_MISM 527
-#define MSG_VIEW_CREATED 528
-#define MSG_VIEW_DROPPED 529
-#define MSG_ANSWER_TYPE 530
-#define MSG_COPY_BAD_PHASE 531
-#define MSG_LIST 532
-#define MSG_MEM_ALLOC_ERROR 533
-#define MSG_PTR_NOT_FOUND 534
-#define MSG_SEMANTIC_TREE 535
-#define MSG_WRONG_TYPE 536
-#define MSG_ARRAY_ERROR 537
-#define MSG_BAD_EVAL_TYPE 538
-#define MSG_BAD_FILTER_LINK 539
-#define MSG_BAD_IN_ENDING 540
-#define MSG_BAD_IN_STRING 541
-#define MSG_BAD_LIST_TYPE 542
-#define MSG_BAD_ORDER_MODE 543
-#define MSG_BAD_ORDER_TYPE 544
-#define MSG_GROUP_ON_FUNC 545
-#define MSG_GRP_LIST_MISMAT 546
-#define MSG_LINEAR_ERROR 547
-#define MSG_NO_FUNC_ORDER 548
-#define MSG_NO_OP_MODIF 549
-#define MSG_NO_TABLE_LIST 550
-#define MSG_ORDER_TWICE 551
-#define MSG_UNKNOWN_ERROR 552
-#define MSG_VOID_IN_STRING 553
-#define MSG_VOID_ORDER_LIST 554
-#define MSG_ACCESS_VIOLATN 555
-#define MSG_ARRAY_BNDS_EXCD 556
-#define MSG_BREAKPOINT 557
-#define MSG_CONTROL_C_EXIT 558
-#define MSG_DATA_MISALIGN 559
-#define MSG_FLT_BAD_RESULT 560
-#define MSG_FLT_DENORMAL_OP 561
-#define MSG_FLT_INVALID_OP 562
-#define MSG_FLT_OVERFLOW 563
-#define MSG_FLT_STACK_CHECK 564
-#define MSG_FLT_UNDERFLOW 565
-#define MSG_FLT_ZERO_DIVIDE 566
-#define MSG_GUARD_PAGE 567
-#define MSG_ILLEGAL_INSTR 568
-#define MSG_INT_OVERFLOW 569
-#define MSG_INT_ZERO_DIVIDE 570
-#define MSG_INVALID_DISP 571
-#define MSG_INVALID_HANDLE 572
-#define MSG_NEW_RETURN_NULL 573
-#define MSG_NONCONT_EXCEPT 574
-#define MSG_NO_ACTIVE_DB 575
-#define MSG_NO_MEMORY 576
-#define MSG_PAGE_ERROR 577
-#define MSG_PARSING_QUERY 578
-#define MSG_PRIV_INSTR 579
-#define MSG_SINGLE_STEP 580
-#define MSG_SQL_BAD_TYPE 581
-#define MSG_UNKNOWN_EXCPT 582
-#define MSG_WRONG_FUNCTION 583
-#define MSG_BAD_RESULT_TYPE 584
-#define MSG_BUFF_TOO_SMALL 585
-#define MSG_COL_ALLOC_ERROR 586
-#define MSG_DATA_IS_NULL 587
-#define MSG_GET_ERROR 588
-#define MSG_INV_COL_DATATYP 589
-#define MSG_INV_INIPATH 590
-#define MSG_NO_NBLIN_CONT 591
-#define MSG_NO_SERVER_FOUND 592
-#define MSG_TYPES_ERROR 593
-#define MSG_UNDEFINED_PATH 594
-#define MSG_UNKNOWN_PATH 595
-#define MSG_WRONG_DB_LIST 596
-#define MSG_BAD_SPECIAL_CMD 597
-#define MSG_CURSOR_SET 598
-#define MSG_EVAL_EXPIRED 599
-#define MSG_EVAL_ONLY 600
-#define MSG_INV_SPECIAL_CMD 601
-#define MSG_PROGRESS_INFO 602
-#define MSG_PROMPT_CANCEL 603
-#define MSG_ARG_ALREADY_SET 604
-#define MSG_BAD_ARG_NUM 605
-#define MSG_BAD_CHECK_VAL 606
-#define MSG_BAD_EXEC_MODE 607
-#define MSG_BAD_MAX_PARAM 608
-#define MSG_BAD_MAX_SETTING 609
-#define MSG_BAD_USETEMP 610
-#define MSG_BAD_USETEMP_VAL 611
-#define MSG_CHECK_LEVEL 612
-#define MSG_COLS_REDUCED 613
-#define MSG_COLUMN_MISMATCH 614
-#define MSG_COL_NOT_IN_DB 615
-#define MSG_DB_NOT_SPEC 616
-#define MSG_DONE 617
-#define MSG_EXEC_MODE_IS 618
-#define MSG_EXEC_MODE_RESET 619
-#define MSG_HUGE_DEFAULT 620
-#define MSG_INDEX_ONE_SAVE 621
-#define MSG_INDEX_SEP_SAVE 622
-#define MSG_INVALID_OPTION 623
-#define MSG_INV_COL_NUM 624
-#define MSG_INV_INFO_TYPE 625
-#define MSG_INV_RESULT_TYPE 626
-#define MSG_LANG_ACTIVE 627
-#define MSG_MAX_BITMAP 628
-#define MSG_MYSQL_CNC_OFF 629
-#define MSG_MYSQL_CNC_ON 630
-#define MSG_MYSQL_NOT_SUP 631
-#define MSG_MY_CNC_ALREADY 632
-#define MSG_NO_AVAIL_RESULT 633
-#define MSG_NO_HQL_CONV 634
-#define MSG_NO_MYSQL_CONN 635
-#define MSG_NO_UNIX_CATINFO 636
-#define MSG_OPENING 637
-#define MSG_PLUG_NOT_RUN 638
-#define MSG_PROMPT_NIY 639
-#define MSG_QUERY_SAVED 640
-#define MSG_REC_SKIPPED 641
-#define MSG_ROWS_SELECTED 642
-#define MSG_ROWS_TRUNCATED 643
-#define MSG_SLEEP 644
-#define MSG_SPEC_CMD_SEP 645
-#define MSG_SYSTEM_ERROR 646
-#define MSG_UNLOADABLE 647
-#define MSG_UNLOADABLE_PRM 648
-#define MSG_USETEMP_IS 649
-#define MSG_USETEMP_RESET 650
-#define MSG_USETEMP_SET 651
-#define MSG_USING_INDEX 652
-#define MSG_VOID_QUERY 653
-#define MSG_WORK_TOO_SMALL 654
-#define MSG_WRITING_QUERY 655
-#define MSG_X_ARG_SET 656
-#define MSG_BAS_NS_LIST 657
-#define MSG_DOM_NOT_SUPP 658
-#define MSG_AFTER 659
-#define MSG_ARG_OUT_CONTEXT 660
-#define MSG_ARG_OUT_RANGE 661
-#define MSG_ARG_PTR_NOSEM 662
-#define MSG_ARG_PTR_NOSEMS 663
-#define MSG_BAD_ARG_TYPE 664
-#define MSG_ERR_RET_RULE 665
-#define MSG_ERR_RET_TYPE 666
-#define MSG_FUNC_REF_DEL 667
-#define MSG_INV_TOPSEM_CMD 668
-#define MSG_NON_EVAL_SEM 669
-#define MSG_N_FULL_PARSES 670
-#define MSG_PARSE_NULL_SEM 671
-#define MSG_PNODE_RULE 672
-#define MSG_SCAN_NOT_IMP 673
-#define MSG_SEM_BAD_REF 674
-#define MSG_SEM_UNKNOWN 675
-#define MSG_SUBARG_NOSEM 676
-#define MSG_SUBARG_OUTRANGE 677
-#define MSG_SYNTAX_ERROR 678
-#define MSG_TOPSEM_ERROR 679
-#define MSG_UNKN_ERR_CODE 680
-#define MSG_ATTRIBUTE_ERROR 681
-#define MSG_BAD_PHRASE_NB 682
-#define MSG_INV_OPERATOR 683
-#define MSG_NO_LANGUAGE 684
-#define MSG_PIX_ERROR 685
-#define MSG_PIX_TEST_ERROR 686
-#define MSG_PLUG_NOT_INIT 687
-#define MSG_STACK_ERROR 688
-#define MSG_STACK_OVERFLOW 689
-#define MSG_APPL_ACCESSIBLE 690
-#define MSG_APPL_BAD_SAVE 691
-#define MSG_APPL_CREATED 692
-#define MSG_APPL_NOT_LOADED 693
-#define MSG_APPL_QUIT 694
-#define MSG_APPL_SAVED 695
-#define MSG_ARG_NOT_AN_ATTR 696
-#define MSG_ATT_NOT_CASE 697
-#define MSG_ATT_POSCODE_BIG 698
-#define MSG_BAD_EDIT_INIT 699
-#define MSG_BAD_FPARM_NEXT 700
-#define MSG_BAD_PHASE_NUM 701
-#define MSG_BAD_SUBLST_TYPE 702
-#define MSG_BAD_USERBLK_LEN 703
-#define MSG_COPY_INV_TYPE 704
-#define MSG_DEBUG_NOT_ACTIV 705
-#define MSG_DEBUG_SET_INV 706
-#define MSG_DICTIONARY 707
-#define MSG_ENDSTR_MISMATCH 708
-#define MSG_ERROR_NO_PARM 709
-#define MSG_EXECUTION_ERROR 710
-#define MSG_FILE_NOT_FOUND 711
-#define MSG_INPUT 712
-#define MSG_INPUT_KEYBD_YET 713
-#define MSG_INV_CONC_BIP 714
-#define MSG_INV_DOMAIN_TYPE 715
-#define MSG_INV_PARAMETER 716
-#define MSG_INV_PARM_TYPE 717
-#define MSG_INV_TRANSF_USE 718
-#define MSG_INV_TYPE_SPEC 719
-#define MSG_LDF_RN_MISMATCH 720
-#define MSG_LDF_WLEN_ERROR 721
-#define MSG_MOVE_INV_TYPE 722
-#define MSG_NODE_FOR_CHAR 723
-#define MSG_NOT_IMPLEMENTED 724
-#define MSG_NOT_IMPL_YET 725
-#define MSG_NOT_MODIFIABLE 726
-#define MSG_NO_ACTIVE_APPL 727
-#define MSG_NO_ACTIVE_UDIC 728
-#define MSG_NO_AREA_FILE 729
-#define MSG_NO_EDITED_LANG 730
-#define MSG_NO_PARAMETER 731
-#define MSG_NO_RCUR_DSK_YET 732
-#define MSG_NO_SOURCE 733
-#define MSG_ONE_PARAM_ONLY 734
-#define MSG_READING_FROM 735
-#define MSG_RESET_TO 736
-#define MSG_STRING_INV_LIST 737
-#define MSG_UNKNOWN_SEM 738
-#define MSG_USED_FREE_MEM 739
-#define MSG_WRONG_PASSWORD 740
-#define MSG_WRONG_USERFILE 741
-#define MSG_ACT_ALLOC_FAIL 742
-#define MSG_APPL_ACTIVE 743
-#define MSG_BAD_CASE_SPEC 744
-#define MSG_DOSALMEM_NOMEM 745
-#define MSG_EXIT_FROM_LANG 746
-#define MSG_GLOBAL_ERROR 747
-#define MSG_HUGE_WARNING_1 748
-#define MSG_HUGE_WARNING_2 749
-#define MSG_LANG_ALLOC_FAIL 750
-#define MSG_MALLOC_ERROR 751
-#define MSG_NO_INIT_LANG 752
-#define MSG_NULL_ENTRY 753
-#define MSG_READ_MEM_ERROR 754
-#define MSG_READ_SEG_ERROR 755
-#define MSG_RECEIVED 756
-#define MSG_RET_FROM_LANG 757
-#define MSG_STRG_NOT_FOUND 758
-#define MSG_SUBALLOC_ERROR 759
-#define MSG_SUBAL_HUGE_ERR 760
-#define MSG_S_ACCESS_DENIED 761
-#define MSG_S_ERROR 762
-#define MSG_S_ERROR_NUM 763
-#define MSG_S_INTRUPT_ERROR 764
-#define MSG_S_INVALID_PARM 765
-#define MSG_S_INV_ADDRESS 766
-#define MSG_S_UNKNOWN_ERROR 767
-#define MSG_VOID_POS_DICT 768
-#define MSG_WORK_AREA 769
-#define MSG_BAD_AGGREG_FUNC 770
-#define MSG_BAD_MAX_HAVING 771
-#define MSG_BUILDING_GROUPS 772
-#define MSG_CD_ONE_STEP 773
-#define MSG_CNTDIS_COL_LOST 774
-#define MSG_COMPUTING 775
-#define MSG_DISTINCT_ROWS 776
-#define MSG_DISTINCT_VALUES 777
-#define MSG_FETCHING_DATA 778
-#define MSG_FETCHING_ROWS 779
-#define MSG_GROUPBY_NOT_ALL 780
-#define MSG_HAVING_FILTER 781
-#define MSG_IDLE 782
-#define MSG_INTERNAL 783
-#define MSG_INV_QUERY_TYPE 784
-#define MSG_MAKING_DISTINCT 785
-#define MSG_MAXTMP_TRUNCATE 786
-#define MSG_MEM_ALLOC_YET 787
-#define MSG_NOT_ENOUGH_MEM 788
-#define MSG_NO_NULL_CONST 789
-#define MSG_OFFSET_NOT_SUPP 790
-#define MSG_OPENING_QUERY 791
-#define MSG_OPEN_SORT_ERROR 792
-#define MSG_PROC_WOULD_LOOP 793
-#define MSG_RSC_ALLOC_ERROR 794
-#define MSG_SMART_SORTING 795
-#define MSG_SMART_SORT_ERR 796
-#define MSG_SORTING 797
-#define MSG_DEF_ALLOC_ERROR 798
-#define MSG_GET_FUNC_ERR 799
-#define MSG_PROCADD_ERROR 800
-#define MSG_PXDEF_IS_NULL 801
-#define MSG_SHARED_LIB_ERR 802
-#define MSG_ADPOS_IN_DICTP 803
-#define MSG_BAD_CHAR_SPEC 804
-#define MSG_BAD_GENRE 805
-#define MSG_BAD_INPUT 806
-#define MSG_BAD_LOCDFON_ARG 807
-#define MSG_BAD_LOCNODE_USE 808
-#define MSG_BAD_POS_CODE 809
-#define MSG_BAD_POS_TYPE 810
-#define MSG_BAD_TYPE_FOR_S 811
-#define MSG_BLOCK_NO_MATCH 812
-#define MSG_BXP_NULL 813
-#define MSG_DIRECT_VARTOK 814
-#define MSG_FSBPARP_NULL 815
-#define MSG_LOCSTRG_TOO_BIG 816
-#define MSG_MISSING_POS 817
-#define MSG_NO_POS_ADDED 818
-#define MSG_NO_TERM_IN_TOK 819
-#define MSG_POS_TOO_LONG 820
-#define MSG_RENUM_RULES 821
-#define MSG_RULE_ENTERED 822
-#define MSG_TOO_MANY_POS 823
-#define MSG_TO_FTR_NOT_NULL 824
-#define MSG_TO_PIX_NOT_NULL 825
-#define MSG_TO_SEM_NOT_NULL 826
-#define MSG_UNKNOWN_POS 827
-#define MSG_UNKNOWN_SYNONYM 828
-#define MSG_USE_NO_MATCH 829
-#define MSG_ALLOC_ERROR 830
-#define MSG_ARG_TWO_CONST 831
-#define MSG_BAD_ARGTYPES 832
-#define MSG_BAD_ARGUMENTS 833
-#define MSG_BAD_ROW_VALIST 834
-#define MSG_BAD_ROW_VALNB 835
-#define MSG_BAD_SCF_ARGTYPE 836
-#define MSG_BAD_SUB_SELECT 837
-#define MSG_BAD_TYPE_FOR_IN 838
-#define MSG_CONNECT_ERROR 839
-#define MSG_EXIT_EVAL_ERR 840
-#define MSG_FORMAT_ERROR 841
-#define MSG_INIT_ERROR 842
-#define MSG_INVALID_OPER 843
-#define MSG_NO_SFEXIT_UNIX 844
-#define MSG_READING_RECORD 845
-#define MSG_REQU_ARG_NUM 846
-#define MSG_SFUNC_NOT_IMPL 847
-#define MSG_UNKNOWN_DOMAIN 848
-#define MSG_WRONG_ARG_NUM 849
-#define MSG_WRONG_OP_PARM 850
-#define MSG_WRONG_PARMS 851
-#define MSG_AMBIG_CORREL 852
-#define MSG_BAD_CHECK_TYPE 853
-#define MSG_BAD_CORREL 854
-#define MSG_BAD_XOBJ_TYPE 855
-#define MSG_HBUF_TOO_SMALL 856
-#define MSG_MISSING 857
-#define MSG_MULT_DISTINCT 858
-#define MSG_NO_TABLE_COL 859
-#define MSG_ARG_REF_LOOP 860
-#define MSG_GETCWD_ERR_NO 861
-#define MSG_UNRESOLVED_ARG 862
-#define MSG_ARGS_SYNTAX_ERR 863
-#define MSG_AMBIG_COL_QUAL 864
-#define MSG_AMBIG_SPEC_COL 865
-#define MSG_BAD_COL_QUALIF 866
-#define MSG_BAD_FETCH_RC 867
-#define MSG_BAD_FILTER_OP 868
-#define MSG_BAD_HAV_FILTER 869
-#define MSG_BAD_JOIN_FILTER 870
-#define MSG_BAD_SET_TYPE 871
-#define MSG_BAD_SPECIAL_COL 872
-#define MSG_BAD_SPEC_COLUMN 873
-#define MSG_BAD_SQL_PARAM 874
-#define MSG_BAD_TABLE_LIST 875
-#define MSG_BAD_UPD_COR 876
-#define MSG_BAD_VALUE_TYPE 877
-#define MSG_BUILD_DIST_GRPS 878
-#define MSG_CHECKING_ROWS 879
-#define MSG_COL_INVAL_TABLE 880
-#define MSG_COL_ISNOT_TABLE 881
-#define MSG_COL_NOTIN_TABLE 882
-#define MSG_COL_NOTIN_UPDT 883
-#define MSG_COMPUTING_DIST 884
-#define MSG_COMPUTING_FUNC 885
-#define MSG_DELETING_ROWS 886
-#define MSG_ERROR 887
-#define MSG_FILGRP_NO_TABLE 888
-#define MSG_FILTER_NO_TABLE 889
-#define MSG_INSERTING 890
-#define MSG_INSERT_MISMATCH 891
-#define MSG_INV_FILTER 892
-#define MSG_INV_UPDT_TABLE 893
-#define MSG_INV_VALUE_LIST 894
-#define MSG_INV_WHERE_JOIN 895
-#define MSG_NOT_LINEARIZED 896
-#define MSG_NO_CONST_FILTER 897
-#define MSG_NO_INDEX_GBX 898
-#define MSG_READB_BAD_INIT 899
-#define MSG_READING 900
-#define MSG_SEVERAL_TREES 901
-#define MSG_UNKNW_QRY_TYPE 902
-#define MSG_UNQ_COL_SEV_TAB 903
-#define MSG_UPDATING_ROWS 904
-#define MSG_VAL_TOO_LONG 905
-#define MSG_BAD_FILTEST_OP 906
-#define MSG_BAD_SUBSEL_TYPE 907
-#define MSG_BAD_SUB_RESULT 908
-#define MSG_CORREL_NO_QRY 909
-#define MSG_FLTST_NO_CORREL 910
-#define MSG_NO_MEM_CORR_SUB 911
-#define MSG_NO_QUERY_ARRAY 912
-#define MSG_PROCESS_SUBQRY 913
-#define MSG_READ_ERROR_RC 914
-#define MSG_RES_NOT_UNIQUE 915
-#define MSG_SQL_BLOCK_MISM 916
-#define MSG_SUBQRY_ONEITEM 917
-#define MSG_SUB_OPEN_YET 918
-#define MSG_FNC_NOTIN_SLIST 919
-#define MSG_NO_FORMAT_COL 920
-#define MSG_ORDER_OUT_RANGE 921
-#define MSG_SEP_IN_FIELD 922
-#define MSG_BAD_OPEN_MODE 923
-#define MSG_OPEN_MODE_ERROR 924
-#define MSG_RECORD_NO_SEP 925
-#define MSG_BAD_BLK_ESTIM 926
-#define MSG_BAD_FREQ_SET 927
-#define MSG_BAD_RECFM 928
-#define MSG_BAD_RECFM_VAL 929
-#define MSG_BIN_F_TOO_LONG 930
-#define MSG_CHSIZE_ERROR 931
-#define MSG_DEL_FILE_ERR 932
-#define MSG_DEL_READ_ERROR 933
-#define MSG_DEL_WRITE_ERROR 934
-#define MSG_DVAL_NOTIN_LIST 935
-#define MSG_FILELEN_ERROR 936
-#define MSG_FILE_IS_EMPTY 937
-#define MSG_FILE_MAP_ERROR 938
-#define MSG_FPUTS_ERROR 939
-#define MSG_FSEEK_ERROR 940
-#define MSG_FSETPOS_ERROR 941
-#define MSG_FTELL_ERROR 942
-#define MSG_FUNCTION_ERROR 943
-#define MSG_GETFILESIZE_ERR 944
-#define MSG_GET_DIST_VALS 945
-#define MSG_INDEX_NOT_DEF 946
-#define MSG_INDEX_YET_ON 947
-#define MSG_INDX_COL_NOTIN 948
-#define MSG_INDX_EXIST_YET 949
-#define MSG_INSERT_ERROR 950
-#define MSG_INV_DEF_READ 951
-#define MSG_INV_MAP_POS 952
-#define MSG_MAP_VIEW_ERROR 953
-#define MSG_NOT_FIXED_LEN 954
-#define MSG_NO_INDEX_IN 955
-#define MSG_NO_RECOV_SPACE 956
-#define MSG_NO_ROWID_FOR_AM 957
-#define MSG_OPEN_STRERROR 958
-#define MSG_OPTBLK_RD_ERR 959
-#define MSG_OPTBLK_WR_ERR 960
-#define MSG_OPT_BMAP_RD_ERR 961
-#define MSG_OPT_BMAP_WR_ERR 962
-#define MSG_OPT_DVAL_RD_ERR 963
-#define MSG_OPT_DVAL_WR_ERR 964
-#define MSG_OPT_LOGIC_ERR 965
-#define MSG_READ_ERROR 966
-#define MSG_READ_SEEK_ERROR 967
-#define MSG_TABLE_NOT_OPT 968
-#define MSG_TRUNCATE_ERROR 969
-#define MSG_VALUE_TOO_LONG 970
-#define MSG_WRITE_SEEK_ERR 971
-#define MSG_BAD_BIN_FMT 972
-#define MSG_BAD_DEF_READ 973
-#define MSG_COL_NOT_SORTED 974
-#define MSG_ERROR_IN_LSK 975
-#define MSG_ERROR_IN_SFP 976
-#define MSG_FILE_OPEN_YET 977
-#define MSG_FWRITE_ERROR 978
-#define MSG_INVALID_FTYPE 979
-#define MSG_INV_REC_POS 980
-#define MSG_NO_BIG_DELETE 981
-#define MSG_NO_CLUSTER_COL 982
-#define MSG_OPEN_ERROR 983
-#define MSG_OPTIMIZING 984
-#define MSG_OPT_CANCELLED 985
-#define MSG_OPT_HEAD_RD_ERR 986
-#define MSG_OPT_HEAD_WR_ERR 987
-#define MSG_OPT_MAX_RD_ERR 988
-#define MSG_OPT_MAX_WR_ERR 989
-#define MSG_OPT_MIN_RD_ERR 990
-#define MSG_OPT_MIN_WR_ERR 991
-#define MSG_OPT_NOT_MATCH 992
-#define MSG_VALUE_TOO_BIG 993
-#define MSG_WRITING_ERROR 994
-#define MSG_BAD_FIELD_RANK 995
-#define MSG_BAD_FLD_FORMAT 996
-#define MSG_BAD_FLD_LENGTH 997
-#define MSG_BAD_LINEFLD_FMT 998
-#define MSG_BAD_QUOTE_FIELD 999
-#define MSG_CANNOT_OPEN 1000
-#define MSG_EOF_AFTER_LINE 1001
-#define MSG_ERR_READING_REC 1002
-#define MSG_FIELD_TOO_LONG 1003
-#define MSG_FLD_TOO_LNG_FOR 1004
-#define MSG_FMT_WRITE_NIY 1005
-#define MSG_LINE_TOO_LONG 1006
-#define MSG_LRECL_TOO_SMALL 1007
-#define MSG_MISPLACED_QUOTE 1008
-#define MSG_MISSING_EOL 1009
-#define MSG_MISSING_FIELD 1010
-#define MSG_MISSING_FNAME 1011
-#define MSG_NO_FLD_FORMAT 1012
-#define MSG_QUOTE_IN_QUOTE 1013
-#define MSG_TOO_MANY_FIELDS 1014
-#define MSG_UNBALANCE_QUOTE 1015
-#define MSG_BAD_JCOL_TYPE 1016
-#define MSG_COL_USED_TWICE 1017
-#define MSG_DUMMY_NO_COLS 1018
-#define MSG_JCT_MISS_COLS 1019
-#define MSG_JCT_MISS_TABLE 1020
-#define MSG_JCT_NO_FILTER 1021
-#define MSG_JCT_NO_KEY 1022
-#define MSG_NO_DMY_DIR_ACC 1023
-#define MSG_NO_EXP_LINK 1024
-#define MSG_VIR_NO_DELETE 1025
-#define MSG_VIR_READ_ONLY 1026
-#define MSG_BAD_JOIN_EXP 1027
-#define MSG_BAD_JOIN_OP 1028
-#define MSG_COLUMN_NOT_KEY 1029
-#define MSG_DB_SORT_ERROR 1030
-#define MSG_LINJOINDB_ERROR 1031
-#define MSG_MULT_KEY_ERROR 1032
-#define MSG_NO_JOIN_TO_EXP 1033
-#define MSG_NO_MULCOL_JOIN 1034
-#define MSG_READ_ONLY 1035
-#define MSG_ROWID_NOT_IMPL 1036
-#define MSG_SETRECPOS_NIY 1037
-#define MSG_TABLE_MULT_JOIN 1038
-#define MSG_TDB_USE_ERROR 1039
-#define MSG_BAD_CARDINALITY 1040
-#define MSG_BAD_DIRECTORY 1041
-#define MSG_BAD_FILE_HANDLE 1042
-#define MSG_INV_DIRCOL_OFST 1043
-#define MSG_MAXSIZE_ERROR 1044
-#define MSG_MUL_MAKECOL_ERR 1045
-#define MSG_NEXT_FILE_ERROR 1046
-#define MSG_NO_DIR_INDX_RD 1047
-#define MSG_NO_INDEX_READ 1048
-#define MSG_NO_MUL_DIR_ACC 1049
-#define MSG_SRCH_CLOSE_ERR 1050
-#define MSG_TABDIR_READONLY 1051
-#define MSG_TABMUL_READONLY 1052
-#define MSG_NO_EXT_FILTER 1053
-#define MSG_NO_EXT_UPDATE 1054
-#define MSG_NO_ODBC_DELETE 1055
-#define MSG_NO_ODBC_DIRECT 1056
-#define MSG_NO_ODBC_MUL 1057
-#define MSG_NO_ODBC_SPECOL 1058
-#define MSG_NO_UPDEL_JOIN 1059
-#define MSG_ODBC_READ_ONLY 1060
-#define MSG_PARM_CNT_MISS 1061
-#define MSG_COLNAM_TOO_LONG 1062
-#define MSG_NOT_ENOUGH_COLS 1063
-#define MSG_NO_DEF_FNCCOL 1064
-#define MSG_NO_DEF_PIVOTCOL 1065
-#define MSG_NO_MATCH_COL 1066
-#define MSG_NO_MORE_COL 1067
-#define MSG_NO_PIV_DIR_ACC 1068
-#define MSG_NO_TABLE_DEL 1069
-#define MSG_SRC_TABLE_UNDEF 1070
-#define MSG_TABLE_READ_ONLY 1071
-#define MSG_TOO_MANY_COLS 1072
-#define MSG_BAD_COLDEF_TYPE 1073
-#define MSG_BAD_MERGE_TYPE 1074
-#define MSG_COL_NB_MISM 1075
-#define MSG_ERROR_OPENING 1076
-#define MSG_FETCH_NO_RES 1077
-#define MSG_LOAD_CDLL_ERROR 1078
-#define MSG_NO_NBCOL 1079
-#define MSG_NO_NBLIN 1080
-#define MSG_NO_PROMPTING 1081
-#define MSG_NO_REMOTE_FNC 1082
-#define MSG_NO_VIEW_COLDEF 1083
-#define MSG_PLG_READ_ONLY 1084
-#define MSG_PLM_NULL_SFP 1085
-#define MSG_QUERY_NOT_EXEC 1086
-#define MSG_REMOTE_CONN_ERR 1087
-#define MSG_RPC_SERVER_ERR 1088
-#define MSG_BAD_QUERY_OPEN 1089
-#define MSG_BAD_RETURN_TYPE 1090
-#define MSG_BAD_VIEW_OPEN 1091
-#define MSG_NO_QRY_DELETE 1092
-#define MSG_NO_SQL_DELETE 1093
-#define MSG_NO_VIEW_SORT 1094
-#define MSG_NULL_COL_VALUE 1095
-#define MSG_QRY_READ_ONLY 1096
-#define MSG_READCOL_ERROR 1097
-#define MSG_SQL_READ_ONLY 1098
-#define MSG_GET_NAME_ERR 1099
-#define MSG_INV_SUBTYPE 1100
-#define MSG_NO_CURLY_BRKT 1101
-#define MSG_NO_KEY_UPDATE 1102
-#define MSG_NO_SECTION_NAME 1103
-#define MSG_NO_SEC_UPDATE 1104
-#define MSG_SEC_KEY_FIRST 1105
-#define MSG_SEC_NAME_FIRST 1106
-#define MSG_NO_MATCHING_COL 1107
-#define MSG_BAD_BYTE_NUM 1108
-#define MSG_BAD_BYTE_READ 1109
-#define MSG_BAD_READ_NUMBER 1110
-#define MSG_BLK_IS_NULL 1111
-#define MSG_EMPTY_FILE 1112
-#define MSG_MAKE_EMPTY_FILE 1113
-#define MSG_MAKING 1114
-#define MSG_NO_VCT_DELETE 1115
-#define MSG_OPEN_EMPTY_FILE 1116
-#define MSG_OPT_INIT 1117
-#define MSG_SFP_ERROR 1118
-#define MSG_TO_BLK_IS_NULL 1119
-#define MSG_TRUNC_BY_ESTIM 1120
-#define MSG_UPDATE_ERROR 1121
-#define MSG_WRITE_STRERROR 1122
-#define MSG_WRITING 1123
-#define MSG_BAD_COL_XPATH 1124
-#define MSG_BAD_NODE_TYPE 1125
-#define MSG_BAD_VALNODE 1126
-#define MSG_BAD_VAL_UPDATE 1127
-#define MSG_COL_ALLOC_ERR 1128
-#define MSG_COM_ERROR 1129
-#define MSG_CONCAT_SUBNODE 1130
-#define MSG_CREATED_PLUGDB 1131
-#define MSG_DEPREC_FLAG 1132
-#define MSG_EMPTY_DOC 1133
-#define MSG_FAIL_ADD_NODE 1134
-#define MSG_FILE_UNFOUND 1135
-#define MSG_INIT_FAILED 1136
-#define MSG_INV_COL_TYPE 1137
-#define MSG_LOADING_FAILED 1138
-#define MSG_MISSING_NODE 1139
-#define MSG_MISSING_ROWNODE 1140
-#define MSG_MIS_TAG_LIST 1141
-#define MSG_NEW_DOC_FAILED 1142
-#define MSG_NO_ROW_NODE 1143
-#define MSG_VAL_ALLOC_ERR 1144
-#define MSG_XMLTAB_INIT_ERR 1145
-#define MSG_XML_INIT_ERROR 1146
-#define MSG_XPATH_NOT_SUPP 1147
-#define MSG_DLL_LOAD_ERROR 1148
-#define MSG_GZOPEN_ERROR 1149
-#define MSG_GZPUTS_ERROR 1150
-#define MSG_NO_ZIP_DELETE 1151
-#define MSG_NO_ZIP_DIR_ACC 1152
-#define MSG_UPD_ZIP_NOT_IMP 1153
-#define MSG_MAC_NO_DELETE 1154
-#define MSG_MAC_NO_INDEX 1155
-#define MSG_MAC_READ_ONLY 1156
-#define MSG_BAD_FIELD_TYPE 1157
-#define MSG_BAD_PARM_COUNT 1158
-#define MSG_NO_JOIN_UPDEL 1159
-#define MSG_NO_MYSQL_DELETE 1160
-#define MSG_NO_REF_DELETE 1161
-#define MSG_NO_REF_UPDATE 1162
-#define MSG_NO_SPEC_COL 1163
-#define MSG_ADD_NULL_DOM 1164
-#define MSG_BAD_DOM_VALUE 1165
-#define MSG_BAD_SET_STRING 1166
-#define MSG_BAD_VALBLK_INDX 1167
-#define MSG_BAD_VALBLK_TYPE 1168
-#define MSG_COMPUTE_NIY 1169
-#define MSG_DOMAIN_EMPTY 1170
-#define MSG_DOMAIN_FULL 1171
-#define MSG_DOM_FILE_ERROR 1172
-#define MSG_DOM_OPEN_ERROR 1173
-#define MSG_DOM_READ_ERROR 1174
-#define MSG_DOM_READ_ONLY 1175
-#define MSG_DOM_WRITE_ERROR 1176
-#define MSG_ERR_NUM_GT_MAX 1177
-#define MSG_INV_TOK_DOMAIN 1178
-#define MSG_MEMSIZE_TOO_BIG 1179
-#define MSG_NO_DOM_DELETE 1180
-#define MSG_NO_DOM_MATCH 1181
-#define MSG_SET_NULL_DOM 1182
-#define MSG_STRING_TOO_BIG 1183
-#define MSG_VALTYPE_NOMATCH 1184
-#define MSG_NO_DATE_FMT 1185
-#define MSG_NO_LISTVAL_HERE 1186
-#define MSG_BAD_COL_FORMAT 1187
-#define MSG_BAD_DATETIME 1188
-#define MSG_BAD_DATE_OPER 1189
-#define MSG_BAD_EXP_OPER 1190
-#define MSG_BAD_PAD_ARGTYP 1191
-#define MSG_BAD_TRIM_ARGTYP 1192
-#define MSG_BLKTYPLEN_MISM 1193
-#define MSG_COMPUTE_ERROR 1194
-#define MSG_FIX_OVFLW_ADD 1195
-#define MSG_FIX_OVFLW_TIMES 1196
-#define MSG_FIX_UNFLW_ADD 1197
-#define MSG_FIX_UNFLW_TIMES 1198
-#define MSG_HARRY_COMP_NIY 1199
-#define MSG_NO_CHAR_FROM 1200
-#define MSG_NO_FORMAT_TYPE 1201
-#define MSG_ONLY_LOG10_IMPL 1202
-#define MSG_OP_RES_TOO_LONG 1203
-#define MSG_SET_STR_TRUNC 1204
-#define MSG_SUB_RES_TOO_LNG 1205
-#define MSG_VALIST_MISMATCH 1206
-#define MSG_VALSTR_TOO_LONG 1207
-#define MSG_ZERO_DIVIDE 1208
-#define MSG_ADDVAL_ERROR 1209
-#define MSG_ARRAY_ALLOC_ERR 1210
-#define MSG_BAD_DEF_ARG 1211
-#define MSG_BAD_FUNC_MODE 1212
-#define MSG_BAD_INDEX_COL 1213
-#define MSG_BAD_INDEX_DEF 1214
-#define MSG_BAD_INDEX_FILE 1215
-#define MSG_BAD_INDEX_PART 1216
-#define MSG_EOF_INDEX_FILE 1217
-#define MSG_FILE_CLOSE_ERR 1218
-#define MSG_FILE_MAP_ERR 1219
-#define MSG_FUNC_ERRNO 1220
-#define MSG_FUNC_ERROR 1221
-#define MSG_GRP_COL_MISM 1222
-#define MSG_HANDLE_IS_NULL 1223
-#define MSG_HI_OFFSET_ERR 1224
-#define MSG_INDEX_DEF_ERR 1225
-#define MSG_INDEX_INIT_ERR 1226
-#define MSG_INDEX_NOT_UNIQ 1227
-#define MSG_INT_COL_ERROR 1228
-#define MSG_KEY_ALLOC_ERR 1229
-#define MSG_MAP_OBJ_ERR 1230
-#define MSG_MISS_LEAD_COL 1231
-#define MSG_NEW_TABLE_ERR 1232
-#define MSG_NO_KEY_COL 1233
-#define MSG_NO_PART_MAP 1234
-#define MSG_NUMVAL_NOMATCH 1235
-#define MSG_RANGE_NIY 1236
-#define MSG_RANGE_NO_JOIN 1237
-#define MSG_REDUCE_INDEX 1238
-#define MSG_SAVING_INDEX 1239
-#define MSG_TABLE_NO_INDEX 1240
-#define MSG_XCOL_MISMATCH 1241
-#define MSG_XFILE_READERR 1242
-#define MSG_XFILE_TOO_SMALL 1243
-#define MSG_XFILE_WRITERR 1244
-#define MSG_ADD_BAD_TYPE 1245
-#define MSG_BAD_ARRAY_TYPE 1246
-#define MSG_BAD_CONST_TYPE 1247
-#define MSG_BAD_CONV_TYPE 1248
-#define MSG_BAD_FLOAT_CONV 1249
-#define MSG_BAD_TEST_TYPE 1250
-#define MSG_FIND_BAD_TYPE 1251
+#define MSG_BAD_ARRAY_VAL 239
+#define MSG_BAD_SET_CASE 240
+#define MSG_MISSING_ARG 241
+#define MSG_NO_SUB_VAL 242
+#define MSG_PREC_VBLP_NULL 243
+#define MSG_X_ON_TAB 244
+#define MSG_BAD_COLCRT_ARG 245
+#define MSG_BAD_COLSIZE 246
+#define MSG_BAD_COL_ENTRY 247
+#define MSG_BAD_COL_TYPE 248
+#define MSG_BAD_FILE_LIST 249
+#define MSG_BAD_GETVIEW_RET 250
+#define MSG_BAD_OFFSET_VAL 251
+#define MSG_BAD_TABLE_LINE 252
+#define MSG_BAD_TABLE_TYPE 253
+#define MSG_COLSEC_TOO_BIG 254
+#define MSG_COL_HAS_NO_DEF 255
+#define MSG_COL_NOT_CODED 256
+#define MSG_ERASED 257
+#define MSG_ERASE_FAILED 258
+#define MSG_INDEX_DROPPED 259
+#define MSG_INDX_ALL_DROP 260
+#define MSG_INV_QUALIFIER 261
+#define MSG_LOADING_DB 262
+#define MSG_NO_COL_FOUND 263
+#define MSG_NO_COL_SECTION 264
+#define MSG_NO_FEAT_SUPPORT 265
+#define MSG_NO_FILE_LIST 266
+#define MSG_NO_INDEX 267
+#define MSG_NO_MORE_VAR 268
+#define MSG_NO_MUL_VCT 269
+#define MSG_NO_OPT_COLUMN 270
+#define MSG_NO_SUCH_INDEX 271
+#define MSG_NO_SUCH_TABLE 272
+#define MSG_NO_TABLE_INDEX 273
+#define MSG_OPEN_ERROR_ON 274
+#define MSG_RECORD_ERROR 275
+#define MSG_SUBSET_ERROR 276
+#define MSG_TABLE_ALREADY 277
+#define MSG_TABLE_NOT_IN_DB 278
+#define MSG_TABLE_NO_OPT 279
+#define MSG_TAB_NOT_LOADED 280
+#define MSG_TAB_NOT_SPEC 281
+#define MSG_TB_VW_NOTIN_DB 282
+#define MSG_TOO_MANY_COLTAB 283
+#define MSG_TOO_MANY_JUMPS 284
+#define MSG_TOO_MANY_TABLES 285
+#define MSG_VIEW_ALREADY 286
+#define MSG_VIEW_NOT_IN_DB 287
+#define MSG_WRITE_ERROR 288
+#define MSG_XDB_DEL_ERROR 289
+#define MSG_COL_NOTIN_GRPBY 290
+#define MSG_DOMAIN_ERROR 291
+#define MSG_NO_TOKEN_DB 292
+#define MSG_SPCOL_READONLY 293
+#define MSG_TYPE_VALUE_ERR 294
+#define MSG_UNDEFINED_AM 295
+#define MSG_VALUE_ERROR 296
+#define MSG_SORTING_VAL 297
+#define MSG_NAME_CONV_ERR 298
+#define MSG_WS_CONV_ERR 299
+#define MSG_BAD_COMPARE_OP 300
+#define MSG_BAD_EXP_ARGTYPE 301
+#define MSG_BAD_IN_ARGTYPE 302
+#define MSG_BAD_SUBSEL_IN_X 303
+#define MSG_IN_ARGTYPE_MISM 304
+#define MSG_ROW_ARGNB_ERR 305
+#define MSG_TYPE_CONV_ERROR 306
+#define MSG_NO_MAP_INSERT 307
+#define MSG_SEEK_ERROR 308
+#define MSG_BAD_DBF_FILE 309
+#define MSG_BAD_DBF_REC 310
+#define MSG_BAD_DBF_TYPE 311
+#define MSG_BAD_HEADER 312
+#define MSG_BAD_HEAD_END 313
+#define MSG_BAD_LRECL 314
+#define MSG_BIN_MODE_FAIL 315
+#define MSG_DBASE_FILE 316
+#define MSG_FOXPRO_FILE 317
+#define MSG_NOT_A_DBF_FILE 318
+#define MSG_NO_0DH_HEAD 319
+#define MSG_NO_DBF_INSERT 320
+#define MSG_NO_READ_32 321
+#define MSG_NO_MODE_PADDED 322
+#define MSG_SETEOF_ERROR 323
+#define MSG_REMOVE_ERROR 324
+#define MSG_RENAME_ERROR 325
+#define MSG_BAD_HEADER_VAL 326
+#define MSG_BAD_MAX_NREC 327
+#define MSG_HEAD_OPEN_ERROR 328
+#define MSG_HEAD_READ_ERROR 329
+#define MSG_HEAD_WRITE_ERR 330
+#define MSG_MAP_VEC_ONLY 331
+#define MSG_MKEMPTY_NIY 332
+#define MSG_BAD_BLK_SIZE 333
+#define MSG_BAD_LINE_LEN 334
+#define MSG_FUNC_ERR_S 335
+#define MSG_INV_RAND_ACC 336
+#define MSG_NOP_ZLIB_INDEX 337
+#define MSG_NO_PART_DEL 338
+#define MSG_NO_PAR_BLK_INS 339
+#define MSG_NO_SETPOS_YET 340
+#define MSG_BAD_ARRAY_OPER 341
+#define MSG_BAD_FILTER 342
+#define MSG_BAD_FILTER_CONV 343
+#define MSG_BAD_HAV_FILTYPE 344
+#define MSG_BAD_TYPE_LIKE 345
+#define MSG_ILL_FILTER_CONV 346
+#define MSG_IN_WITHOUT_SUB 347
+#define MSG_UNMATCH_FIL_ARG 348
+#define MSG_VALUE_NOT_ALLOC 349
+#define MSG_VOID_FIRST_ARG 350
+#define MSG_DISTINCT_ERROR 351
+#define MSG_INV_FNC_BUFTYPE 352
+#define MSG_INV_SET_SUBTYPE 353
+#define MSG_NO_AGGR_FUNC 354
+#define MSG_APP_STILL_ACTIV 355
+#define MSG_AREAFILE_NOTFND 356
+#define MSG_BAD_LANG_SIZE 357
+#define MSG_BAD_PARAMETERS 358
+#define MSG_BAD_PARAM_TYPE 359
+#define MSG_GRAM_ALLOC_ERR 360
+#define MSG_GRAM_MISMATCH 361
+#define MSG_GRAM_SUBSET_ERR 362
+#define MSG_INVALID_BIP 363
+#define MSG_LANGUAGE_QUIT 364
+#define MSG_LANG_ALREADY_UP 365
+#define MSG_LANG_BAD_SAVE 366
+#define MSG_LANG_NOT_FREED 367
+#define MSG_LANG_SAVED 368
+#define MSG_LANG_WR_LEN_ERR 369
+#define MSG_LDF_ALLOC_ERROR 370
+#define MSG_LDF_W_LEN_ERROR 371
+#define MSG_LNG_NOT_IN_LIST 372
+#define MSG_METAFILE_NOTFND 373
+#define MSG_NODE_SUBSET_ERR 374
+#define MSG_NO_LANG_TO_QUIT 375
+#define MSG_NO_MORE_LANG 376
+#define MSG_ONE_LANG_YET 377
+#define MSG_ON_LANGUAGE 378
+#define MSG_OPEN_W_ERROR 379
+#define MSG_RULE_SUBSET_ERR 380
+#define MSG_UP_LANGUAGE 381
+#define MSG_VM_LANG 382
+#define MSG_BUILD_INDEX 383
+#define MSG_CD_ORDER_ERROR 384
+#define MSG_DSORT_LOG_ERROR 385
+#define MSG_JOIN_KEY_NO_COL 386
+#define MSG_KEY_ALLOC_ERROR 387
+#define MSG_LOGICAL_ERROR 388
+#define MSG_MEM_ALLOC_ERR 389
+#define MSG_QUERY_CANCELLED 390
+#define MSG_RC_READING 391
+#define MSG_REORDER_INDEX 392
+#define MSG_SORTING_INDEX 393
+#define MSG_SORT_JOIN_INDEX 394
+#define MSG_TOO_MANY_KEYS 395
+#define MSG_TYPE_MISMATCH 396
+#define MSG_REGISTER_ERR 397
+#define MSG_XPATH_CNTX_ERR 398
+#define MSG_XPATH_EVAL_ERR 399
+#define MSG_API_CONF_ERROR 400
+#define MSG_BAD_HANDLE_VAL 401
+#define MSG_COL_NUM_MISM 402
+#define MSG_CONNECT_CANCEL 403
+#define MSG_INV_COLUMN_TYPE 404
+#define MSG_NO_CONNECT_ADDR 405
+#define MSG_NO_TABCOL_DATA 406
+#define MSG_NO_TAB_DATA 407
+#define MSG_SEQUENCE_ERROR 408
+#define MSG_SQL_CONF_ERROR 409
+#define MSG_CONNECTED 410
+#define MSG_CONN_CLOSED 411
+#define MSG_CONN_CREATED 412
+#define MSG_CONN_DROPPED 413
+#define MSG_CONN_OPEN 414
+#define MSG_CONN_SUC_OPEN 415
+#define MSG_DISCONNECTED 416
+#define MSG_IS_NOT_CONN 417
+#define MSG_NAME_IS_USED 418
+#define MSG_NO_SUCH_SERVER 419
+#define MSG_BAD_COLIST_ITEM 420
+#define MSG_BAD_COLIST_TYPE 421
+#define MSG_BAD_COL_IN_FILT 422
+#define MSG_BAD_FUNC_ARG 423
+#define MSG_BAD_FUNC_ARGTYP 424
+#define MSG_BAD_OPERATOR 425
+#define MSG_BAD_PROJNUM 426
+#define MSG_BAD_SEM_DOMAIN 427
+#define MSG_CLN_NOT_IN_JOIN 428
+#define MSG_COLIST_BAD_TYPE 429
+#define MSG_COLUMN_ERROR 430
+#define MSG_COL_NOT_EXIST 431
+#define MSG_COL_NOT_FOUND 432
+#define MSG_COL_NOT_IN_JOIN 433
+#define MSG_DUPLICAT_COUNT 434
+#define MSG_DUP_PROJNUM 435
+#define MSG_FILTER_ATTACH 436
+#define MSG_GRBY_TAB_NOTIMP 437
+#define MSG_NON_DUP_HAVING 438
+#define MSG_NOT_IMPL_JOIN 439
+#define MSG_NOT_IMPL_SET 440
+#define MSG_NO_COL_IN_TABLE 441
+#define MSG_NO_MULT_HAVING 442
+#define MSG_NO_TABLE_DESC 443
+#define MSG_REMOVE_NOT_IMPL 444
+#define MSG_TYPE_TO_VERIFY 445
+#define MSG_UNDEF_COL_COUNT 446
+#define MSG_UNKNOWN_NAME 447
+#define MSG_WRONG_COL_NUM 448
+#define MSG_ALL_DELETED 449
+#define MSG_BAD_LOCALE 450
+#define MSG_BAD_QUERY_TYPE 451
+#define MSG_BUFSIZE_ERROR 452
+#define MSG_END_OF_DELETE 453
+#define MSG_END_OF_INSERT 454
+#define MSG_END_OF_QUERY 455
+#define MSG_END_OF_UPDATE 456
+#define MSG_NCOL_GT_MAXCOL 457
+#define MSG_OPEN_ERROR_IS 458
+#define MSG_SET_LOCALE 459
+#define MSG_X_ARG_ADDED 460
+#define MSG_ALG_CHOICE_AUTO 461
+#define MSG_ALG_CHOICE_BAD 462
+#define MSG_ALG_CHOICE_QRY 463
+#define MSG_ALG_CURLY_BRK 464
+#define MSG_ALTER_DB_ERR 465
+#define MSG_APPL_IS_ACTIVE 466
+#define MSG_APPL_NOT_INIT 467
+#define MSG_AVGLEN_ERROR 468
+#define MSG_BAD_DEF_TYPE 469
+#define MSG_BAD_DIST_JN_FIL 470
+#define MSG_BAD_DIST_JOIN 471
+#define MSG_BAD_DOM_COL_DEF 472
+#define MSG_BAD_FIELD_FMT 473
+#define MSG_BAD_OUTER_JOIN 474
+#define MSG_BAD_SETTINGS 475
+#define MSG_BAD_XMODE_VAL 476
+#define MSG_DATABASE_ACTIVE 477
+#define MSG_DATABASE_LOADED 478
+#define MSG_DB_ALREADY_DEF 479
+#define MSG_DB_ALTERED 480
+#define MSG_DB_CREATED 481
+#define MSG_DB_REMOVED 482
+#define MSG_DB_STOPPED 483
+#define MSG_DIS_NOHEAD_JOIN 484
+#define MSG_DROP_DB_ERR 485
+#define MSG_DUP_COL_NAME 486
+#define MSG_EXECUTING 487
+#define MSG_EXEC_MODE_SET 488
+#define MSG_INDEX_CREATED 489
+#define MSG_INV_DATA_PATH 490
+#define MSG_INV_WORK_PATH 491
+#define MSG_IN_USE 492
+#define MSG_LIC_NO_MYSQL 493
+#define MSG_LINE_LENGTH 494
+#define MSG_LINE_MAXLIN 495
+#define MSG_LINE_MAXRES 496
+#define MSG_LINE_MAXTMP 497
+#define MSG_MAC_WIN_ONLY 498
+#define MSG_MALLOC_NULL 499
+#define MSG_MAP_NO_MORE 500
+#define MSG_MISSING_COL_DEF 501
+#define MSG_MISSING_CONNECT 502
+#define MSG_MISSING_SERV_DB 503
+#define MSG_MISS_NAME_LRECL 504
+#define MSG_MISS_TABLE_LIST 505
+#define MSG_MISS_VCT_ELMT 506
+#define MSG_NEW_CHAR_NULL 507
+#define MSG_NODEF_FROM_VIEW 508
+#define MSG_NO_COL_ADDING 509
+#define MSG_NO_COL_DEF_AS 510
+#define MSG_NO_DATABASE 511
+#define MSG_NO_FULL_JOIN 512
+#define MSG_NO_FUL_OUT_JOIN 513
+#define MSG_NO_HEAD_JOIN 514
+#define MSG_NO_ODBC_COL 515
+#define MSG_NO_SELECTED_DB 516
+#define MSG_NO_SELF_PIVOT 517
+#define MSG_NULL_QUERY 518
+#define MSG_READY 519
+#define MSG_SEC_NOT_FOUND 520
+#define MSG_SET_OP_NOT_IMPL 521
+#define MSG_TABLE_ALTERED 522
+#define MSG_TABLE_CREATED 523
+#define MSG_TABLE_DROPPED 524
+#define MSG_TDB_NXT_NOT_NUL 525
+#define MSG_TYPE_DEF_MISM 526
+#define MSG_TYPE_RECFM_MISM 527
+#define MSG_VIEW_CREATED 528
+#define MSG_VIEW_DROPPED 529
+#define MSG_ANSWER_TYPE 530
+#define MSG_COPY_BAD_PHASE 531
+#define MSG_LIST 532
+#define MSG_MEM_ALLOC_ERROR 533
+#define MSG_PTR_NOT_FOUND 534
+#define MSG_SEMANTIC_TREE 535
+#define MSG_WRONG_TYPE 536
+#define MSG_ARRAY_ERROR 537
+#define MSG_BAD_EVAL_TYPE 538
+#define MSG_BAD_FILTER_LINK 539
+#define MSG_BAD_IN_ENDING 540
+#define MSG_BAD_IN_STRING 541
+#define MSG_BAD_LIST_TYPE 542
+#define MSG_BAD_ORDER_MODE 543
+#define MSG_BAD_ORDER_TYPE 544
+#define MSG_GROUP_ON_FUNC 545
+#define MSG_GRP_LIST_MISMAT 546
+#define MSG_LINEAR_ERROR 547
+#define MSG_NO_FUNC_ORDER 548
+#define MSG_NO_OP_MODIF 549
+#define MSG_NO_TABLE_LIST 550
+#define MSG_ORDER_TWICE 551
+#define MSG_UNKNOWN_ERROR 552
+#define MSG_VOID_IN_STRING 553
+#define MSG_VOID_ORDER_LIST 554
+#define MSG_ACCESS_VIOLATN 555
+#define MSG_ARRAY_BNDS_EXCD 556
+#define MSG_BREAKPOINT 557
+#define MSG_CONTROL_C_EXIT 558
+#define MSG_DATA_MISALIGN 559
+#define MSG_FLT_BAD_RESULT 560
+#define MSG_FLT_DENORMAL_OP 561
+#define MSG_FLT_INVALID_OP 562
+#define MSG_FLT_OVERFLOW 563
+#define MSG_FLT_STACK_CHECK 564
+#define MSG_FLT_UNDERFLOW 565
+#define MSG_FLT_ZERO_DIVIDE 566
+#define MSG_GUARD_PAGE 567
+#define MSG_ILLEGAL_INSTR 568
+#define MSG_INT_OVERFLOW 569
+#define MSG_INT_ZERO_DIVIDE 570
+#define MSG_INVALID_DISP 571
+#define MSG_INVALID_HANDLE 572
+#define MSG_NEW_RETURN_NULL 573
+#define MSG_NONCONT_EXCEPT 574
+#define MSG_NO_ACTIVE_DB 575
+#define MSG_NO_MEMORY 576
+#define MSG_PAGE_ERROR 577
+#define MSG_PARSING_QUERY 578
+#define MSG_PRIV_INSTR 579
+#define MSG_SINGLE_STEP 580
+#define MSG_SQL_BAD_TYPE 581
+#define MSG_UNKNOWN_EXCPT 582
+#define MSG_WRONG_FUNCTION 583
+#define MSG_BAD_RESULT_TYPE 584
+#define MSG_BUFF_TOO_SMALL 585
+#define MSG_COL_ALLOC_ERROR 586
+#define MSG_DATA_IS_NULL 587
+#define MSG_GET_ERROR 588
+#define MSG_INV_COL_DATATYP 589
+#define MSG_INV_INIPATH 590
+#define MSG_NO_NBLIN_CONT 591
+#define MSG_NO_SERVER_FOUND 592
+#define MSG_TYPES_ERROR 593
+#define MSG_UNDEFINED_PATH 594
+#define MSG_UNKNOWN_PATH 595
+#define MSG_WRONG_DB_LIST 596
+#define MSG_BAD_SPECIAL_CMD 597
+#define MSG_CURSOR_SET 598
+#define MSG_EVAL_EXPIRED 599
+#define MSG_EVAL_ONLY 600
+#define MSG_INV_SPECIAL_CMD 601
+#define MSG_PROGRESS_INFO 602
+#define MSG_PROMPT_CANCEL 603
+#define MSG_ARG_ALREADY_SET 604
+#define MSG_BAD_ARG_NUM 605
+#define MSG_BAD_CHECK_VAL 606
+#define MSG_BAD_EXEC_MODE 607
+#define MSG_BAD_MAX_PARAM 608
+#define MSG_BAD_MAX_SETTING 609
+#define MSG_BAD_USETEMP 610
+#define MSG_BAD_USETEMP_VAL 611
+#define MSG_CHECK_LEVEL 612
+#define MSG_COLS_REDUCED 613
+#define MSG_COLUMN_MISMATCH 614
+#define MSG_COL_NOT_IN_DB 615
+#define MSG_DB_NOT_SPEC 616
+#define MSG_DONE 617
+#define MSG_EXEC_MODE_IS 618
+#define MSG_EXEC_MODE_RESET 619
+#define MSG_HUGE_DEFAULT 620
+#define MSG_INDEX_ONE_SAVE 621
+#define MSG_INDEX_SEP_SAVE 622
+#define MSG_INVALID_OPTION 623
+#define MSG_INV_COL_NUM 624
+#define MSG_INV_INFO_TYPE 625
+#define MSG_INV_RESULT_TYPE 626
+#define MSG_LANG_ACTIVE 627
+#define MSG_MAX_BITMAP 628
+#define MSG_MYSQL_CNC_OFF 629
+#define MSG_MYSQL_CNC_ON 630
+#define MSG_MYSQL_NOT_SUP 631
+#define MSG_MY_CNC_ALREADY 632
+#define MSG_NO_AVAIL_RESULT 633
+#define MSG_NO_HQL_CONV 634
+#define MSG_NO_MYSQL_CONN 635
+#define MSG_NO_UNIX_CATINFO 636
+#define MSG_OPENING 637
+#define MSG_PLUG_NOT_RUN 638
+#define MSG_PROMPT_NIY 639
+#define MSG_QUERY_SAVED 640
+#define MSG_REC_SKIPPED 641
+#define MSG_ROWS_SELECTED 642
+#define MSG_ROWS_TRUNCATED 643
+#define MSG_SLEEP 644
+#define MSG_SPEC_CMD_SEP 645
+#define MSG_SYSTEM_ERROR 646
+#define MSG_UNLOADABLE 647
+#define MSG_UNLOADABLE_PRM 648
+#define MSG_USETEMP_IS 649
+#define MSG_USETEMP_RESET 650
+#define MSG_USETEMP_SET 651
+#define MSG_USING_INDEX 652
+#define MSG_VOID_QUERY 653
+#define MSG_WORK_TOO_SMALL 654
+#define MSG_WRITING_QUERY 655
+#define MSG_X_ARG_SET 656
+#define MSG_BAS_NS_LIST 657
+#define MSG_DOM_NOT_SUPP 658
+#define MSG_AFTER 659
+#define MSG_ARG_OUT_CONTEXT 660
+#define MSG_ARG_OUT_RANGE 661
+#define MSG_ARG_PTR_NOSEM 662
+#define MSG_ARG_PTR_NOSEMS 663
+#define MSG_BAD_ARG_TYPE 664
+#define MSG_ERR_RET_RULE 665
+#define MSG_ERR_RET_TYPE 666
+#define MSG_FUNC_REF_DEL 667
+#define MSG_INV_TOPSEM_CMD 668
+#define MSG_NON_EVAL_SEM 669
+#define MSG_N_FULL_PARSES 670
+#define MSG_PARSE_NULL_SEM 671
+#define MSG_PNODE_RULE 672
+#define MSG_SCAN_NOT_IMP 673
+#define MSG_SEM_BAD_REF 674
+#define MSG_SEM_UNKNOWN 675
+#define MSG_SUBARG_NOSEM 676
+#define MSG_SUBARG_OUTRANGE 677
+#define MSG_SYNTAX_ERROR 678
+#define MSG_TOPSEM_ERROR 679
+#define MSG_UNKN_ERR_CODE 680
+#define MSG_ATTRIBUTE_ERROR 681
+#define MSG_BAD_PHRASE_NB 682
+#define MSG_INV_OPERATOR 683
+#define MSG_NO_LANGUAGE 684
+#define MSG_PIX_ERROR 685
+#define MSG_PIX_TEST_ERROR 686
+#define MSG_PLUG_NOT_INIT 687
+#define MSG_STACK_ERROR 688
+#define MSG_STACK_OVERFLOW 689
+#define MSG_APPL_ACCESSIBLE 690
+#define MSG_APPL_BAD_SAVE 691
+#define MSG_APPL_CREATED 692
+#define MSG_APPL_NOT_LOADED 693
+#define MSG_APPL_QUIT 694
+#define MSG_APPL_SAVED 695
+#define MSG_ARG_NOT_AN_ATTR 696
+#define MSG_ATT_NOT_CASE 697
+#define MSG_ATT_POSCODE_BIG 698
+#define MSG_BAD_EDIT_INIT 699
+#define MSG_BAD_FPARM_NEXT 700
+#define MSG_BAD_PHASE_NUM 701
+#define MSG_BAD_SUBLST_TYPE 702
+#define MSG_BAD_USERBLK_LEN 703
+#define MSG_COPY_INV_TYPE 704
+#define MSG_DEBUG_NOT_ACTIV 705
+#define MSG_DEBUG_SET_INV 706
+#define MSG_DICTIONARY 707
+#define MSG_ENDSTR_MISMATCH 708
+#define MSG_ERROR_NO_PARM 709
+#define MSG_EXECUTION_ERROR 710
+#define MSG_FILE_NOT_FOUND 711
+#define MSG_INPUT 712
+#define MSG_INPUT_KEYBD_YET 713
+#define MSG_INV_CONC_BIP 714
+#define MSG_INV_DOMAIN_TYPE 715
+#define MSG_INV_PARAMETER 716
+#define MSG_INV_PARM_TYPE 717
+#define MSG_INV_TRANSF_USE 718
+#define MSG_INV_TYPE_SPEC 719
+#define MSG_LDF_RN_MISMATCH 720
+#define MSG_LDF_WLEN_ERROR 721
+#define MSG_MOVE_INV_TYPE 722
+#define MSG_NODE_FOR_CHAR 723
+#define MSG_NOT_IMPLEMENTED 724
+#define MSG_NOT_IMPL_YET 725
+#define MSG_NOT_MODIFIABLE 726
+#define MSG_NO_ACTIVE_APPL 727
+#define MSG_NO_ACTIVE_UDIC 728
+#define MSG_NO_AREA_FILE 729
+#define MSG_NO_EDITED_LANG 730
+#define MSG_NO_PARAMETER 731
+#define MSG_NO_RCUR_DSK_YET 732
+#define MSG_NO_SOURCE 733
+#define MSG_ONE_PARAM_ONLY 734
+#define MSG_READING_FROM 735
+#define MSG_RESET_TO 736
+#define MSG_STRING_INV_LIST 737
+#define MSG_UNKNOWN_SEM 738
+#define MSG_USED_FREE_MEM 739
+#define MSG_WRONG_PASSWORD 740
+#define MSG_WRONG_USERFILE 741
+#define MSG_ACT_ALLOC_FAIL 742
+#define MSG_APPL_ACTIVE 743
+#define MSG_BAD_CASE_SPEC 744
+#define MSG_DOSALMEM_NOMEM 745
+#define MSG_EXIT_FROM_LANG 746
+#define MSG_GLOBAL_ERROR 747
+#define MSG_HUGE_WARNING_1 748
+#define MSG_HUGE_WARNING_2 749
+#define MSG_LANG_ALLOC_FAIL 750
+#define MSG_MALLOC_ERROR 751
+#define MSG_NO_INIT_LANG 752
+#define MSG_NULL_ENTRY 753
+#define MSG_READ_MEM_ERROR 754
+#define MSG_READ_SEG_ERROR 755
+#define MSG_RECEIVED 756
+#define MSG_RET_FROM_LANG 757
+#define MSG_STRG_NOT_FOUND 758
+#define MSG_SUBALLOC_ERROR 759
+#define MSG_SUBAL_HUGE_ERR 760
+#define MSG_S_ACCESS_DENIED 761
+#define MSG_S_ERROR 762
+#define MSG_S_ERROR_NUM 763
+#define MSG_S_INTRUPT_ERROR 764
+#define MSG_S_INVALID_PARM 765
+#define MSG_S_INV_ADDRESS 766
+#define MSG_S_UNKNOWN_ERROR 767
+#define MSG_VOID_POS_DICT 768
+#define MSG_WORK_AREA 769
+#define MSG_BAD_AGGREG_FUNC 770
+#define MSG_BAD_MAX_HAVING 771
+#define MSG_BUILDING_GROUPS 772
+#define MSG_CD_ONE_STEP 773
+#define MSG_CNTDIS_COL_LOST 774
+#define MSG_COMPUTING 775
+#define MSG_DISTINCT_ROWS 776
+#define MSG_DISTINCT_VALUES 777
+#define MSG_FETCHING_DATA 778
+#define MSG_FETCHING_ROWS 779
+#define MSG_GROUPBY_NOT_ALL 780
+#define MSG_HAVING_FILTER 781
+#define MSG_IDLE 782
+#define MSG_INTERNAL 783
+#define MSG_INV_QUERY_TYPE 784
+#define MSG_MAKING_DISTINCT 785
+#define MSG_MAXTMP_TRUNCATE 786
+#define MSG_MEM_ALLOC_YET 787
+#define MSG_NOT_ENOUGH_MEM 788
+#define MSG_NO_NULL_CONST 789
+#define MSG_OFFSET_NOT_SUPP 790
+#define MSG_OPENING_QUERY 791
+#define MSG_OPEN_SORT_ERROR 792
+#define MSG_PROC_WOULD_LOOP 793
+#define MSG_RSC_ALLOC_ERROR 794
+#define MSG_SMART_SORTING 795
+#define MSG_SMART_SORT_ERR 796
+#define MSG_SORTING 797
+#define MSG_DEF_ALLOC_ERROR 798
+#define MSG_GET_FUNC_ERR 799
+#define MSG_PROCADD_ERROR 800
+#define MSG_PXDEF_IS_NULL 801
+#define MSG_SHARED_LIB_ERR 802
+#define MSG_ADPOS_IN_DICTP 803
+#define MSG_BAD_CHAR_SPEC 804
+#define MSG_BAD_GENRE 805
+#define MSG_BAD_INPUT 806
+#define MSG_BAD_LOCDFON_ARG 807
+#define MSG_BAD_LOCNODE_USE 808
+#define MSG_BAD_POS_CODE 809
+#define MSG_BAD_POS_TYPE 810
+#define MSG_BAD_TYPE_FOR_S 811
+#define MSG_BLOCK_NO_MATCH 812
+#define MSG_BXP_NULL 813
+#define MSG_DIRECT_VARTOK 814
+#define MSG_FSBPARP_NULL 815
+#define MSG_LOCSTRG_TOO_BIG 816
+#define MSG_MISSING_POS 817
+#define MSG_NO_POS_ADDED 818
+#define MSG_NO_TERM_IN_TOK 819
+#define MSG_POS_TOO_LONG 820
+#define MSG_RENUM_RULES 821
+#define MSG_RULE_ENTERED 822
+#define MSG_TOO_MANY_POS 823
+#define MSG_TO_FTR_NOT_NULL 824
+#define MSG_TO_PIX_NOT_NULL 825
+#define MSG_TO_SEM_NOT_NULL 826
+#define MSG_UNKNOWN_POS 827
+#define MSG_UNKNOWN_SYNONYM 828
+#define MSG_USE_NO_MATCH 829
+#define MSG_ALLOC_ERROR 830
+#define MSG_ARG_TWO_CONST 831
+#define MSG_BAD_ARGTYPES 832
+#define MSG_BAD_ARGUMENTS 833
+#define MSG_BAD_ROW_VALIST 834
+#define MSG_BAD_ROW_VALNB 835
+#define MSG_BAD_SCF_ARGTYPE 836
+#define MSG_BAD_SUB_SELECT 837
+#define MSG_BAD_TYPE_FOR_IN 838
+#define MSG_CONNECT_ERROR 839
+#define MSG_EXIT_EVAL_ERR 840
+#define MSG_FORMAT_ERROR 841
+#define MSG_INIT_ERROR 842
+#define MSG_INVALID_OPER 843
+#define MSG_NO_SFEXIT_UNIX 844
+#define MSG_READING_RECORD 845
+#define MSG_REQU_ARG_NUM 846
+#define MSG_SFUNC_NOT_IMPL 847
+#define MSG_UNKNOWN_DOMAIN 848
+#define MSG_WRONG_ARG_NUM 849
+#define MSG_WRONG_OP_PARM 850
+#define MSG_WRONG_PARMS 851
+#define MSG_AMBIG_CORREL 852
+#define MSG_BAD_CHECK_TYPE 853
+#define MSG_BAD_CORREL 854
+#define MSG_BAD_XOBJ_TYPE 855
+#define MSG_HBUF_TOO_SMALL 856
+#define MSG_MISSING 857
+#define MSG_MULT_DISTINCT 858
+#define MSG_NO_TABLE_COL 859
+#define MSG_ARG_REF_LOOP 860
+#define MSG_GETCWD_ERR_NO 861
+#define MSG_UNRESOLVED_ARG 862
+#define MSG_ARGS_SYNTAX_ERR 863
+#define MSG_AMBIG_COL_QUAL 864
+#define MSG_AMBIG_SPEC_COL 865
+#define MSG_BAD_COL_QUALIF 866
+#define MSG_BAD_FETCH_RC 867
+#define MSG_BAD_FILTER_OP 868
+#define MSG_BAD_HAV_FILTER 869
+#define MSG_BAD_JOIN_FILTER 870
+#define MSG_BAD_SET_TYPE 871
+#define MSG_BAD_SPECIAL_COL 872
+#define MSG_BAD_SPEC_COLUMN 873
+#define MSG_BAD_SQL_PARAM 874
+#define MSG_BAD_TABLE_LIST 875
+#define MSG_BAD_UPD_COR 876
+#define MSG_BAD_VALUE_TYPE 877
+#define MSG_BUILD_DIST_GRPS 878
+#define MSG_CHECKING_ROWS 879
+#define MSG_COL_INVAL_TABLE 880
+#define MSG_COL_ISNOT_TABLE 881
+#define MSG_COL_NOTIN_TABLE 882
+#define MSG_COL_NOTIN_UPDT 883
+#define MSG_COMPUTING_DIST 884
+#define MSG_COMPUTING_FUNC 885
+#define MSG_DELETING_ROWS 886
+#define MSG_ERROR 887
+#define MSG_FILGRP_NO_TABLE 888
+#define MSG_FILTER_NO_TABLE 889
+#define MSG_INSERTING 890
+#define MSG_INSERT_MISMATCH 891
+#define MSG_INV_FILTER 892
+#define MSG_INV_UPDT_TABLE 893
+#define MSG_INV_VALUE_LIST 894
+#define MSG_INV_WHERE_JOIN 895
+#define MSG_NOT_LINEARIZED 896
+#define MSG_NO_CONST_FILTER 897
+#define MSG_NO_INDEX_GBX 898
+#define MSG_READB_BAD_INIT 899
+#define MSG_READING 900
+#define MSG_SEVERAL_TREES 901
+#define MSG_UNKNW_QRY_TYPE 902
+#define MSG_UNQ_COL_SEV_TAB 903
+#define MSG_UPDATING_ROWS 904
+#define MSG_VAL_TOO_LONG 905
+#define MSG_BAD_FILTEST_OP 906
+#define MSG_BAD_SUBSEL_TYPE 907
+#define MSG_BAD_SUB_RESULT 908
+#define MSG_CORREL_NO_QRY 909
+#define MSG_FLTST_NO_CORREL 910
+#define MSG_NO_MEM_CORR_SUB 911
+#define MSG_NO_QUERY_ARRAY 912
+#define MSG_PROCESS_SUBQRY 913
+#define MSG_READ_ERROR_RC 914
+#define MSG_RES_NOT_UNIQUE 915
+#define MSG_SQL_BLOCK_MISM 916
+#define MSG_SUBQRY_ONEITEM 917
+#define MSG_SUB_OPEN_YET 918
+#define MSG_FNC_NOTIN_SLIST 919
+#define MSG_NO_FORMAT_COL 920
+#define MSG_ORDER_OUT_RANGE 921
+#define MSG_SEP_IN_FIELD 922
+#define MSG_BAD_OPEN_MODE 923
+#define MSG_OPEN_MODE_ERROR 924
+#define MSG_RECORD_NO_SEP 925
+#define MSG_BAD_BLK_ESTIM 926
+#define MSG_BAD_FREQ_SET 927
+#define MSG_BAD_RECFM 928
+#define MSG_BAD_RECFM_VAL 929
+#define MSG_BIN_F_TOO_LONG 930
+#define MSG_CHSIZE_ERROR 931
+#define MSG_DEL_FILE_ERR 932
+#define MSG_DEL_READ_ERROR 933
+#define MSG_DEL_WRITE_ERROR 934
+#define MSG_DVAL_NOTIN_LIST 935
+#define MSG_FILELEN_ERROR 936
+#define MSG_FILE_IS_EMPTY 937
+#define MSG_FILE_MAP_ERROR 938
+#define MSG_FPUTS_ERROR 939
+#define MSG_FSEEK_ERROR 940
+#define MSG_FSETPOS_ERROR 941
+#define MSG_FTELL_ERROR 942
+#define MSG_FUNCTION_ERROR 943
+#define MSG_GETFILESIZE_ERR 944
+#define MSG_GET_DIST_VALS 945
+#define MSG_INDEX_NOT_DEF 946
+#define MSG_INDEX_YET_ON 947
+#define MSG_INDX_COL_NOTIN 948
+#define MSG_INDX_EXIST_YET 949
+#define MSG_INSERT_ERROR 950
+#define MSG_INV_DEF_READ 951
+#define MSG_INV_MAP_POS 952
+#define MSG_MAP_VIEW_ERROR 953
+#define MSG_NOT_FIXED_LEN 954
+#define MSG_NO_INDEX_IN 955
+#define MSG_NO_RECOV_SPACE 956
+#define MSG_NO_ROWID_FOR_AM 957
+#define MSG_OPEN_STRERROR 958
+#define MSG_OPTBLK_RD_ERR 959
+#define MSG_OPTBLK_WR_ERR 960
+#define MSG_OPT_BMAP_RD_ERR 961
+#define MSG_OPT_BMAP_WR_ERR 962
+#define MSG_OPT_DVAL_RD_ERR 963
+#define MSG_OPT_DVAL_WR_ERR 964
+#define MSG_OPT_LOGIC_ERR 965
+#define MSG_READ_ERROR 966
+#define MSG_READ_SEEK_ERROR 967
+#define MSG_TABLE_NOT_OPT 968
+#define MSG_TRUNCATE_ERROR 969
+#define MSG_VALUE_TOO_LONG 970
+#define MSG_WRITE_SEEK_ERR 971
+#define MSG_BAD_BIN_FMT 972
+#define MSG_BAD_DEF_READ 973
+#define MSG_COL_NOT_SORTED 974
+#define MSG_ERROR_IN_LSK 975
+#define MSG_ERROR_IN_SFP 976
+#define MSG_FILE_OPEN_YET 977
+#define MSG_FWRITE_ERROR 978
+#define MSG_INVALID_FTYPE 979
+#define MSG_INV_REC_POS 980
+#define MSG_NO_BIG_DELETE 981
+#define MSG_NO_CLUSTER_COL 982
+#define MSG_OPEN_ERROR 983
+#define MSG_OPTIMIZING 984
+#define MSG_OPT_CANCELLED 985
+#define MSG_OPT_HEAD_RD_ERR 986
+#define MSG_OPT_HEAD_WR_ERR 987
+#define MSG_OPT_MAX_RD_ERR 988
+#define MSG_OPT_MAX_WR_ERR 989
+#define MSG_OPT_MIN_RD_ERR 990
+#define MSG_OPT_MIN_WR_ERR 991
+#define MSG_OPT_NOT_MATCH 992
+#define MSG_VALUE_TOO_BIG 993
+#define MSG_WRITING_ERROR 994
+#define MSG_BAD_FIELD_RANK 995
+#define MSG_BAD_FLD_FORMAT 996
+#define MSG_BAD_FLD_LENGTH 997
+#define MSG_BAD_LINEFLD_FMT 998
+#define MSG_BAD_QUOTE_FIELD 999
+#define MSG_CANNOT_OPEN 1000
+#define MSG_EOF_AFTER_LINE 1001
+#define MSG_ERR_READING_REC 1002
+#define MSG_FIELD_TOO_LONG 1003
+#define MSG_FLD_TOO_LNG_FOR 1004
+#define MSG_FMT_WRITE_NIY 1005
+#define MSG_LINE_TOO_LONG 1006
+#define MSG_LRECL_TOO_SMALL 1007
+#define MSG_MISPLACED_QUOTE 1008
+#define MSG_MISSING_EOL 1009
+#define MSG_MISSING_FIELD 1010
+#define MSG_MISSING_FNAME 1011
+#define MSG_NO_FLD_FORMAT 1012
+#define MSG_QUOTE_IN_QUOTE 1013
+#define MSG_TOO_MANY_FIELDS 1014
+#define MSG_UNBALANCE_QUOTE 1015
+#define MSG_BAD_JCOL_TYPE 1016
+#define MSG_COL_USED_TWICE 1017
+#define MSG_DUMMY_NO_COLS 1018
+#define MSG_JCT_MISS_COLS 1019
+#define MSG_JCT_MISS_TABLE 1020
+#define MSG_JCT_NO_FILTER 1021
+#define MSG_JCT_NO_KEY 1022
+#define MSG_NO_DMY_DIR_ACC 1023
+#define MSG_NO_EXP_LINK 1024
+#define MSG_VIR_NO_DELETE 1025
+#define MSG_VIR_READ_ONLY 1026
+#define MSG_BAD_JOIN_EXP 1027
+#define MSG_BAD_JOIN_OP 1028
+#define MSG_COLUMN_NOT_KEY 1029
+#define MSG_DB_SORT_ERROR 1030
+#define MSG_LINJOINDB_ERROR 1031
+#define MSG_MULT_KEY_ERROR 1032
+#define MSG_NO_JOIN_TO_EXP 1033
+#define MSG_NO_MULCOL_JOIN 1034
+#define MSG_READ_ONLY 1035
+#define MSG_ROWID_NOT_IMPL 1036
+#define MSG_SETRECPOS_NIY 1037
+#define MSG_TABLE_MULT_JOIN 1038
+#define MSG_TDB_USE_ERROR 1039
+#define MSG_BAD_CARDINALITY 1040
+#define MSG_BAD_DIRECTORY 1041
+#define MSG_BAD_FILE_HANDLE 1042
+#define MSG_INV_DIRCOL_OFST 1043
+#define MSG_MAXSIZE_ERROR 1044
+#define MSG_MUL_MAKECOL_ERR 1045
+#define MSG_NEXT_FILE_ERROR 1046
+#define MSG_NO_DIR_INDX_RD 1047
+#define MSG_NO_INDEX_READ 1048
+#define MSG_NO_MUL_DIR_ACC 1049
+#define MSG_SRCH_CLOSE_ERR 1050
+#define MSG_TABDIR_READONLY 1051
+#define MSG_TABMUL_READONLY 1052
+#define MSG_NO_EXT_FILTER 1053
+#define MSG_NO_EXT_UPDATE 1054
+#define MSG_NO_ODBC_DELETE 1055
+#define MSG_NO_ODBC_DIRECT 1056
+#define MSG_NO_ODBC_MUL 1057
+#define MSG_NO_ODBC_SPECOL 1058
+#define MSG_NO_UPDEL_JOIN 1059
+#define MSG_ODBC_READ_ONLY 1060
+#define MSG_PARM_CNT_MISS 1061
+#define MSG_COLNAM_TOO_LONG 1062
+#define MSG_NOT_ENOUGH_COLS 1063
+#define MSG_NO_DEF_FNCCOL 1064
+#define MSG_NO_DEF_PIVOTCOL 1065
+#define MSG_NO_MATCH_COL 1066
+#define MSG_NO_MORE_COL 1067
+#define MSG_NO_PIV_DIR_ACC 1068
+#define MSG_NO_TABLE_DEL 1069
+#define MSG_SRC_TABLE_UNDEF 1070
+#define MSG_TABLE_READ_ONLY 1071
+#define MSG_TOO_MANY_COLS 1072
+#define MSG_BAD_COLDEF_TYPE 1073
+#define MSG_BAD_MERGE_TYPE 1074
+#define MSG_COL_NB_MISM 1075
+#define MSG_ERROR_OPENING 1076
+#define MSG_FETCH_NO_RES 1077
+#define MSG_LOAD_CDLL_ERROR 1078
+#define MSG_NO_NBCOL 1079
+#define MSG_NO_NBLIN 1080
+#define MSG_NO_PROMPTING 1081
+#define MSG_NO_REMOTE_FNC 1082
+#define MSG_NO_VIEW_COLDEF 1083
+#define MSG_PLG_READ_ONLY 1084
+#define MSG_PLM_NULL_SFP 1085
+#define MSG_QUERY_NOT_EXEC 1086
+#define MSG_REMOTE_CONN_ERR 1087
+#define MSG_RPC_SERVER_ERR 1088
+#define MSG_BAD_QUERY_OPEN 1089
+#define MSG_BAD_RETURN_TYPE 1090
+#define MSG_BAD_VIEW_OPEN 1091
+#define MSG_NO_QRY_DELETE 1092
+#define MSG_NO_SQL_DELETE 1093
+#define MSG_NO_VIEW_SORT 1094
+#define MSG_NULL_COL_VALUE 1095
+#define MSG_QRY_READ_ONLY 1096
+#define MSG_READCOL_ERROR 1097
+#define MSG_SQL_READ_ONLY 1098
+#define MSG_GET_NAME_ERR 1099
+#define MSG_INV_SUBTYPE 1100
+#define MSG_NO_CURLY_BRKT 1101
+#define MSG_NO_KEY_UPDATE 1102
+#define MSG_NO_SECTION_NAME 1103
+#define MSG_NO_SEC_UPDATE 1104
+#define MSG_SEC_KEY_FIRST 1105
+#define MSG_SEC_NAME_FIRST 1106
+#define MSG_NO_MATCHING_COL 1107
+#define MSG_BAD_BYTE_NUM 1108
+#define MSG_BAD_BYTE_READ 1109
+#define MSG_BAD_READ_NUMBER 1110
+#define MSG_BLK_IS_NULL 1111
+#define MSG_EMPTY_FILE 1112
+#define MSG_MAKE_EMPTY_FILE 1113
+#define MSG_MAKING 1114
+#define MSG_NO_VCT_DELETE 1115
+#define MSG_OPEN_EMPTY_FILE 1116
+#define MSG_OPT_INIT 1117
+#define MSG_SFP_ERROR 1118
+#define MSG_TO_BLK_IS_NULL 1119
+#define MSG_TRUNC_BY_ESTIM 1120
+#define MSG_UPDATE_ERROR 1121
+#define MSG_WRITE_STRERROR 1122
+#define MSG_WRITING 1123
+#define MSG_BAD_COL_XPATH 1124
+#define MSG_BAD_NODE_TYPE 1125
+#define MSG_BAD_VALNODE 1126
+#define MSG_BAD_VAL_UPDATE 1127
+#define MSG_COL_ALLOC_ERR 1128
+#define MSG_COM_ERROR 1129
+#define MSG_CONCAT_SUBNODE 1130
+#define MSG_CREATED_PLUGDB 1131
+#define MSG_DEPREC_FLAG 1132
+#define MSG_EMPTY_DOC 1133
+#define MSG_FAIL_ADD_NODE 1134
+#define MSG_FILE_UNFOUND 1135
+#define MSG_INIT_FAILED 1136
+#define MSG_INV_COL_TYPE 1137
+#define MSG_LOADING_FAILED 1138
+#define MSG_MISSING_NODE 1139
+#define MSG_MISSING_ROWNODE 1140
+#define MSG_MIS_TAG_LIST 1141
+#define MSG_NEW_DOC_FAILED 1142
+#define MSG_NO_ROW_NODE 1143
+#define MSG_VAL_ALLOC_ERR 1144
+#define MSG_XMLTAB_INIT_ERR 1145
+#define MSG_XML_INIT_ERROR 1146
+#define MSG_XPATH_NOT_SUPP 1147
+#define MSG_DLL_LOAD_ERROR 1148
+#define MSG_GZOPEN_ERROR 1149
+#define MSG_GZPUTS_ERROR 1150
+#define MSG_NO_ZIP_DELETE 1151
+#define MSG_NO_ZIP_DIR_ACC 1152
+#define MSG_UPD_ZIP_NOT_IMP 1153
+#define MSG_MAC_NO_DELETE 1154
+#define MSG_MAC_NO_INDEX 1155
+#define MSG_MAC_READ_ONLY 1156
+#define MSG_BAD_FIELD_TYPE 1157
+#define MSG_BAD_PARM_COUNT 1158
+#define MSG_NO_JOIN_UPDEL 1159
+#define MSG_NO_MYSQL_DELETE 1160
+#define MSG_NO_REF_DELETE 1161
+#define MSG_NO_REF_UPDATE 1162
+#define MSG_NO_SPEC_COL 1163
+#define MSG_ADD_NULL_DOM 1164
+#define MSG_BAD_DOM_VALUE 1165
+#define MSG_BAD_SET_STRING 1166
+#define MSG_BAD_VALBLK_INDX 1167
+#define MSG_BAD_VALBLK_TYPE 1168
+#define MSG_COMPUTE_NIY 1169
+#define MSG_DOMAIN_EMPTY 1170
+#define MSG_DOMAIN_FULL 1171
+#define MSG_DOM_FILE_ERROR 1172
+#define MSG_DOM_OPEN_ERROR 1173
+#define MSG_DOM_READ_ERROR 1174
+#define MSG_DOM_READ_ONLY 1175
+#define MSG_DOM_WRITE_ERROR 1176
+#define MSG_ERR_NUM_GT_MAX 1177
+#define MSG_INV_TOK_DOMAIN 1178
+#define MSG_MEMSIZE_TOO_BIG 1179
+#define MSG_NO_DOM_DELETE 1180
+#define MSG_NO_DOM_MATCH 1181
+#define MSG_SET_NULL_DOM 1182
+#define MSG_STRING_TOO_BIG 1183
+#define MSG_VALTYPE_NOMATCH 1184
+#define MSG_NO_DATE_FMT 1185
+#define MSG_NO_LISTVAL_HERE 1186
+#define MSG_BAD_COL_FORMAT 1187
+#define MSG_BAD_DATETIME 1188
+#define MSG_BAD_DATE_OPER 1189
+#define MSG_BAD_EXP_OPER 1190
+#define MSG_BAD_PAD_ARGTYP 1191
+#define MSG_BAD_TRIM_ARGTYP 1192
+#define MSG_BLKTYPLEN_MISM 1193
+#define MSG_COMPUTE_ERROR 1194
+#define MSG_FIX_OVFLW_ADD 1195
+#define MSG_FIX_OVFLW_TIMES 1196
+#define MSG_FIX_UNFLW_ADD 1197
+#define MSG_FIX_UNFLW_TIMES 1198
+#define MSG_HARRY_COMP_NIY 1199
+#define MSG_NO_CHAR_FROM 1200
+#define MSG_NO_FORMAT_TYPE 1201
+#define MSG_ONLY_LOG10_IMPL 1202
+#define MSG_OP_RES_TOO_LONG 1203
+#define MSG_SET_STR_TRUNC 1204
+#define MSG_SUB_RES_TOO_LNG 1205
+#define MSG_VALIST_MISMATCH 1206
+#define MSG_VALSTR_TOO_LONG 1207
+#define MSG_ZERO_DIVIDE 1208
+#define MSG_ADDVAL_ERROR 1209
+#define MSG_ARRAY_ALLOC_ERR 1210
+#define MSG_BAD_DEF_ARG 1211
+#define MSG_BAD_FUNC_MODE 1212
+#define MSG_BAD_INDEX_COL 1213
+#define MSG_BAD_INDEX_DEF 1214
+#define MSG_BAD_INDEX_FILE 1215
+#define MSG_BAD_INDEX_PART 1216
+#define MSG_EOF_INDEX_FILE 1217
+#define MSG_FILE_CLOSE_ERR 1218
+#define MSG_FILE_MAP_ERR 1219
+#define MSG_FUNC_ERRNO 1220
+#define MSG_FUNC_ERROR 1221
+#define MSG_GRP_COL_MISM 1222
+#define MSG_HANDLE_IS_NULL 1223
+#define MSG_HI_OFFSET_ERR 1224
+#define MSG_INDEX_DEF_ERR 1225
+#define MSG_INDEX_INIT_ERR 1226
+#define MSG_INDEX_NOT_UNIQ 1227
+#define MSG_INT_COL_ERROR 1228
+#define MSG_KEY_ALLOC_ERR 1229
+#define MSG_MAP_OBJ_ERR 1230
+#define MSG_MISS_LEAD_COL 1231
+#define MSG_NEW_TABLE_ERR 1232
+#define MSG_NO_KEY_COL 1233
+#define MSG_NO_PART_MAP 1234
+#define MSG_NUMVAL_NOMATCH 1235
+#define MSG_RANGE_NIY 1236
+#define MSG_RANGE_NO_JOIN 1237
+#define MSG_REDUCE_INDEX 1238
+#define MSG_SAVING_INDEX 1239
+#define MSG_TABLE_NO_INDEX 1240
+#define MSG_XCOL_MISMATCH 1241
+#define MSG_XFILE_READERR 1242
+#define MSG_XFILE_TOO_SMALL 1243
+#define MSG_XFILE_WRITERR 1244
+#define MSG_ADD_BAD_TYPE 1245
+#define MSG_BAD_ARRAY_TYPE 1246
+#define MSG_BAD_CONST_TYPE 1247
+#define MSG_BAD_CONV_TYPE 1248
+#define MSG_BAD_FLOAT_CONV 1249
+#define MSG_BAD_TEST_TYPE 1250
+#define MSG_FIND_BAD_TYPE 1251
diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc
index 073c16f18ec..706f41780fe 100644
--- a/storage/connect/mycat.cc
+++ b/storage/connect/mycat.cc
@@ -1,657 +1,657 @@
-/* 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.3 */
-/* */
-/* Author: Olivier Bertrand 2012 - 2013 */
-/* */
-/* 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"
-
-/**************************************************************************/
-/* Extern static variables. */
-/**************************************************************************/
-#if defined(WIN32)
-extern "C" HINSTANCE s_hModule; // Saved module handle
-#endif // !WIN32
-
-extern int xtrace;
-
-/**************************************************************************/
-/* 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, ...);
-
-/**************************************************************************/
-/* Allocate the result structure that will contain result data. */
-/**************************************************************************/
-PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
- int *dbtype, int *buftyp, unsigned int *length,
- bool blank = false, bool nonull = false)
- {
- char cname[NAM_LEN+1];
- int i;
- PCOLRES *pcrp, crp;
- PQRYRES qrp;
-
- /************************************************************************/
- /* Allocate the structure used to contain the result set. */
- /************************************************************************/
- qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
- pcrp = &qrp->Colresp;
- qrp->Continued = false;
- qrp->Truncated = false;
- qrp->Info = false;
- qrp->Suball = true;
- qrp->Maxres = maxres;
- qrp->Maxsize = 0;
- qrp->Nblin = 0;
- qrp->Nbcol = 0; // will be ncol
- qrp->Cursor = 0;
- qrp->BadLines = 0;
-
- for (i = 0; i < ncol; i++) {
- *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
- crp = *pcrp;
- pcrp = &crp->Next;
- crp->Colp = NULL;
- crp->Ncol = ++qrp->Nbcol;
- crp->Type = buftyp[i];
- crp->Length = length[i];
- crp->Clen = GetTypeSize(crp->Type, length[i]);
- crp->Prec = 0;
- crp->DBtype = dbtype[i];
-
- if (ids > 0) {
-#if defined(XMSG)
- // Get header from message file
- strncpy(cname, PlugReadMessage(g, ids + crp->Ncol, NULL), NAM_LEN);
- cname[NAM_LEN] = 0; // for truncated long names
-#elif defined(WIN32)
- // Get header from ressource file
- LoadString(s_hModule, ids + crp->Ncol, cname, sizeof(cname));
-#else // !WIN32
- GetRcString(ids + crp->Ncol, cname, sizeof(cname));
-#endif // !WIN32
- crp->Name = (PSZ)PlugSubAlloc(g, NULL, strlen(cname) + 1);
- strcpy(crp->Name, cname);
- } else
- crp->Name = NULL; // Will be set by caller
-
- // Allocate the Value Block that will contain data
- if (crp->Length || nonull)
- crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
- crp->Length, 0, true, blank);
- else
- crp->Kdata = NULL;
-
- if (g->Trace)
- htrc("Column(%d) %s type=%d len=%d value=%p\n",
- crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);
-
- } // endfor i
-
- *pcrp = NULL;
-
- return qrp;
- } // end of PlgAllocResult
-
-/***********************************************************************/
-/* Get a unique char identifier for types. The letter used are: */
-/* ABCDEF..I.KLM.O..R.T.VWXY.. */
-/***********************************************************************/
-char GetTypeID(char *type)
- {
- return (!type) ? 'D' // DOS (default)
- : (!stricmp(type, "FMT")) ? 'T' // CSV
- : (!stricmp(type, "DIR")) ? 'R' // diR
- : (!stricmp(type, "DBF")) ? 'A' // dbAse
- : (!stricmp(type, "SYS")) ? 'I' // INI
- : (!stricmp(type, "TBL")) ? 'L' // tbL
- : (!stricmp(type, "MYSQL")) ? 'Y' // mYsql
- : (!stricmp(type, "OEM")) ? 'E' : toupper(*type);
- } // end of GetTypeID
-
-/* ------------------------- 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 type
- char tc= GetTypeID(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 'T':
- case 'C':
- // 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)
- {
- char tc;
- 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 */
- /*********************************************************************/
- tc= GetTypeID((char*)am);
-
- switch (tc) {
- case 'F':
- case 'B':
- case 'A':
- case 'D': tdp= new(g) DOSDEF; break;
- case 'T':
- 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 --------------------------- */
+/* 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.3 */
+/* */
+/* Author: Olivier Bertrand 2012 - 2013 */
+/* */
+/* 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"
+
+/**************************************************************************/
+/* Extern static variables. */
+/**************************************************************************/
+#if defined(WIN32)
+extern "C" HINSTANCE s_hModule; // Saved module handle
+#endif // !WIN32
+
+extern int xtrace;
+
+/**************************************************************************/
+/* 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, ...);
+
+/**************************************************************************/
+/* Allocate the result structure that will contain result data. */
+/**************************************************************************/
+PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
+ int *dbtype, int *buftyp, unsigned int *length,
+ bool blank = false, bool nonull = false)
+ {
+ char cname[NAM_LEN+1];
+ int i;
+ PCOLRES *pcrp, crp;
+ PQRYRES qrp;
+
+ /************************************************************************/
+ /* Allocate the structure used to contain the result set. */
+ /************************************************************************/
+ qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
+ pcrp = &qrp->Colresp;
+ qrp->Continued = false;
+ qrp->Truncated = false;
+ qrp->Info = false;
+ qrp->Suball = true;
+ qrp->Maxres = maxres;
+ qrp->Maxsize = 0;
+ qrp->Nblin = 0;
+ qrp->Nbcol = 0; // will be ncol
+ qrp->Cursor = 0;
+ qrp->BadLines = 0;
+
+ for (i = 0; i < ncol; i++) {
+ *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
+ crp = *pcrp;
+ pcrp = &crp->Next;
+ crp->Colp = NULL;
+ crp->Ncol = ++qrp->Nbcol;
+ crp->Type = buftyp[i];
+ crp->Length = length[i];
+ crp->Clen = GetTypeSize(crp->Type, length[i]);
+ crp->Prec = 0;
+ crp->DBtype = dbtype[i];
+
+ if (ids > 0) {
+#if defined(XMSG)
+ // Get header from message file
+ strncpy(cname, PlugReadMessage(g, ids + crp->Ncol, NULL), NAM_LEN);
+ cname[NAM_LEN] = 0; // for truncated long names
+#elif defined(WIN32)
+ // Get header from ressource file
+ LoadString(s_hModule, ids + crp->Ncol, cname, sizeof(cname));
+#else // !WIN32
+ GetRcString(ids + crp->Ncol, cname, sizeof(cname));
+#endif // !WIN32
+ crp->Name = (PSZ)PlugSubAlloc(g, NULL, strlen(cname) + 1);
+ strcpy(crp->Name, cname);
+ } else
+ crp->Name = NULL; // Will be set by caller
+
+ // Allocate the Value Block that will contain data
+ if (crp->Length || nonull)
+ crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
+ crp->Length, 0, true, blank);
+ else
+ crp->Kdata = NULL;
+
+ if (g->Trace)
+ htrc("Column(%d) %s type=%d len=%d value=%p\n",
+ crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);
+
+ } // endfor i
+
+ *pcrp = NULL;
+
+ return qrp;
+ } // end of PlgAllocResult
+
+/***********************************************************************/
+/* Get a unique char identifier for types. The letter used are: */
+/* ABCDEF..I.KLM.O..R.T.VWXY.. */
+/***********************************************************************/
+char GetTypeID(char *type)
+ {
+ return (!type) ? 'D' // DOS (default)
+ : (!stricmp(type, "FMT")) ? 'T' // CSV
+ : (!stricmp(type, "DIR")) ? 'R' // diR
+ : (!stricmp(type, "DBF")) ? 'A' // dbAse
+ : (!stricmp(type, "SYS")) ? 'I' // INI
+ : (!stricmp(type, "TBL")) ? 'L' // tbL
+ : (!stricmp(type, "MYSQL")) ? 'Y' // mYsql
+ : (!stricmp(type, "OEM")) ? 'E' : toupper(*type);
+ } // end of GetTypeID
+
+/* ------------------------- 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 type
+ char tc= GetTypeID(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 'T':
+ case 'C':
+ // 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)
+ {
+ char tc;
+ 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 */
+ /*********************************************************************/
+ tc= GetTypeID((char*)am);
+
+ switch (tc) {
+ case 'F':
+ case 'B':
+ case 'A':
+ case 'D': tdp= new(g) DOSDEF; break;
+ case 'T':
+ 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 --------------------------- */
diff --git a/storage/connect/mycat.h b/storage/connect/mycat.h
index f7eb834d58c..63c304dd8d9 100644
--- a/storage/connect/mycat.h
+++ b/storage/connect/mycat.h
@@ -1,64 +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
+/* 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
diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp
index 98ce81d04ff..8120e87de88 100644
--- a/storage/connect/myconn.cpp
+++ b/storage/connect/myconn.cpp
@@ -1,547 +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
+/************** 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
diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h
index 2f13c01f9bf..32bcfb802a1 100644
--- a/storage/connect/myconn.h
+++ b/storage/connect/myconn.h
@@ -1,91 +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
-
+/***********************************************************************/
+/* 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
+
diff --git a/storage/connect/myutil.cpp b/storage/connect/myutil.cpp
index 6c08aacc683..0a6e06ade87 100644
--- a/storage/connect/myutil.cpp
+++ b/storage/connect/myutil.cpp
@@ -1,193 +1,193 @@
-/************** 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 if (!stricmp(typname, "bigint") || !stricmp(typname, "longlong"))
- type = TYPE_BIGINT;
- 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;
- case TYPE_BIGINT:
- mytype = MYSQL_TYPE_LONGLONG;
- 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:
- case MYSQL_TYPE_ENUM: // ???
- type = TYPE_INT;
- break;
- case MYSQL_TYPE_LONGLONG:
- type = TYPE_BIGINT;
- break;
- 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
-
+/************** 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 if (!stricmp(typname, "bigint") || !stricmp(typname, "longlong"))
+ type = TYPE_BIGINT;
+ 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;
+ case TYPE_BIGINT:
+ mytype = MYSQL_TYPE_LONGLONG;
+ 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:
+ case MYSQL_TYPE_ENUM: // ???
+ type = TYPE_INT;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ type = TYPE_BIGINT;
+ break;
+ 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
+
diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp
index 33d181fcfaf..8c63d84afd4 100644
--- a/storage/connect/odbconn.cpp
+++ b/storage/connect/odbconn.cpp
@@ -1,2039 +1,2039 @@
-/************ Odbconn C++ Functions Source Code File (.CPP) ************/
-/* Name: ODBCONN.CPP Version 1.6 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
-/* */
-/* This file contains the ODBC connection classes functions. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant MariaDB header file. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-//nclude <io.h>
-//nclude <fcntl.h>
-#if defined(__BORLANDC__)
-#define __MFC_COMPAT__ // To define min/max as macro
-#endif
-//#include <windows.h>
-#else
-#if defined(UNIX)
-#include <errno.h>
-#else
-//nclude <io.h>
-#endif
-//nclude <fcntl.h>
-#define NODW
-#endif
-
-/***********************************************************************/
-/* Required objects includes. */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "xobject.h"
-//#include "kindex.h"
-#include "xtable.h"
-#include "tabodbc.h"
-#include "plgcnx.h" // For DB types
-#include "resource.h"
-#include "valblk.h"
-
-
-#if defined(WIN32)
-/***********************************************************************/
-/* For dynamic load of ODBC32.DLL */
-/***********************************************************************/
-#pragma comment(lib, "odbc32.lib")
-extern "C" HINSTANCE s_hModule; // Saved module handle
-#else // !WIN32
-extern "C" int GetRcString(int id, char *buf, int bufsize);
-#endif // !WIN32
-
-/***********************************************************************/
-/* Some macro's (should be defined elsewhere to be more accessible) */
-/***********************************************************************/
-#if defined(_DEBUG)
-#define ASSERT(f) assert(f)
-#define DEBUG_ONLY(f) (f)
-#else // !_DEBUG
-#define ASSERT(f) ((void)0)
-#define DEBUG_ONLY(f) ((void)0)
-#endif // !_DEBUG
-
-/***********************************************************************/
-/* GetSQLType: returns the SQL_TYPE corresponding to a PLG type. */
-/***********************************************************************/
-static short GetSQLType(int type)
- {
- short tp = SQL_TYPE_NULL;
-
- switch (type) {
- case TYPE_STRING: tp = SQL_CHAR; break;
- case TYPE_SHORT: tp = SQL_SMALLINT; break;
- case TYPE_INT: tp = SQL_INTEGER; break;
- case TYPE_DATE: tp = SQL_TIMESTAMP; break;
- case TYPE_BIGINT: tp = SQL_BIGINT; break; // (-5)
- case TYPE_FLOAT: tp = SQL_DOUBLE; break;
- } // endswitch type
-
- return tp;
- } // end of GetSQLType
-
-/***********************************************************************/
-/* GetSQLCType: returns the SQL_C_TYPE corresponding to a PLG type. */
-/***********************************************************************/
-static int GetSQLCType(int type)
- {
- int tp = SQL_TYPE_NULL;
-
- switch (type) {
- case TYPE_STRING: tp = SQL_C_CHAR; break;
- case TYPE_SHORT: tp = SQL_C_SHORT; break;
- case TYPE_INT: tp = SQL_C_LONG; break;
- case TYPE_DATE: tp = SQL_C_TIMESTAMP; break;
- case TYPE_BIGINT: tp = SQL_C_SBIGINT; break;
- case TYPE_FLOAT: tp = SQL_C_DOUBLE; break;
- } // endswitch type
-
- return tp;
- } // end of GetSQLCType
-
-/***********************************************************************/
-/* TranslateSQLType: translate a SQL Type to a PLG type. */
-/***********************************************************************/
-int TranslateSQLType(int stp, int prec, int& len)
- {
- int type;
-
- switch (stp) {
- case SQL_CHAR: // 1
- case SQL_VARCHAR: // 12
- type = TYPE_STRING;
- break;
- case SQL_LONGVARCHAR: // (-1)
- type = TYPE_STRING;
- len = min(abs(len), 255);
- break;
- case SQL_NUMERIC: // 2
- case SQL_DECIMAL: // 3
- type = (prec) ? TYPE_FLOAT
- : (len > 10) ? TYPE_BIGINT : TYPE_INT;
- break;
- case SQL_INTEGER: // 4
- type = TYPE_INT;
- break;
- case SQL_SMALLINT: // 5
- case SQL_TINYINT: // (-6)
- case SQL_BIT: // (-7)
- type = TYPE_SHORT;
- break;
- case SQL_FLOAT: // 6
- case SQL_REAL: // 7
- case SQL_DOUBLE: // 8
- type = TYPE_FLOAT;
- break;
- case SQL_DATETIME: // 9
-// case SQL_DATE: // 9
- type = TYPE_DATE;
- len = 10;
- break;
- case SQL_INTERVAL: // 10
-// case SQL_TIME: // 10
- type = TYPE_STRING;
- len = 8 + ((prec) ? (prec+1) : 0);
- break;
- case SQL_TIMESTAMP: // 11
- type = TYPE_DATE;
- len = 19 + ((prec) ? (prec+1) : 0);
- break;
- case SQL_BIGINT: // (-5)
- type = TYPE_BIGINT;
- break;
- case SQL_UNKNOWN_TYPE: // 0
- case SQL_BINARY: // (-2)
- case SQL_VARBINARY: // (-3)
- case SQL_LONGVARBINARY: // (-4)
-// case SQL_BIT: // (-7)
- case SQL_GUID: // (-11)
- default:
- type = TYPE_ERROR;
- len = 0;
- } // endswitch type
-
- return type;
- } // end of TranslateSQLType
-
-/***********************************************************************/
-/* ODBConn static members initialization. */
-/***********************************************************************/
- HENV ODBConn::m_henv = SQL_NULL_HENV;
- int ODBConn::m_nAlloc = 0; // per-Appl reference to HENV above
-
-/**************************************************************************/
-/* Allocate the result structure that will contain result data. */
-/**************************************************************************/
-PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
- int *dbtype, int *buftyp, unsigned int *length,
- bool blank = true, bool nonull = true);
-
-/***********************************************************************/
-/* Allocate the structure used to refer to the result set. */
-/***********************************************************************/
-CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, char *tab, PQRYRES qrp)
- {
- size_t i, m, n;
- CATPARM *cap;
-
-#if defined(_DEBUG)
- assert(qrp);
-#endif
- m = (size_t)qrp->Maxres;
- n = (size_t)qrp->Nbcol;
- cap = (CATPARM *)PlugSubAlloc(g, NULL, sizeof(CATPARM));
- memset(cap, 0, sizeof(CATPARM));
- cap->Id = fid;
- cap->Qrp = qrp;
- cap->Tab = (PUCHAR)tab;
- cap->Vlen = (SQLLEN* *)PlugSubAlloc(g, NULL, n * sizeof(SDWORD *));
-
- for (i = 0; i < n; i++)
- cap->Vlen[i] = (SQLLEN *)PlugSubAlloc(g, NULL, m * sizeof(SDWORD));
-
- cap->Status = (UWORD *)PlugSubAlloc(g, NULL, m * sizeof(UWORD));
- return cap;
- } // end of AllocCatInfo
-
-/***********************************************************************/
-/* Check for nulls and reset them to Null (?) values. */
-/***********************************************************************/
-void ResetNullValues(CATPARM *cap)
- {
- int i, n, ncol;
- PCOLRES crp;
- PQRYRES qrp = cap->Qrp;
-
-#if defined(_DEBUG)
- assert(qrp);
-#endif
-
- ncol = qrp->Nbcol;
-
- for (i = 0, crp = qrp->Colresp; i < ncol && crp; i++, crp = crp->Next)
- for (n = 0; n < qrp->Nblin; n++)
- if (cap->Vlen[i][n] == SQL_NULL_DATA)
- crp->Kdata->Reset(n);
-
- } // end of ResetNullValues
-
-/***********************************************************************/
-/* ODBCColumns: constructs the result blocks containing all columns */
-/* of an ODBC table that will be retrieved by GetData commands. */
-/* Note: The first two columns (Qualifier, Owner) are ignored. */
-/***********************************************************************/
-PQRYRES ODBCColumns(PGLOBAL g, ODBConn *op, char *dsn, char *table,
- char *colpat)
- {
- static int dbtype[] = {DB_CHAR, DB_CHAR,
- DB_CHAR, DB_SHORT, DB_CHAR,
- DB_INT, DB_INT, DB_SHORT,
- DB_SHORT, DB_SHORT, DB_CHAR};
- static int buftyp[] = {TYPE_STRING, TYPE_STRING,
- TYPE_STRING, TYPE_SHORT, TYPE_STRING,
- TYPE_INT, TYPE_INT, TYPE_SHORT,
- TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
- static unsigned int length[] = {0, 0, 0, 6, 20, 10, 10, 6, 6, 6, 128};
- int n, ncol = 11;
- int maxres;
- PQRYRES qrp;
- CATPARM *cap;
- ODBConn *ocp = op;
-
- if (!op) {
- /**********************************************************************/
- /* Open the connection with the ODBC data source. */
- /**********************************************************************/
- ocp = new(g) ODBConn(g, NULL);
-
- if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
- return NULL;
-
- } // endif op
-
- /************************************************************************/
- /* Do an evaluation of the result size. */
- /************************************************************************/
- n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
- maxres = (n) ? (int)n : 250;
- n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
- length[0] = (n) ? (n + 1) : 128;
- n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
- length[1] = (n) ? (n + 1) : 128;
- n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
- length[2] = (n) ? (n + 1) : 128;
-
-#ifdef DEBTRACE
- htrc("ODBCColumns: max=%d len=%d,%d,%d\n",
- maxres, length[0], length[1], length[2]);
-#endif
-
- /************************************************************************/
- /* Allocate the structures used to refer to the result set. */
- /************************************************************************/
- qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS + 1,
- dbtype, buftyp, length);
-
-#ifdef DEBTRACE
- htrc("Getting col results ncol=%d\n", qrp->Nbcol);
-#endif
-
- cap = AllocCatInfo(g, CAT_COL, table, qrp);
- cap->Pat = (PUCHAR)colpat;
-
- /************************************************************************/
- /* Now get the results into blocks. */
- /************************************************************************/
- if ((n = ocp->GetCatInfo(cap)) >= 0) {
- qrp->Nblin = n;
- ResetNullValues(cap);
-
-#ifdef DEBTRACE
- htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
-#endif
- } else
- qrp = NULL;
-
- /************************************************************************/
- /* Close any local connection. */
- /************************************************************************/
- if (!op)
- ocp->Close();
-
- /************************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /************************************************************************/
- return qrp;
- } // end of ODBCColumns
-
-/**************************************************************************/
-/* MyODBCCols: returns column info as required by ha_connect::pre_create. */
-/**************************************************************************/
-PQRYRES MyODBCCols(PGLOBAL g, char *tab, char *dsn)
- {
- int type, len, prec;
- PCOLRES crpt, crpl, crpp;
- PQRYRES qrp;
- ODBConn *ocp = new(g) ODBConn(g, NULL);
-
- /**********************************************************************/
- /* Open the connection with the ODBC data source. */
- /**********************************************************************/
- if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
- return NULL;
-
- /**********************************************************************/
- /* Get the information about the ODBC table columns. */
- /**********************************************************************/
- if ((qrp = ODBCColumns(g, ocp, dsn, tab, NULL)))
- dsn = ocp->GetConnect(); // Complete connect string
- else
- return NULL;
-
- /************************************************************************/
- /* Close the local connection. */
- /************************************************************************/
- ocp->Close();
-
- /************************************************************************/
- /* Keep only the info used by ha_connect::pre_create. */
- /************************************************************************/
- qrp->Colresp = qrp->Colresp->Next->Next; // Skip Owner and Table names
-
- crpt = qrp->Colresp->Next; // SQL type
- crpl = crpt->Next->Next; // Length
- crpp = crpl->Next->Next; // Decimals
-
- for (int i = 0; i < qrp->Nblin; i++) {
- // Types must be PLG types, not SQL types
- type = crpt->Kdata->GetIntValue(i);
- len = crpl->Kdata->GetIntValue(i);
- prec = crpp->Kdata->GetIntValue(i);
- type = TranslateSQLType(type, prec, len);
- crpt->Kdata->SetValue(type, i);
-
- // Some data sources do not count prec in length
- if (type == TYPE_FLOAT)
- len += (prec + 2); // To be safe
-
- // Could have been changed for blobs or numeric
- crpl->Kdata->SetValue(len, i);
- } // endfor i
-
- crpp->Next = crpp->Next->Next->Next; // Should be Remark
- qrp->Nbcol = 7; // Was 11, skipped 4
- return qrp;
- } // end of MyODBCCols
-
-/*************************************************************************/
-/* ODBCDataSources: constructs the result blocks containing all ODBC */
-/* data sources available on the local host. */
-/*************************************************************************/
-PQRYRES ODBCDataSources(PGLOBAL g)
- {
- static int dbtype[] = {DB_CHAR, DB_CHAR};
- static int buftyp[] = {TYPE_STRING, TYPE_STRING};
- static unsigned int length[] = {0, 256};
- int n, ncol = 2;
- int maxres;
- PQRYRES qrp;
- ODBConn *ocp = new(g) ODBConn(g, NULL);
-
- /************************************************************************/
- /* Do an evaluation of the result size. */
- /************************************************************************/
- maxres = 512; // This is completely arbitrary
- n = ocp->GetMaxValue(SQL_MAX_DSN_LENGTH);
- length[0] = (n) ? (n + 1) : 256;
-
-#ifdef DEBTRACE
- htrc("ODBCDataSources: max=%d len=%d\n", maxres, length[0]);
-#endif
-
- /************************************************************************/
- /* Allocate the structures used to refer to the result set. */
- /************************************************************************/
- qrp = PlgAllocResult(g, ncol, maxres, 0, dbtype, buftyp, length);
- qrp->Colresp->Name = "Name";
- qrp->Colresp->Next->Name = "Description";
-
- /************************************************************************/
- /* Now get the results into blocks. */
- /************************************************************************/
- if (ocp->GetDataSources(qrp))
- qrp = NULL;
-
- /************************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /************************************************************************/
- return qrp;
- } // end of ODBCDataSources
-
-#if 0 // Currently not used by CONNECT
-/***********************************************************************/
-/* ODBCTables: constructs the result blocks containing all tables in */
-/* an ODBC database that will be retrieved by GetData commands. */
-/* Note: The first two columns (Qualifier, Owner) are ignored. */
-/***********************************************************************/
-PQRYRES ODBCTables(PGLOBAL g, ODBConn *op, char *dsn, char *tabpat,
- char *tabtyp)
- {
- static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, DB_CHAR};
- static int buftyp[] = {TYPE_STRING, TYPE_STRING,
- TYPE_STRING, TYPE_STRING};
- static unsigned int length[] = {0, 0, 16, 128};
- int n, ncol = 4;
- int maxres;
- PQRYRES qrp;
- CATPARM *cap;
- ODBConn *ocp = op;
-
- if (!op) {
- /**********************************************************************/
- /* Open the connection with the ODBC data source. */
- /**********************************************************************/
- ocp = new(g) ODBConn(g, NULL);
-
- if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
- return NULL;
-
- } // endif op
-
- /************************************************************************/
- /* Do an evaluation of the result size. */
- /************************************************************************/
- maxres = 512; // This is completely arbitrary
- n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
- length[0] = (n) ? (n + 1) : 128;
- n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
- length[1] = (n) ? (n + 1) : 128;
-
-#ifdef DEBTRACE
- htrc("ODBCTables: max=%d len=%d,%d\n",
- maxres, length[0], length[1]);
-#endif
-
- /************************************************************************/
- /* Allocate the structures used to refer to the result set. */
- /************************************************************************/
- qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES + 1,
- dbtype, buftyp, length);
-
- cap = AllocCatInfo(g, CAT_TAB, tabpat, qrp);
- cap->Pat = (PUCHAR)tabtyp;
-
-#ifdef DEBTRACE
- htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
-#endif
-
- /************************************************************************/
- /* Now get the results into blocks. */
- /************************************************************************/
- if ((n = ocp->GetCatInfo(cap)) >= 0) {
- qrp->Nblin = n;
- ResetNullValues(cap);
-
-#ifdef DEBTRACE
- htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
-#endif
- } else
- qrp = NULL;
-
- /************************************************************************/
- /* Close any local connection. */
- /************************************************************************/
- if (!op)
- ocp->Close();
-
- /************************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /************************************************************************/
- return qrp;
- } // end of ODBCTables
-
-/**************************************************************************/
-/* PrimaryKeys: constructs the result blocks containing all the */
-/* ODBC catalog information concerning primary keys. */
-/**************************************************************************/
-PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table)
- {
- static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, DB_SHORT, DB_CHAR};
- static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
- TYPE_SHORT, TYPE_STRING};
- static unsigned int length[] = {0, 0, 0, 6, 128};
- int n, ncol = 5;
- int maxres;
- PQRYRES qrp;
- CATPARM *cap;
- ODBConn *ocp = op;
-
- if (!op) {
- /**********************************************************************/
- /* Open the connection with the ODBC data source. */
- /**********************************************************************/
- ocp = new(g) ODBConn(g, NULL);
-
- if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
- return NULL;
-
- } // endif op
-
- /************************************************************************/
- /* Do an evaluation of the result size. */
- /************************************************************************/
- n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
- maxres = (n) ? (int)n : 250;
- n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
- length[0] = (n) ? (n + 1) : 128;
- n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
- length[1] = (n) ? (n + 1) : 128;
- n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
- length[2] = (n) ? (n + 1) : 128;
-
-#ifdef DEBTRACE
- htrc("ODBCPrimaryKeys: max=%d len=%d,%d,%d\n",
- maxres, length[0], length[1], length[2]);
-#endif
-
- /************************************************************************/
- /* Allocate the structure used to refer to the result set. */
- /************************************************************************/
- qrp = PlgAllocResult(g, ncol, maxres, IDS_PKEY + 1,
- dbtype, buftyp, length);
-
-#ifdef DEBTRACE
- htrc("Getting pkey results ncol=%d\n", qrp->Nbcol);
-#endif
-
- cap = AllocCatInfo(g, CAT_KEY, table, qrp);
-
- /************************************************************************/
- /* Now get the results into blocks. */
- /************************************************************************/
- if ((n = ocp->GetCatInfo(cap)) >= 0) {
- qrp->Nblin = n;
- ResetNullValues(cap);
-
-#ifdef DEBTRACE
- htrc("PrimaryKeys: NBCOL=%d NBLIN=%d\n",
- qrp->Nbcol, qrp->Nblin);
-#endif
- } else
- qrp = NULL;
-
- /************************************************************************/
- /* Close any local connection. */
- /************************************************************************/
- if (!op)
- ocp->Close();
-
- /************************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /************************************************************************/
- return qrp;
- } // end of ODBCPrimaryKeys
-
-/**************************************************************************/
-/* Statistics: constructs the result blocks containing statistics */
-/* about one or several tables to be retrieved by GetData commands. */
-/**************************************************************************/
-PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat,
- int un, int acc)
- {
- static int dbtype[] = {DB_CHAR, DB_CHAR, DB_SHORT, DB_CHAR,
- DB_CHAR, DB_SHORT, DB_SHORT, DB_CHAR,
- DB_CHAR, DB_INT, DB_INT, DB_CHAR};
- static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_STRING,
- TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_STRING,
- TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_STRING};
- static unsigned int length[] = {0, 0 ,6 ,0 ,0 ,6 ,6 ,0 ,2 ,10 ,10 ,128};
- int n, ncol = 12;
- int maxres;
- PQRYRES qrp;
- CATPARM *cap;
- ODBConn *ocp = op;
-
- if (!op) {
- /**********************************************************************/
- /* Open the connection with the ODBC data source. */
- /**********************************************************************/
- ocp = new(g) ODBConn(g, NULL);
-
- if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
- return NULL;
-
- } // endif op
-
- /************************************************************************/
- /* Do an evaluation of the result size. */
- /************************************************************************/
- n = 1 + ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_INDEX);
- maxres = (n) ? (int)n : 32;
- n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
- length[0] = (n) ? (n + 1) : 128;
- n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
- length[1] = length[4] = (n) ? (n + 1) : 128;
- n = ocp->GetMaxValue(SQL_MAX_QUALIFIER_NAME_LEN);
- length[3] = (n) ? (n + 1) : length[1];
- n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
- length[7] = (n) ? (n + 1) : 128;
-
-#ifdef DEBTRACE
- htrc("SemStatistics: max=%d pat=%s\n", maxres, SVP(pat));
-#endif
-
- /************************************************************************/
- /* Allocate the structure used to refer to the result set. */
- /************************************************************************/
- qrp = PlgAllocResult(g, ncol, maxres, IDS_STAT + 1,
- dbtype, buftyp, length);
-
-#ifdef DEBTRACE
- htrc("Getting stat results ncol=%d\n", qrp->Nbcol);
-#endif
-
- cap = AllocCatInfo(g, CAT_STAT, pat, qrp);
- cap->Unique = (un < 0) ? SQL_INDEX_UNIQUE : (UWORD)un;
- cap->Accuracy = (acc < 0) ? SQL_QUICK : (UWORD)acc;
-
- /************************************************************************/
- /* Now get the results into blocks. */
- /************************************************************************/
- if ((n = ocp->GetCatInfo(cap)) >= 0) {
- qrp->Nblin = n;
- ResetNullValues(cap);
-
-#ifdef DEBTRACE
- htrc("Statistics: NBCOL=%d NBLIN=%d\n",
- qrp->Nbcol, qrp->Nblin);
-#endif
- } else
- qrp = NULL;
-
- /************************************************************************/
- /* Close any local connection. */
- /************************************************************************/
- if (!op)
- ocp->Close();
-
- /************************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /************************************************************************/
- return qrp;
- } // end of Statistics
-
-/***********************************************************************/
-/* GetColumnInfo: used when defining a ODBC table. The issue is that */
-/* some ODBC drivers give key information by SQLPrimaryKeys while */
-/* others do not implement it but give info using SQLStatistics. */
-/***********************************************************************/
-PQRYRES GetColumnInfo(PGLOBAL g, char*& dsn,
- char *table, int ver, PVBLK& vbp)
- {
- PCOLRES crp;
- PQRYRES qrpc, qrp;
- PVBLK vbp2;
- ODBConn *ocp = new(g) ODBConn(g, NULL);
-
- /**********************************************************************/
- /* Open the connection with the ODBC data source. */
- /**********************************************************************/
- if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
- return NULL;
- else if (ver > 0)
- ocp->m_Catver = ver;
-
- /**********************************************************************/
- /* Get the information about the ODBC table columns. */
- /**********************************************************************/
- if ((qrpc = ODBCColumns(g, ocp, dsn, table, NULL)))
- dsn = ocp->GetConnect(); // Complete connect string
- else
- return NULL;
-
- if ((qrp = ODBCPrimaryKeys(g, ocp, dsn, table))) {
- // Oracle, ...
- if (qrp->Nblin) {
- crp = qrp->Colresp->Next->Next;
- vbp = crp->Kdata;
- vbp->ReAlloc(vbp->GetValPointer(), qrp->Nblin);
- } // endif Nblin
-
- } else if ((qrp = ODBCStatistics(g, ocp, dsn, table, -1, -1))) {
- // Case of Microsoft Jet Engine
- if (qrp->Nblin) {
- int i, n = 0;
- PCOLRES crp2;
-
- crp = qrp->Colresp->Next->Next->Next->Next;
- crp2 = crp->Next->Next->Next;
-
- // This test may have to be modified for other ODBC drivers
- for (i = 0; i < qrp->Nblin; i++)
- if (!strcmp(crp->Kdata->GetCharValue(i), "PrimaryKey"))
- n++;
-
- if (n) {
- vbp2 = crp2->Kdata;
- vbp = AllocValBlock(g, NULL, vbp2->GetType(), n,
- vbp2->GetVlen(), 0, false, false);
-
- for (i = 0, n = 0; i < qrp->Nblin; i++)
- if (!strcmp(crp->Kdata->GetCharValue(i), "PrimaryKey"))
- vbp->SetValue(vbp2, n++, i);
-
- } // endif n
-
- } // endif Nblin
-
- } // endif qrp
-
- /************************************************************************/
- /* Close the local connection. */
- /************************************************************************/
- ocp->Close();
-
- return qrpc;
- } // end of GetColumnInfo
-#endif // 0
-
-/***********************************************************************/
-/* Implementation of DBX class. */
-/***********************************************************************/
-DBX::DBX(RETCODE rc)
- {
- m_RC = rc;
-
- for (int i = 0; i < MAX_NUM_OF_MSG; i++)
- m_ErrMsg[i] = NULL;
-
- } // end of DBX constructor
-
-/***********************************************************************/
-/* This function is called by ThrowDBX. */
-/***********************************************************************/
-void DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt)
- {
- if (pdb) {
- SWORD len;
- RETCODE rc;
- UCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1];
- UCHAR state[SQL_SQLSTATE_SIZE + 1];
- SDWORD native;
- PGLOBAL g = pdb->m_G;
-
- rc = SQLError(pdb->m_henv, pdb->m_hdbc, hstmt, state,
- &native, msg, SQL_MAX_MESSAGE_LENGTH - 1, &len);
-
- if (rc != SQL_INVALID_HANDLE)
- // Skip non-errors
- for (int i = 0; i < MAX_NUM_OF_MSG
- && (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
- && strcmp((char*)state, "00000"); i++) {
- m_ErrMsg[i] = (PSZ)PlugSubAlloc(g, NULL, strlen((char*)msg) + 1);
- strcpy(m_ErrMsg[i], (char*)msg);
-
-#ifdef DEBTRACE
- htrc("%s, Native=%d\n", msg, native);
-#endif
-
- rc = SQLError(pdb->m_henv, pdb->m_hdbc, hstmt, state,
- &native, msg, SQL_MAX_MESSAGE_LENGTH - 1, &len);
- } // endfor i
-
- else
- m_ErrMsg[0] = MSG(BAD_HANDLE_VAL);
-
- } else
- m_ErrMsg[0] = "No connexion address provided";
-
- } // end of BuildErrorMessage
-
-/***********************************************************************/
-/* ODBConn construction/destruction. */
-/***********************************************************************/
-ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
- {
- m_G = g;
- m_Tdb = tdbp;
- m_hdbc = SQL_NULL_HDBC;
-//m_Recset = NULL
- m_hstmt = SQL_NULL_HSTMT;
- m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT;
- m_QueryTimeout = DEFAULT_QUERY_TIMEOUT;
- m_UpdateOptions = 0;
- m_RowsetSize = (DWORD)((tdbp) ? tdbp->Rows : 10);
- m_Catver = (tdbp) ? tdbp->Catver : 0;
- m_Connect = NULL;
- m_Updatable = true;
-//m_Transactions = false;
- m_IDQuoteChar = '\'';
-//*m_ErrMsg = '\0';
- } // end of ODBConn
-
-//ODBConn::~ODBConn()
-// {
-//if (Connected())
-// EndCom();
-
-// } // end of ~ODBConn
-
-/***********************************************************************/
-/* Screen for errors. */
-/***********************************************************************/
-bool ODBConn::Check(RETCODE rc)
- {
- switch (rc) {
- case SQL_SUCCESS_WITH_INFO:
- if (m_G->Trace) {
- DBX x(rc);
-
- x.BuildErrorMessage(this, m_hstmt);
- htrc("ODBC Success With Info, hstmt=%p %s\n",
- m_hstmt, x.GetErrorMessage(0));
- } // endif Trace
-
- // Fall through
- case SQL_SUCCESS:
- case SQL_NO_DATA_FOUND:
- return true;
- } // endswitch rc
-
- return false;
- } // end of Check
-
-/***********************************************************************/
-/* DB exception throw routines. */
-/***********************************************************************/
-void ODBConn::ThrowDBX(RETCODE rc, HSTMT hstmt)
- {
- DBX* xp = new(m_G) DBX(rc);
-
- xp->BuildErrorMessage(this, hstmt);
- throw xp;
- } // end of ThrowDBX
-
-void ODBConn::ThrowDBX(PSZ msg)
- {
- DBX* xp = new(m_G) DBX(0);
-
- xp->m_ErrMsg[0] = msg;
- throw xp;
- } // end of ThrowDBX
-
-/***********************************************************************/
-/* Utility routine. */
-/***********************************************************************/
-PSZ ODBConn::GetStringInfo(ushort infotype)
- {
-//ASSERT(m_hdbc != SQL_NULL_HDBC);
- char *p, buffer[MAX_STRING_INFO];
- SWORD result;
- RETCODE rc;
-
- rc = SQLGetInfo(m_hdbc, infotype, buffer, sizeof(buffer), &result);
-
- if (!Check(rc))
- ThrowDBX(rc); // Temporary
-// *buffer = '\0';
-
- p = (char *)PlugSubAlloc(m_G, NULL, strlen(buffer) + 1);
- strcpy(p, buffer);
- return p;
- } // end of GetStringInfo
-
-/***********************************************************************/
-/* Utility routine. */
-/***********************************************************************/
-int ODBConn::GetMaxValue(ushort infotype)
- {
-//ASSERT(m_hdbc != SQL_NULL_HDBC);
- ushort maxval;
- RETCODE rc;
-
- rc = SQLGetInfo(m_hdbc, infotype, &maxval, 0, NULL);
-
- if (!Check(rc))
- maxval = 0;
-
- return (int)maxval;
- } // end of GetMaxValue
-
-/***********************************************************************/
-/* Utility routines. */
-/***********************************************************************/
-void ODBConn::OnSetOptions(HSTMT hstmt)
- {
- RETCODE rc;
- ASSERT(m_hdbc != SQL_NULL_HDBC);
-
- if ((signed)m_QueryTimeout != -1) {
- // Attempt to set query timeout. Ignore failure
- rc = SQLSetStmtOption(hstmt, SQL_QUERY_TIMEOUT, m_QueryTimeout);
-
- if (!Check(rc))
- // don't attempt it again
- m_QueryTimeout = (DWORD)-1;
-
- } // endif m_QueryTimeout
-
- if (m_RowsetSize > 0) {
- // Attempt to set rowset size.
- // In case of failure reset it to 0 to use Fetch.
- rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, m_RowsetSize);
-
- if (!Check(rc))
- // don't attempt it again
- m_RowsetSize = 0;
-
- } // endif m_RowsetSize
-
- } // end of OnSetOptions
-
-/***********************************************************************/
-/* Open: connect to a data source. */
-/***********************************************************************/
-int ODBConn::Open(PSZ ConnectString, DWORD options)
- {
- PGLOBAL& g = m_G;
-//ASSERT_VALID(this);
-//ASSERT(ConnectString == NULL || AfxIsValidString(ConnectString));
- ASSERT(!(options & noOdbcDialog && options & forceOdbcDialog));
-
- m_Updatable = !(options & openReadOnly);
- m_Connect = ConnectString;
-
- // Allocate the HDBC and make connection
- try {
- PSZ ver;
-
- AllocConnect(options);
- ver = GetStringInfo(SQL_ODBC_VER);
-
- if (Connect(options)) {
- strcpy(g->Message, MSG(CONNECT_CANCEL));
- return 0;
- } // endif
-
- ver = GetStringInfo(SQL_DRIVER_ODBC_VER);
- } catch(DBX *xp) {
-// strcpy(g->Message, xp->m_ErrMsg[0]);
- strcpy(g->Message, xp->GetErrorMessage(0));
- Free();
- return -1;
- } // end try-catch
-
- // Verify support for required functionality and cache info
- VerifyConnect();
- GetConnectInfo();
- return 1;
- } // end of Open
-
-/***********************************************************************/
-/* Allocate an henv (first time called) and hdbc. */
-/***********************************************************************/
-void ODBConn::AllocConnect(DWORD Options)
- {
- if (m_hdbc != SQL_NULL_HDBC)
- return;
-
- RETCODE rc;
-//AfxLockGlobals(CRIT_ODBC);
-
- // Need to allocate an environment for first connection
- if (m_henv == SQL_NULL_HENV) {
- ASSERT(m_nAlloc == 0);
-
- rc = SQLAllocEnv(&m_henv);
-
- if (!Check(rc)) {
-// AfxUnlockGlobals(CRIT_ODBC);
- ThrowDBX(rc); // Fatal
- } // endif
-
- } // endif m_henv
-
- // Do the real thing, allocating connection data
- rc = SQLAllocConnect(m_henv, &m_hdbc);
-
- if (!Check(rc)) {
-// AfxUnlockGlobals(CRIT_ODBC);
- ThrowDBX(rc); // Fatal
- } // endif
-
- m_nAlloc++; // allocated at last
-//AfxUnlockGlobals(CRIT_ODBC);
-
-#if defined(_DEBUG)
- if (Options & traceSQL) {
- SQLSetConnectOption(m_hdbc, SQL_OPT_TRACEFILE, (DWORD)"xodbc.out");
- SQLSetConnectOption(m_hdbc, SQL_OPT_TRACE, 1);
- } // endif
-#endif // _DEBUG
-
- rc = SQLSetConnectOption(m_hdbc, SQL_LOGIN_TIMEOUT, m_LoginTimeout);
-
-#ifdef DEBTRACE
- if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
- htrc("Warning: Failure setting login timeout\n");
-#endif
-
- if (!m_Updatable) {
- rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE,
- SQL_MODE_READ_ONLY);
-#ifdef DEBTRACE
- if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
- htrc("Warning: Failure setting read only access mode\n");
-#endif
- } // endif
-
- // Turn on cursor lib support
- if (Options & useCursorLib)
- rc = SQLSetConnectOption(m_hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_ODBC);
-
- return;
- } // end of AllocConnect
-
-/***********************************************************************/
-/* Connect to data source using SQLDriverConnect. */
-/***********************************************************************/
-bool ODBConn::Connect(DWORD Options)
- {
- RETCODE rc;
- SWORD nResult;
- PUCHAR ConnOut = (PUCHAR)PlugSubAlloc(m_G, NULL, MAX_CONNECT_LEN);
- UWORD wConnectOption = SQL_DRIVER_COMPLETE;
-#if defined(WIN32)
- HWND hWndTop = GetForegroundWindow();
- HWND hWnd = GetParent(hWndTop);
-
- if (hWnd == NULL)
- hWnd = GetDesktopWindow();
-#else // !WIN32
- HWND hWnd = NULL;
-#endif // !WIN32
- PGLOBAL& g = m_G;
- PDBUSER dup = PlgGetUser(g);
-
- if (Options & noOdbcDialog || dup->Remote)
- wConnectOption = SQL_DRIVER_NOPROMPT;
- else if (Options & forceOdbcDialog)
- wConnectOption = SQL_DRIVER_PROMPT;
-
- rc = SQLDriverConnect(m_hdbc, hWnd, (PUCHAR)m_Connect,
- SQL_NTS, ConnOut, MAX_CONNECT_LEN,
- &nResult, wConnectOption);
-
-#if defined(WIN32)
- if (hWndTop)
- EnableWindow(hWndTop, true);
-#endif // WIN32
-
- // If user hit 'Cancel'
- if (rc == SQL_NO_DATA_FOUND) {
- Free();
- return true;
- } // endif rc
-
- if (!Check(rc)) {
-#ifdef DEBTRACE
- if (!hWnd == NULL)
- htrc("Error: No default window for SQLDriverConnect\n");
-#endif
- ThrowDBX(rc);
- } // endif Check
-
- // Save connect string returned from ODBC
- m_Connect = (PSZ)ConnOut;
-
- // All done
- return false;
- } // end of Connect
-
-void ODBConn::VerifyConnect()
- {
-#if defined(NEWMSG) || defined(XMSG)
- PGLOBAL& g = m_G;
-#endif // NEWMSG || XMSG
- RETCODE rc;
- SWORD result;
- SWORD conformance;
-
- rc = SQLGetInfo(m_hdbc, SQL_ODBC_API_CONFORMANCE,
- &conformance, sizeof(conformance), &result);
-
- if (!Check(rc))
- ThrowDBX(rc);
-
- if (conformance < SQL_OAC_LEVEL1)
- ThrowDBX(MSG(API_CONF_ERROR));
-
- rc = SQLGetInfo(m_hdbc, SQL_ODBC_SQL_CONFORMANCE,
- &conformance, sizeof(conformance), &result);
-
- if (!Check(rc))
- ThrowDBX(rc);
-
- if (conformance < SQL_OSC_MINIMUM)
- ThrowDBX(MSG(SQL_CONF_ERROR));
-
- } // end of VerifyConnect
-
-void ODBConn::GetConnectInfo()
- {
- RETCODE rc;
- SWORD nResult;
-#if 0 // Update not implemented yet
- UDWORD DrvPosOp;
-
- // Reset the database update options
- m_UpdateOptions = 0;
-
- // Check for SQLSetPos support
- rc = SQLGetInfo(m_hdbc, SQL_POS_OPERATIONS,
- &DrvPosOp, sizeof(DrvPosOp), &nResult);
-
- if (Check(rc) &&
- (DrvPosOp & SQL_POS_UPDATE) &&
- (DrvPosOp & SQL_POS_DELETE) &&
- (DrvPosOp & SQL_POS_ADD))
- m_UpdateOptions = SQL_SETPOSUPDATES;
-
- // Check for positioned update SQL support
- UDWORD PosStatements;
-
- rc = SQLGetInfo(m_hdbc, SQL_POSITIONED_STATEMENTS,
- &PosStatements, sizeof(PosStatements),
- &nResult);
-
- if (Check(rc) &&
- (PosStatements & SQL_PS_POSITIONED_DELETE) &&
- (PosStatements & SQL_PS_POSITIONED_UPDATE))
- m_UpdateOptions |= SQL_POSITIONEDSQL;
-
- if (m_Updatable) {
- // Make sure data source is Updatable
- char ReadOnly[10];
-
- rc = SQLGetInfo(m_hdbc, SQL_DATA_SOURCE_READ_ONLY,
- ReadOnly, sizeof(ReadOnly), &nResult);
-
- if (Check(rc) && nResult == 1)
- m_Updatable = !!strcmp(ReadOnly, "Y");
- else
- m_Updatable = false;
-
-#ifdef DEBTRACE
- htrc("Warning: data source is readonly\n");
-#endif
- } else // Make data source is !Updatable
- rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE,
- SQL_MODE_READ_ONLY);
-#endif // 0
-
- // Cache the quote char to use when constructing SQL
- char QuoteChar[2];
-
- rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
- QuoteChar, sizeof(QuoteChar), &nResult);
-
- if (Check(rc) && nResult == 1)
- m_IDQuoteChar = QuoteChar[0];
- else
- m_IDQuoteChar = ' ';
-
-#ifdef DEBTRACE
- htrc("DBMS: %s, Version: %s",
- GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER));
-#endif // DEBTRACE
- } // end of GetConnectInfo
-
-/***********************************************************************/
-/* Allocate record set and execute an SQL query. */
-/***********************************************************************/
-int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
- {
- PGLOBAL& g = m_G;
- void *buffer;
- bool b;
- UWORD n;
- SWORD ncol, len, tp;
- SQLLEN afrw;
- ODBCCOL *colp;
- RETCODE rc;
- HSTMT hstmt;
-
-//m_Recset = new(m_G) RECSET(this);
-//ASSERT(m_Recset);
-
- try {
- b = false;
-
- if (m_hstmt) {
- RETCODE rc;
-
-// All this did not seems to make sense and was been commented out
-// if (IsOpen())
-// Close(SQL_CLOSE);
-
- rc = SQLFreeStmt(m_hstmt, SQL_CLOSE);
- hstmt = m_hstmt;
- m_hstmt = NULL;
- ThrowDBX(MSG(SEQUENCE_ERROR));
- } else {
- rc = SQLAllocStmt(m_hdbc, &hstmt);
-
- if (!Check(rc))
- ThrowDBX(SQL_INVALID_HANDLE);
-
- } // endif hstmt
-
- OnSetOptions(hstmt);
- b = true;
-
- if (g->Trace) {
- htrc("ExecDirect hstmt=%p %.64s\n", hstmt, sql);
- fflush(debug);
- } // endif Trace
-
- do {
- rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
- } while (rc == SQL_STILL_EXECUTING);
-
- if (!Check(rc))
- ThrowDBX(rc, hstmt);
-
- do {
- rc = SQLNumResultCols(hstmt, &ncol);
- } while (rc == SQL_STILL_EXECUTING);
-
- if (ncol == 0) {
- // Update or Delete statement
- rc = SQLRowCount(hstmt, &afrw);
-
- if (!Check(rc))
- ThrowDBX(rc, hstmt);
-
- return afrw;
- } // endif ncol
-
- for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
- if (!colp->IsSpecial())
- n++;
-
- // n can be 0 for query such as Select count(*) from table
- if (n && n != (UWORD)ncol)
- ThrowDBX(MSG(COL_NUM_MISM));
-
- // Now bind the column buffers
- for (n = 1, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
- if (!colp->IsSpecial()) {
- buffer = colp->GetBuffer(m_RowsetSize);
- len = colp->GetBuflen();
- tp = GetSQLCType(colp->GetResultType());
-
- if (tp == SQL_TYPE_NULL) {
- sprintf(m_G->Message, MSG(INV_COLUMN_TYPE),
- colp->GetResultType(), SVP(colp->GetName()));
- ThrowDBX(m_G->Message);
- } // endif tp
-
- if (g->Trace) {
- htrc("Binding col=%u type=%d buf=%p len=%d slen=%p\n",
- n, tp, buffer, len, colp->GetStrLen());
- fflush(debug);
- } // endif Trace
-
- rc = SQLBindCol(hstmt, n, tp, buffer, len, colp->GetStrLen());
-
- if (!Check(rc))
- ThrowDBX(rc, hstmt);
-
- n++;
- } // endif pcol
-
- } catch(DBX *x) {
-#ifdef DEBTRACE
- for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
- htrc(x->m_ErrMsg[i]);
-#endif
- strcpy(m_G->Message, x->GetErrorMessage(0));
-
- if (b)
- SQLCancel(hstmt);
-
- rc = SQLFreeStmt(hstmt, SQL_DROP);
- m_hstmt = NULL;
- return -1;
- } // end try/catch
-
- m_hstmt = hstmt;
- return (int)m_RowsetSize; // May have been reset in OnSetOptions
- } // end of ExecDirectSQL
-
-/***********************************************************************/
-/* Get the number of lines of the result set. */
-/***********************************************************************/
-int ODBConn::GetResultSize(char *sql, ODBCCOL *colp)
- {
- int n = 0;
- RETCODE rc;
-
- if (ExecDirectSQL(sql, colp) < 0)
- return -1;
-
- try {
- for (n = 0; ; n++) {
- do {
- rc = SQLFetch(m_hstmt);
- } while (rc == SQL_STILL_EXECUTING);
-
- if (!Check(rc))
- ThrowDBX(rc, m_hstmt);
-
- if (rc == SQL_NO_DATA_FOUND)
- break;
-
- } // endfor n
-
- } catch(DBX *x) {
-// strcpy(m_G->Message, x->m_ErrMsg[0]);
- strcpy(m_G->Message, x->GetErrorMessage(0));
-#ifdef DEBTRACE
- for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
- htrc(x->m_ErrMsg[i]);
-#endif
- SQLCancel(m_hstmt);
- n = -2;
- } // end try/catch
-
- rc = SQLFreeStmt(m_hstmt, SQL_DROP);
- m_hstmt = NULL;
-
- if (n != 1)
- return -3;
- else
- return colp->GetIntValue();
-
- } // end of GetResultSize
-
-/***********************************************************************/
-/* Fetch next row. */
-/***********************************************************************/
-int ODBConn::Fetch()
- {
- ASSERT(m_hstmt);
- int irc;
- SQLULEN crow;
- RETCODE rc;
- PGLOBAL& g = m_G;
-
- try {
-// do {
- if (m_RowsetSize) {
- rc = SQLExtendedFetch(m_hstmt, SQL_FETCH_NEXT, 1, &crow, NULL);
- } else {
- rc = SQLFetch(m_hstmt);
- crow = 1;
- } // endif m_RowsetSize
-// } while (rc == SQL_STILL_EXECUTING);
-
- if (g->Trace)
- htrc("Fetch: hstmt=%p RowseSize=%d rc=%d\n",
- m_hstmt, m_RowsetSize, rc);
-
- if (!Check(rc))
- ThrowDBX(rc, m_hstmt);
-
- irc = (rc == SQL_NO_DATA_FOUND) ? 0 : (int)crow;
- } catch(DBX *x) {
- if (g->Trace)
- for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
- htrc(x->m_ErrMsg[i]);
-
- strcpy(g->Message, x->GetErrorMessage(0));
- irc = -1;
- } // end try/catch
-
- return irc;
- } // end of Fetch
-
-/***********************************************************************/
-/* Prepare an SQL statement for insert. */
-/***********************************************************************/
-int ODBConn::PrepareSQL(char *sql)
- {
- PGLOBAL& g = m_G;
- bool b;
- SWORD nparm;
- RETCODE rc;
- HSTMT hstmt;
-
- try {
- b = false;
-
- if (m_hstmt) {
- RETCODE rc = SQLFreeStmt(m_hstmt, SQL_CLOSE);
-
- hstmt = m_hstmt;
- m_hstmt = NULL;
- ThrowDBX(MSG(SEQUENCE_ERROR));
- } else {
- rc = SQLAllocStmt(m_hdbc, &hstmt);
-
- if (!Check(rc))
- ThrowDBX(SQL_INVALID_HANDLE);
-
- } // endif hstmt
-
- OnSetOptions(hstmt);
- b = true;
-
- if (g->Trace) {
- htrc("Prepare hstmt=%p %.64s\n", hstmt, sql);
- fflush(debug);
- } // endif Trace
-
- do {
- rc = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
- } while (rc == SQL_STILL_EXECUTING);
-
- if (!Check(rc))
- ThrowDBX(rc, hstmt);
-
- do {
- rc = SQLNumParams(hstmt, &nparm);
- } while (rc == SQL_STILL_EXECUTING);
-
- } catch(DBX *x) {
-#ifdef DEBTRACE
- for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
- htrc(x->m_ErrMsg[i]);
-#endif
- strcpy(m_G->Message, x->GetErrorMessage(0));
-
- if (b)
- SQLCancel(hstmt);
-
- rc = SQLFreeStmt(hstmt, SQL_DROP);
- m_hstmt = NULL;
- return -1;
- } // end try/catch
-
- m_hstmt = hstmt;
- return (int)nparm;
- } // end of PrepareSQL
-
-/***********************************************************************/
-/* Bind a parameter for inserting. */
-/***********************************************************************/
-bool ODBConn::ExecuteSQL(void)
- {
- RETCODE rc;
-
- try {
- rc = SQLExecute(m_hstmt);
-
- if (!Check(rc))
- ThrowDBX(rc, m_hstmt);
-
- } catch(DBX *x) {
- strcpy(m_G->Message, x->GetErrorMessage(0));
- SQLCancel(m_hstmt);
- rc = SQLFreeStmt(m_hstmt, SQL_DROP);
- m_hstmt = NULL;
- return true;
- } // end try/catch
-
- return false;
- } // end of ExecuteSQL
-
-/***********************************************************************/
-/* Bind a parameter for inserting. */
-/***********************************************************************/
-bool ODBConn::BindParam(ODBCCOL *colp)
- {
- void *buf;
- UWORD n = colp->GetRank();
- SWORD ct, sqlt;
- UDWORD len;
- SQLLEN *strlen = colp->GetStrLen();
- RETCODE rc;
-
-#if 0
- try {
- SWORD dec, nul;
- rc = SQLDescribeParam(m_hstmt, n, &sqlt, &len, &dec, &nul);
-
- if (!Check(rc))
- ThrowDBX(rc, m_hstmt);
-
- } catch(DBX *x) {
- strcpy(m_G->Message, x->GetErrorMessage(0));
- } // end try/catch
-#endif // 0
-
- buf = colp->GetBuffer(0);
-// len = colp->GetBuflen();
- len = IsTypeNum(colp->GetResultType()) ? 0 : colp->GetBuflen();
- ct = GetSQLCType(colp->GetResultType());
- sqlt = GetSQLType(colp->GetResultType());
- *strlen = IsTypeNum(colp->GetResultType()) ? 0 : SQL_NTS;
-
- try {
- rc = SQLBindParameter(m_hstmt, n, SQL_PARAM_INPUT, ct, sqlt,
- len, 0, buf, 0, strlen);
-
- if (!Check(rc))
- ThrowDBX(rc, m_hstmt);
-
- } catch(DBX *x) {
- strcpy(m_G->Message, x->GetErrorMessage(0));
- SQLCancel(m_hstmt);
- rc = SQLFreeStmt(m_hstmt, SQL_DROP);
- m_hstmt = NULL;
- return true;
- } // end try/catch
-
- return false;
- } // end of BindParam
-
-/***********************************************************************/
-/* Get the list of Data Sources and set it in qrp. */
-/***********************************************************************/
-bool ODBConn::GetDataSources(PQRYRES qrp)
- {
- UCHAR *dsn, *des;
- UWORD dir = SQL_FETCH_FIRST;
- SWORD n1, n2, p1, p2;
- PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next;
- RETCODE rc;
-
- n1 = crp1->Clen;
- n2 = crp2->Clen;
-
- try {
- rc = SQLAllocEnv(&m_henv);
-
- if (!Check(rc))
- ThrowDBX(rc); // Fatal
-
- for (int i = 0; i < qrp->Maxres; i++) {
- dsn = (UCHAR*)crp1->Kdata->GetValPtr(i);
- des = (UCHAR*)crp2->Kdata->GetValPtr(i);
- rc = SQLDataSources(m_henv, dir, dsn, n1, &p1, des, n2, &p2);
-
- if (rc == SQL_NO_DATA_FOUND)
- break;
- else if (!Check(rc))
- ThrowDBX(rc); // Fatal
-
- qrp->Nblin++;
- dir = SQL_FETCH_NEXT;
- } // endfor i
-
- } catch(DBX *x) {
- strcpy(m_G->Message, x->GetErrorMessage(0));
- SQLFreeEnv(m_henv);
- return true;
- } // end try/catch
-
- SQLFreeEnv(m_henv);
- return false;
- } // end of GetDataSources
-
-/***********************************************************************/
-/* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
-/***********************************************************************/
-int ODBConn::GetCatInfo(CATPARM *cap)
- {
-#if defined(NEWMSG) || defined(XMSG)
- PGLOBAL& g = m_G;
-#endif // NEWMSG || XMSG
- void *buffer;
- int i, irc;
- bool b;
- UWORD n;
- SWORD ncol, len, tp;
- SQLULEN crow;
- PCOLRES crp;
- RETCODE rc;
- HSTMT hstmt = NULL;
- SQLLEN *vl, *vlen;
- PVAL *pval = NULL;
-
- try {
- b = false;
-
- if (!m_hstmt) {
- rc = SQLAllocStmt(m_hdbc, &hstmt);
-
- if (!Check(rc))
- ThrowDBX(SQL_INVALID_HANDLE);
-
- } else
- ThrowDBX(MSG(SEQUENCE_ERROR));
-
- b = true;
-
- if ((m_RowsetSize = cap->Qrp->Maxres) > 0) {
- if (m_Catver) {
- // Attempt to set rowset size.
- // In case of failure reset it to 0 to use Fetch.
- if (m_Catver == 3) // ODBC Ver 3
- rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE,
- (SQLPOINTER)m_RowsetSize, 0);
- else
- rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, m_RowsetSize);
-
- if (!Check(rc))
- m_RowsetSize = 1; // don't attempt it again
-// ThrowDBX(rc, hstmt); // Temporary
-
- if (m_Catver == 3) { // ODBC Ver 3
- rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, cap->Status, 0);
- rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &crow, 0);
- } // endif m_Catver
-
- } else // ORABUG
- m_RowsetSize = 1;
-
- } else
- ThrowDBX("0-sized result");
-
- // Now do call the proper ODBC API
- switch (cap->Id) {
- case CAT_TAB:
-// rc = SQLSetStmtAttr(hstmt, SQL_ATTR_METADATA_ID,
-// (SQLPOINTER)false, 0);
- rc = SQLTables(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS,
- cap->Pat, SQL_NTS);
- break;
- case CAT_COL:
-// rc = SQLSetStmtAttr(hstmt, SQL_ATTR_METADATA_ID,
-// (SQLPOINTER)true, 0);
- rc = SQLColumns(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS,
- cap->Pat, SQL_NTS);
- break;
- case CAT_KEY:
- rc = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS);
- break;
- case CAT_STAT:
- rc = SQLStatistics(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS,
- cap->Unique, cap->Accuracy);
- break;
- case CAT_SPC:
- ThrowDBX("SQLSpecialColumns not available yet");
- } // endswitch infotype
-
- if (!Check(rc))
- ThrowDBX(rc, hstmt);
-
- rc = SQLNumResultCols(hstmt, &ncol);
-
- // n + 1 because we ignore the first column
- if ((n = (UWORD)cap->Qrp->Nbcol) + 1 > (UWORD)ncol)
- ThrowDBX(MSG(COL_NUM_MISM));
-
- if (m_RowsetSize == 1 && cap->Qrp->Maxres > 1) {
- pval = (PVAL *)PlugSubAlloc(m_G, NULL, n * sizeof(PVAL));
- vlen = (SQLLEN *)PlugSubAlloc(m_G, NULL, n * sizeof(SDWORD *));
- } // endif
-
- // Now bind the column buffers
- for (n = 0, crp = cap->Qrp->Colresp; crp; crp = crp->Next) {
- if (pval) {
- pval[n] = AllocateValue(m_G, crp->Kdata->GetType(),
- crp->Kdata->GetVlen(), 0);
- buffer = pval[n]->GetTo_Val();
- vl = vlen + n;
- } else {
- buffer = crp->Kdata->GetValPointer();
- vl = cap->Vlen[n];
- } // endif pval
-
- len = GetTypeSize(crp->Type, crp->Clen);
- tp = GetSQLCType(crp->Type);
-
- if (tp == SQL_TYPE_NULL) {
- sprintf(m_G->Message, MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
- ThrowDBX(m_G->Message);
- } // endif tp
-
- // n + 2 because column numbers begin with 1 and because
- // we ignore the first column
- rc = SQLBindCol(hstmt, n + 2, tp, buffer, len, vl);
-
- if (!Check(rc))
- ThrowDBX(rc, hstmt);
-
- n++;
- } // endfor crp
-
- // Now fetch the result
- if (m_Catver != 3) {
- if (m_RowsetSize > 1) {
- rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 1, &crow, cap->Status);
- } else if (pval) {
- for (n = 0; n < cap->Qrp->Maxres; n++) {
- if ((rc = SQLFetch(hstmt)) != SQL_SUCCESS)
- break;
-
- for (i = 0, crp = cap->Qrp->Colresp; crp; i++, crp = crp->Next) {
- crp->Kdata->SetValue(pval[i], n);
- cap->Vlen[i][n] = vlen[i];
- } // endfor crp
-
- } // endfor n
-
- if ((crow = n) && rc == SQL_NO_DATA)
- rc = SQL_SUCCESS;
-
- } else {
- rc = SQLFetch(hstmt);
- crow = 1;
- } // endif's
-
- } else // ODBC Ver 3
- rc = SQLFetch(hstmt);
-
-// if (!Check(rc))
- if (rc == SQL_NO_DATA_FOUND) {
- if (cap->Pat)
- sprintf(m_G->Message, MSG(NO_TABCOL_DATA), cap->Tab, cap->Pat);
- else
- sprintf(m_G->Message, MSG(NO_TAB_DATA), cap->Tab);
-
- ThrowDBX(m_G->Message);
- } else if (rc != SQL_SUCCESS)
- ThrowDBX(rc, hstmt);
-
- irc = (int)crow;
- } catch(DBX *x) {
-#ifdef DEBTRACE
- for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
- htrc(x->m_ErrMsg[i]);
-#endif
- strcpy(m_G->Message, x->GetErrorMessage(0));
- irc = -1;
- } // end try/catch
-
- if (b)
- SQLCancel(hstmt);
-
- // All this (hstmt vs> m_hstmt) to be revisited
- if (hstmt)
- rc = SQLFreeStmt(hstmt, SQL_DROP);
-
- return irc;
- } // end of GetCatInfo
-
-/***********************************************************************/
-/* Disconnect connection */
-/***********************************************************************/
-void ODBConn::Close()
- {
- RETCODE rc;
-
-#if 0
- // Close any open recordsets
- AfxLockGlobals(CRIT_ODBC);
- TRY
- {
- while (!m_listRecordsets.IsEmpty())
- {
- CRecordset* pSet = (CRecordset*)m_listRecordsets.GetHead();
- pSet->Close(); // will implicitly remove from list
- pSet->m_pDatabase = NULL;
- }
- }
- CATCH_ALL(e)
- {
- AfxUnlockGlobals(CRIT_ODBC);
- THROW_LAST();
- }
- END_CATCH_ALL
- AfxUnlockGlobals(CRIT_ODBC);
-#endif // 0
-
- if (m_hstmt) {
- // Is required for multiple tables
- rc = SQLFreeStmt(m_hstmt, SQL_DROP);
- m_hstmt = NULL;
- } // endif m_hstmt
-
- if (m_hdbc != SQL_NULL_HDBC) {
- rc = SQLDisconnect(m_hdbc);
- rc = SQLFreeConnect(m_hdbc);
- m_hdbc = SQL_NULL_HDBC;
-
-// AfxLockGlobals(CRIT_ODBC);
- ASSERT(m_nAlloc != 0);
- m_nAlloc--;
-// AfxUnlockGlobals(CRIT_ODBC);
- } // endif m_hdbc
-
- } // end of Close
-
-// Silently disconnect and free all ODBC resources.
-// Don't throw any exceptions
-void ODBConn::Free()
- {
- // Trap failures upon close
- try {
- Close();
- } catch(DBX*) {
- // Nothing we can do
-#ifdef DEBTRACE
- htrc("Error: exception by Close ignored in Free\n");
-#endif
-// DELETE_EXCEPTION(x);
- } // endcatch
-
- // free henv if refcount goes to 0
-//AfxLockGlobals(CRIT_ODBC);
- if (m_henv != SQL_NULL_HENV) {
- ASSERT(m_nAlloc >= 0);
-
- if (m_nAlloc == 0) {
- // free last connection - release HENV
-#ifdef DEBTRACE
- RETCODE rc = SQLFreeEnv(m_henv);
- if (rc != SQL_SUCCESS) // Nothing we can do
- htrc("Error: SQLFreeEnv failure ignored in Free\n");
-#else
- SQLFreeEnv(m_henv);
-#endif
- m_henv = SQL_NULL_HENV;
- } // endif m_nAlloc
- }
-//AfxUnlockGlobals(CRIT_ODBC);
- } // end of Free
-
-#if 0
-//////////////////////////////////////////////////////////////////////////////
-// CRecordset helpers
-
-//id AFXAPI AfxSetCurrentRecord(int* plCurrentRecord, int nRows, RETCODE nRetCode);
-//id AFXAPI AfxSetRecordCount(int* plRecordCount, int lCurrentRecord,
-//bool bEOFSeen, RETCODE nRetCode);
-
-/***********************************************************************/
-/* RECSET class implementation */
-/***********************************************************************/
-RECSET::RECSET(ODBConn *dbcp)
- {
- m_pDB = dbcp;
- m_hstmt = SQL_NULL_HSTMT;
- m_OpenType = snapshot;
- m_Options = none;
-
-#if 0
- m_lOpen = AFX_RECORDSET_STATUS_UNKNOWN;
- m_nEditMode = noMode;
- m_nDefaultType = snapshot;
-
- m_bAppendable = false;
- m_bUpdatable = false;
- m_bScrollable = false;
- m_bRecordsetDb = false;
- m_bRebindParams = false;
- m_bLongBinaryColumns = false;
- m_nLockMode = optimistic;
- m_dwInitialGetDataLen = 0;
- m_rgODBCFieldInfos = NULL;
- m_rgFieldInfos = NULL;
- m_rgRowStatus = NULL;
- m_dwRowsetSize = 25;
- m_dwAllocatedRowsetSize = 0;
-
- m_nFields = 0;
- m_nParams = 0;
- m_nFieldsBound = 0;
- m_lCurrentRecord = AFX_CURRENT_RECORD_UNDEFINED;
- m_lRecordCount = 0;
- m_bUseUpdateSQL = false;
- m_bUseODBCCursorLib = false;
- m_nResultCols = -1;
- m_bCheckCacheForDirtyFields = true;
-
- m_pbFieldFlags = NULL;
- m_pbParamFlags = NULL;
- m_plParamLength = NULL;
- m_pvFieldProxy = NULL;
- m_pvParamProxy = NULL;
- m_nProxyFields = 0;
- m_nProxyParams = 0;
-
- m_hstmtUpdate = SQL_NULL_HSTMT;
-#endif // 0
- } // end of RECSET constructor
-
-RECSET::~RECSET()
- {
- try {
- if (m_hstmt) {
-#ifdef DEBTRACE
- if (m_dwOptions & useMultiRowFetch) {
- htrc("WARNING: Close called implicitly from destructor\n");
- htrc("Use of multi row fetch requires explicit call\n");
- htrc("to Close or memory leaks will result\n");
- }
-#endif
- Close();
- } // endif m_hstmt
-
-// if (m_bRecordsetDb)
-// delete m_pDB; ??????
-
- m_pDB = NULL;
- } catch(DBX*) {
- // Nothing we can do
-#ifdef DEBTRACE
- htrc("Error: Exception ignored in ~RECSET\n");
-#endif
- } // endtry/catch
-
- } // end of ~RECSET
-
-/***********************************************************************/
-/* Open: this function does the following: */
-/* Allocates the hstmt, */
-/* Bind columns, */
-/* Execute the SQL statement */
-/***********************************************************************/
-bool RECSET::Open(PSZ sql, uint Type, DWORD options)
- {
- ASSERT(m_pDB && m_pDB->IsOpen());
- ASSERT(Type == DB_USE_DEFAULT_TYPE || Type == dynaset ||
- Type == snapshot || Type == forwardOnly || Type == dynamic);
-//ASSERT(!(options & readOnly && options & appendOnly));
-
- // Cache state info and allocate hstmt
- SetState(Type, sql, options);
-
- try {
- if (m_hstmt) {
- if (IsOpen())
- Close(SQL_CLOSE);
-
- } else {
- RETCODE rc = SQLAllocStmt(m_pDB->m_hdbc, &m_hstmt);
-
- if (!Check(rc))
- ThrowDBException(SQL_INVALID_HANDLE);
-
- } // endif m_hstmt
-
- m_pDB->OnSetOptions(m_hstmt);
-
- // Allocate the field/param status arrays, if necessary
-// bool bUnbound = false;
-
-// if (m_nFields > 0 || m_nParams > 0)
-// AllocStatusArrays();
-// else
-// bUnbound = true;
-
- // Build SQL and prep/execute or just execute direct
-// BuildSQL(sql);
- PrepareAndExecute(sql);
-
- // Cache some field info and prepare the rowset
- AllocAndCacheFieldInfo();
- AllocRowset();
-
- // If late binding, still need to allocate status arrays
-// if (bUnbound && (m_nFields > 0 || m_nParams > 0))
-// AllocStatusArrays();
-
- } catch(DBX *x) {
- Close(SQL_DROP);
-// strcpy(m_pDB->m_G->Message, x->GetErrorMessage[0]);
- strcpy(m_pDB->m_G->Message, x->GetErrorMessage(0));
- return true;
- } // endtry/catch
-
- return false;
- } // end of Open
-
-/***********************************************************************/
-/* Close a hstmt. */
-/***********************************************************************/
-void RECSET::Close(SWORD option)
- {
- if (m_hstmt != SQL_NULL_HSTMT) {
- RETCODE rc = SQLFreeStmt(m_hstmt, option);
-
- if (option == SQL_DROP)
- m_hstmt = SQL_NULL_HSTMT;
-
- } // endif m_hstmt
-
-#if 0
- m_lOpen = RECORDSET_STATUS_CLOSED;
- m_bBOF = true;
- m_bEOF = true;
- m_bDeleted = false;
- m_bAppendable = false;
- m_bUpdatable = false;
- m_bScrollable = false;
- m_bRebindParams = false;
- m_bLongBinaryColumns = false;
- m_nLockMode = optimistic;
- m_nFieldsBound = 0;
- m_nResultCols = -1;
-#endif // 0
- } // end of Close
-#endif // 0
-
+/************ Odbconn C++ Functions Source Code File (.CPP) ************/
+/* Name: ODBCONN.CPP Version 1.6 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
+/* */
+/* This file contains the ODBC connection classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(WIN32)
+//nclude <io.h>
+//nclude <fcntl.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <errno.h>
+#else
+//nclude <io.h>
+#endif
+//nclude <fcntl.h>
+#define NODW
+#endif
+
+/***********************************************************************/
+/* Required objects includes. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xobject.h"
+//#include "kindex.h"
+#include "xtable.h"
+#include "tabodbc.h"
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+#include "valblk.h"
+
+
+#if defined(WIN32)
+/***********************************************************************/
+/* For dynamic load of ODBC32.DLL */
+/***********************************************************************/
+#pragma comment(lib, "odbc32.lib")
+extern "C" HINSTANCE s_hModule; // Saved module handle
+#else // !WIN32
+extern "C" int GetRcString(int id, char *buf, int bufsize);
+#endif // !WIN32
+
+/***********************************************************************/
+/* Some macro's (should be defined elsewhere to be more accessible) */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define ASSERT(f) assert(f)
+#define DEBUG_ONLY(f) (f)
+#else // !_DEBUG
+#define ASSERT(f) ((void)0)
+#define DEBUG_ONLY(f) ((void)0)
+#endif // !_DEBUG
+
+/***********************************************************************/
+/* GetSQLType: returns the SQL_TYPE corresponding to a PLG type. */
+/***********************************************************************/
+static short GetSQLType(int type)
+ {
+ short tp = SQL_TYPE_NULL;
+
+ switch (type) {
+ case TYPE_STRING: tp = SQL_CHAR; break;
+ case TYPE_SHORT: tp = SQL_SMALLINT; break;
+ case TYPE_INT: tp = SQL_INTEGER; break;
+ case TYPE_DATE: tp = SQL_TIMESTAMP; break;
+ case TYPE_BIGINT: tp = SQL_BIGINT; break; // (-5)
+ case TYPE_FLOAT: tp = SQL_DOUBLE; break;
+ } // endswitch type
+
+ return tp;
+ } // end of GetSQLType
+
+/***********************************************************************/
+/* GetSQLCType: returns the SQL_C_TYPE corresponding to a PLG type. */
+/***********************************************************************/
+static int GetSQLCType(int type)
+ {
+ int tp = SQL_TYPE_NULL;
+
+ switch (type) {
+ case TYPE_STRING: tp = SQL_C_CHAR; break;
+ case TYPE_SHORT: tp = SQL_C_SHORT; break;
+ case TYPE_INT: tp = SQL_C_LONG; break;
+ case TYPE_DATE: tp = SQL_C_TIMESTAMP; break;
+ case TYPE_BIGINT: tp = SQL_C_SBIGINT; break;
+ case TYPE_FLOAT: tp = SQL_C_DOUBLE; break;
+ } // endswitch type
+
+ return tp;
+ } // end of GetSQLCType
+
+/***********************************************************************/
+/* TranslateSQLType: translate a SQL Type to a PLG type. */
+/***********************************************************************/
+int TranslateSQLType(int stp, int prec, int& len)
+ {
+ int type;
+
+ switch (stp) {
+ case SQL_CHAR: // 1
+ case SQL_VARCHAR: // 12
+ type = TYPE_STRING;
+ break;
+ case SQL_LONGVARCHAR: // (-1)
+ type = TYPE_STRING;
+ len = min(abs(len), 255);
+ break;
+ case SQL_NUMERIC: // 2
+ case SQL_DECIMAL: // 3
+ type = (prec) ? TYPE_FLOAT
+ : (len > 10) ? TYPE_BIGINT : TYPE_INT;
+ break;
+ case SQL_INTEGER: // 4
+ type = TYPE_INT;
+ break;
+ case SQL_SMALLINT: // 5
+ case SQL_TINYINT: // (-6)
+ case SQL_BIT: // (-7)
+ type = TYPE_SHORT;
+ break;
+ case SQL_FLOAT: // 6
+ case SQL_REAL: // 7
+ case SQL_DOUBLE: // 8
+ type = TYPE_FLOAT;
+ break;
+ case SQL_DATETIME: // 9
+// case SQL_DATE: // 9
+ type = TYPE_DATE;
+ len = 10;
+ break;
+ case SQL_INTERVAL: // 10
+// case SQL_TIME: // 10
+ type = TYPE_STRING;
+ len = 8 + ((prec) ? (prec+1) : 0);
+ break;
+ case SQL_TIMESTAMP: // 11
+ type = TYPE_DATE;
+ len = 19 + ((prec) ? (prec+1) : 0);
+ break;
+ case SQL_BIGINT: // (-5)
+ type = TYPE_BIGINT;
+ break;
+ case SQL_UNKNOWN_TYPE: // 0
+ case SQL_BINARY: // (-2)
+ case SQL_VARBINARY: // (-3)
+ case SQL_LONGVARBINARY: // (-4)
+// case SQL_BIT: // (-7)
+ case SQL_GUID: // (-11)
+ default:
+ type = TYPE_ERROR;
+ len = 0;
+ } // endswitch type
+
+ return type;
+ } // end of TranslateSQLType
+
+/***********************************************************************/
+/* ODBConn static members initialization. */
+/***********************************************************************/
+ HENV ODBConn::m_henv = SQL_NULL_HENV;
+ int ODBConn::m_nAlloc = 0; // per-Appl reference to HENV above
+
+/**************************************************************************/
+/* Allocate the result structure that will contain result data. */
+/**************************************************************************/
+PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
+ int *dbtype, int *buftyp, unsigned int *length,
+ bool blank = true, bool nonull = true);
+
+/***********************************************************************/
+/* Allocate the structure used to refer to the result set. */
+/***********************************************************************/
+CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, char *tab, PQRYRES qrp)
+ {
+ size_t i, m, n;
+ CATPARM *cap;
+
+#if defined(_DEBUG)
+ assert(qrp);
+#endif
+ m = (size_t)qrp->Maxres;
+ n = (size_t)qrp->Nbcol;
+ cap = (CATPARM *)PlugSubAlloc(g, NULL, sizeof(CATPARM));
+ memset(cap, 0, sizeof(CATPARM));
+ cap->Id = fid;
+ cap->Qrp = qrp;
+ cap->Tab = (PUCHAR)tab;
+ cap->Vlen = (SQLLEN* *)PlugSubAlloc(g, NULL, n * sizeof(SDWORD *));
+
+ for (i = 0; i < n; i++)
+ cap->Vlen[i] = (SQLLEN *)PlugSubAlloc(g, NULL, m * sizeof(SDWORD));
+
+ cap->Status = (UWORD *)PlugSubAlloc(g, NULL, m * sizeof(UWORD));
+ return cap;
+ } // end of AllocCatInfo
+
+/***********************************************************************/
+/* Check for nulls and reset them to Null (?) values. */
+/***********************************************************************/
+void ResetNullValues(CATPARM *cap)
+ {
+ int i, n, ncol;
+ PCOLRES crp;
+ PQRYRES qrp = cap->Qrp;
+
+#if defined(_DEBUG)
+ assert(qrp);
+#endif
+
+ ncol = qrp->Nbcol;
+
+ for (i = 0, crp = qrp->Colresp; i < ncol && crp; i++, crp = crp->Next)
+ for (n = 0; n < qrp->Nblin; n++)
+ if (cap->Vlen[i][n] == SQL_NULL_DATA)
+ crp->Kdata->Reset(n);
+
+ } // end of ResetNullValues
+
+/***********************************************************************/
+/* ODBCColumns: constructs the result blocks containing all columns */
+/* of an ODBC table that will be retrieved by GetData commands. */
+/* Note: The first two columns (Qualifier, Owner) are ignored. */
+/***********************************************************************/
+PQRYRES ODBCColumns(PGLOBAL g, ODBConn *op, char *dsn, char *table,
+ char *colpat)
+ {
+ static int dbtype[] = {DB_CHAR, DB_CHAR,
+ DB_CHAR, DB_SHORT, DB_CHAR,
+ DB_INT, DB_INT, DB_SHORT,
+ DB_SHORT, DB_SHORT, DB_CHAR};
+ static int buftyp[] = {TYPE_STRING, TYPE_STRING,
+ TYPE_STRING, TYPE_SHORT, TYPE_STRING,
+ TYPE_INT, TYPE_INT, TYPE_SHORT,
+ TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
+ static unsigned int length[] = {0, 0, 0, 6, 20, 10, 10, 6, 6, 6, 128};
+ int n, ncol = 11;
+ int maxres;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = op;
+
+ if (!op) {
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ } // endif op
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
+ maxres = (n) ? (int)n : 250;
+ n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
+ length[0] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+ length[1] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
+ length[2] = (n) ? (n + 1) : 128;
+
+#ifdef DEBTRACE
+ htrc("ODBCColumns: max=%d len=%d,%d,%d\n",
+ maxres, length[0], length[1], length[2]);
+#endif
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS + 1,
+ dbtype, buftyp, length);
+
+#ifdef DEBTRACE
+ htrc("Getting col results ncol=%d\n", qrp->Nbcol);
+#endif
+
+ cap = AllocCatInfo(g, CAT_COL, table, qrp);
+ cap->Pat = (PUCHAR)colpat;
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+ ResetNullValues(cap);
+
+#ifdef DEBTRACE
+ htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+#endif
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ if (!op)
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCColumns
+
+/**************************************************************************/
+/* MyODBCCols: returns column info as required by ha_connect::pre_create. */
+/**************************************************************************/
+PQRYRES MyODBCCols(PGLOBAL g, char *tab, char *dsn)
+ {
+ int type, len, prec;
+ PCOLRES crpt, crpl, crpp;
+ PQRYRES qrp;
+ ODBConn *ocp = new(g) ODBConn(g, NULL);
+
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ /**********************************************************************/
+ /* Get the information about the ODBC table columns. */
+ /**********************************************************************/
+ if ((qrp = ODBCColumns(g, ocp, dsn, tab, NULL)))
+ dsn = ocp->GetConnect(); // Complete connect string
+ else
+ return NULL;
+
+ /************************************************************************/
+ /* Close the local connection. */
+ /************************************************************************/
+ ocp->Close();
+
+ /************************************************************************/
+ /* Keep only the info used by ha_connect::pre_create. */
+ /************************************************************************/
+ qrp->Colresp = qrp->Colresp->Next->Next; // Skip Owner and Table names
+
+ crpt = qrp->Colresp->Next; // SQL type
+ crpl = crpt->Next->Next; // Length
+ crpp = crpl->Next->Next; // Decimals
+
+ for (int i = 0; i < qrp->Nblin; i++) {
+ // Types must be PLG types, not SQL types
+ type = crpt->Kdata->GetIntValue(i);
+ len = crpl->Kdata->GetIntValue(i);
+ prec = crpp->Kdata->GetIntValue(i);
+ type = TranslateSQLType(type, prec, len);
+ crpt->Kdata->SetValue(type, i);
+
+ // Some data sources do not count prec in length
+ if (type == TYPE_FLOAT)
+ len += (prec + 2); // To be safe
+
+ // Could have been changed for blobs or numeric
+ crpl->Kdata->SetValue(len, i);
+ } // endfor i
+
+ crpp->Next = crpp->Next->Next->Next; // Should be Remark
+ qrp->Nbcol = 7; // Was 11, skipped 4
+ return qrp;
+ } // end of MyODBCCols
+
+/*************************************************************************/
+/* ODBCDataSources: constructs the result blocks containing all ODBC */
+/* data sources available on the local host. */
+/*************************************************************************/
+PQRYRES ODBCDataSources(PGLOBAL g)
+ {
+ static int dbtype[] = {DB_CHAR, DB_CHAR};
+ static int buftyp[] = {TYPE_STRING, TYPE_STRING};
+ static unsigned int length[] = {0, 256};
+ int n, ncol = 2;
+ int maxres;
+ PQRYRES qrp;
+ ODBConn *ocp = new(g) ODBConn(g, NULL);
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ maxres = 512; // This is completely arbitrary
+ n = ocp->GetMaxValue(SQL_MAX_DSN_LENGTH);
+ length[0] = (n) ? (n + 1) : 256;
+
+#ifdef DEBTRACE
+ htrc("ODBCDataSources: max=%d len=%d\n", maxres, length[0]);
+#endif
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, 0, dbtype, buftyp, length);
+ qrp->Colresp->Name = "Name";
+ qrp->Colresp->Next->Name = "Description";
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if (ocp->GetDataSources(qrp))
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCDataSources
+
+#if 0 // Currently not used by CONNECT
+/***********************************************************************/
+/* ODBCTables: constructs the result blocks containing all tables in */
+/* an ODBC database that will be retrieved by GetData commands. */
+/* Note: The first two columns (Qualifier, Owner) are ignored. */
+/***********************************************************************/
+PQRYRES ODBCTables(PGLOBAL g, ODBConn *op, char *dsn, char *tabpat,
+ char *tabtyp)
+ {
+ static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, DB_CHAR};
+ static int buftyp[] = {TYPE_STRING, TYPE_STRING,
+ TYPE_STRING, TYPE_STRING};
+ static unsigned int length[] = {0, 0, 16, 128};
+ int n, ncol = 4;
+ int maxres;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = op;
+
+ if (!op) {
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ } // endif op
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ maxres = 512; // This is completely arbitrary
+ n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
+ length[0] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+ length[1] = (n) ? (n + 1) : 128;
+
+#ifdef DEBTRACE
+ htrc("ODBCTables: max=%d len=%d,%d\n",
+ maxres, length[0], length[1]);
+#endif
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES + 1,
+ dbtype, buftyp, length);
+
+ cap = AllocCatInfo(g, CAT_TAB, tabpat, qrp);
+ cap->Pat = (PUCHAR)tabtyp;
+
+#ifdef DEBTRACE
+ htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
+#endif
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+ ResetNullValues(cap);
+
+#ifdef DEBTRACE
+ htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+#endif
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ if (!op)
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCTables
+
+/**************************************************************************/
+/* PrimaryKeys: constructs the result blocks containing all the */
+/* ODBC catalog information concerning primary keys. */
+/**************************************************************************/
+PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table)
+ {
+ static int dbtype[] = {DB_CHAR, DB_CHAR, DB_CHAR, DB_SHORT, DB_CHAR};
+ static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
+ TYPE_SHORT, TYPE_STRING};
+ static unsigned int length[] = {0, 0, 0, 6, 128};
+ int n, ncol = 5;
+ int maxres;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = op;
+
+ if (!op) {
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ } // endif op
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
+ maxres = (n) ? (int)n : 250;
+ n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
+ length[0] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+ length[1] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
+ length[2] = (n) ? (n + 1) : 128;
+
+#ifdef DEBTRACE
+ htrc("ODBCPrimaryKeys: max=%d len=%d,%d,%d\n",
+ maxres, length[0], length[1], length[2]);
+#endif
+
+ /************************************************************************/
+ /* Allocate the structure used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_PKEY + 1,
+ dbtype, buftyp, length);
+
+#ifdef DEBTRACE
+ htrc("Getting pkey results ncol=%d\n", qrp->Nbcol);
+#endif
+
+ cap = AllocCatInfo(g, CAT_KEY, table, qrp);
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+ ResetNullValues(cap);
+
+#ifdef DEBTRACE
+ htrc("PrimaryKeys: NBCOL=%d NBLIN=%d\n",
+ qrp->Nbcol, qrp->Nblin);
+#endif
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ if (!op)
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCPrimaryKeys
+
+/**************************************************************************/
+/* Statistics: constructs the result blocks containing statistics */
+/* about one or several tables to be retrieved by GetData commands. */
+/**************************************************************************/
+PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat,
+ int un, int acc)
+ {
+ static int dbtype[] = {DB_CHAR, DB_CHAR, DB_SHORT, DB_CHAR,
+ DB_CHAR, DB_SHORT, DB_SHORT, DB_CHAR,
+ DB_CHAR, DB_INT, DB_INT, DB_CHAR};
+ static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_STRING,
+ TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_STRING,
+ TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_STRING};
+ static unsigned int length[] = {0, 0 ,6 ,0 ,0 ,6 ,6 ,0 ,2 ,10 ,10 ,128};
+ int n, ncol = 12;
+ int maxres;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = op;
+
+ if (!op) {
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ } // endif op
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ n = 1 + ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_INDEX);
+ maxres = (n) ? (int)n : 32;
+ n = ocp->GetMaxValue(SQL_MAX_USER_NAME_LEN);
+ length[0] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+ length[1] = length[4] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_QUALIFIER_NAME_LEN);
+ length[3] = (n) ? (n + 1) : length[1];
+ n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
+ length[7] = (n) ? (n + 1) : 128;
+
+#ifdef DEBTRACE
+ htrc("SemStatistics: max=%d pat=%s\n", maxres, SVP(pat));
+#endif
+
+ /************************************************************************/
+ /* Allocate the structure used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_STAT + 1,
+ dbtype, buftyp, length);
+
+#ifdef DEBTRACE
+ htrc("Getting stat results ncol=%d\n", qrp->Nbcol);
+#endif
+
+ cap = AllocCatInfo(g, CAT_STAT, pat, qrp);
+ cap->Unique = (un < 0) ? SQL_INDEX_UNIQUE : (UWORD)un;
+ cap->Accuracy = (acc < 0) ? SQL_QUICK : (UWORD)acc;
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+ ResetNullValues(cap);
+
+#ifdef DEBTRACE
+ htrc("Statistics: NBCOL=%d NBLIN=%d\n",
+ qrp->Nbcol, qrp->Nblin);
+#endif
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ if (!op)
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of Statistics
+
+/***********************************************************************/
+/* GetColumnInfo: used when defining a ODBC table. The issue is that */
+/* some ODBC drivers give key information by SQLPrimaryKeys while */
+/* others do not implement it but give info using SQLStatistics. */
+/***********************************************************************/
+PQRYRES GetColumnInfo(PGLOBAL g, char*& dsn,
+ char *table, int ver, PVBLK& vbp)
+ {
+ PCOLRES crp;
+ PQRYRES qrpc, qrp;
+ PVBLK vbp2;
+ ODBConn *ocp = new(g) ODBConn(g, NULL);
+
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+ else if (ver > 0)
+ ocp->m_Catver = ver;
+
+ /**********************************************************************/
+ /* Get the information about the ODBC table columns. */
+ /**********************************************************************/
+ if ((qrpc = ODBCColumns(g, ocp, dsn, table, NULL)))
+ dsn = ocp->GetConnect(); // Complete connect string
+ else
+ return NULL;
+
+ if ((qrp = ODBCPrimaryKeys(g, ocp, dsn, table))) {
+ // Oracle, ...
+ if (qrp->Nblin) {
+ crp = qrp->Colresp->Next->Next;
+ vbp = crp->Kdata;
+ vbp->ReAlloc(vbp->GetValPointer(), qrp->Nblin);
+ } // endif Nblin
+
+ } else if ((qrp = ODBCStatistics(g, ocp, dsn, table, -1, -1))) {
+ // Case of Microsoft Jet Engine
+ if (qrp->Nblin) {
+ int i, n = 0;
+ PCOLRES crp2;
+
+ crp = qrp->Colresp->Next->Next->Next->Next;
+ crp2 = crp->Next->Next->Next;
+
+ // This test may have to be modified for other ODBC drivers
+ for (i = 0; i < qrp->Nblin; i++)
+ if (!strcmp(crp->Kdata->GetCharValue(i), "PrimaryKey"))
+ n++;
+
+ if (n) {
+ vbp2 = crp2->Kdata;
+ vbp = AllocValBlock(g, NULL, vbp2->GetType(), n,
+ vbp2->GetVlen(), 0, false, false);
+
+ for (i = 0, n = 0; i < qrp->Nblin; i++)
+ if (!strcmp(crp->Kdata->GetCharValue(i), "PrimaryKey"))
+ vbp->SetValue(vbp2, n++, i);
+
+ } // endif n
+
+ } // endif Nblin
+
+ } // endif qrp
+
+ /************************************************************************/
+ /* Close the local connection. */
+ /************************************************************************/
+ ocp->Close();
+
+ return qrpc;
+ } // end of GetColumnInfo
+#endif // 0
+
+/***********************************************************************/
+/* Implementation of DBX class. */
+/***********************************************************************/
+DBX::DBX(RETCODE rc)
+ {
+ m_RC = rc;
+
+ for (int i = 0; i < MAX_NUM_OF_MSG; i++)
+ m_ErrMsg[i] = NULL;
+
+ } // end of DBX constructor
+
+/***********************************************************************/
+/* This function is called by ThrowDBX. */
+/***********************************************************************/
+void DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt)
+ {
+ if (pdb) {
+ SWORD len;
+ RETCODE rc;
+ UCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1];
+ UCHAR state[SQL_SQLSTATE_SIZE + 1];
+ SDWORD native;
+ PGLOBAL g = pdb->m_G;
+
+ rc = SQLError(pdb->m_henv, pdb->m_hdbc, hstmt, state,
+ &native, msg, SQL_MAX_MESSAGE_LENGTH - 1, &len);
+
+ if (rc != SQL_INVALID_HANDLE)
+ // Skip non-errors
+ for (int i = 0; i < MAX_NUM_OF_MSG
+ && (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
+ && strcmp((char*)state, "00000"); i++) {
+ m_ErrMsg[i] = (PSZ)PlugSubAlloc(g, NULL, strlen((char*)msg) + 1);
+ strcpy(m_ErrMsg[i], (char*)msg);
+
+#ifdef DEBTRACE
+ htrc("%s, Native=%d\n", msg, native);
+#endif
+
+ rc = SQLError(pdb->m_henv, pdb->m_hdbc, hstmt, state,
+ &native, msg, SQL_MAX_MESSAGE_LENGTH - 1, &len);
+ } // endfor i
+
+ else
+ m_ErrMsg[0] = MSG(BAD_HANDLE_VAL);
+
+ } else
+ m_ErrMsg[0] = "No connexion address provided";
+
+ } // end of BuildErrorMessage
+
+/***********************************************************************/
+/* ODBConn construction/destruction. */
+/***********************************************************************/
+ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
+ {
+ m_G = g;
+ m_Tdb = tdbp;
+ m_hdbc = SQL_NULL_HDBC;
+//m_Recset = NULL
+ m_hstmt = SQL_NULL_HSTMT;
+ m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT;
+ m_QueryTimeout = DEFAULT_QUERY_TIMEOUT;
+ m_UpdateOptions = 0;
+ m_RowsetSize = (DWORD)((tdbp) ? tdbp->Rows : 10);
+ m_Catver = (tdbp) ? tdbp->Catver : 0;
+ m_Connect = NULL;
+ m_Updatable = true;
+//m_Transactions = false;
+ m_IDQuoteChar = '\'';
+//*m_ErrMsg = '\0';
+ } // end of ODBConn
+
+//ODBConn::~ODBConn()
+// {
+//if (Connected())
+// EndCom();
+
+// } // end of ~ODBConn
+
+/***********************************************************************/
+/* Screen for errors. */
+/***********************************************************************/
+bool ODBConn::Check(RETCODE rc)
+ {
+ switch (rc) {
+ case SQL_SUCCESS_WITH_INFO:
+ if (m_G->Trace) {
+ DBX x(rc);
+
+ x.BuildErrorMessage(this, m_hstmt);
+ htrc("ODBC Success With Info, hstmt=%p %s\n",
+ m_hstmt, x.GetErrorMessage(0));
+ } // endif Trace
+
+ // Fall through
+ case SQL_SUCCESS:
+ case SQL_NO_DATA_FOUND:
+ return true;
+ } // endswitch rc
+
+ return false;
+ } // end of Check
+
+/***********************************************************************/
+/* DB exception throw routines. */
+/***********************************************************************/
+void ODBConn::ThrowDBX(RETCODE rc, HSTMT hstmt)
+ {
+ DBX* xp = new(m_G) DBX(rc);
+
+ xp->BuildErrorMessage(this, hstmt);
+ throw xp;
+ } // end of ThrowDBX
+
+void ODBConn::ThrowDBX(PSZ msg)
+ {
+ DBX* xp = new(m_G) DBX(0);
+
+ xp->m_ErrMsg[0] = msg;
+ throw xp;
+ } // end of ThrowDBX
+
+/***********************************************************************/
+/* Utility routine. */
+/***********************************************************************/
+PSZ ODBConn::GetStringInfo(ushort infotype)
+ {
+//ASSERT(m_hdbc != SQL_NULL_HDBC);
+ char *p, buffer[MAX_STRING_INFO];
+ SWORD result;
+ RETCODE rc;
+
+ rc = SQLGetInfo(m_hdbc, infotype, buffer, sizeof(buffer), &result);
+
+ if (!Check(rc))
+ ThrowDBX(rc); // Temporary
+// *buffer = '\0';
+
+ p = (char *)PlugSubAlloc(m_G, NULL, strlen(buffer) + 1);
+ strcpy(p, buffer);
+ return p;
+ } // end of GetStringInfo
+
+/***********************************************************************/
+/* Utility routine. */
+/***********************************************************************/
+int ODBConn::GetMaxValue(ushort infotype)
+ {
+//ASSERT(m_hdbc != SQL_NULL_HDBC);
+ ushort maxval;
+ RETCODE rc;
+
+ rc = SQLGetInfo(m_hdbc, infotype, &maxval, 0, NULL);
+
+ if (!Check(rc))
+ maxval = 0;
+
+ return (int)maxval;
+ } // end of GetMaxValue
+
+/***********************************************************************/
+/* Utility routines. */
+/***********************************************************************/
+void ODBConn::OnSetOptions(HSTMT hstmt)
+ {
+ RETCODE rc;
+ ASSERT(m_hdbc != SQL_NULL_HDBC);
+
+ if ((signed)m_QueryTimeout != -1) {
+ // Attempt to set query timeout. Ignore failure
+ rc = SQLSetStmtOption(hstmt, SQL_QUERY_TIMEOUT, m_QueryTimeout);
+
+ if (!Check(rc))
+ // don't attempt it again
+ m_QueryTimeout = (DWORD)-1;
+
+ } // endif m_QueryTimeout
+
+ if (m_RowsetSize > 0) {
+ // Attempt to set rowset size.
+ // In case of failure reset it to 0 to use Fetch.
+ rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, m_RowsetSize);
+
+ if (!Check(rc))
+ // don't attempt it again
+ m_RowsetSize = 0;
+
+ } // endif m_RowsetSize
+
+ } // end of OnSetOptions
+
+/***********************************************************************/
+/* Open: connect to a data source. */
+/***********************************************************************/
+int ODBConn::Open(PSZ ConnectString, DWORD options)
+ {
+ PGLOBAL& g = m_G;
+//ASSERT_VALID(this);
+//ASSERT(ConnectString == NULL || AfxIsValidString(ConnectString));
+ ASSERT(!(options & noOdbcDialog && options & forceOdbcDialog));
+
+ m_Updatable = !(options & openReadOnly);
+ m_Connect = ConnectString;
+
+ // Allocate the HDBC and make connection
+ try {
+ PSZ ver;
+
+ AllocConnect(options);
+ ver = GetStringInfo(SQL_ODBC_VER);
+
+ if (Connect(options)) {
+ strcpy(g->Message, MSG(CONNECT_CANCEL));
+ return 0;
+ } // endif
+
+ ver = GetStringInfo(SQL_DRIVER_ODBC_VER);
+ } catch(DBX *xp) {
+// strcpy(g->Message, xp->m_ErrMsg[0]);
+ strcpy(g->Message, xp->GetErrorMessage(0));
+ Free();
+ return -1;
+ } // end try-catch
+
+ // Verify support for required functionality and cache info
+ VerifyConnect();
+ GetConnectInfo();
+ return 1;
+ } // end of Open
+
+/***********************************************************************/
+/* Allocate an henv (first time called) and hdbc. */
+/***********************************************************************/
+void ODBConn::AllocConnect(DWORD Options)
+ {
+ if (m_hdbc != SQL_NULL_HDBC)
+ return;
+
+ RETCODE rc;
+//AfxLockGlobals(CRIT_ODBC);
+
+ // Need to allocate an environment for first connection
+ if (m_henv == SQL_NULL_HENV) {
+ ASSERT(m_nAlloc == 0);
+
+ rc = SQLAllocEnv(&m_henv);
+
+ if (!Check(rc)) {
+// AfxUnlockGlobals(CRIT_ODBC);
+ ThrowDBX(rc); // Fatal
+ } // endif
+
+ } // endif m_henv
+
+ // Do the real thing, allocating connection data
+ rc = SQLAllocConnect(m_henv, &m_hdbc);
+
+ if (!Check(rc)) {
+// AfxUnlockGlobals(CRIT_ODBC);
+ ThrowDBX(rc); // Fatal
+ } // endif
+
+ m_nAlloc++; // allocated at last
+//AfxUnlockGlobals(CRIT_ODBC);
+
+#if defined(_DEBUG)
+ if (Options & traceSQL) {
+ SQLSetConnectOption(m_hdbc, SQL_OPT_TRACEFILE, (DWORD)"xodbc.out");
+ SQLSetConnectOption(m_hdbc, SQL_OPT_TRACE, 1);
+ } // endif
+#endif // _DEBUG
+
+ rc = SQLSetConnectOption(m_hdbc, SQL_LOGIN_TIMEOUT, m_LoginTimeout);
+
+#ifdef DEBTRACE
+ if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
+ htrc("Warning: Failure setting login timeout\n");
+#endif
+
+ if (!m_Updatable) {
+ rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE,
+ SQL_MODE_READ_ONLY);
+#ifdef DEBTRACE
+ if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
+ htrc("Warning: Failure setting read only access mode\n");
+#endif
+ } // endif
+
+ // Turn on cursor lib support
+ if (Options & useCursorLib)
+ rc = SQLSetConnectOption(m_hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_ODBC);
+
+ return;
+ } // end of AllocConnect
+
+/***********************************************************************/
+/* Connect to data source using SQLDriverConnect. */
+/***********************************************************************/
+bool ODBConn::Connect(DWORD Options)
+ {
+ RETCODE rc;
+ SWORD nResult;
+ PUCHAR ConnOut = (PUCHAR)PlugSubAlloc(m_G, NULL, MAX_CONNECT_LEN);
+ UWORD wConnectOption = SQL_DRIVER_COMPLETE;
+#if defined(WIN32)
+ HWND hWndTop = GetForegroundWindow();
+ HWND hWnd = GetParent(hWndTop);
+
+ if (hWnd == NULL)
+ hWnd = GetDesktopWindow();
+#else // !WIN32
+ HWND hWnd = NULL;
+#endif // !WIN32
+ PGLOBAL& g = m_G;
+ PDBUSER dup = PlgGetUser(g);
+
+ if (Options & noOdbcDialog || dup->Remote)
+ wConnectOption = SQL_DRIVER_NOPROMPT;
+ else if (Options & forceOdbcDialog)
+ wConnectOption = SQL_DRIVER_PROMPT;
+
+ rc = SQLDriverConnect(m_hdbc, hWnd, (PUCHAR)m_Connect,
+ SQL_NTS, ConnOut, MAX_CONNECT_LEN,
+ &nResult, wConnectOption);
+
+#if defined(WIN32)
+ if (hWndTop)
+ EnableWindow(hWndTop, true);
+#endif // WIN32
+
+ // If user hit 'Cancel'
+ if (rc == SQL_NO_DATA_FOUND) {
+ Free();
+ return true;
+ } // endif rc
+
+ if (!Check(rc)) {
+#ifdef DEBTRACE
+ if (!hWnd == NULL)
+ htrc("Error: No default window for SQLDriverConnect\n");
+#endif
+ ThrowDBX(rc);
+ } // endif Check
+
+ // Save connect string returned from ODBC
+ m_Connect = (PSZ)ConnOut;
+
+ // All done
+ return false;
+ } // end of Connect
+
+void ODBConn::VerifyConnect()
+ {
+#if defined(NEWMSG) || defined(XMSG)
+ PGLOBAL& g = m_G;
+#endif // NEWMSG || XMSG
+ RETCODE rc;
+ SWORD result;
+ SWORD conformance;
+
+ rc = SQLGetInfo(m_hdbc, SQL_ODBC_API_CONFORMANCE,
+ &conformance, sizeof(conformance), &result);
+
+ if (!Check(rc))
+ ThrowDBX(rc);
+
+ if (conformance < SQL_OAC_LEVEL1)
+ ThrowDBX(MSG(API_CONF_ERROR));
+
+ rc = SQLGetInfo(m_hdbc, SQL_ODBC_SQL_CONFORMANCE,
+ &conformance, sizeof(conformance), &result);
+
+ if (!Check(rc))
+ ThrowDBX(rc);
+
+ if (conformance < SQL_OSC_MINIMUM)
+ ThrowDBX(MSG(SQL_CONF_ERROR));
+
+ } // end of VerifyConnect
+
+void ODBConn::GetConnectInfo()
+ {
+ RETCODE rc;
+ SWORD nResult;
+#if 0 // Update not implemented yet
+ UDWORD DrvPosOp;
+
+ // Reset the database update options
+ m_UpdateOptions = 0;
+
+ // Check for SQLSetPos support
+ rc = SQLGetInfo(m_hdbc, SQL_POS_OPERATIONS,
+ &DrvPosOp, sizeof(DrvPosOp), &nResult);
+
+ if (Check(rc) &&
+ (DrvPosOp & SQL_POS_UPDATE) &&
+ (DrvPosOp & SQL_POS_DELETE) &&
+ (DrvPosOp & SQL_POS_ADD))
+ m_UpdateOptions = SQL_SETPOSUPDATES;
+
+ // Check for positioned update SQL support
+ UDWORD PosStatements;
+
+ rc = SQLGetInfo(m_hdbc, SQL_POSITIONED_STATEMENTS,
+ &PosStatements, sizeof(PosStatements),
+ &nResult);
+
+ if (Check(rc) &&
+ (PosStatements & SQL_PS_POSITIONED_DELETE) &&
+ (PosStatements & SQL_PS_POSITIONED_UPDATE))
+ m_UpdateOptions |= SQL_POSITIONEDSQL;
+
+ if (m_Updatable) {
+ // Make sure data source is Updatable
+ char ReadOnly[10];
+
+ rc = SQLGetInfo(m_hdbc, SQL_DATA_SOURCE_READ_ONLY,
+ ReadOnly, sizeof(ReadOnly), &nResult);
+
+ if (Check(rc) && nResult == 1)
+ m_Updatable = !!strcmp(ReadOnly, "Y");
+ else
+ m_Updatable = false;
+
+#ifdef DEBTRACE
+ htrc("Warning: data source is readonly\n");
+#endif
+ } else // Make data source is !Updatable
+ rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE,
+ SQL_MODE_READ_ONLY);
+#endif // 0
+
+ // Cache the quote char to use when constructing SQL
+ char QuoteChar[2];
+
+ rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
+ QuoteChar, sizeof(QuoteChar), &nResult);
+
+ if (Check(rc) && nResult == 1)
+ m_IDQuoteChar = QuoteChar[0];
+ else
+ m_IDQuoteChar = ' ';
+
+#ifdef DEBTRACE
+ htrc("DBMS: %s, Version: %s",
+ GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER));
+#endif // DEBTRACE
+ } // end of GetConnectInfo
+
+/***********************************************************************/
+/* Allocate record set and execute an SQL query. */
+/***********************************************************************/
+int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
+ {
+ PGLOBAL& g = m_G;
+ void *buffer;
+ bool b;
+ UWORD n;
+ SWORD ncol, len, tp;
+ SQLLEN afrw;
+ ODBCCOL *colp;
+ RETCODE rc;
+ HSTMT hstmt;
+
+//m_Recset = new(m_G) RECSET(this);
+//ASSERT(m_Recset);
+
+ try {
+ b = false;
+
+ if (m_hstmt) {
+ RETCODE rc;
+
+// All this did not seems to make sense and was been commented out
+// if (IsOpen())
+// Close(SQL_CLOSE);
+
+ rc = SQLFreeStmt(m_hstmt, SQL_CLOSE);
+ hstmt = m_hstmt;
+ m_hstmt = NULL;
+ ThrowDBX(MSG(SEQUENCE_ERROR));
+ } else {
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE);
+
+ } // endif hstmt
+
+ OnSetOptions(hstmt);
+ b = true;
+
+ if (g->Trace) {
+ htrc("ExecDirect hstmt=%p %.64s\n", hstmt, sql);
+ fflush(debug);
+ } // endif Trace
+
+ do {
+ rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, hstmt);
+
+ do {
+ rc = SQLNumResultCols(hstmt, &ncol);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (ncol == 0) {
+ // Update or Delete statement
+ rc = SQLRowCount(hstmt, &afrw);
+
+ if (!Check(rc))
+ ThrowDBX(rc, hstmt);
+
+ return afrw;
+ } // endif ncol
+
+ for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
+ if (!colp->IsSpecial())
+ n++;
+
+ // n can be 0 for query such as Select count(*) from table
+ if (n && n != (UWORD)ncol)
+ ThrowDBX(MSG(COL_NUM_MISM));
+
+ // Now bind the column buffers
+ for (n = 1, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
+ if (!colp->IsSpecial()) {
+ buffer = colp->GetBuffer(m_RowsetSize);
+ len = colp->GetBuflen();
+ tp = GetSQLCType(colp->GetResultType());
+
+ if (tp == SQL_TYPE_NULL) {
+ sprintf(m_G->Message, MSG(INV_COLUMN_TYPE),
+ colp->GetResultType(), SVP(colp->GetName()));
+ ThrowDBX(m_G->Message);
+ } // endif tp
+
+ if (g->Trace) {
+ htrc("Binding col=%u type=%d buf=%p len=%d slen=%p\n",
+ n, tp, buffer, len, colp->GetStrLen());
+ fflush(debug);
+ } // endif Trace
+
+ rc = SQLBindCol(hstmt, n, tp, buffer, len, colp->GetStrLen());
+
+ if (!Check(rc))
+ ThrowDBX(rc, hstmt);
+
+ n++;
+ } // endif pcol
+
+ } catch(DBX *x) {
+#ifdef DEBTRACE
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+#endif
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+
+ if (b)
+ SQLCancel(hstmt);
+
+ rc = SQLFreeStmt(hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ return -1;
+ } // end try/catch
+
+ m_hstmt = hstmt;
+ return (int)m_RowsetSize; // May have been reset in OnSetOptions
+ } // end of ExecDirectSQL
+
+/***********************************************************************/
+/* Get the number of lines of the result set. */
+/***********************************************************************/
+int ODBConn::GetResultSize(char *sql, ODBCCOL *colp)
+ {
+ int n = 0;
+ RETCODE rc;
+
+ if (ExecDirectSQL(sql, colp) < 0)
+ return -1;
+
+ try {
+ for (n = 0; ; n++) {
+ do {
+ rc = SQLFetch(m_hstmt);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, m_hstmt);
+
+ if (rc == SQL_NO_DATA_FOUND)
+ break;
+
+ } // endfor n
+
+ } catch(DBX *x) {
+// strcpy(m_G->Message, x->m_ErrMsg[0]);
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+#ifdef DEBTRACE
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+#endif
+ SQLCancel(m_hstmt);
+ n = -2;
+ } // end try/catch
+
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+
+ if (n != 1)
+ return -3;
+ else
+ return colp->GetIntValue();
+
+ } // end of GetResultSize
+
+/***********************************************************************/
+/* Fetch next row. */
+/***********************************************************************/
+int ODBConn::Fetch()
+ {
+ ASSERT(m_hstmt);
+ int irc;
+ SQLULEN crow;
+ RETCODE rc;
+ PGLOBAL& g = m_G;
+
+ try {
+// do {
+ if (m_RowsetSize) {
+ rc = SQLExtendedFetch(m_hstmt, SQL_FETCH_NEXT, 1, &crow, NULL);
+ } else {
+ rc = SQLFetch(m_hstmt);
+ crow = 1;
+ } // endif m_RowsetSize
+// } while (rc == SQL_STILL_EXECUTING);
+
+ if (g->Trace)
+ htrc("Fetch: hstmt=%p RowseSize=%d rc=%d\n",
+ m_hstmt, m_RowsetSize, rc);
+
+ if (!Check(rc))
+ ThrowDBX(rc, m_hstmt);
+
+ irc = (rc == SQL_NO_DATA_FOUND) ? 0 : (int)crow;
+ } catch(DBX *x) {
+ if (g->Trace)
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ strcpy(g->Message, x->GetErrorMessage(0));
+ irc = -1;
+ } // end try/catch
+
+ return irc;
+ } // end of Fetch
+
+/***********************************************************************/
+/* Prepare an SQL statement for insert. */
+/***********************************************************************/
+int ODBConn::PrepareSQL(char *sql)
+ {
+ PGLOBAL& g = m_G;
+ bool b;
+ SWORD nparm;
+ RETCODE rc;
+ HSTMT hstmt;
+
+ try {
+ b = false;
+
+ if (m_hstmt) {
+ RETCODE rc = SQLFreeStmt(m_hstmt, SQL_CLOSE);
+
+ hstmt = m_hstmt;
+ m_hstmt = NULL;
+ ThrowDBX(MSG(SEQUENCE_ERROR));
+ } else {
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE);
+
+ } // endif hstmt
+
+ OnSetOptions(hstmt);
+ b = true;
+
+ if (g->Trace) {
+ htrc("Prepare hstmt=%p %.64s\n", hstmt, sql);
+ fflush(debug);
+ } // endif Trace
+
+ do {
+ rc = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, hstmt);
+
+ do {
+ rc = SQLNumParams(hstmt, &nparm);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ } catch(DBX *x) {
+#ifdef DEBTRACE
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+#endif
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+
+ if (b)
+ SQLCancel(hstmt);
+
+ rc = SQLFreeStmt(hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ return -1;
+ } // end try/catch
+
+ m_hstmt = hstmt;
+ return (int)nparm;
+ } // end of PrepareSQL
+
+/***********************************************************************/
+/* Bind a parameter for inserting. */
+/***********************************************************************/
+bool ODBConn::ExecuteSQL(void)
+ {
+ RETCODE rc;
+
+ try {
+ rc = SQLExecute(m_hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(rc, m_hstmt);
+
+ } catch(DBX *x) {
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+ SQLCancel(m_hstmt);
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of ExecuteSQL
+
+/***********************************************************************/
+/* Bind a parameter for inserting. */
+/***********************************************************************/
+bool ODBConn::BindParam(ODBCCOL *colp)
+ {
+ void *buf;
+ UWORD n = colp->GetRank();
+ SWORD ct, sqlt;
+ UDWORD len;
+ SQLLEN *strlen = colp->GetStrLen();
+ RETCODE rc;
+
+#if 0
+ try {
+ SWORD dec, nul;
+ rc = SQLDescribeParam(m_hstmt, n, &sqlt, &len, &dec, &nul);
+
+ if (!Check(rc))
+ ThrowDBX(rc, m_hstmt);
+
+ } catch(DBX *x) {
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+ } // end try/catch
+#endif // 0
+
+ buf = colp->GetBuffer(0);
+// len = colp->GetBuflen();
+ len = IsTypeNum(colp->GetResultType()) ? 0 : colp->GetBuflen();
+ ct = GetSQLCType(colp->GetResultType());
+ sqlt = GetSQLType(colp->GetResultType());
+ *strlen = IsTypeNum(colp->GetResultType()) ? 0 : SQL_NTS;
+
+ try {
+ rc = SQLBindParameter(m_hstmt, n, SQL_PARAM_INPUT, ct, sqlt,
+ len, 0, buf, 0, strlen);
+
+ if (!Check(rc))
+ ThrowDBX(rc, m_hstmt);
+
+ } catch(DBX *x) {
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+ SQLCancel(m_hstmt);
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of BindParam
+
+/***********************************************************************/
+/* Get the list of Data Sources and set it in qrp. */
+/***********************************************************************/
+bool ODBConn::GetDataSources(PQRYRES qrp)
+ {
+ UCHAR *dsn, *des;
+ UWORD dir = SQL_FETCH_FIRST;
+ SWORD n1, n2, p1, p2;
+ PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next;
+ RETCODE rc;
+
+ n1 = crp1->Clen;
+ n2 = crp2->Clen;
+
+ try {
+ rc = SQLAllocEnv(&m_henv);
+
+ if (!Check(rc))
+ ThrowDBX(rc); // Fatal
+
+ for (int i = 0; i < qrp->Maxres; i++) {
+ dsn = (UCHAR*)crp1->Kdata->GetValPtr(i);
+ des = (UCHAR*)crp2->Kdata->GetValPtr(i);
+ rc = SQLDataSources(m_henv, dir, dsn, n1, &p1, des, n2, &p2);
+
+ if (rc == SQL_NO_DATA_FOUND)
+ break;
+ else if (!Check(rc))
+ ThrowDBX(rc); // Fatal
+
+ qrp->Nblin++;
+ dir = SQL_FETCH_NEXT;
+ } // endfor i
+
+ } catch(DBX *x) {
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+ SQLFreeEnv(m_henv);
+ return true;
+ } // end try/catch
+
+ SQLFreeEnv(m_henv);
+ return false;
+ } // end of GetDataSources
+
+/***********************************************************************/
+/* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
+/***********************************************************************/
+int ODBConn::GetCatInfo(CATPARM *cap)
+ {
+#if defined(NEWMSG) || defined(XMSG)
+ PGLOBAL& g = m_G;
+#endif // NEWMSG || XMSG
+ void *buffer;
+ int i, irc;
+ bool b;
+ UWORD n;
+ SWORD ncol, len, tp;
+ SQLULEN crow;
+ PCOLRES crp;
+ RETCODE rc;
+ HSTMT hstmt = NULL;
+ SQLLEN *vl, *vlen;
+ PVAL *pval = NULL;
+
+ try {
+ b = false;
+
+ if (!m_hstmt) {
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE);
+
+ } else
+ ThrowDBX(MSG(SEQUENCE_ERROR));
+
+ b = true;
+
+ if ((m_RowsetSize = cap->Qrp->Maxres) > 0) {
+ if (m_Catver) {
+ // Attempt to set rowset size.
+ // In case of failure reset it to 0 to use Fetch.
+ if (m_Catver == 3) // ODBC Ver 3
+ rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE,
+ (SQLPOINTER)m_RowsetSize, 0);
+ else
+ rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, m_RowsetSize);
+
+ if (!Check(rc))
+ m_RowsetSize = 1; // don't attempt it again
+// ThrowDBX(rc, hstmt); // Temporary
+
+ if (m_Catver == 3) { // ODBC Ver 3
+ rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, cap->Status, 0);
+ rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &crow, 0);
+ } // endif m_Catver
+
+ } else // ORABUG
+ m_RowsetSize = 1;
+
+ } else
+ ThrowDBX("0-sized result");
+
+ // Now do call the proper ODBC API
+ switch (cap->Id) {
+ case CAT_TAB:
+// rc = SQLSetStmtAttr(hstmt, SQL_ATTR_METADATA_ID,
+// (SQLPOINTER)false, 0);
+ rc = SQLTables(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS,
+ cap->Pat, SQL_NTS);
+ break;
+ case CAT_COL:
+// rc = SQLSetStmtAttr(hstmt, SQL_ATTR_METADATA_ID,
+// (SQLPOINTER)true, 0);
+ rc = SQLColumns(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS,
+ cap->Pat, SQL_NTS);
+ break;
+ case CAT_KEY:
+ rc = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS);
+ break;
+ case CAT_STAT:
+ rc = SQLStatistics(hstmt, NULL, 0, NULL, 0, cap->Tab, SQL_NTS,
+ cap->Unique, cap->Accuracy);
+ break;
+ case CAT_SPC:
+ ThrowDBX("SQLSpecialColumns not available yet");
+ } // endswitch infotype
+
+ if (!Check(rc))
+ ThrowDBX(rc, hstmt);
+
+ rc = SQLNumResultCols(hstmt, &ncol);
+
+ // n + 1 because we ignore the first column
+ if ((n = (UWORD)cap->Qrp->Nbcol) + 1 > (UWORD)ncol)
+ ThrowDBX(MSG(COL_NUM_MISM));
+
+ if (m_RowsetSize == 1 && cap->Qrp->Maxres > 1) {
+ pval = (PVAL *)PlugSubAlloc(m_G, NULL, n * sizeof(PVAL));
+ vlen = (SQLLEN *)PlugSubAlloc(m_G, NULL, n * sizeof(SDWORD *));
+ } // endif
+
+ // Now bind the column buffers
+ for (n = 0, crp = cap->Qrp->Colresp; crp; crp = crp->Next) {
+ if (pval) {
+ pval[n] = AllocateValue(m_G, crp->Kdata->GetType(),
+ crp->Kdata->GetVlen(), 0);
+ buffer = pval[n]->GetTo_Val();
+ vl = vlen + n;
+ } else {
+ buffer = crp->Kdata->GetValPointer();
+ vl = cap->Vlen[n];
+ } // endif pval
+
+ len = GetTypeSize(crp->Type, crp->Clen);
+ tp = GetSQLCType(crp->Type);
+
+ if (tp == SQL_TYPE_NULL) {
+ sprintf(m_G->Message, MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
+ ThrowDBX(m_G->Message);
+ } // endif tp
+
+ // n + 2 because column numbers begin with 1 and because
+ // we ignore the first column
+ rc = SQLBindCol(hstmt, n + 2, tp, buffer, len, vl);
+
+ if (!Check(rc))
+ ThrowDBX(rc, hstmt);
+
+ n++;
+ } // endfor crp
+
+ // Now fetch the result
+ if (m_Catver != 3) {
+ if (m_RowsetSize > 1) {
+ rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 1, &crow, cap->Status);
+ } else if (pval) {
+ for (n = 0; n < cap->Qrp->Maxres; n++) {
+ if ((rc = SQLFetch(hstmt)) != SQL_SUCCESS)
+ break;
+
+ for (i = 0, crp = cap->Qrp->Colresp; crp; i++, crp = crp->Next) {
+ crp->Kdata->SetValue(pval[i], n);
+ cap->Vlen[i][n] = vlen[i];
+ } // endfor crp
+
+ } // endfor n
+
+ if ((crow = n) && rc == SQL_NO_DATA)
+ rc = SQL_SUCCESS;
+
+ } else {
+ rc = SQLFetch(hstmt);
+ crow = 1;
+ } // endif's
+
+ } else // ODBC Ver 3
+ rc = SQLFetch(hstmt);
+
+// if (!Check(rc))
+ if (rc == SQL_NO_DATA_FOUND) {
+ if (cap->Pat)
+ sprintf(m_G->Message, MSG(NO_TABCOL_DATA), cap->Tab, cap->Pat);
+ else
+ sprintf(m_G->Message, MSG(NO_TAB_DATA), cap->Tab);
+
+ ThrowDBX(m_G->Message);
+ } else if (rc != SQL_SUCCESS)
+ ThrowDBX(rc, hstmt);
+
+ irc = (int)crow;
+ } catch(DBX *x) {
+#ifdef DEBTRACE
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+#endif
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+ irc = -1;
+ } // end try/catch
+
+ if (b)
+ SQLCancel(hstmt);
+
+ // All this (hstmt vs> m_hstmt) to be revisited
+ if (hstmt)
+ rc = SQLFreeStmt(hstmt, SQL_DROP);
+
+ return irc;
+ } // end of GetCatInfo
+
+/***********************************************************************/
+/* Disconnect connection */
+/***********************************************************************/
+void ODBConn::Close()
+ {
+ RETCODE rc;
+
+#if 0
+ // Close any open recordsets
+ AfxLockGlobals(CRIT_ODBC);
+ TRY
+ {
+ while (!m_listRecordsets.IsEmpty())
+ {
+ CRecordset* pSet = (CRecordset*)m_listRecordsets.GetHead();
+ pSet->Close(); // will implicitly remove from list
+ pSet->m_pDatabase = NULL;
+ }
+ }
+ CATCH_ALL(e)
+ {
+ AfxUnlockGlobals(CRIT_ODBC);
+ THROW_LAST();
+ }
+ END_CATCH_ALL
+ AfxUnlockGlobals(CRIT_ODBC);
+#endif // 0
+
+ if (m_hstmt) {
+ // Is required for multiple tables
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ } // endif m_hstmt
+
+ if (m_hdbc != SQL_NULL_HDBC) {
+ rc = SQLDisconnect(m_hdbc);
+ rc = SQLFreeConnect(m_hdbc);
+ m_hdbc = SQL_NULL_HDBC;
+
+// AfxLockGlobals(CRIT_ODBC);
+ ASSERT(m_nAlloc != 0);
+ m_nAlloc--;
+// AfxUnlockGlobals(CRIT_ODBC);
+ } // endif m_hdbc
+
+ } // end of Close
+
+// Silently disconnect and free all ODBC resources.
+// Don't throw any exceptions
+void ODBConn::Free()
+ {
+ // Trap failures upon close
+ try {
+ Close();
+ } catch(DBX*) {
+ // Nothing we can do
+#ifdef DEBTRACE
+ htrc("Error: exception by Close ignored in Free\n");
+#endif
+// DELETE_EXCEPTION(x);
+ } // endcatch
+
+ // free henv if refcount goes to 0
+//AfxLockGlobals(CRIT_ODBC);
+ if (m_henv != SQL_NULL_HENV) {
+ ASSERT(m_nAlloc >= 0);
+
+ if (m_nAlloc == 0) {
+ // free last connection - release HENV
+#ifdef DEBTRACE
+ RETCODE rc = SQLFreeEnv(m_henv);
+ if (rc != SQL_SUCCESS) // Nothing we can do
+ htrc("Error: SQLFreeEnv failure ignored in Free\n");
+#else
+ SQLFreeEnv(m_henv);
+#endif
+ m_henv = SQL_NULL_HENV;
+ } // endif m_nAlloc
+ }
+//AfxUnlockGlobals(CRIT_ODBC);
+ } // end of Free
+
+#if 0
+//////////////////////////////////////////////////////////////////////////////
+// CRecordset helpers
+
+//id AFXAPI AfxSetCurrentRecord(int* plCurrentRecord, int nRows, RETCODE nRetCode);
+//id AFXAPI AfxSetRecordCount(int* plRecordCount, int lCurrentRecord,
+//bool bEOFSeen, RETCODE nRetCode);
+
+/***********************************************************************/
+/* RECSET class implementation */
+/***********************************************************************/
+RECSET::RECSET(ODBConn *dbcp)
+ {
+ m_pDB = dbcp;
+ m_hstmt = SQL_NULL_HSTMT;
+ m_OpenType = snapshot;
+ m_Options = none;
+
+#if 0
+ m_lOpen = AFX_RECORDSET_STATUS_UNKNOWN;
+ m_nEditMode = noMode;
+ m_nDefaultType = snapshot;
+
+ m_bAppendable = false;
+ m_bUpdatable = false;
+ m_bScrollable = false;
+ m_bRecordsetDb = false;
+ m_bRebindParams = false;
+ m_bLongBinaryColumns = false;
+ m_nLockMode = optimistic;
+ m_dwInitialGetDataLen = 0;
+ m_rgODBCFieldInfos = NULL;
+ m_rgFieldInfos = NULL;
+ m_rgRowStatus = NULL;
+ m_dwRowsetSize = 25;
+ m_dwAllocatedRowsetSize = 0;
+
+ m_nFields = 0;
+ m_nParams = 0;
+ m_nFieldsBound = 0;
+ m_lCurrentRecord = AFX_CURRENT_RECORD_UNDEFINED;
+ m_lRecordCount = 0;
+ m_bUseUpdateSQL = false;
+ m_bUseODBCCursorLib = false;
+ m_nResultCols = -1;
+ m_bCheckCacheForDirtyFields = true;
+
+ m_pbFieldFlags = NULL;
+ m_pbParamFlags = NULL;
+ m_plParamLength = NULL;
+ m_pvFieldProxy = NULL;
+ m_pvParamProxy = NULL;
+ m_nProxyFields = 0;
+ m_nProxyParams = 0;
+
+ m_hstmtUpdate = SQL_NULL_HSTMT;
+#endif // 0
+ } // end of RECSET constructor
+
+RECSET::~RECSET()
+ {
+ try {
+ if (m_hstmt) {
+#ifdef DEBTRACE
+ if (m_dwOptions & useMultiRowFetch) {
+ htrc("WARNING: Close called implicitly from destructor\n");
+ htrc("Use of multi row fetch requires explicit call\n");
+ htrc("to Close or memory leaks will result\n");
+ }
+#endif
+ Close();
+ } // endif m_hstmt
+
+// if (m_bRecordsetDb)
+// delete m_pDB; ??????
+
+ m_pDB = NULL;
+ } catch(DBX*) {
+ // Nothing we can do
+#ifdef DEBTRACE
+ htrc("Error: Exception ignored in ~RECSET\n");
+#endif
+ } // endtry/catch
+
+ } // end of ~RECSET
+
+/***********************************************************************/
+/* Open: this function does the following: */
+/* Allocates the hstmt, */
+/* Bind columns, */
+/* Execute the SQL statement */
+/***********************************************************************/
+bool RECSET::Open(PSZ sql, uint Type, DWORD options)
+ {
+ ASSERT(m_pDB && m_pDB->IsOpen());
+ ASSERT(Type == DB_USE_DEFAULT_TYPE || Type == dynaset ||
+ Type == snapshot || Type == forwardOnly || Type == dynamic);
+//ASSERT(!(options & readOnly && options & appendOnly));
+
+ // Cache state info and allocate hstmt
+ SetState(Type, sql, options);
+
+ try {
+ if (m_hstmt) {
+ if (IsOpen())
+ Close(SQL_CLOSE);
+
+ } else {
+ RETCODE rc = SQLAllocStmt(m_pDB->m_hdbc, &m_hstmt);
+
+ if (!Check(rc))
+ ThrowDBException(SQL_INVALID_HANDLE);
+
+ } // endif m_hstmt
+
+ m_pDB->OnSetOptions(m_hstmt);
+
+ // Allocate the field/param status arrays, if necessary
+// bool bUnbound = false;
+
+// if (m_nFields > 0 || m_nParams > 0)
+// AllocStatusArrays();
+// else
+// bUnbound = true;
+
+ // Build SQL and prep/execute or just execute direct
+// BuildSQL(sql);
+ PrepareAndExecute(sql);
+
+ // Cache some field info and prepare the rowset
+ AllocAndCacheFieldInfo();
+ AllocRowset();
+
+ // If late binding, still need to allocate status arrays
+// if (bUnbound && (m_nFields > 0 || m_nParams > 0))
+// AllocStatusArrays();
+
+ } catch(DBX *x) {
+ Close(SQL_DROP);
+// strcpy(m_pDB->m_G->Message, x->GetErrorMessage[0]);
+ strcpy(m_pDB->m_G->Message, x->GetErrorMessage(0));
+ return true;
+ } // endtry/catch
+
+ return false;
+ } // end of Open
+
+/***********************************************************************/
+/* Close a hstmt. */
+/***********************************************************************/
+void RECSET::Close(SWORD option)
+ {
+ if (m_hstmt != SQL_NULL_HSTMT) {
+ RETCODE rc = SQLFreeStmt(m_hstmt, option);
+
+ if (option == SQL_DROP)
+ m_hstmt = SQL_NULL_HSTMT;
+
+ } // endif m_hstmt
+
+#if 0
+ m_lOpen = RECORDSET_STATUS_CLOSED;
+ m_bBOF = true;
+ m_bEOF = true;
+ m_bDeleted = false;
+ m_bAppendable = false;
+ m_bUpdatable = false;
+ m_bScrollable = false;
+ m_bRebindParams = false;
+ m_bLongBinaryColumns = false;
+ m_nLockMode = optimistic;
+ m_nFieldsBound = 0;
+ m_nResultCols = -1;
+#endif // 0
+ } // end of Close
+#endif // 0
+
diff --git a/storage/connect/odbconn.h b/storage/connect/odbconn.h
index 7f1567eaa70..2bf18c049f7 100644
--- a/storage/connect/odbconn.h
+++ b/storage/connect/odbconn.h
@@ -1,185 +1,185 @@
-/***********************************************************************/
-/* 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);
- bool GetDataSources(PQRYRES qrp);
-
- 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
+/***********************************************************************/
+/* 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);
+ bool GetDataSources(PQRYRES qrp);
+
+ 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
diff --git a/storage/connect/osutil.c b/storage/connect/osutil.c
index 435ea58b8c9..5b32f0f5a3b 100644
--- a/storage/connect/osutil.c
+++ b/storage/connect/osutil.c
@@ -1,232 +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
+#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
diff --git a/storage/connect/osutil.h b/storage/connect/osutil.h
index 62987d5082a..7fcd0cd05d8 100644
--- a/storage/connect/osutil.h
+++ b/storage/connect/osutil.h
@@ -1,103 +1,103 @@
-#ifndef __OSUTIL_H__
-#define __OSUTIL_H__
-
-#if defined(UNIX) || defined(UNIV_LINUX)
-#include "my_global.h"
-#include <errno.h>
-#include <stddef.h>
-#include "os.h"
-
-#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__ */
+#ifndef __OSUTIL_H__
+#define __OSUTIL_H__
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include "my_global.h"
+#include <errno.h>
+#include <stddef.h>
+#include "os.h"
+
+#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__ */
diff --git a/storage/connect/plgcnx.h b/storage/connect/plgcnx.h
index d37ea3594b8..33b0ba64edc 100644
--- a/storage/connect/plgcnx.h
+++ b/storage/connect/plgcnx.h
@@ -1,218 +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 ---------------------------- */
+/**************************************************************************/
+/* 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 ---------------------------- */
diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h
index 13d2f81cdc1..6da5917dcaa 100644
--- a/storage/connect/plgdbsem.h
+++ b/storage/connect/plgdbsem.h
@@ -1,523 +1,523 @@
-/************** 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 *);
-
-
-#define MSGID_NONE 0
-#define MSGID_CANNOT_OPEN 1
-#define MSGID_OPEN_MODE_ERROR 2
-#define MSGID_OPEN_STRERROR 3
-#define MSGID_OPEN_ERROR_AND_STRERROR 4
-#define MSGID_OPEN_MODE_STRERROR 5
-#define MSGID_OPEN_EMPTY_FILE 6
-
-FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode);
-int global_open(GLOBAL *g, int msgid, const char *filename, int flags);
-int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode);
+/************** 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 *);
+
+
+#define MSGID_NONE 0
+#define MSGID_CANNOT_OPEN 1
+#define MSGID_OPEN_MODE_ERROR 2
+#define MSGID_OPEN_STRERROR 3
+#define MSGID_OPEN_ERROR_AND_STRERROR 4
+#define MSGID_OPEN_MODE_STRERROR 5
+#define MSGID_OPEN_EMPTY_FILE 6
+
+FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode);
+int global_open(GLOBAL *g, int msgid, const char *filename, int flags);
+int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode);
diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp
index fd697fec314..6969b49cb81 100644
--- a/storage/connect/plgdbutl.cpp
+++ b/storage/connect/plgdbutl.cpp
@@ -1,1558 +1,1558 @@
-/********** PlgDBUtl Fpe C++ Program Source Code File (.CPP) ***********/
-/* PROGRAM NAME: PLGDBUTL */
-/* ------------- */
-/* Version 3.7 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* Utility functions used by DB semantic routines. */
-/* */
-/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
-/* -------------------------------------- */
-/* */
-/* REQUIRED FILES: */
-/* --------------- */
-/* See Readme.C for a list and description of required SYSTEM files. */
-/* */
-/* PLGDBUTL.C - Source code */
-/* GLOBAL.H - Global declaration file */
-/* PLGDBSEM.H - DB application declaration file */
-/* */
-/* REQUIRED LIBRARIES: */
-/* ------------------- */
-/* OS2.LIB - OS2 libray */
-/* LLIBCE.LIB - Protect mode/standard combined large model C */
-/* library */
-/* */
-/* REQUIRED PROGRAMS: */
-/* ------------------ */
-/* IBM, MS, Borland or GNU C++ Compiler */
-/* IBM, MS, Borland or GNU Linker */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant MariaDB header file. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-#include <io.h>
-#include <fcntl.h>
-#include <errno.h>
-#define BIGMEM 1048576 // 1 Megabyte
-#else // !WIN32
-#include <unistd.h>
-#include <fcntl.h>
-#if defined(THREAD)
-#include <pthread.h>
-#endif // THREAD
-#include <stdarg.h>
-#define BIGMEM 2147483647 // Max int value
-#endif // !WIN32
-#include <locale.h>
-
-/***********************************************************************/
-/* Include application header files */
-/***********************************************************************/
-#include "global.h" // header containing all global declarations.
-#include "plgdbsem.h" // header containing the DB applic. declarations.
-#include "preparse.h" // For DATPAR
-#include "osutil.h"
-#include "maputil.h"
-#include "catalog.h"
-#include "colblk.h"
-#include "xtable.h" // header of TBX, TDB and TDBASE classes
-#include "tabcol.h" // header of XTAB and COLUMN classes
-
-/***********************************************************************/
-/* Macro or external routine definition */
-/***********************************************************************/
-#if defined(THREAD)
-#if defined(WIN32)
-extern CRITICAL_SECTION parsec; // Used calling the Flex parser
-#else // !WIN32
-extern pthread_mutex_t parmut;
-#endif // !WIN32
-#endif // THREAD
-
-#define PLGINI "plugdb.ini" /* Configuration settings file */
-#define PLGXINI "plgcnx.ini" /* Configuration settings file */
-
-/***********************************************************************/
-/* DB static variables. */
-/***********************************************************************/
-bool Initdone = false;
-bool plugin = false; // True when called by the XDB plugin handler
-
-extern "C" {
- char plgxini[_MAX_PATH] = PLGXINI;
- char plgini[_MAX_PATH] = PLGINI;
-#if defined(WIN32)
- char nmfile[_MAX_PATH] = ".\\Log\\plugdb.out";
- char pdebug[_MAX_PATH] = ".\\Log\\plgthread.out";
-
- HINSTANCE s_hModule; // Saved module handle
-#else // !WIN32
- char nmfile[_MAX_PATH] = "./Log/plugdb.out";
- char pdebug[_MAX_PATH] = "./Log/plgthread.out";
-#endif // !WIN32
-
-#if defined(XMSG)
- char msglang[16] = "ENGLISH"; // Default language
-#endif
-} // extern "C"
-
-extern "C" int trace;
-extern "C" char version[];
-
-// The debug trace used by the main thread
- FILE *pfile = NULL;
-
-MBLOCK Nmblk = {NULL, false, 0, false, NULL}; // Used to init MBLOCK's
-
-/***********************************************************************/
-/* Routines called externally and internally by utility routines. */
-/***********************************************************************/
-bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
-bool EvalLikePattern(LPCSTR, LPCSTR);
-void PlugConvertConstant(PGLOBAL, void* &, short&);
-
-#ifdef DOMDOC_SUPPORT
-void CloseXMLFile(PGLOBAL, PFBLOCK, bool);
-#endif // DOMDOC_SUPPORT
-
-#ifdef LIBXML2_SUPPORT
-void CloseXML2File(PGLOBAL, PFBLOCK, bool);
-#endif // LIBXML2_SUPPORT
-
-
-/***********************************************************************/
-/* Routines for file IO with error reporting to g->Message */
-/***********************************************************************/
-static void
-global_open_error_msg(GLOBAL *g, int msgid, const char *path, const char *mode)
-{
- int len;
- switch (msgid)
- {
- case MSGID_CANNOT_OPEN:
- len= snprintf(g->Message, sizeof(g->Message) - 1,
- MSG(CANNOT_OPEN), // Cannot open %s
- path);
- break;
-
- case MSGID_OPEN_MODE_ERROR:
- len= snprintf(g->Message, sizeof(g->Message) - 1,
- MSG(OPEN_MODE_ERROR), // "Open(%s) error %d on %s"
- mode, (int) errno, path);
- break;
-
- case MSGID_OPEN_MODE_STRERROR:
- len= snprintf(g->Message, sizeof(g->Message) - 1,
- MSG(OPEN_MODE_ERROR) ": %s", // Open(%s) error %d on %s: %s
- mode, (int) errno, path, strerror(errno));
- break;
-
- case MSGID_OPEN_STRERROR:
- len= snprintf(g->Message, sizeof(g->Message) - 1,
- MSG(OPEN_STRERROR), // "open error: %s"
- strerror(errno));
- break;
-
- case MSGID_OPEN_ERROR_AND_STRERROR:
- len= snprintf(g->Message, sizeof(g->Message) - 1,
- MSG(OPEN_ERROR) "%s",// "Open error %d in mode %d on %s: %s"
- errno, mode, path, strerror(errno));
- break;
-
- case MSGID_OPEN_EMPTY_FILE:
- len= snprintf(g->Message, sizeof(g->Message) - 1,
- MSG(OPEN_EMPTY_FILE), // "Opening empty file %s: %s"
- path, strerror(errno));
- default:
- DBUG_ASSERT(0);
- /* Fall through*/
- case 0:
- len= 0;
- }
- g->Message[len]= '\0';
-}
-
-
-FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode)
-{
- FILE *f;
- if (!(f= fopen(path, mode)))
- global_open_error_msg(g, msgid, path, mode);
- return f;
-}
-
-
-int global_open(GLOBAL *g, int msgid, const char *path, int flags)
-{
- int h;
- if ((h= open(path, flags)) <= 0)
- global_open_error_msg(g, msgid, path, "");
- return h;
-}
-
-
-int global_open(GLOBAL *g, int msgid, const char *path, int flags, int mode)
-{
- int h;
- if ((h= open(path, flags, mode)) <= 0)
- {
- char modestr[64];
- snprintf(modestr, sizeof(modestr), "%d", mode);
- global_open_error_msg(g, msgid, path, modestr);
- }
- return h;
-}
-
-
-/**************************************************************************/
-/* Utility for external callers (such as XDB) */
-/**************************************************************************/
-DllExport char *GetIni(int n = 0)
- {
- switch (n) {
- case 1: return plgxini; break;
- case 2: return nmfile; break;
- case 3: return pdebug; break;
- case 4: return version; break;
-#if defined(XMSG)
- case 5: return msglang; break;
-#endif // XMSG
-// default: return plgini;
- } // endswitch GetIni
-
- return plgini;
- } // end of GetIni
-
-DllExport void SetTrc(void)
- {
- // If tracing is on, debug must be initialized.
- debug = pfile;
- } // end of SetTrc
-
-#if 0
-/**************************************************************************/
-/* Tracing output function. */
-/**************************************************************************/
-void ptrc(char const *fmt, ...)
- {
- va_list ap;
- va_start (ap, fmt);
-
-// if (trace == 0 || (trace == 1 && !pfile) || !fmt)
-// printf("In %s wrong trace=%d pfile=%p fmt=%p\n",
-// __FILE__, trace, pfile, fmt);
-
- if (trace == 1)
- vfprintf(pfile, fmt, ap);
- else
- vprintf(fmt, ap);
-
- va_end (ap);
- } // end of ptrc
-#endif // 0
-
-/***********************************************************************/
-/* Allocate and initialize the new DB User Block. */
-/***********************************************************************/
-PDBUSER PlgMakeUser(PGLOBAL g)
- {
- PDBUSER dbuserp;
-
- if (!(dbuserp = (PDBUSER)PlugAllocMem(g, (uint)sizeof(DBUSERBLK)))) {
- sprintf(g->Message, MSG(MALLOC_ERROR), "PlgMakeUser");
- return NULL;
- } // endif dbuserp
-
- memset(dbuserp, 0, sizeof(DBUSERBLK));
-//dbuserp->Act2 = g->Activityp;
-//#if defined(UNIX)
-// dbuserp->LineLen = 160;
-//#else
-// dbuserp->LineLen = 78;
-//#endif
-//dbuserp->Maxres = MAXRES;
-//dbuserp->Maxlin = MAXLIN;
-//dbuserp->Maxbmp = MAXBMP;
-//dbuserp->AlgChoice = AMOD_AUTO;
- dbuserp->UseTemp = TMP_AUTO;
- dbuserp->Check = CHK_ALL;
- strcpy(dbuserp->Server, "CONNECT");
- return dbuserp;
- } // end of PlgMakeUser
-
-/***********************************************************************/
-/* PlgGetUser: returns DBUSER block pointer. */
-/***********************************************************************/
-PDBUSER PlgGetUser(PGLOBAL g)
- {
- PDBUSER dup = (PDBUSER)((g->Activityp) ? g->Activityp->Aptr : NULL);
-
- if (!dup)
- strcpy(g->Message, MSG(APPL_NOT_INIT));
-
- return dup;
- } // end of PlgGetUser
-
-/***********************************************************************/
-/* PlgGetCatalog: returns CATALOG class pointer. */
-/***********************************************************************/
-PCATLG PlgGetCatalog(PGLOBAL g, bool jump)
- {
- PDBUSER dbuserp = PlgGetUser(g);
- PCATLG cat = (dbuserp) ? dbuserp->Catalog : NULL;
-
- if (!cat && jump) {
- // Raise exception so caller doesn't have to check return value
- strcpy(g->Message, MSG(NO_ACTIVE_DB));
- longjmp(g->jumper[g->jump_level], 1);
- } // endif cat
-
- return cat;
- } // end of PlgGetCatalog
-
-/***********************************************************************/
-/* PlgGetCatalog: returns CATALOG class pointer. */
-/***********************************************************************/
-char *PlgGetDataPath(PGLOBAL g)
- {
- PCATLG cat = PlgGetCatalog(g, false);
-
- if (!cat)
- return GetIniString(g, NULL, "DataBase", "DataPath", "", plgini);
-
- return cat->GetDataPath();
- } // end of PlgGetDataPath
-
-/***********************************************************************/
-/* PlgGetXdbPath: sets the fully qualified file name of a database */
-/* description file in lgn and the new datapath in dp. */
-/* New database description file is a Configuration Settings file */
-/* that will be used and updated in case of DB modifications such */
-/* as Insert into a VCT file. Look for it and use it if found. */
-/* By default the configuration file is DataPath\name.xdb but the */
-/* configuration file name may also be specified in Plugdb.ini. */
-/***********************************************************************/
-bool PlgSetXdbPath(PGLOBAL g, PSZ dbname, PSZ dbpath,
- char *lgn, int lgsize,
- char *path, int psize)
- {
- char *dp, datapath[_MAX_PATH], ft[_MAX_EXT] = ".xdb";
- int n;
-
- if (path) {
- dp = path;
- n = psize;
- } else {
- dp = datapath;
- n = sizeof(datapath);
- } // endif path
-
- GetPrivateProfileString("DataBase", "DataPath", "", dp, n, plgini);
-
- if (trace)
- htrc("PlgSetXdbPath: path=%s\n", dp);
-
- if (dbpath) {
- char fn[_MAX_FNAME];
-
- strcpy(lgn, dbpath);
- _splitpath(lgn, NULL, NULL, fn, NULL);
-
- if (!*fn) // Old style use command
- strcat(lgn, dbname);
-
- _splitpath(lgn, NULL, NULL, dbname, NULL); // Extract DB name
- } else if (strcspn(dbname, ":/\\.") < strlen(dbname)) {
- // dbname name contains the path name of the XDB file
- strcpy(lgn, dbname);
- _splitpath(lgn, NULL, NULL, dbname, NULL); // Extract DB name
- } else
- /*******************************************************************/
- /* New database description file is a Configuration Settings file */
- /* that will be used and updated in case of DB modifications such */
- /* as Insert into a VCT file. Look for it and use it if found. */
- /* By default the configuration file is DataPath\name.xdb but the */
- /* configuration file name may also be specified in Plugdb.ini. */
- /*******************************************************************/
- GetPrivateProfileString("DBnames", dbname, "", lgn, lgsize, plgini);
-
- if (*lgn) {
-#if !defined(UNIX)
- char drive[_MAX_DRIVE];
- char direc[_MAX_DIR];
-#endif
- char fname[_MAX_FNAME];
- char ftype[_MAX_EXT];
-
- _splitpath(lgn, NULL, NULL, fname, ftype);
-
- if (!*ftype)
- strcat(lgn, ft);
- else if (!stricmp(ftype, ".var")) {
- strcpy(g->Message, MSG(NO_MORE_VAR));
- return true;
- } // endif ftype
-
- // Given DB description path may be relative to data path
- PlugSetPath(lgn, lgn, dp);
-
- // New data path is the path of the configuration setting file
-#if !defined(UNIX)
- _splitpath(lgn, drive, direc, NULL, NULL);
- _makepath(dp, drive, direc, "", "");
-#else
-//#error This must be tested for trailing slash
- _splitpath(lgn, NULL, dp, NULL, NULL);
-#endif
- } else {
- // Try dbname[.ext] in the current directory
- strcpy(lgn, dbname);
-
- if (!strchr(dbname, '.'))
- strcat(lgn, ft);
-
- PlugSetPath(lgn, lgn, dp);
- } // endif lgn
-
- if (trace)
- htrc("PlgSetXdbPath: new DB description file=%s\n", lgn);
-
- return false;
- } // end of PlgSetXdbPath
-
-/***********************************************************************/
-/* Extract from a path name the required component. */
-/* This function assumes there is enough space in the buffer. */
-/***********************************************************************/
-char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op)
- {
- char *drive = NULL, *direc = NULL, *fname = NULL, *ftype = NULL;
-
- switch (op) { // Determine which part to extract
-#if !defined(UNIX)
- case OP_FDISK: drive = pBuff; break;
-#endif // !UNIX
- case OP_FPATH: direc = pBuff; break;
- case OP_FNAME: fname = pBuff; break;
- case OP_FTYPE: ftype = pBuff; break;
- default:
- sprintf(g->Message, MSG(INVALID_OPER), op, "ExtractFromPath");
- return NULL;
- } // endswitch op
-
- // Now do the extraction
- _splitpath(FileName, drive, direc, fname, ftype);
- return pBuff;
- } // end of PlgExtractFromPath
-
-/***********************************************************************/
-/* Check the occurence and matching of a pattern against a string. */
-/* Because this function is only used for catalog name checking, */
-/* it must be case insensitive. */
-/***********************************************************************/
-bool PlugCheckPattern(PGLOBAL g, LPCSTR string, LPCSTR pat)
- {
- if (pat && strlen(pat)) {
- // This leaves 512 bytes (MAX_STR / 2) for each components
- LPSTR name = g->Message + MAX_STR / 2;
-
- strlwr(strcpy(name, string));
- strlwr(strcpy(g->Message, pat)); // Can be modified by Eval
- return EvalLikePattern(name, g->Message);
- } else
- return true;
-
- } // end of PlugCheckPattern
-
-/***********************************************************************/
-/* PlugEvalLike: evaluates a LIKE clause. */
-/* Syntaxe: M like P escape C. strg->M, pat->P, C not implemented yet */
-/***********************************************************************/
-bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci)
- {
- char *tp, *sp;
- bool b;
-
- if (trace)
- htrc("LIKE: strg='%s' pattern='%s'\n", strg, pat);
-
- if (ci) { /* Case insensitive test */
- if (strlen(pat) + strlen(strg) + 1 < MAX_STR)
- tp = g->Message;
- else if (!(tp = new char[strlen(pat) + strlen(strg) + 2])) {
- strcpy(g->Message, MSG(NEW_RETURN_NULL));
- longjmp(g->jumper[g->jump_level], OP_LIKE);
- } /* endif tp */
-
- sp = tp + strlen(pat) + 1;
- strlwr(strcpy(tp, pat)); /* Make a lower case copy of pat */
- strlwr(strcpy(sp, strg)); /* Make a lower case copy of strg */
- } else { /* Case sensitive test */
- if (strlen(pat) < MAX_STR) /* In most of the case for small pat */
- tp = g->Message; /* Use this as temporary work space. */
- else if (!(tp = new char[strlen(pat) + 1])) {
- strcpy(g->Message, MSG(NEW_RETURN_NULL));
- longjmp(g->jumper[g->jump_level], OP_LIKE);
- } /* endif tp */
-
- strcpy(tp, pat); /* Make a copy to be worked into */
- sp = (char*)strg;
- } /* endif ci */
-
- b = EvalLikePattern(sp, tp);
-
- if (tp != g->Message) /* If working space was obtained */
- delete [] tp; /* by the use of new, delete it. */
-
- return (b);
- } /* end of PlugEvalLike */
-
-/***********************************************************************/
-/* M and P are variable length character string. If M and P are zero */
-/* length strings then the Like predicate is true. */
-/* */
-/* The Like predicate is true if: */
-/* */
-/* 1- A subtring of M is a sequence of 0 or more contiguous <CR> of M */
-/* and each <CR> of M is part of exactly one substring. */
-/* */
-/* 2- If the i-th <subtring-specifyer> of P is an <arbitrary-char- */
-/* specifier>, the i-th subtring of M is any single <CR>. */
-/* */
-/* 3- If the i-th <subtring-specifyer> of P is an <arbitrary-string- */
-/* specifier>, then the i-th subtring of M is any sequence of zero */
-/* or more <CR>. */
-/* */
-/* 4- If the i-th <subtring-specifyer> of P is neither an <arbitrary- */
-/* character-specifier> nor an <arbitrary-string-specifier>, then */
-/* the i-th substring of M is equal to that <substring-specifier> */
-/* according to the collating sequence of the <like-predicate>, */
-/* without the appending of <space-character>, and has the same */
-/* length as that <substring-specifier>. */
-/* */
-/* 5- The number of substrings of M is equal to the number of */
-/* <subtring-specifiers> of P. */
-/* */
-/* Otherwise M like P is false. */
-/***********************************************************************/
-bool EvalLikePattern(LPCSTR sp, LPCSTR tp)
- {
- LPSTR p;
- char c;
- int n;
- bool b, t = false;
-
- if (trace)
- htrc("Eval Like: sp=%s tp=%s\n",
- (sp) ? sp : "Null", (tp) ? tp : "Null");
-
- /********************************************************************/
- /* If pattern is void, Like is true only if string is also void. */
- /********************************************************************/
- if (!*tp)
- return (!*sp);
-
- /********************************************************************/
- /* Analyse eventual arbitrary specifications ahead of pattern. */
- /********************************************************************/
- for (p = (LPSTR)tp; p;)
- switch (*p) { /* it can contain % and/or _ */
- case '%': /* An % has been found */
- t = true; /* Note eventual character skip */
- p++;
- break;
- case '_': /* An _ has been found */
- if (*sp) { /* If more character in string */
- sp++; /* skip it */
- p++;
- } else
- return false; /* Like condition is not met */
-
- break;
- default:
- tp = p; /* Point to rest of template */
- p = NULL; /* To stop For loop */
- break;
- } /* endswitch */
-
- if ((p = (LPSTR)strpbrk(tp, "%_"))) /* Get position of next % or _ */
- n = p - tp;
- else
- n = strlen(tp); /* Get length of pattern head */
-
- if (trace)
- htrc(" testing: t=%d sp=%s tp=%s p=%p\n", t, sp, tp, p);
-
- if (n > (signed)strlen(sp)) /* If head is longer than strg */
- b = false; /* Like condition is not met */
- else if (n == 0) /* If void <substring-specifier> */
- b = (t || !*sp); /* true if % or void strg. */
- else if (!t) {
- /*******************************************************************/
- /* No character to skip, check occurence of <subtring-specifier> */
- /* at the very beginning of remaining string. */
- /*******************************************************************/
- if (p) {
- if ((b = !strncmp(sp, tp, n)))
- b = EvalLikePattern(sp + n, p);
-
- } else
- b = !strcmp(sp, tp); /* strg and tmp heads match */
-
- } else
- if (p)
- /*****************************************************************/
- /* Here is the case explaining why we need a recursive routine. */
- /* The test must be done not only against the first occurence */
- /* of the <substring-specifier> in the remaining string, */
- /* but also with all eventual succeeding ones. */
- /*****************************************************************/
- for (b = false, c = *p; !b && (signed)strlen(sp) >= n; sp++) {
- *p = '\0'; /* Separate pattern header */
-
- if ((sp = strstr(sp, tp))) {
- *p = c;
- b = EvalLikePattern(sp + n, p);
- } else {
- *p = c;
- b = false;
- break;
- } /* endif s */
-
- } /* endfor b, sp */
-
- else {
- sp += (strlen(sp) - n);
- b = !strcmp(sp, tp);
- } /* endif p */
-
- if (trace)
- htrc(" done: b=%d n=%d sp=%s tp=%s\n",
- b, n, (sp) ? sp : "Null", tp);
-
- return (b);
- } /* end of EvalLikePattern */
-
-/***********************************************************************/
-/* PlugConvertConstant: convert a Plug constant to an Xobject. */
-/***********************************************************************/
-void PlugConvertConstant(PGLOBAL g, void* & value, short& type)
- {
- if (trace)
- htrc("PlugConvertConstant: value=%p type=%hd\n", value, type);
-
- if (type != TYPE_XOBJECT) {
- value = new(g) CONSTANT(g, value, type);
- type = TYPE_XOBJECT;
- } // endif type
-
- } // end of PlugConvertConstant
-
-/***********************************************************************/
-/* Call the Flex preparser to convert a date format to a sscanf input */
-/* format and a Strftime output format. Flag if not 0 indicates that */
-/* non quoted blanks are not included in the output format. */
-/***********************************************************************/
-PDTP MakeDateFormat(PGLOBAL g, PSZ dfmt, bool in, bool out, int flag)
- {
- PDTP pdp = (PDTP)PlugSubAlloc(g, NULL, sizeof(DATPAR));
-
- if (trace)
- htrc("MakeDateFormat: dfmt=%s\n", dfmt);
-
- memset(pdp, 0, sizeof(DATPAR));
- pdp->Format = pdp->Curp = dfmt;
- pdp->Outsize = 2 * strlen(dfmt) + 1;
-
- if (in)
- pdp->InFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
-
- if (out)
- pdp->OutFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
-
- pdp->Flag = flag;
-
- /*********************************************************************/
- /* Call the FLEX generated parser. In multi-threading mode the next */
- /* instruction is included in an Enter/LeaveCriticalSection bracket. */
- /*********************************************************************/
-#if defined(THREAD)
-#if defined(WIN32)
- EnterCriticalSection((LPCRITICAL_SECTION)&parsec);
-#else // !WIN32
- pthread_mutex_lock(&parmut);
-#endif // !WIN32
-#endif // THREAD
- /*int rc =*/ fmdflex(pdp);
-#if defined(THREAD)
-#if defined(WIN32)
- LeaveCriticalSection((LPCRITICAL_SECTION)&parsec);
-#else // !WIN32
- pthread_mutex_unlock(&parmut);
-#endif // !WIN32
-#endif // THREAD
-
- if (trace)
- htrc("Done: in=%s out=%s\n", SVP(pdp->InFmt), SVP(pdp->OutFmt));
- return pdp;
- } // end of MakeDateFormat
-
-/***********************************************************************/
-/* Extract the date from a formatted string according to format. */
-/***********************************************************************/
-int ExtractDate(char *dts, PDTP pdp, int defy, int val[6])
- {
- char *fmt, c, d, e, W[8][12];
- int i, k, m, numval;
- int n, y = 30;
-
- if (pdp)
- fmt = pdp->InFmt;
- else // assume standard MySQL date format
- fmt = "%4d-%2d-%2d %2d:%2d:%2d";
-
- if (trace)
- htrc("ExtractDate: dts=%s fmt=%s defy=%d\n", dts, fmt, defy);
-
- // Set default values for time only use
- if (defy) {
- // This may be a default value for year
- y = defy;
- val[0] = y;
- y = (y < 100) ? y : 30;
- } else
- val[0] = 70;
-
- val[1] = 1;
- val[2] = 1;
-
- for (i = 3; i < 6; i++)
- val[i] = 0;
-
- numval = 0;
-
- // Get the date field parse it with derived input format
- m = sscanf(dts, fmt, W[0], W[1], W[2], W[3], W[4], W[5], W[6], W[7]);
-
- if (m > pdp->Num)
- m = pdp->Num;
-
- for (i = 0; i < m; i++) {
- n = *(int*)W[i];
-
- switch (k = pdp->Index[i]) {
- case 0:
- if (n < y)
- n += 100;
-
- val[0] = n;
- numval = max(numval, 1);
- break;
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- val[k] = n;
- numval = max(numval, k + 1);
- break;
- case -1:
- c = toupper(W[i][0]);
- d = toupper(W[i][1]);
- e = toupper(W[i][2]);
-
- switch (c) {
- case 'J':
- n = (d == 'A') ? 1
- : (e == 'N') ? 6 : 7; break;
- case 'F': n = 2; break;
- case 'M':
- n = (e == 'R') ? 3 : 5; break;
- case 'A':
- n = (d == 'P') ? 4 : 8; break;
- break;
- case 'S': n = 9; break;
- case 'O': n = 10; break;
- case 'N': n = 11; break;
- case 'D': n = 12; break;
- } /* endswitch c */
-
- val[1] = n;
- numval = max(numval, 2);
- break;
- case -6:
- c = toupper(W[i][0]);
- n = val[3] % 12;
-
- if (c == 'P')
- n += 12;
-
- val[3] = n;
- break;
- } // endswitch Plugpar
-
- } // endfor i
-
- if (trace)
- htrc("numval=%d val=(%d,%d,%d,%d,%d,%d)\n",
- numval, val[0], val[1], val[2], val[3], val[4], val[5]);
-
- return numval;
- } // end of ExtractDate
-
-/***********************************************************************/
-/* Open file routine: the purpose of this routine is to make a list */
-/* of all open file so they can be closed in SQLINIT on error jump. */
-/***********************************************************************/
-FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype)
- {
- FILE *fop;
- PFBLOCK fp;
- PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
-
- if (trace) {
- htrc("PlugOpenFile: fname=%s ftype=%s\n", fname, ftype);
- htrc("dbuserp=%p\n", dbuserp);
- } // endif trace
-
- if ((fop= global_fopen(g, MSGID_OPEN_MODE_STRERROR, fname, ftype)) != NULL) {
- if (trace)
- htrc(" fop=%p\n", fop);
-
- fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
-
- if (trace)
- htrc(" fp=%p\n", fp);
-
- // fname may be in volatile memory such as stack
- fp->Fname = (char*)PlugSubAlloc(g, NULL, strlen(fname) + 1);
- strcpy((char*)fp->Fname, fname);
- fp->Count = 1;
- fp->Type = TYPE_FB_FILE;
- fp->File = fop;
- fp->Mode = MODE_ANY; // ???
- fp->Next = dbuserp->Openlist;
- dbuserp->Openlist = fp;
- } /* endif fop */
-
- if (trace)
- htrc(" returning fop=%p\n", fop);
-
- return (fop);
- } // end of PlugOpenFile
-
-/***********************************************************************/
-/* Close file routine: the purpose of this routine is to avoid */
-/* double closing that freeze the system on some Unix platforms. */
-/***********************************************************************/
-int PlugCloseFile(PGLOBAL g, PFBLOCK fp, bool all)
- {
- int rc = 0;
-
- if (trace)
- htrc("PlugCloseFile: fp=%p count=%hd type=%hd\n",
- fp, ((fp) ? fp->Count : 0), ((fp) ? fp->Type : 0));
-
- if (!fp || !fp->Count)
- return rc;
-
- switch (fp->Type) {
- case TYPE_FB_FILE:
- if (fclose((FILE *)fp->File) == EOF)
- rc = errno;
-
- fp->File = NULL;
- fp->Mode = MODE_ANY;
- fp->Count = 0;
- break;
- case TYPE_FB_MAP:
- if ((fp->Count = (all) ? 0 : fp->Count - 1))
- break;
-
- if (CloseMemMap(fp->Memory, fp->Length))
- rc = (int)GetLastError();
-
- fp->Memory = NULL;
- fp->Mode = MODE_ANY;
- // Passthru
- case TYPE_FB_HANDLE:
- if (fp->Handle && fp->Handle != INVALID_HANDLE_VALUE)
- if (CloseFileHandle(fp->Handle))
- rc = (rc) ? rc : (int)GetLastError();
-
- fp->Handle = INVALID_HANDLE_VALUE;
- fp->Mode = MODE_ANY;
- fp->Count = 0;
- break;
-#ifdef DOMDOC_SUPPORT
- case TYPE_FB_XML:
- CloseXMLFile(g, fp, all);
- break;
-#endif // DOMDOC_SUPPORT
-#ifdef LIBXML2_SUPPORT
- case TYPE_FB_XML2:
- CloseXML2File(g, fp, all);
- break;
-#endif // LIBXML2_SUPPORT
- default:
- rc = RC_FX;
- } // endswitch Type
-
- return rc;
- } // end of PlugCloseFile
-
-/***********************************************************************/
-/* PlugCleanup: Cleanup remaining items of a SQL query. */
-/***********************************************************************/
-void PlugCleanup(PGLOBAL g, bool dofree)
- {
- PCATLG cat;
- PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
-
- // The test on Catalog is to avoid a Windows bug that can make
- // LoadString in PlugGetMessage to fail in some case
- if (!dbuserp || !(cat = dbuserp->Catalog))
- return;
-
- /*********************************************************************/
- /* Close eventually still open/mapped files. */
- /*********************************************************************/
- for (PFBLOCK fp = dbuserp->Openlist; fp; fp = fp->Next)
- PlugCloseFile(g, fp, true);
-
- dbuserp->Openlist = NULL;
-
- if (dofree) {
- /*******************************************************************/
- /* Cleanup any non suballocated memory still not freed. */
- /*******************************************************************/
- for (PMBLOCK mp = dbuserp->Memlist; mp; mp = mp->Next)
- PlgDBfree(*mp);
-
- dbuserp->Memlist = NULL;
-
- /*******************************************************************/
- /* If not using permanent storage catalog, reset volatile values. */
- /*******************************************************************/
- cat->Reset();
-
- /*******************************************************************/
- /* This is the place to reset the pointer on domains. */
- /*******************************************************************/
- dbuserp->Subcor = false;
- dbuserp->Step = STEP(PARSING_QUERY);
- dbuserp->ProgMax = dbuserp->ProgCur = dbuserp->ProgSav = 0;
- } // endif dofree
-
- } // end of PlugCleanup
-
-/***********************************************************************/
-/* That stupid Windows 98 does not provide this function. */
-/***********************************************************************/
-bool WritePrivateProfileInt(LPCSTR sec, LPCSTR key, int n, LPCSTR ini)
- {
- char buf[12];
-
- sprintf(buf, "%d", n);
- return WritePrivateProfileString(sec, key, buf, ini);
- } // end of WritePrivateProfileInt
-
-/***********************************************************************/
-/* Retrieve a size from an INI file with eventual K or M following. */
-/***********************************************************************/
-int GetIniSize(char *section, char *key, char *def, char *ini)
- {
- char c, buff[32];
- int i;
- int n = 0;
-
- GetPrivateProfileString(section, key, def, buff, sizeof(buff), ini);
-
- if ((i = sscanf(buff, " %d %c ", &n, &c)) == 2)
- switch (toupper(c)) {
- case 'M':
- n *= 1024;
- case 'K':
- n *= 1024;
- } // endswitch c
-
- if (trace)
- htrc("GetIniSize: key=%s buff=%s i=%d n=%d\n", key, buff, i, n);
-
- return n;
- } // end of GetIniSize
-
-/***********************************************************************/
-/* Allocate a string retrieved from an INI file and return its address */
-/***********************************************************************/
-DllExport PSZ GetIniString(PGLOBAL g, void *mp, LPCSTR sec, LPCSTR key,
- LPCSTR def, LPCSTR ini)
- {
- char buff[_MAX_PATH];
- PSZ p;
- int n, m = sizeof(buff);
- char *buf = buff;
-
-#if defined(_DEBUG)
- assert (sec && key);
-#endif
-
- again:
- n = GetPrivateProfileString(sec, key, def, buf, m, ini);
-
- if (n == m - 1) {
- // String may have been truncated, make sure to have all
- if (buf != buff)
- delete [] buf;
-
- m *= 2;
- buf = new char[m];
- goto again;
- } // endif n
-
- p = (PSZ)PlugSubAlloc(g, mp, n + 1);
-
- if (trace)
- htrc("GetIniString: sec=%s key=%s buf=%s\n", sec, key, buf);
-
- strcpy(p, buf);
-
- if (buf != buff)
- delete [] buf;
-
- return p;
- } // end of GetIniString
-
-/***********************************************************************/
-/* GetAmName: return the name correponding to an AM code. */
-/***********************************************************************/
-char *GetAmName(PGLOBAL g, AMT am, void *memp)
- {
- char *amn= (char*)PlugSubAlloc(g, memp, 16);
-
- switch (am) {
- case TYPE_AM_ERROR: strcpy(amn, "ERROR"); break;
- case TYPE_AM_ROWID: strcpy(amn, "ROWID"); break;
- case TYPE_AM_FILID: strcpy(amn, "FILID"); break;
- case TYPE_AM_VIEW: strcpy(amn, "VIEW"); break;
- case TYPE_AM_COUNT: strcpy(amn, "COUNT"); break;
- case TYPE_AM_DCD: strcpy(amn, "DCD"); break;
- case TYPE_AM_CMS: strcpy(amn, "CMS"); break;
- case TYPE_AM_MAP: strcpy(amn, "MAP"); break;
- case TYPE_AM_FMT: strcpy(amn, "FMT"); break;
- case TYPE_AM_CSV: strcpy(amn, "CSV"); break;
- case TYPE_AM_MCV: strcpy(amn, "MCV"); break;
- case TYPE_AM_DOS: strcpy(amn, "DOS"); break;
- case TYPE_AM_FIX: strcpy(amn, "FIX"); break;
- case TYPE_AM_BIN: strcpy(amn, "BIN"); break;
- case TYPE_AM_VCT: strcpy(amn, "VEC"); break;
- case TYPE_AM_VMP: strcpy(amn, "VMP"); break;
- case TYPE_AM_DBF: strcpy(amn, "DBF"); break;
- case TYPE_AM_QRY: strcpy(amn, "QRY"); break;
- case TYPE_AM_SQL: strcpy(amn, "SQL"); break;
- case TYPE_AM_PLG: strcpy(amn, "PLG"); break;
- case TYPE_AM_PLM: strcpy(amn, "PLM"); break;
- case TYPE_AM_DOM: strcpy(amn, "DOM"); break;
- case TYPE_AM_DIR: strcpy(amn, "DIR"); break;
- case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break;
- case TYPE_AM_MAC: strcpy(amn, "MAC"); break;
- case TYPE_AM_OEM: strcpy(amn, "OEM"); break;
- case TYPE_AM_OUT: strcpy(amn, "OUT"); break;
- default: sprintf(amn, "OEM(%d)", am);
- } // endswitch am
-
- return amn;
- } // end of GetAmName
-
-#if defined(WIN32) && !defined(NOCATCH)
-/***********************************************************************/
-/* GetExceptionDesc: return the description of an exception code. */
-/***********************************************************************/
-char *GetExceptionDesc(PGLOBAL g, unsigned int e)
- {
- char *p;
-
- switch (e) {
- case EXCEPTION_GUARD_PAGE:
- p = MSG(GUARD_PAGE);
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- p = MSG(DATA_MISALIGN);
- break;
- case EXCEPTION_BREAKPOINT:
- p = MSG(BREAKPOINT);
- break;
- case EXCEPTION_SINGLE_STEP:
- p = MSG(SINGLE_STEP);
- break;
- case EXCEPTION_ACCESS_VIOLATION:
- p = MSG(ACCESS_VIOLATN);
- break;
- case EXCEPTION_IN_PAGE_ERROR:
- p = MSG(PAGE_ERROR);
- break;
- case EXCEPTION_INVALID_HANDLE:
- p = MSG(INVALID_HANDLE);
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- p = MSG(ILLEGAL_INSTR);
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- p = MSG(NONCONT_EXCEPT);
- break;
- case EXCEPTION_INVALID_DISPOSITION:
- p = MSG(INVALID_DISP);
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- p = MSG(ARRAY_BNDS_EXCD);
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- p = MSG(FLT_DENORMAL_OP);
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- p = MSG(FLT_ZERO_DIVIDE);
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- p = MSG(FLT_BAD_RESULT);
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- p = MSG(FLT_INVALID_OP);
- break;
- case EXCEPTION_FLT_OVERFLOW:
- p = MSG(FLT_OVERFLOW);
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- p = MSG(FLT_STACK_CHECK);
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- p = MSG(FLT_UNDERFLOW);
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- p = MSG(INT_ZERO_DIVIDE);
- break;
- case EXCEPTION_INT_OVERFLOW:
- p = MSG(INT_OVERFLOW);
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- p = MSG(PRIV_INSTR);
- break;
- case EXCEPTION_STACK_OVERFLOW:
- p = MSG(STACK_OVERFLOW);
- break;
- case CONTROL_C_EXIT:
- p = MSG(CONTROL_C_EXIT);
- break;
- case STATUS_NO_MEMORY:
- p = MSG(NO_MEMORY);
- break;
- default:
- p = MSG(UNKNOWN_EXCPT);
- break;
- } // endswitch nSE
-
- return p;
- } // end of GetExceptionDesc
-#endif // WIN32 && !NOCATCH
-
-/***********************************************************************/
-/* PlgDBalloc: allocates or suballocates memory conditionally. */
-/* If mp.Sub is true at entry, this forces suballocation. */
-/* If the memory is allocated, makes an entry in an allocation list */
-/* so it can be freed at the normal or error query completion. */
-/***********************************************************************/
-void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp)
- {
-//bool b;
- size_t maxsub, minsub;
- void *arp = (area) ? area : g->Sarea;
- PPOOLHEADER pph = (PPOOLHEADER)arp;
-
- if (mp.Memp) {
- // This is a reallocation. If this block is not suballocated, it
- // was already placed in the chain of memory blocks and we must
- // not do it again as it can trigger a loop when freeing them.
- // Note: this works if blocks can be reallocated only once.
- // Otherwise a new boolean must be added to the block that
- // indicate that it is chained, or a test on the whole chain be
- // done to check whether the block is already there.
-// b = mp.Sub;
- mp.Sub = false; // Restrict suballocation to one quarter
- } // endif Memp
-
- // Suballoc when possible if mp.Sub is initially true, but leaving
- // a minimum amount of storage for future operations such as the
- // optimize recalculation after insert; otherwise
- // suballoc only if size is smaller than one quarter of free mem.
- minsub = (pph->FreeBlk + pph->To_Free + 524248) >> 2;
- maxsub = (pph->FreeBlk < minsub) ? 0 : pph->FreeBlk - minsub;
- mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2));
-
- if (trace)
- htrc("PlgDBalloc: in %p size=%d used=%d free=%d sub=%d\n",
- arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub);
-
- if (!mp.Sub) {
- // For allocations greater than one fourth of remaining storage
- // in the area, do allocate from virtual storage.
-#if defined(WIN32)
- if (mp.Size >= BIGMEM)
- mp.Memp = VirtualAlloc(NULL, mp.Size, MEM_COMMIT, PAGE_READWRITE);
- else
-#endif
- mp.Memp = malloc(mp.Size);
-
- if (!mp.Inlist && mp.Memp) {
- // New allocated block, put it in the memory block chain.
- PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
-
- mp.Next = dbuserp->Memlist;
- dbuserp->Memlist = &mp;
- mp.Inlist = true;
- } // endif mp
-
- } else
- // Suballocating is Ok.
- mp.Memp = PlugSubAlloc(g, area, mp.Size);
-
- return mp.Memp;
- } // end of PlgDBalloc
-
-/***********************************************************************/
-/* PlgDBrealloc: reallocates memory conditionally. */
-/* Note that this routine can fail only when block size is increased */
-/* because otherwise we keep the old storage on failure. */
-/***********************************************************************/
-void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize)
- {
- MBLOCK m;
-
-#if defined(_DEBUG)
-// assert (mp.Memp != NULL);
-#endif
-
- if (trace)
- htrc("PlgDBrealloc: %p size=%d sub=%d\n", mp.Memp, mp.Size, mp.Sub);
-
- if (newsize == mp.Size)
- return mp.Memp; // Nothing to do
- else
- m = mp;
-
- if (!mp.Sub && mp.Size < BIGMEM && newsize < BIGMEM) {
- // Allocation was done by malloc, try to use realloc but
- // suballoc if newsize is smaller than one quarter of free mem.
- size_t maxsub;
- PPOOLHEADER pph = (PPOOLHEADER)((area) ? area : g->Sarea);
-
- maxsub = (pph->FreeBlk < 131072) ? 0 : pph->FreeBlk - 131072;
-
- if ((mp.Sub = (newsize <= (maxsub >> 2)))) {
- mp.Memp = PlugSubAlloc(g, area, newsize);
- memcpy(mp.Memp, m.Memp, min(m.Size, newsize));
- PlgDBfree(m); // Free the old block
- } else if (!(mp.Memp = realloc(mp.Memp, newsize))) {
- mp = m; // Possible only if newsize > Size
- return NULL; // Failed
- } // endif's
-
- mp.Size = newsize;
- } else if (!mp.Sub || newsize > mp.Size) {
- // Was suballocated or Allocation was done by VirtualAlloc
- // Make a new allocation and copy the useful part
- // Note: DO NOT reset Memp and Sub so we know that this
- // is a reallocation in PlgDBalloc
- mp.Size = newsize;
-
- if (PlgDBalloc(g, area, mp)) {
- memcpy(mp.Memp, m.Memp, min(m.Size, newsize));
- PlgDBfree(m); // Free the old block
- } else {
- mp = m; // No space to realloc, do nothing
-
- if (newsize > m.Size)
- return NULL; // Failed
-
- } // endif PlgDBalloc
-
- } // endif's
-
- if (trace)
- htrc(" newsize=%d newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub);
-
- return mp.Memp;
- } // end of PlgDBrealloc
-
-/***********************************************************************/
-/* PlgDBfree: free memory if not suballocated. */
-/***********************************************************************/
-void PlgDBfree(MBLOCK& mp)
- {
- if (trace)
- htrc("PlgDBfree: %p sub=%d size=%d\n", mp.Memp, mp.Sub, mp.Size);
-
- if (!mp.Sub && mp.Memp)
-#if defined(WIN32)
- if (mp.Size >= BIGMEM)
- VirtualFree(mp.Memp, 0, MEM_RELEASE);
- else
-#endif
- free(mp.Memp);
-
- // Do not reset Next to avoid cutting the Mblock chain
- mp.Memp = NULL;
- mp.Sub = false;
- mp.Size = 0;
- } // end of PlgDBfree
-
-#if 0 // Not used yet
-/***********************************************************************/
-/* Program for sub-allocating one item in a storage area. */
-/* Note: This function is equivalent to PlugSubAlloc except that in */
-/* case of insufficient memory, it returns NULL instead of doing a */
-/* long jump. The caller must test the return value for error. */
-/***********************************************************************/
-void *PlgDBSubAlloc(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(DEBTRACE)
- htrc("PlgDBSubAlloc: memp=%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 = NULL;
- PACTIVITY ap;
-
- if (memp == g->Sarea)
- pname = "Work";
- else if ((ap = g->Activityp)) {
- if (memp == ap->LangRulep)
- pname = "Rule";
- else if (memp == ap->Nodep[0])
- pname = "Dictionary";
- else if (memp == ap->Nodep[1])
- pname = "Vartok";
- else if (memp == ap->Nodep[2])
- pname = "Lexicon";
- else if (memp == ap->User_Dictp)
- pname = "User dictionary";
- else if (ap->Aptr)
- pname = "Application";
-
- } // endif memp
-
- if (pname)
- sprintf(g->Message,
- "Not enough memory in %s area for request of %d (used=%d free=%d)",
- pname, size, pph->To_Free, pph->FreeBlk);
- else
- sprintf(g->Message, MSG(SUBALLOC_ERROR),
- memp, size, pph->To_Free, pph->FreeBlk);
-
-#if defined(DEBTRACE)
- htrc("%s\n", g->Message);
-#endif
-
- return NULL;
- } // endif size
-
- /*********************************************************************/
- /* 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(DEBTRACE)
- htrc("Done memp=%p used=%d free=%d\n",
- memp, pph->To_Free, pph->FreeBlk);
-#endif
- return (memp);
- } // end of PlgDBSubAlloc
-#endif // 0 Not used yet
-
-/***********************************************************************/
-/* PUTOUT: Plug DB object typing routine. */
-/***********************************************************************/
-void PlugPutOut(PGLOBAL g, FILE *f, short t, void *v, uint n)
- {
- char m[64];
-
- if (trace)
- htrc("PUTOUT: f=%p t=%d v=%p n=%d\n", f, t, v, n);
-
- if (!v)
- return;
-
- memset(m, ' ', n); /* Make margin string */
- m[n] = '\0';
- n += 2; /* Increase margin */
-
- switch (t) {
- case TYPE_ERROR:
- fprintf(f, "--> %s\n", (PSZ)v);
- break;
-
- case TYPE_STRING:
- case TYPE_PSZ:
- fprintf(f, "%s%s\n", m, (PSZ)v);
- break;
-
- case TYPE_FLOAT:
- fprintf(f, "%s%lf\n", m, *(double *)v);
- break;
-
- case TYPE_LIST:
- case TYPE_COLIST:
- case TYPE_COL:
- {PPARM p;
-
- if (t == TYPE_LIST)
- fprintf(f, "%s%s\n", m, MSG(LIST));
- else
- fprintf(f, "%s%s\n", m, "Colist:");
-
- for (p = (PPARM)v; p; p = p->Next)
- PlugPutOut(g, f, p->Type, p->Value, n);
-
- } break;
-
- case TYPE_INT:
- fprintf(f, "%s%d\n", m, *(int *)v);
- break;
-
- case TYPE_SHORT:
- fprintf(f, "%s%hd\n", m, *(short *)v);
- break;
-
- case TYPE_VOID:
- break;
-
- case TYPE_SQL:
- case TYPE_TABLE:
- case TYPE_TDB:
- case TYPE_XOBJECT:
- ((PBLOCK)v)->Print(g, f, n-2);
- break;
-
- default:
- fprintf(f, "%s%s %d\n", m, MSG(ANSWER_TYPE), t);
- } /* endswitch */
-
- return;
- } /* end of PlugPutOut */
-
-/***********************************************************************/
-/* NewPointer: makes a table of pointer values to be changed later. */
-/***********************************************************************/
-DllExport void NewPointer(PTABS t, void *oldv, void *newv)
- {
- PTABPTR tp;
-
- if (!oldv) /* error ?????????? */
- return;
-
- if (!t->P1 || t->P1->Num == 50)
- if (!(tp = new TABPTR)) {
- PGLOBAL g = t->G;
-
- sprintf(g->Message, "NewPointer: %s", MSG(MEM_ALLOC_ERROR));
- longjmp(g->jumper[g->jump_level], 3);
- } else {
- tp->Next = t->P1;
- tp->Num = 0;
- t->P1 = tp;
- } /* endif tp */
-
- t->P1->Old[t->P1->Num] = oldv;
- t->P1->New[t->P1->Num++] = newv;
- } /* end of NewPointer */
-
-#if 0
-/***********************************************************************/
-/* Compare two files and return 0 if they are identical, else 1. */
-/***********************************************************************/
-int FileComp(PGLOBAL g, char *file1, char *file2)
- {
- char *fn[2], *bp[2], buff1[4096], buff2[4096];
- int i, k, n[2], h[2] = {-1,-1};
- int len[2], rc = -1;
-
- fn[0] = file1; fn[1] = file2;
- bp[0] = buff1; bp[1] = buff2;
-
- for (i = 0; i < 2; i++) {
-#if defined(WIN32)
- h[i]= global_open(g, MSGID_NONE, fn[i], _O_RDONLY | _O_BINARY);
-#else // !WIN32
- h[i]= global_open(g, MSGOD_NONE, fn[i], O_RDONLY);
-#endif // !WIN32
-
- if (h[i] == -1) {
-// if (errno != ENOENT) {
- sprintf(g->Message, MSG(OPEN_MODE_ERROR),
- "rb", (int)errno, fn[i]);
- strcat(strcat(g->Message, ": "), strerror(errno));
- longjmp(g->jumper[g->jump_level], 666);
-// } else
-// len[i] = 0; // File does not exist yet
-
- } else {
- if ((len[i] = _filelength(h[i])) < 0) {
- sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", fn[i]);
- longjmp(g->jumper[g->jump_level], 666);
- } // endif len
-
- } // endif h
-
- } // endfor i
-
- if (len[0] != len[1])
- rc = 1;
-
- while (rc == -1) {
- for (i = 0; i < 2; i++)
- if ((n[i] = read(h[i], bp[i], 4096)) < 0) {
- sprintf(g->Message, MSG(READ_ERROR), fn[i], strerror(errno));
- goto fin;
- } // endif n
-
- if (n[0] != n[1])
- rc = 1;
- else if (*n == 0)
- rc = 0;
- else for (k = 0; k < *n; k++)
- if (*(bp[0] + k) != *(bp[1] + k)) {
- rc = 1;
- goto fin;
- } // endif bp
-
- } // endwhile
-
- fin:
- for (i = 0; i < 2; i++)
- if (h[i] != -1)
- close(h[i]);
-
- return rc;
- } // end of FileComp
-#endif // 0
+/********** PlgDBUtl Fpe C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: PLGDBUTL */
+/* ------------- */
+/* Version 3.7 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* Utility functions used by DB semantic routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* See Readme.C for a list and description of required SYSTEM files. */
+/* */
+/* PLGDBUTL.C - Source code */
+/* GLOBAL.H - Global declaration file */
+/* PLGDBSEM.H - DB application declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* OS2.LIB - OS2 libray */
+/* LLIBCE.LIB - Protect mode/standard combined large model C */
+/* library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, MS, Borland or GNU C++ Compiler */
+/* IBM, MS, Borland or GNU Linker */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+#define BIGMEM 1048576 // 1 Megabyte
+#else // !WIN32
+#include <unistd.h>
+#include <fcntl.h>
+#if defined(THREAD)
+#include <pthread.h>
+#endif // THREAD
+#include <stdarg.h>
+#define BIGMEM 2147483647 // Max int value
+#endif // !WIN32
+#include <locale.h>
+
+/***********************************************************************/
+/* Include application header files */
+/***********************************************************************/
+#include "global.h" // header containing all global declarations.
+#include "plgdbsem.h" // header containing the DB applic. declarations.
+#include "preparse.h" // For DATPAR
+#include "osutil.h"
+#include "maputil.h"
+#include "catalog.h"
+#include "colblk.h"
+#include "xtable.h" // header of TBX, TDB and TDBASE classes
+#include "tabcol.h" // header of XTAB and COLUMN classes
+
+/***********************************************************************/
+/* Macro or external routine definition */
+/***********************************************************************/
+#if defined(THREAD)
+#if defined(WIN32)
+extern CRITICAL_SECTION parsec; // Used calling the Flex parser
+#else // !WIN32
+extern pthread_mutex_t parmut;
+#endif // !WIN32
+#endif // THREAD
+
+#define PLGINI "plugdb.ini" /* Configuration settings file */
+#define PLGXINI "plgcnx.ini" /* Configuration settings file */
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+bool Initdone = false;
+bool plugin = false; // True when called by the XDB plugin handler
+
+extern "C" {
+ char plgxini[_MAX_PATH] = PLGXINI;
+ char plgini[_MAX_PATH] = PLGINI;
+#if defined(WIN32)
+ char nmfile[_MAX_PATH] = ".\\Log\\plugdb.out";
+ char pdebug[_MAX_PATH] = ".\\Log\\plgthread.out";
+
+ HINSTANCE s_hModule; // Saved module handle
+#else // !WIN32
+ char nmfile[_MAX_PATH] = "./Log/plugdb.out";
+ char pdebug[_MAX_PATH] = "./Log/plgthread.out";
+#endif // !WIN32
+
+#if defined(XMSG)
+ char msglang[16] = "ENGLISH"; // Default language
+#endif
+} // extern "C"
+
+extern "C" int trace;
+extern "C" char version[];
+
+// The debug trace used by the main thread
+ FILE *pfile = NULL;
+
+MBLOCK Nmblk = {NULL, false, 0, false, NULL}; // Used to init MBLOCK's
+
+/***********************************************************************/
+/* Routines called externally and internally by utility routines. */
+/***********************************************************************/
+bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
+bool EvalLikePattern(LPCSTR, LPCSTR);
+void PlugConvertConstant(PGLOBAL, void* &, short&);
+
+#ifdef DOMDOC_SUPPORT
+void CloseXMLFile(PGLOBAL, PFBLOCK, bool);
+#endif // DOMDOC_SUPPORT
+
+#ifdef LIBXML2_SUPPORT
+void CloseXML2File(PGLOBAL, PFBLOCK, bool);
+#endif // LIBXML2_SUPPORT
+
+
+/***********************************************************************/
+/* Routines for file IO with error reporting to g->Message */
+/***********************************************************************/
+static void
+global_open_error_msg(GLOBAL *g, int msgid, const char *path, const char *mode)
+{
+ int len;
+ switch (msgid)
+ {
+ case MSGID_CANNOT_OPEN:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(CANNOT_OPEN), // Cannot open %s
+ path);
+ break;
+
+ case MSGID_OPEN_MODE_ERROR:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_MODE_ERROR), // "Open(%s) error %d on %s"
+ mode, (int) errno, path);
+ break;
+
+ case MSGID_OPEN_MODE_STRERROR:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_MODE_ERROR) ": %s", // Open(%s) error %d on %s: %s
+ mode, (int) errno, path, strerror(errno));
+ break;
+
+ case MSGID_OPEN_STRERROR:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_STRERROR), // "open error: %s"
+ strerror(errno));
+ break;
+
+ case MSGID_OPEN_ERROR_AND_STRERROR:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_ERROR) "%s",// "Open error %d in mode %d on %s: %s"
+ errno, mode, path, strerror(errno));
+ break;
+
+ case MSGID_OPEN_EMPTY_FILE:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_EMPTY_FILE), // "Opening empty file %s: %s"
+ path, strerror(errno));
+ default:
+ DBUG_ASSERT(0);
+ /* Fall through*/
+ case 0:
+ len= 0;
+ }
+ g->Message[len]= '\0';
+}
+
+
+FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode)
+{
+ FILE *f;
+ if (!(f= fopen(path, mode)))
+ global_open_error_msg(g, msgid, path, mode);
+ return f;
+}
+
+
+int global_open(GLOBAL *g, int msgid, const char *path, int flags)
+{
+ int h;
+ if ((h= open(path, flags)) <= 0)
+ global_open_error_msg(g, msgid, path, "");
+ return h;
+}
+
+
+int global_open(GLOBAL *g, int msgid, const char *path, int flags, int mode)
+{
+ int h;
+ if ((h= open(path, flags, mode)) <= 0)
+ {
+ char modestr[64];
+ snprintf(modestr, sizeof(modestr), "%d", mode);
+ global_open_error_msg(g, msgid, path, modestr);
+ }
+ return h;
+}
+
+
+/**************************************************************************/
+/* Utility for external callers (such as XDB) */
+/**************************************************************************/
+DllExport char *GetIni(int n = 0)
+ {
+ switch (n) {
+ case 1: return plgxini; break;
+ case 2: return nmfile; break;
+ case 3: return pdebug; break;
+ case 4: return version; break;
+#if defined(XMSG)
+ case 5: return msglang; break;
+#endif // XMSG
+// default: return plgini;
+ } // endswitch GetIni
+
+ return plgini;
+ } // end of GetIni
+
+DllExport void SetTrc(void)
+ {
+ // If tracing is on, debug must be initialized.
+ debug = pfile;
+ } // end of SetTrc
+
+#if 0
+/**************************************************************************/
+/* Tracing output function. */
+/**************************************************************************/
+void ptrc(char const *fmt, ...)
+ {
+ va_list ap;
+ va_start (ap, fmt);
+
+// if (trace == 0 || (trace == 1 && !pfile) || !fmt)
+// printf("In %s wrong trace=%d pfile=%p fmt=%p\n",
+// __FILE__, trace, pfile, fmt);
+
+ if (trace == 1)
+ vfprintf(pfile, fmt, ap);
+ else
+ vprintf(fmt, ap);
+
+ va_end (ap);
+ } // end of ptrc
+#endif // 0
+
+/***********************************************************************/
+/* Allocate and initialize the new DB User Block. */
+/***********************************************************************/
+PDBUSER PlgMakeUser(PGLOBAL g)
+ {
+ PDBUSER dbuserp;
+
+ if (!(dbuserp = (PDBUSER)PlugAllocMem(g, (uint)sizeof(DBUSERBLK)))) {
+ sprintf(g->Message, MSG(MALLOC_ERROR), "PlgMakeUser");
+ return NULL;
+ } // endif dbuserp
+
+ memset(dbuserp, 0, sizeof(DBUSERBLK));
+//dbuserp->Act2 = g->Activityp;
+//#if defined(UNIX)
+// dbuserp->LineLen = 160;
+//#else
+// dbuserp->LineLen = 78;
+//#endif
+//dbuserp->Maxres = MAXRES;
+//dbuserp->Maxlin = MAXLIN;
+//dbuserp->Maxbmp = MAXBMP;
+//dbuserp->AlgChoice = AMOD_AUTO;
+ dbuserp->UseTemp = TMP_AUTO;
+ dbuserp->Check = CHK_ALL;
+ strcpy(dbuserp->Server, "CONNECT");
+ return dbuserp;
+ } // end of PlgMakeUser
+
+/***********************************************************************/
+/* PlgGetUser: returns DBUSER block pointer. */
+/***********************************************************************/
+PDBUSER PlgGetUser(PGLOBAL g)
+ {
+ PDBUSER dup = (PDBUSER)((g->Activityp) ? g->Activityp->Aptr : NULL);
+
+ if (!dup)
+ strcpy(g->Message, MSG(APPL_NOT_INIT));
+
+ return dup;
+ } // end of PlgGetUser
+
+/***********************************************************************/
+/* PlgGetCatalog: returns CATALOG class pointer. */
+/***********************************************************************/
+PCATLG PlgGetCatalog(PGLOBAL g, bool jump)
+ {
+ PDBUSER dbuserp = PlgGetUser(g);
+ PCATLG cat = (dbuserp) ? dbuserp->Catalog : NULL;
+
+ if (!cat && jump) {
+ // Raise exception so caller doesn't have to check return value
+ strcpy(g->Message, MSG(NO_ACTIVE_DB));
+ longjmp(g->jumper[g->jump_level], 1);
+ } // endif cat
+
+ return cat;
+ } // end of PlgGetCatalog
+
+/***********************************************************************/
+/* PlgGetCatalog: returns CATALOG class pointer. */
+/***********************************************************************/
+char *PlgGetDataPath(PGLOBAL g)
+ {
+ PCATLG cat = PlgGetCatalog(g, false);
+
+ if (!cat)
+ return GetIniString(g, NULL, "DataBase", "DataPath", "", plgini);
+
+ return cat->GetDataPath();
+ } // end of PlgGetDataPath
+
+/***********************************************************************/
+/* PlgGetXdbPath: sets the fully qualified file name of a database */
+/* description file in lgn and the new datapath in dp. */
+/* New database description file is a Configuration Settings file */
+/* that will be used and updated in case of DB modifications such */
+/* as Insert into a VCT file. Look for it and use it if found. */
+/* By default the configuration file is DataPath\name.xdb but the */
+/* configuration file name may also be specified in Plugdb.ini. */
+/***********************************************************************/
+bool PlgSetXdbPath(PGLOBAL g, PSZ dbname, PSZ dbpath,
+ char *lgn, int lgsize,
+ char *path, int psize)
+ {
+ char *dp, datapath[_MAX_PATH], ft[_MAX_EXT] = ".xdb";
+ int n;
+
+ if (path) {
+ dp = path;
+ n = psize;
+ } else {
+ dp = datapath;
+ n = sizeof(datapath);
+ } // endif path
+
+ GetPrivateProfileString("DataBase", "DataPath", "", dp, n, plgini);
+
+ if (trace)
+ htrc("PlgSetXdbPath: path=%s\n", dp);
+
+ if (dbpath) {
+ char fn[_MAX_FNAME];
+
+ strcpy(lgn, dbpath);
+ _splitpath(lgn, NULL, NULL, fn, NULL);
+
+ if (!*fn) // Old style use command
+ strcat(lgn, dbname);
+
+ _splitpath(lgn, NULL, NULL, dbname, NULL); // Extract DB name
+ } else if (strcspn(dbname, ":/\\.") < strlen(dbname)) {
+ // dbname name contains the path name of the XDB file
+ strcpy(lgn, dbname);
+ _splitpath(lgn, NULL, NULL, dbname, NULL); // Extract DB name
+ } else
+ /*******************************************************************/
+ /* New database description file is a Configuration Settings file */
+ /* that will be used and updated in case of DB modifications such */
+ /* as Insert into a VCT file. Look for it and use it if found. */
+ /* By default the configuration file is DataPath\name.xdb but the */
+ /* configuration file name may also be specified in Plugdb.ini. */
+ /*******************************************************************/
+ GetPrivateProfileString("DBnames", dbname, "", lgn, lgsize, plgini);
+
+ if (*lgn) {
+#if !defined(UNIX)
+ char drive[_MAX_DRIVE];
+ char direc[_MAX_DIR];
+#endif
+ char fname[_MAX_FNAME];
+ char ftype[_MAX_EXT];
+
+ _splitpath(lgn, NULL, NULL, fname, ftype);
+
+ if (!*ftype)
+ strcat(lgn, ft);
+ else if (!stricmp(ftype, ".var")) {
+ strcpy(g->Message, MSG(NO_MORE_VAR));
+ return true;
+ } // endif ftype
+
+ // Given DB description path may be relative to data path
+ PlugSetPath(lgn, lgn, dp);
+
+ // New data path is the path of the configuration setting file
+#if !defined(UNIX)
+ _splitpath(lgn, drive, direc, NULL, NULL);
+ _makepath(dp, drive, direc, "", "");
+#else
+//#error This must be tested for trailing slash
+ _splitpath(lgn, NULL, dp, NULL, NULL);
+#endif
+ } else {
+ // Try dbname[.ext] in the current directory
+ strcpy(lgn, dbname);
+
+ if (!strchr(dbname, '.'))
+ strcat(lgn, ft);
+
+ PlugSetPath(lgn, lgn, dp);
+ } // endif lgn
+
+ if (trace)
+ htrc("PlgSetXdbPath: new DB description file=%s\n", lgn);
+
+ return false;
+ } // end of PlgSetXdbPath
+
+/***********************************************************************/
+/* Extract from a path name the required component. */
+/* This function assumes there is enough space in the buffer. */
+/***********************************************************************/
+char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op)
+ {
+ char *drive = NULL, *direc = NULL, *fname = NULL, *ftype = NULL;
+
+ switch (op) { // Determine which part to extract
+#if !defined(UNIX)
+ case OP_FDISK: drive = pBuff; break;
+#endif // !UNIX
+ case OP_FPATH: direc = pBuff; break;
+ case OP_FNAME: fname = pBuff; break;
+ case OP_FTYPE: ftype = pBuff; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_OPER), op, "ExtractFromPath");
+ return NULL;
+ } // endswitch op
+
+ // Now do the extraction
+ _splitpath(FileName, drive, direc, fname, ftype);
+ return pBuff;
+ } // end of PlgExtractFromPath
+
+/***********************************************************************/
+/* Check the occurence and matching of a pattern against a string. */
+/* Because this function is only used for catalog name checking, */
+/* it must be case insensitive. */
+/***********************************************************************/
+bool PlugCheckPattern(PGLOBAL g, LPCSTR string, LPCSTR pat)
+ {
+ if (pat && strlen(pat)) {
+ // This leaves 512 bytes (MAX_STR / 2) for each components
+ LPSTR name = g->Message + MAX_STR / 2;
+
+ strlwr(strcpy(name, string));
+ strlwr(strcpy(g->Message, pat)); // Can be modified by Eval
+ return EvalLikePattern(name, g->Message);
+ } else
+ return true;
+
+ } // end of PlugCheckPattern
+
+/***********************************************************************/
+/* PlugEvalLike: evaluates a LIKE clause. */
+/* Syntaxe: M like P escape C. strg->M, pat->P, C not implemented yet */
+/***********************************************************************/
+bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci)
+ {
+ char *tp, *sp;
+ bool b;
+
+ if (trace)
+ htrc("LIKE: strg='%s' pattern='%s'\n", strg, pat);
+
+ if (ci) { /* Case insensitive test */
+ if (strlen(pat) + strlen(strg) + 1 < MAX_STR)
+ tp = g->Message;
+ else if (!(tp = new char[strlen(pat) + strlen(strg) + 2])) {
+ strcpy(g->Message, MSG(NEW_RETURN_NULL));
+ longjmp(g->jumper[g->jump_level], OP_LIKE);
+ } /* endif tp */
+
+ sp = tp + strlen(pat) + 1;
+ strlwr(strcpy(tp, pat)); /* Make a lower case copy of pat */
+ strlwr(strcpy(sp, strg)); /* Make a lower case copy of strg */
+ } else { /* Case sensitive test */
+ if (strlen(pat) < MAX_STR) /* In most of the case for small pat */
+ tp = g->Message; /* Use this as temporary work space. */
+ else if (!(tp = new char[strlen(pat) + 1])) {
+ strcpy(g->Message, MSG(NEW_RETURN_NULL));
+ longjmp(g->jumper[g->jump_level], OP_LIKE);
+ } /* endif tp */
+
+ strcpy(tp, pat); /* Make a copy to be worked into */
+ sp = (char*)strg;
+ } /* endif ci */
+
+ b = EvalLikePattern(sp, tp);
+
+ if (tp != g->Message) /* If working space was obtained */
+ delete [] tp; /* by the use of new, delete it. */
+
+ return (b);
+ } /* end of PlugEvalLike */
+
+/***********************************************************************/
+/* M and P are variable length character string. If M and P are zero */
+/* length strings then the Like predicate is true. */
+/* */
+/* The Like predicate is true if: */
+/* */
+/* 1- A subtring of M is a sequence of 0 or more contiguous <CR> of M */
+/* and each <CR> of M is part of exactly one substring. */
+/* */
+/* 2- If the i-th <subtring-specifyer> of P is an <arbitrary-char- */
+/* specifier>, the i-th subtring of M is any single <CR>. */
+/* */
+/* 3- If the i-th <subtring-specifyer> of P is an <arbitrary-string- */
+/* specifier>, then the i-th subtring of M is any sequence of zero */
+/* or more <CR>. */
+/* */
+/* 4- If the i-th <subtring-specifyer> of P is neither an <arbitrary- */
+/* character-specifier> nor an <arbitrary-string-specifier>, then */
+/* the i-th substring of M is equal to that <substring-specifier> */
+/* according to the collating sequence of the <like-predicate>, */
+/* without the appending of <space-character>, and has the same */
+/* length as that <substring-specifier>. */
+/* */
+/* 5- The number of substrings of M is equal to the number of */
+/* <subtring-specifiers> of P. */
+/* */
+/* Otherwise M like P is false. */
+/***********************************************************************/
+bool EvalLikePattern(LPCSTR sp, LPCSTR tp)
+ {
+ LPSTR p;
+ char c;
+ int n;
+ bool b, t = false;
+
+ if (trace)
+ htrc("Eval Like: sp=%s tp=%s\n",
+ (sp) ? sp : "Null", (tp) ? tp : "Null");
+
+ /********************************************************************/
+ /* If pattern is void, Like is true only if string is also void. */
+ /********************************************************************/
+ if (!*tp)
+ return (!*sp);
+
+ /********************************************************************/
+ /* Analyse eventual arbitrary specifications ahead of pattern. */
+ /********************************************************************/
+ for (p = (LPSTR)tp; p;)
+ switch (*p) { /* it can contain % and/or _ */
+ case '%': /* An % has been found */
+ t = true; /* Note eventual character skip */
+ p++;
+ break;
+ case '_': /* An _ has been found */
+ if (*sp) { /* If more character in string */
+ sp++; /* skip it */
+ p++;
+ } else
+ return false; /* Like condition is not met */
+
+ break;
+ default:
+ tp = p; /* Point to rest of template */
+ p = NULL; /* To stop For loop */
+ break;
+ } /* endswitch */
+
+ if ((p = (LPSTR)strpbrk(tp, "%_"))) /* Get position of next % or _ */
+ n = p - tp;
+ else
+ n = strlen(tp); /* Get length of pattern head */
+
+ if (trace)
+ htrc(" testing: t=%d sp=%s tp=%s p=%p\n", t, sp, tp, p);
+
+ if (n > (signed)strlen(sp)) /* If head is longer than strg */
+ b = false; /* Like condition is not met */
+ else if (n == 0) /* If void <substring-specifier> */
+ b = (t || !*sp); /* true if % or void strg. */
+ else if (!t) {
+ /*******************************************************************/
+ /* No character to skip, check occurence of <subtring-specifier> */
+ /* at the very beginning of remaining string. */
+ /*******************************************************************/
+ if (p) {
+ if ((b = !strncmp(sp, tp, n)))
+ b = EvalLikePattern(sp + n, p);
+
+ } else
+ b = !strcmp(sp, tp); /* strg and tmp heads match */
+
+ } else
+ if (p)
+ /*****************************************************************/
+ /* Here is the case explaining why we need a recursive routine. */
+ /* The test must be done not only against the first occurence */
+ /* of the <substring-specifier> in the remaining string, */
+ /* but also with all eventual succeeding ones. */
+ /*****************************************************************/
+ for (b = false, c = *p; !b && (signed)strlen(sp) >= n; sp++) {
+ *p = '\0'; /* Separate pattern header */
+
+ if ((sp = strstr(sp, tp))) {
+ *p = c;
+ b = EvalLikePattern(sp + n, p);
+ } else {
+ *p = c;
+ b = false;
+ break;
+ } /* endif s */
+
+ } /* endfor b, sp */
+
+ else {
+ sp += (strlen(sp) - n);
+ b = !strcmp(sp, tp);
+ } /* endif p */
+
+ if (trace)
+ htrc(" done: b=%d n=%d sp=%s tp=%s\n",
+ b, n, (sp) ? sp : "Null", tp);
+
+ return (b);
+ } /* end of EvalLikePattern */
+
+/***********************************************************************/
+/* PlugConvertConstant: convert a Plug constant to an Xobject. */
+/***********************************************************************/
+void PlugConvertConstant(PGLOBAL g, void* & value, short& type)
+ {
+ if (trace)
+ htrc("PlugConvertConstant: value=%p type=%hd\n", value, type);
+
+ if (type != TYPE_XOBJECT) {
+ value = new(g) CONSTANT(g, value, type);
+ type = TYPE_XOBJECT;
+ } // endif type
+
+ } // end of PlugConvertConstant
+
+/***********************************************************************/
+/* Call the Flex preparser to convert a date format to a sscanf input */
+/* format and a Strftime output format. Flag if not 0 indicates that */
+/* non quoted blanks are not included in the output format. */
+/***********************************************************************/
+PDTP MakeDateFormat(PGLOBAL g, PSZ dfmt, bool in, bool out, int flag)
+ {
+ PDTP pdp = (PDTP)PlugSubAlloc(g, NULL, sizeof(DATPAR));
+
+ if (trace)
+ htrc("MakeDateFormat: dfmt=%s\n", dfmt);
+
+ memset(pdp, 0, sizeof(DATPAR));
+ pdp->Format = pdp->Curp = dfmt;
+ pdp->Outsize = 2 * strlen(dfmt) + 1;
+
+ if (in)
+ pdp->InFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
+
+ if (out)
+ pdp->OutFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
+
+ pdp->Flag = flag;
+
+ /*********************************************************************/
+ /* Call the FLEX generated parser. In multi-threading mode the next */
+ /* instruction is included in an Enter/LeaveCriticalSection bracket. */
+ /*********************************************************************/
+#if defined(THREAD)
+#if defined(WIN32)
+ EnterCriticalSection((LPCRITICAL_SECTION)&parsec);
+#else // !WIN32
+ pthread_mutex_lock(&parmut);
+#endif // !WIN32
+#endif // THREAD
+ /*int rc =*/ fmdflex(pdp);
+#if defined(THREAD)
+#if defined(WIN32)
+ LeaveCriticalSection((LPCRITICAL_SECTION)&parsec);
+#else // !WIN32
+ pthread_mutex_unlock(&parmut);
+#endif // !WIN32
+#endif // THREAD
+
+ if (trace)
+ htrc("Done: in=%s out=%s\n", SVP(pdp->InFmt), SVP(pdp->OutFmt));
+ return pdp;
+ } // end of MakeDateFormat
+
+/***********************************************************************/
+/* Extract the date from a formatted string according to format. */
+/***********************************************************************/
+int ExtractDate(char *dts, PDTP pdp, int defy, int val[6])
+ {
+ char *fmt, c, d, e, W[8][12];
+ int i, k, m, numval;
+ int n, y = 30;
+
+ if (pdp)
+ fmt = pdp->InFmt;
+ else // assume standard MySQL date format
+ fmt = "%4d-%2d-%2d %2d:%2d:%2d";
+
+ if (trace)
+ htrc("ExtractDate: dts=%s fmt=%s defy=%d\n", dts, fmt, defy);
+
+ // Set default values for time only use
+ if (defy) {
+ // This may be a default value for year
+ y = defy;
+ val[0] = y;
+ y = (y < 100) ? y : 30;
+ } else
+ val[0] = 70;
+
+ val[1] = 1;
+ val[2] = 1;
+
+ for (i = 3; i < 6; i++)
+ val[i] = 0;
+
+ numval = 0;
+
+ // Get the date field parse it with derived input format
+ m = sscanf(dts, fmt, W[0], W[1], W[2], W[3], W[4], W[5], W[6], W[7]);
+
+ if (m > pdp->Num)
+ m = pdp->Num;
+
+ for (i = 0; i < m; i++) {
+ n = *(int*)W[i];
+
+ switch (k = pdp->Index[i]) {
+ case 0:
+ if (n < y)
+ n += 100;
+
+ val[0] = n;
+ numval = max(numval, 1);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ val[k] = n;
+ numval = max(numval, k + 1);
+ break;
+ case -1:
+ c = toupper(W[i][0]);
+ d = toupper(W[i][1]);
+ e = toupper(W[i][2]);
+
+ switch (c) {
+ case 'J':
+ n = (d == 'A') ? 1
+ : (e == 'N') ? 6 : 7; break;
+ case 'F': n = 2; break;
+ case 'M':
+ n = (e == 'R') ? 3 : 5; break;
+ case 'A':
+ n = (d == 'P') ? 4 : 8; break;
+ break;
+ case 'S': n = 9; break;
+ case 'O': n = 10; break;
+ case 'N': n = 11; break;
+ case 'D': n = 12; break;
+ } /* endswitch c */
+
+ val[1] = n;
+ numval = max(numval, 2);
+ break;
+ case -6:
+ c = toupper(W[i][0]);
+ n = val[3] % 12;
+
+ if (c == 'P')
+ n += 12;
+
+ val[3] = n;
+ break;
+ } // endswitch Plugpar
+
+ } // endfor i
+
+ if (trace)
+ htrc("numval=%d val=(%d,%d,%d,%d,%d,%d)\n",
+ numval, val[0], val[1], val[2], val[3], val[4], val[5]);
+
+ return numval;
+ } // end of ExtractDate
+
+/***********************************************************************/
+/* Open file routine: the purpose of this routine is to make a list */
+/* of all open file so they can be closed in SQLINIT on error jump. */
+/***********************************************************************/
+FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype)
+ {
+ FILE *fop;
+ PFBLOCK fp;
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ if (trace) {
+ htrc("PlugOpenFile: fname=%s ftype=%s\n", fname, ftype);
+ htrc("dbuserp=%p\n", dbuserp);
+ } // endif trace
+
+ if ((fop= global_fopen(g, MSGID_OPEN_MODE_STRERROR, fname, ftype)) != NULL) {
+ if (trace)
+ htrc(" fop=%p\n", fop);
+
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+
+ if (trace)
+ htrc(" fp=%p\n", fp);
+
+ // fname may be in volatile memory such as stack
+ fp->Fname = (char*)PlugSubAlloc(g, NULL, strlen(fname) + 1);
+ strcpy((char*)fp->Fname, fname);
+ fp->Count = 1;
+ fp->Type = TYPE_FB_FILE;
+ fp->File = fop;
+ fp->Mode = MODE_ANY; // ???
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ } /* endif fop */
+
+ if (trace)
+ htrc(" returning fop=%p\n", fop);
+
+ return (fop);
+ } // end of PlugOpenFile
+
+/***********************************************************************/
+/* Close file routine: the purpose of this routine is to avoid */
+/* double closing that freeze the system on some Unix platforms. */
+/***********************************************************************/
+int PlugCloseFile(PGLOBAL g, PFBLOCK fp, bool all)
+ {
+ int rc = 0;
+
+ if (trace)
+ htrc("PlugCloseFile: fp=%p count=%hd type=%hd\n",
+ fp, ((fp) ? fp->Count : 0), ((fp) ? fp->Type : 0));
+
+ if (!fp || !fp->Count)
+ return rc;
+
+ switch (fp->Type) {
+ case TYPE_FB_FILE:
+ if (fclose((FILE *)fp->File) == EOF)
+ rc = errno;
+
+ fp->File = NULL;
+ fp->Mode = MODE_ANY;
+ fp->Count = 0;
+ break;
+ case TYPE_FB_MAP:
+ if ((fp->Count = (all) ? 0 : fp->Count - 1))
+ break;
+
+ if (CloseMemMap(fp->Memory, fp->Length))
+ rc = (int)GetLastError();
+
+ fp->Memory = NULL;
+ fp->Mode = MODE_ANY;
+ // Passthru
+ case TYPE_FB_HANDLE:
+ if (fp->Handle && fp->Handle != INVALID_HANDLE_VALUE)
+ if (CloseFileHandle(fp->Handle))
+ rc = (rc) ? rc : (int)GetLastError();
+
+ fp->Handle = INVALID_HANDLE_VALUE;
+ fp->Mode = MODE_ANY;
+ fp->Count = 0;
+ break;
+#ifdef DOMDOC_SUPPORT
+ case TYPE_FB_XML:
+ CloseXMLFile(g, fp, all);
+ break;
+#endif // DOMDOC_SUPPORT
+#ifdef LIBXML2_SUPPORT
+ case TYPE_FB_XML2:
+ CloseXML2File(g, fp, all);
+ break;
+#endif // LIBXML2_SUPPORT
+ default:
+ rc = RC_FX;
+ } // endswitch Type
+
+ return rc;
+ } // end of PlugCloseFile
+
+/***********************************************************************/
+/* PlugCleanup: Cleanup remaining items of a SQL query. */
+/***********************************************************************/
+void PlugCleanup(PGLOBAL g, bool dofree)
+ {
+ PCATLG cat;
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ // The test on Catalog is to avoid a Windows bug that can make
+ // LoadString in PlugGetMessage to fail in some case
+ if (!dbuserp || !(cat = dbuserp->Catalog))
+ return;
+
+ /*********************************************************************/
+ /* Close eventually still open/mapped files. */
+ /*********************************************************************/
+ for (PFBLOCK fp = dbuserp->Openlist; fp; fp = fp->Next)
+ PlugCloseFile(g, fp, true);
+
+ dbuserp->Openlist = NULL;
+
+ if (dofree) {
+ /*******************************************************************/
+ /* Cleanup any non suballocated memory still not freed. */
+ /*******************************************************************/
+ for (PMBLOCK mp = dbuserp->Memlist; mp; mp = mp->Next)
+ PlgDBfree(*mp);
+
+ dbuserp->Memlist = NULL;
+
+ /*******************************************************************/
+ /* If not using permanent storage catalog, reset volatile values. */
+ /*******************************************************************/
+ cat->Reset();
+
+ /*******************************************************************/
+ /* This is the place to reset the pointer on domains. */
+ /*******************************************************************/
+ dbuserp->Subcor = false;
+ dbuserp->Step = STEP(PARSING_QUERY);
+ dbuserp->ProgMax = dbuserp->ProgCur = dbuserp->ProgSav = 0;
+ } // endif dofree
+
+ } // end of PlugCleanup
+
+/***********************************************************************/
+/* That stupid Windows 98 does not provide this function. */
+/***********************************************************************/
+bool WritePrivateProfileInt(LPCSTR sec, LPCSTR key, int n, LPCSTR ini)
+ {
+ char buf[12];
+
+ sprintf(buf, "%d", n);
+ return WritePrivateProfileString(sec, key, buf, ini);
+ } // end of WritePrivateProfileInt
+
+/***********************************************************************/
+/* Retrieve a size from an INI file with eventual K or M following. */
+/***********************************************************************/
+int GetIniSize(char *section, char *key, char *def, char *ini)
+ {
+ char c, buff[32];
+ int i;
+ int n = 0;
+
+ GetPrivateProfileString(section, key, def, buff, sizeof(buff), ini);
+
+ if ((i = sscanf(buff, " %d %c ", &n, &c)) == 2)
+ switch (toupper(c)) {
+ case 'M':
+ n *= 1024;
+ case 'K':
+ n *= 1024;
+ } // endswitch c
+
+ if (trace)
+ htrc("GetIniSize: key=%s buff=%s i=%d n=%d\n", key, buff, i, n);
+
+ return n;
+ } // end of GetIniSize
+
+/***********************************************************************/
+/* Allocate a string retrieved from an INI file and return its address */
+/***********************************************************************/
+DllExport PSZ GetIniString(PGLOBAL g, void *mp, LPCSTR sec, LPCSTR key,
+ LPCSTR def, LPCSTR ini)
+ {
+ char buff[_MAX_PATH];
+ PSZ p;
+ int n, m = sizeof(buff);
+ char *buf = buff;
+
+#if defined(_DEBUG)
+ assert (sec && key);
+#endif
+
+ again:
+ n = GetPrivateProfileString(sec, key, def, buf, m, ini);
+
+ if (n == m - 1) {
+ // String may have been truncated, make sure to have all
+ if (buf != buff)
+ delete [] buf;
+
+ m *= 2;
+ buf = new char[m];
+ goto again;
+ } // endif n
+
+ p = (PSZ)PlugSubAlloc(g, mp, n + 1);
+
+ if (trace)
+ htrc("GetIniString: sec=%s key=%s buf=%s\n", sec, key, buf);
+
+ strcpy(p, buf);
+
+ if (buf != buff)
+ delete [] buf;
+
+ return p;
+ } // end of GetIniString
+
+/***********************************************************************/
+/* GetAmName: return the name correponding to an AM code. */
+/***********************************************************************/
+char *GetAmName(PGLOBAL g, AMT am, void *memp)
+ {
+ char *amn= (char*)PlugSubAlloc(g, memp, 16);
+
+ switch (am) {
+ case TYPE_AM_ERROR: strcpy(amn, "ERROR"); break;
+ case TYPE_AM_ROWID: strcpy(amn, "ROWID"); break;
+ case TYPE_AM_FILID: strcpy(amn, "FILID"); break;
+ case TYPE_AM_VIEW: strcpy(amn, "VIEW"); break;
+ case TYPE_AM_COUNT: strcpy(amn, "COUNT"); break;
+ case TYPE_AM_DCD: strcpy(amn, "DCD"); break;
+ case TYPE_AM_CMS: strcpy(amn, "CMS"); break;
+ case TYPE_AM_MAP: strcpy(amn, "MAP"); break;
+ case TYPE_AM_FMT: strcpy(amn, "FMT"); break;
+ case TYPE_AM_CSV: strcpy(amn, "CSV"); break;
+ case TYPE_AM_MCV: strcpy(amn, "MCV"); break;
+ case TYPE_AM_DOS: strcpy(amn, "DOS"); break;
+ case TYPE_AM_FIX: strcpy(amn, "FIX"); break;
+ case TYPE_AM_BIN: strcpy(amn, "BIN"); break;
+ case TYPE_AM_VCT: strcpy(amn, "VEC"); break;
+ case TYPE_AM_VMP: strcpy(amn, "VMP"); break;
+ case TYPE_AM_DBF: strcpy(amn, "DBF"); break;
+ case TYPE_AM_QRY: strcpy(amn, "QRY"); break;
+ case TYPE_AM_SQL: strcpy(amn, "SQL"); break;
+ case TYPE_AM_PLG: strcpy(amn, "PLG"); break;
+ case TYPE_AM_PLM: strcpy(amn, "PLM"); break;
+ case TYPE_AM_DOM: strcpy(amn, "DOM"); break;
+ case TYPE_AM_DIR: strcpy(amn, "DIR"); break;
+ case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break;
+ case TYPE_AM_MAC: strcpy(amn, "MAC"); break;
+ case TYPE_AM_OEM: strcpy(amn, "OEM"); break;
+ case TYPE_AM_OUT: strcpy(amn, "OUT"); break;
+ default: sprintf(amn, "OEM(%d)", am);
+ } // endswitch am
+
+ return amn;
+ } // end of GetAmName
+
+#if defined(WIN32) && !defined(NOCATCH)
+/***********************************************************************/
+/* GetExceptionDesc: return the description of an exception code. */
+/***********************************************************************/
+char *GetExceptionDesc(PGLOBAL g, unsigned int e)
+ {
+ char *p;
+
+ switch (e) {
+ case EXCEPTION_GUARD_PAGE:
+ p = MSG(GUARD_PAGE);
+ break;
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ p = MSG(DATA_MISALIGN);
+ break;
+ case EXCEPTION_BREAKPOINT:
+ p = MSG(BREAKPOINT);
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ p = MSG(SINGLE_STEP);
+ break;
+ case EXCEPTION_ACCESS_VIOLATION:
+ p = MSG(ACCESS_VIOLATN);
+ break;
+ case EXCEPTION_IN_PAGE_ERROR:
+ p = MSG(PAGE_ERROR);
+ break;
+ case EXCEPTION_INVALID_HANDLE:
+ p = MSG(INVALID_HANDLE);
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ p = MSG(ILLEGAL_INSTR);
+ break;
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ p = MSG(NONCONT_EXCEPT);
+ break;
+ case EXCEPTION_INVALID_DISPOSITION:
+ p = MSG(INVALID_DISP);
+ break;
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ p = MSG(ARRAY_BNDS_EXCD);
+ break;
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ p = MSG(FLT_DENORMAL_OP);
+ break;
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ p = MSG(FLT_ZERO_DIVIDE);
+ break;
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ p = MSG(FLT_BAD_RESULT);
+ break;
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ p = MSG(FLT_INVALID_OP);
+ break;
+ case EXCEPTION_FLT_OVERFLOW:
+ p = MSG(FLT_OVERFLOW);
+ break;
+ case EXCEPTION_FLT_STACK_CHECK:
+ p = MSG(FLT_STACK_CHECK);
+ break;
+ case EXCEPTION_FLT_UNDERFLOW:
+ p = MSG(FLT_UNDERFLOW);
+ break;
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ p = MSG(INT_ZERO_DIVIDE);
+ break;
+ case EXCEPTION_INT_OVERFLOW:
+ p = MSG(INT_OVERFLOW);
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ p = MSG(PRIV_INSTR);
+ break;
+ case EXCEPTION_STACK_OVERFLOW:
+ p = MSG(STACK_OVERFLOW);
+ break;
+ case CONTROL_C_EXIT:
+ p = MSG(CONTROL_C_EXIT);
+ break;
+ case STATUS_NO_MEMORY:
+ p = MSG(NO_MEMORY);
+ break;
+ default:
+ p = MSG(UNKNOWN_EXCPT);
+ break;
+ } // endswitch nSE
+
+ return p;
+ } // end of GetExceptionDesc
+#endif // WIN32 && !NOCATCH
+
+/***********************************************************************/
+/* PlgDBalloc: allocates or suballocates memory conditionally. */
+/* If mp.Sub is true at entry, this forces suballocation. */
+/* If the memory is allocated, makes an entry in an allocation list */
+/* so it can be freed at the normal or error query completion. */
+/***********************************************************************/
+void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp)
+ {
+//bool b;
+ size_t maxsub, minsub;
+ void *arp = (area) ? area : g->Sarea;
+ PPOOLHEADER pph = (PPOOLHEADER)arp;
+
+ if (mp.Memp) {
+ // This is a reallocation. If this block is not suballocated, it
+ // was already placed in the chain of memory blocks and we must
+ // not do it again as it can trigger a loop when freeing them.
+ // Note: this works if blocks can be reallocated only once.
+ // Otherwise a new boolean must be added to the block that
+ // indicate that it is chained, or a test on the whole chain be
+ // done to check whether the block is already there.
+// b = mp.Sub;
+ mp.Sub = false; // Restrict suballocation to one quarter
+ } // endif Memp
+
+ // Suballoc when possible if mp.Sub is initially true, but leaving
+ // a minimum amount of storage for future operations such as the
+ // optimize recalculation after insert; otherwise
+ // suballoc only if size is smaller than one quarter of free mem.
+ minsub = (pph->FreeBlk + pph->To_Free + 524248) >> 2;
+ maxsub = (pph->FreeBlk < minsub) ? 0 : pph->FreeBlk - minsub;
+ mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2));
+
+ if (trace)
+ htrc("PlgDBalloc: in %p size=%d used=%d free=%d sub=%d\n",
+ arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub);
+
+ if (!mp.Sub) {
+ // For allocations greater than one fourth of remaining storage
+ // in the area, do allocate from virtual storage.
+#if defined(WIN32)
+ if (mp.Size >= BIGMEM)
+ mp.Memp = VirtualAlloc(NULL, mp.Size, MEM_COMMIT, PAGE_READWRITE);
+ else
+#endif
+ mp.Memp = malloc(mp.Size);
+
+ if (!mp.Inlist && mp.Memp) {
+ // New allocated block, put it in the memory block chain.
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ mp.Next = dbuserp->Memlist;
+ dbuserp->Memlist = &mp;
+ mp.Inlist = true;
+ } // endif mp
+
+ } else
+ // Suballocating is Ok.
+ mp.Memp = PlugSubAlloc(g, area, mp.Size);
+
+ return mp.Memp;
+ } // end of PlgDBalloc
+
+/***********************************************************************/
+/* PlgDBrealloc: reallocates memory conditionally. */
+/* Note that this routine can fail only when block size is increased */
+/* because otherwise we keep the old storage on failure. */
+/***********************************************************************/
+void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize)
+ {
+ MBLOCK m;
+
+#if defined(_DEBUG)
+// assert (mp.Memp != NULL);
+#endif
+
+ if (trace)
+ htrc("PlgDBrealloc: %p size=%d sub=%d\n", mp.Memp, mp.Size, mp.Sub);
+
+ if (newsize == mp.Size)
+ return mp.Memp; // Nothing to do
+ else
+ m = mp;
+
+ if (!mp.Sub && mp.Size < BIGMEM && newsize < BIGMEM) {
+ // Allocation was done by malloc, try to use realloc but
+ // suballoc if newsize is smaller than one quarter of free mem.
+ size_t maxsub;
+ PPOOLHEADER pph = (PPOOLHEADER)((area) ? area : g->Sarea);
+
+ maxsub = (pph->FreeBlk < 131072) ? 0 : pph->FreeBlk - 131072;
+
+ if ((mp.Sub = (newsize <= (maxsub >> 2)))) {
+ mp.Memp = PlugSubAlloc(g, area, newsize);
+ memcpy(mp.Memp, m.Memp, min(m.Size, newsize));
+ PlgDBfree(m); // Free the old block
+ } else if (!(mp.Memp = realloc(mp.Memp, newsize))) {
+ mp = m; // Possible only if newsize > Size
+ return NULL; // Failed
+ } // endif's
+
+ mp.Size = newsize;
+ } else if (!mp.Sub || newsize > mp.Size) {
+ // Was suballocated or Allocation was done by VirtualAlloc
+ // Make a new allocation and copy the useful part
+ // Note: DO NOT reset Memp and Sub so we know that this
+ // is a reallocation in PlgDBalloc
+ mp.Size = newsize;
+
+ if (PlgDBalloc(g, area, mp)) {
+ memcpy(mp.Memp, m.Memp, min(m.Size, newsize));
+ PlgDBfree(m); // Free the old block
+ } else {
+ mp = m; // No space to realloc, do nothing
+
+ if (newsize > m.Size)
+ return NULL; // Failed
+
+ } // endif PlgDBalloc
+
+ } // endif's
+
+ if (trace)
+ htrc(" newsize=%d newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub);
+
+ return mp.Memp;
+ } // end of PlgDBrealloc
+
+/***********************************************************************/
+/* PlgDBfree: free memory if not suballocated. */
+/***********************************************************************/
+void PlgDBfree(MBLOCK& mp)
+ {
+ if (trace)
+ htrc("PlgDBfree: %p sub=%d size=%d\n", mp.Memp, mp.Sub, mp.Size);
+
+ if (!mp.Sub && mp.Memp)
+#if defined(WIN32)
+ if (mp.Size >= BIGMEM)
+ VirtualFree(mp.Memp, 0, MEM_RELEASE);
+ else
+#endif
+ free(mp.Memp);
+
+ // Do not reset Next to avoid cutting the Mblock chain
+ mp.Memp = NULL;
+ mp.Sub = false;
+ mp.Size = 0;
+ } // end of PlgDBfree
+
+#if 0 // Not used yet
+/***********************************************************************/
+/* Program for sub-allocating one item in a storage area. */
+/* Note: This function is equivalent to PlugSubAlloc except that in */
+/* case of insufficient memory, it returns NULL instead of doing a */
+/* long jump. The caller must test the return value for error. */
+/***********************************************************************/
+void *PlgDBSubAlloc(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(DEBTRACE)
+ htrc("PlgDBSubAlloc: memp=%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 = NULL;
+ PACTIVITY ap;
+
+ if (memp == g->Sarea)
+ pname = "Work";
+ else if ((ap = g->Activityp)) {
+ if (memp == ap->LangRulep)
+ pname = "Rule";
+ else if (memp == ap->Nodep[0])
+ pname = "Dictionary";
+ else if (memp == ap->Nodep[1])
+ pname = "Vartok";
+ else if (memp == ap->Nodep[2])
+ pname = "Lexicon";
+ else if (memp == ap->User_Dictp)
+ pname = "User dictionary";
+ else if (ap->Aptr)
+ pname = "Application";
+
+ } // endif memp
+
+ if (pname)
+ sprintf(g->Message,
+ "Not enough memory in %s area for request of %d (used=%d free=%d)",
+ pname, size, pph->To_Free, pph->FreeBlk);
+ else
+ sprintf(g->Message, MSG(SUBALLOC_ERROR),
+ memp, size, pph->To_Free, pph->FreeBlk);
+
+#if defined(DEBTRACE)
+ htrc("%s\n", g->Message);
+#endif
+
+ return NULL;
+ } // endif size
+
+ /*********************************************************************/
+ /* 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(DEBTRACE)
+ htrc("Done memp=%p used=%d free=%d\n",
+ memp, pph->To_Free, pph->FreeBlk);
+#endif
+ return (memp);
+ } // end of PlgDBSubAlloc
+#endif // 0 Not used yet
+
+/***********************************************************************/
+/* PUTOUT: Plug DB object typing routine. */
+/***********************************************************************/
+void PlugPutOut(PGLOBAL g, FILE *f, short t, void *v, uint n)
+ {
+ char m[64];
+
+ if (trace)
+ htrc("PUTOUT: f=%p t=%d v=%p n=%d\n", f, t, v, n);
+
+ if (!v)
+ return;
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+ n += 2; /* Increase margin */
+
+ switch (t) {
+ case TYPE_ERROR:
+ fprintf(f, "--> %s\n", (PSZ)v);
+ break;
+
+ case TYPE_STRING:
+ case TYPE_PSZ:
+ fprintf(f, "%s%s\n", m, (PSZ)v);
+ break;
+
+ case TYPE_FLOAT:
+ fprintf(f, "%s%lf\n", m, *(double *)v);
+ break;
+
+ case TYPE_LIST:
+ case TYPE_COLIST:
+ case TYPE_COL:
+ {PPARM p;
+
+ if (t == TYPE_LIST)
+ fprintf(f, "%s%s\n", m, MSG(LIST));
+ else
+ fprintf(f, "%s%s\n", m, "Colist:");
+
+ for (p = (PPARM)v; p; p = p->Next)
+ PlugPutOut(g, f, p->Type, p->Value, n);
+
+ } break;
+
+ case TYPE_INT:
+ fprintf(f, "%s%d\n", m, *(int *)v);
+ break;
+
+ case TYPE_SHORT:
+ fprintf(f, "%s%hd\n", m, *(short *)v);
+ break;
+
+ case TYPE_VOID:
+ break;
+
+ case TYPE_SQL:
+ case TYPE_TABLE:
+ case TYPE_TDB:
+ case TYPE_XOBJECT:
+ ((PBLOCK)v)->Print(g, f, n-2);
+ break;
+
+ default:
+ fprintf(f, "%s%s %d\n", m, MSG(ANSWER_TYPE), t);
+ } /* endswitch */
+
+ return;
+ } /* end of PlugPutOut */
+
+/***********************************************************************/
+/* NewPointer: makes a table of pointer values to be changed later. */
+/***********************************************************************/
+DllExport void NewPointer(PTABS t, void *oldv, void *newv)
+ {
+ PTABPTR tp;
+
+ if (!oldv) /* error ?????????? */
+ return;
+
+ if (!t->P1 || t->P1->Num == 50)
+ if (!(tp = new TABPTR)) {
+ PGLOBAL g = t->G;
+
+ sprintf(g->Message, "NewPointer: %s", MSG(MEM_ALLOC_ERROR));
+ longjmp(g->jumper[g->jump_level], 3);
+ } else {
+ tp->Next = t->P1;
+ tp->Num = 0;
+ t->P1 = tp;
+ } /* endif tp */
+
+ t->P1->Old[t->P1->Num] = oldv;
+ t->P1->New[t->P1->Num++] = newv;
+ } /* end of NewPointer */
+
+#if 0
+/***********************************************************************/
+/* Compare two files and return 0 if they are identical, else 1. */
+/***********************************************************************/
+int FileComp(PGLOBAL g, char *file1, char *file2)
+ {
+ char *fn[2], *bp[2], buff1[4096], buff2[4096];
+ int i, k, n[2], h[2] = {-1,-1};
+ int len[2], rc = -1;
+
+ fn[0] = file1; fn[1] = file2;
+ bp[0] = buff1; bp[1] = buff2;
+
+ for (i = 0; i < 2; i++) {
+#if defined(WIN32)
+ h[i]= global_open(g, MSGID_NONE, fn[i], _O_RDONLY | _O_BINARY);
+#else // !WIN32
+ h[i]= global_open(g, MSGOD_NONE, fn[i], O_RDONLY);
+#endif // !WIN32
+
+ if (h[i] == -1) {
+// if (errno != ENOENT) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "rb", (int)errno, fn[i]);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+ longjmp(g->jumper[g->jump_level], 666);
+// } else
+// len[i] = 0; // File does not exist yet
+
+ } else {
+ if ((len[i] = _filelength(h[i])) < 0) {
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", fn[i]);
+ longjmp(g->jumper[g->jump_level], 666);
+ } // endif len
+
+ } // endif h
+
+ } // endfor i
+
+ if (len[0] != len[1])
+ rc = 1;
+
+ while (rc == -1) {
+ for (i = 0; i < 2; i++)
+ if ((n[i] = read(h[i], bp[i], 4096)) < 0) {
+ sprintf(g->Message, MSG(READ_ERROR), fn[i], strerror(errno));
+ goto fin;
+ } // endif n
+
+ if (n[0] != n[1])
+ rc = 1;
+ else if (*n == 0)
+ rc = 0;
+ else for (k = 0; k < *n; k++)
+ if (*(bp[0] + k) != *(bp[1] + k)) {
+ rc = 1;
+ goto fin;
+ } // endif bp
+
+ } // endwhile
+
+ fin:
+ for (i = 0; i < 2; i++)
+ if (h[i] != -1)
+ close(h[i]);
+
+ return rc;
+ } // end of FileComp
+#endif // 0
diff --git a/storage/connect/plgodbc.h b/storage/connect/plgodbc.h
index 94b8b42df1d..46bc41ad16b 100644
--- a/storage/connect/plgodbc.h
+++ b/storage/connect/plgodbc.h
@@ -1,230 +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 ---------------------------- */
+/***********************************************************************/
+/* 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 ---------------------------- */
diff --git a/storage/connect/plgxml.cpp b/storage/connect/plgxml.cpp
index 2e03875eab7..3061a6d697e 100644
--- a/storage/connect/plgxml.cpp
+++ b/storage/connect/plgxml.cpp
@@ -1,140 +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
-
-#ifndef LIBXML2_SUPPORT
-PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
- char *enc, PFBLOCK fp)
- {
- strcpy(g->Message, "libxml2 not supported");
- return NULL;
- } // end of GetLibxmlDoc
-#endif // LIBXML2_SUPPORT
-
-/******************************************************************/
-/* 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
+/******************************************************************/
+/* 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
+
+#ifndef LIBXML2_SUPPORT
+PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
+ char *enc, PFBLOCK fp)
+ {
+ strcpy(g->Message, "libxml2 not supported");
+ return NULL;
+ } // end of GetLibxmlDoc
+#endif // LIBXML2_SUPPORT
+
+/******************************************************************/
+/* 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
diff --git a/storage/connect/plgxml.h b/storage/connect/plgxml.h
index 2ef66072b78..a1d25e6b581 100644
--- a/storage/connect/plgxml.h
+++ b/storage/connect/plgxml.h
@@ -1,177 +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
-
-
+/******************************************************************/
+/* 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
+
+
diff --git a/storage/connect/plugutil.c b/storage/connect/plugutil.c
index 4765acd96a7..79434212038 100644
--- a/storage/connect/plugutil.c
+++ b/storage/connect/plugutil.c
@@ -1,500 +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 -----------------------*/
+/************** 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 -----------------------*/
diff --git a/storage/connect/preparse.h b/storage/connect/preparse.h
index 7851606904c..8b57d487736 100644
--- a/storage/connect/preparse.h
+++ b/storage/connect/preparse.h
@@ -1,61 +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
-
+#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
+
diff --git a/storage/connect/rcmsg.c b/storage/connect/rcmsg.c
index 2a2ee1b5271..df93542a031 100644
--- a/storage/connect/rcmsg.c
+++ b/storage/connect/rcmsg.c
@@ -1,209 +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é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ées (%d octets) tronquées à 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é de connexion %d"; break;
- case IDS_12: p = "%s: Pas plus de %d connexions autorisées pour un programme"; break;
- case IDS_13: p = "%s: clé de connexion invalide %d"; break;
- case IDS_14: p = "SafeDB: %s rc=%d"; break;
- case IDS_15: p = "Mauvaise Dll de communication appelée par le moteur %s"; break;
- case IDS_TAB_01: p = "Qualificateur"; break;
- case IDS_TAB_02: p = "Proprié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ées"; break;
- case IDS_COL_06: p = "Nom_Type"; break;
- case IDS_COL_07: p = "Pré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ées"; break;
- case IDS_INF_03: p = "Précision"; break;
- case IDS_INF_04: p = "Préfixe_Litéral"; break;
- case IDS_INF_05: p = "Suffixe_Litéral"; break;
- case IDS_INF_06: p = "Cré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é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éro_Clé"; break;
- case IDS_PKY_06: p = "Nom_Clé"; 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ées"; break;
- case IDS_SPC_04: p = "Nom_Type"; break;
- case IDS_SPC_05: p = "Pré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
+/**************** 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é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ées (%d octets) tronquées à 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é de connexion %d"; break;
+ case IDS_12: p = "%s: Pas plus de %d connexions autorisées pour un programme"; break;
+ case IDS_13: p = "%s: clé de connexion invalide %d"; break;
+ case IDS_14: p = "SafeDB: %s rc=%d"; break;
+ case IDS_15: p = "Mauvaise Dll de communication appelée par le moteur %s"; break;
+ case IDS_TAB_01: p = "Qualificateur"; break;
+ case IDS_TAB_02: p = "Proprié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ées"; break;
+ case IDS_COL_06: p = "Nom_Type"; break;
+ case IDS_COL_07: p = "Pré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ées"; break;
+ case IDS_INF_03: p = "Précision"; break;
+ case IDS_INF_04: p = "Préfixe_Litéral"; break;
+ case IDS_INF_05: p = "Suffixe_Litéral"; break;
+ case IDS_INF_06: p = "Cré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é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éro_Clé"; break;
+ case IDS_PKY_06: p = "Nom_Clé"; 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ées"; break;
+ case IDS_SPC_04: p = "Nom_Type"; break;
+ case IDS_SPC_05: p = "Pré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
diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp
index 4be4ad5cd07..bf129a2f54a 100644
--- a/storage/connect/reldef.cpp
+++ b/storage/connect/reldef.cpp
@@ -1,421 +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 --------------------------- */
+/************* 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 --------------------------- */
diff --git a/storage/connect/reldef.h b/storage/connect/reldef.h
index 08d65d5a39f..ac006f5c7e9 100644
--- a/storage/connect/reldef.h
+++ b/storage/connect/reldef.h
@@ -1,194 +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
-
+/*************** 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
+
diff --git a/storage/connect/resource.h b/storage/connect/resource.h
index fccff781e05..6870ae775d0 100644
--- a/storage/connect/resource.h
+++ b/storage/connect/resource.h
@@ -1,136 +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
+//{{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
diff --git a/storage/connect/tabcol.cpp b/storage/connect/tabcol.cpp
index d0ec538bb8b..f0e010291c3 100644
--- a/storage/connect/tabcol.cpp
+++ b/storage/connect/tabcol.cpp
@@ -1,170 +1,170 @@
-/************* 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. */
-/***********************************************************************/
-#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. */
-/* 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 */
+/************* 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. */
+/***********************************************************************/
+#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. */
+/* 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 */
diff --git a/storage/connect/tabcol.h b/storage/connect/tabcol.h
index 161f4699448..5cc2050f872 100644
--- a/storage/connect/tabcol.h
+++ b/storage/connect/tabcol.h
@@ -1,110 +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
+/*************** 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
diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp
index 0f9b280d003..5218a322ea6 100644
--- a/storage/connect/tabdos.cpp
+++ b/storage/connect/tabdos.cpp
@@ -1,1228 +1,1228 @@
-/************* TabDos C++ Program Source Code File (.CPP) **************/
-/* PROGRAM NAME: TABDOS */
-/* ------------- */
-/* Version 4.8 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the DOS tables classes. */
-/* */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant sections of the System header files. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-#include <io.h>
-#include <sys\timeb.h> // For testing only
-#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 <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. */
-/***********************************************************************/
-#include "global.h"
-#include "osutil.h"
-#include "plgdbsem.h"
-#include "catalog.h"
-//#include "reldef.h"
-#include "xindex.h"
-#include "filamap.h"
-#include "filamfix.h"
-#include "filamdbf.h"
-#if defined(ZIP_SUPPORT)
-#include "filamzip.h"
-#endif // ZIP_SUPPORT
-#include "tabdos.h"
-#include "tabfix.h"
-#include "tabmul.h"
-
-#define PLGINI "plugdb.ini" // Configuration settings file
-
-#if defined(UNIX)
-#define _fileno fileno
-#define _O_RDONLY O_RDONLY
-#endif
-
-/***********************************************************************/
-/* DB static variables. */
-/***********************************************************************/
-int num_read, num_there, num_eq[2]; // Statistics
-extern "C" char plgini[_MAX_PATH];
-extern "C" int trace;
-
-/***********************************************************************/
-/* Min and Max blocks contains zero ended fields (blank = false). */
-/* No conversion of block values (check = true). */
-/***********************************************************************/
-PVBLK AllocValBlock(PGLOBAL, void *, int, int, int len = 0, int prec = 0,
- bool check = true, bool blank = false);
-
-/* --------------------------- Class DOSDEF -------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-DOSDEF::DOSDEF(void)
- {
- Pseudo = 3;
- Fn = NULL;
- Ofn = NULL;
- To_Indx = NULL;
- Recfm = RECFM_VAR;
- Mapped = false;
- Padded = false;
- Huge = false;
- Accept = false;
- Eof = false;
- To_Pos = NULL;
- Compressed = 0;
- Lrecl = 0;
- AvgLen = 0;
- Block = 0;
- Last = 0;
- Blksize = 0;
- Maxerr = 0;
- ReadMode = 0;
- Ending = 0;
-//Mtime = 0;
- } // end of DOSDEF constructor
-
-/***********************************************************************/
-/* DeleteTableFile: Delete DOS/UNIX table files using platform API. */
-/* If the table file is protected (declared as read/only) we still */
-/* erase the the eventual optimize and index files but return true. */
-/***********************************************************************/
-bool DOSDEF::DeleteTableFile(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- bool rc = false;
-
- // Now delete the table file itself if not protected
- if (!IsReadOnly()) {
- rc = Erase(filename);
- } else
- rc =true;
-
- return rc; // Return true if error
- } // end of DeleteTableFile
-
-/***********************************************************************/
-/* 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 */
-/* when the class was VCTDEF. It also minimizes the specific code. */
-/***********************************************************************/
-bool DOSDEF::Erase(char *filename)
- {
- bool rc;
-
- PlugSetPath(filename, Fn, GetPath());
-#if defined(WIN32)
- rc = !DeleteFile(filename);
-#else // UNIX
- rc = remove(filename);
-#endif // UNIX
-
- return rc; // Return true if error
- } // end of Erase
-
-/***********************************************************************/
-/* DeleteIndexFile: Delete DOS/UNIX index file(s) using platform API. */
-/***********************************************************************/
-bool DOSDEF::DeleteIndexFile(PGLOBAL g, PIXDEF pxdf)
- {
- char *ftype;
- char filename[_MAX_PATH];
- bool sep, rc = false;
-
- if (!pxdf)
- return false; // No index
-
- sep = Cat->GetSepIndex(); // If true indexes are in separate files
-
- if (!sep && To_Indx) {
- strcpy(g->Message, MSG(NO_RECOV_SPACE));
- return true;
- } // endif sep
-
- switch (Recfm) {
- case RECFM_VAR: ftype = ".dnx"; break;
- case RECFM_FIX: ftype = ".fnx"; break;
- case RECFM_BIN: ftype = ".bnx"; break;
- case RECFM_VCT: ftype = ".vnx"; break;
- case RECFM_DBF: ftype = ".dbx"; break;
- default:
- sprintf(g->Message, MSG(BAD_RECFM_VAL), Recfm);
- return true;
- } // endswitch Ftype
-
- /*********************************************************************/
- /* Check for existence of an index file. */
- /*********************************************************************/
- if (sep) {
- // Indexes are save in separate files
-#if !defined(UNIX)
- char drive[_MAX_DRIVE];
-#else
- char *drive = NULL;
-#endif
- char direc[_MAX_DIR];
- char fname[_MAX_FNAME];
-
- for (; pxdf; pxdf = pxdf->GetNext()) {
- _splitpath(Ofn, drive, direc, fname, NULL);
- strcat(strcat(fname, "_"), pxdf->GetName());
- _makepath(filename, drive, direc, fname, ftype);
- PlugSetPath(filename, filename, GetPath());
-#if defined(WIN32)
- rc |= !DeleteFile(filename);
-#else // UNIX
- rc |= remove(filename);
-#endif // UNIX
- } // endfor pxdf
-
- } else { // !sep, no more indexes or name is NULL
- // Drop all indexes, delete the common file
- PlugSetPath(filename, Ofn, GetPath());
- strcat(PlugRemoveType(filename, filename), ftype);
-#if defined(WIN32)
- rc = !DeleteFile(filename);
-#else // UNIX
- rc = remove(filename);
-#endif // UNIX
- } // endif sep
-
- if (rc)
- sprintf(g->Message, MSG(DEL_FILE_ERR), filename);
-
- return rc; // Return true if error
- } // end of DeleteIndexFile
-
-/***********************************************************************/
-/* DefineAM: define specific AM block values from XDB file. */
-/***********************************************************************/
-bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- char buf[8];
- bool map = (am && (*am == 'M' || *am == 'm'));
- LPCSTR dfm = (am && (*am == 'F' || *am == 'f')) ? "F"
- : (am && (*am == 'B' || *am == 'b')) ? "B"
- : (am && !stricmp(am, "DBF")) ? "D" : "V";
-
- Desc = Fn = Cat->GetStringCatInfo(g, Name, "Filename", "");
- Ofn = Cat->GetStringCatInfo(g, Name, "Optname", Fn);
- Cat->GetCharCatInfo(Name, "Recfm", (PSZ)dfm, buf, sizeof(buf));
- Recfm = (toupper(*buf) == 'F') ? RECFM_FIX :
- (toupper(*buf) == 'B') ? RECFM_BIN :
- (toupper(*buf) == 'D') ? RECFM_DBF : RECFM_VAR;
- Lrecl = Cat->GetIntCatInfo(Name, "Lrecl", 0);
-
- if (Recfm != RECFM_DBF)
- Compressed = Cat->GetIntCatInfo(Name, "Compressed", 0);
-
- Mapped = Cat->GetBoolCatInfo(Name, "Mapped", map);
- Block = Cat->GetIntCatInfo(Name, "Blocks", 0);
- Last = Cat->GetIntCatInfo(Name, "Last", 0);
- Ending = Cat->GetIntCatInfo(Name, "Ending", CRLF);
-
- if (Recfm == RECFM_FIX || Recfm == RECFM_BIN) {
- int defhuge = (Cat->GetDefHuge()) ? 1 : 0;
-
- Huge = (Cat->GetIntCatInfo(Name, "Huge", defhuge) != 0);
- Padded = (Cat->GetIntCatInfo(Name, "Padded", 0) != 0);
- Blksize = Cat->GetIntCatInfo(Name, "Blksize", 0);
- Eof = (Cat->GetIntCatInfo(Name, "EOF", 0) != 0);
- } else if (Recfm == RECFM_DBF) {
- Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0);
- Accept = (Cat->GetIntCatInfo(Name, "Accept", 0) != 0);
- ReadMode = Cat->GetIntCatInfo(Name, "Readmode", 0);
- } else // (Recfm == RECFM_VAR)
- AvgLen = Cat->GetIntCatInfo(Name, "Avglen", 0);
-
- // Ignore wrong Index definitions for catalog commands
- return (Cat->GetIndexInfo(g, this) /*&& !Cat->GetCatFnc()*/);
- } // end of DefineAM
-
-/***********************************************************************/
-/* InvalidateIndex: mark all indexes as invalid. */
-/***********************************************************************/
-bool DOSDEF::InvalidateIndex(PGLOBAL g)
- {
- if (To_Indx)
- for (PIXDEF xp = To_Indx; xp; xp = xp->Next)
- xp->Invalid = true;
-
- return false;
- } // end of InvalidateIndex
-
-/***********************************************************************/
-/* GetTable: makes a new Table Description Block. */
-/***********************************************************************/
-PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode)
- {
- // Mapping not used for insert
- USETEMP tmp = PlgGetUser(g)->UseTemp;
- bool map = Mapped && mode != MODE_INSERT &&
- !(tmp != TMP_NO && Recfm == RECFM_VAR
- && mode == MODE_UPDATE) &&
- !(tmp == TMP_FORCE &&
- (mode == MODE_UPDATE || mode == MODE_DELETE));
- PTXF txfp;
- PTDBASE tdbp;
-
- /*********************************************************************/
- /* Allocate table and file processing class of the proper type. */
- /* Column blocks will be allocated only when needed. */
- /*********************************************************************/
- if (Recfm == RECFM_DBF) {
- if (map)
- txfp = new(g) DBMFAM(this);
- else
- txfp = new(g) DBFFAM(this);
-
- tdbp = new(g) TDBFIX(this, txfp);
- } else if (Recfm != RECFM_VAR && Compressed < 2) {
- if (Huge)
- txfp = new(g) BGXFAM(this);
- else if (map)
- txfp = new(g) MPXFAM(this);
-#if defined(ZIP_SUPPORT)
- else if (Compressed)
- txfp = new(g) ZIXFAM(this);
-#endif // ZIP_SUPPORT
- else
- txfp = new(g) FIXFAM(this);
-
- tdbp = new(g) TDBFIX(this, txfp);
- } else {
-#if defined(ZIP_SUPPORT)
- if (Compressed) {
- if (Compressed == 1)
- txfp = new(g) ZIPFAM(this);
- else {
- strcpy(g->Message, "Compress 2 not supported yet");
-// txfp = new(g) ZLBFAM(defp);
- return NULL;
- } // endelse
-
- } else
-#endif // ZIP_SUPPORT
- if (map)
- txfp = new(g) MAPFAM(this);
- else
- txfp = new(g) DOSFAM(this);
-
- // Txfp must be set even for not multiple tables because
- // it is needed when calling Cardinality in GetBlockValues.
- tdbp = new(g) TDBDOS(this, txfp);
- } // endif Recfm
-
- if (Multiple)
- tdbp = new(g) TDBMUL(tdbp);
-
- return tdbp;
- } // end of GetTable
-
-/* ------------------------ Class TDBDOS ----------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBDOS class. This is the common class that */
-/* contain all that is common between the TDBDOS and TDBMAP classes. */
-/***********************************************************************/
-TDBDOS::TDBDOS(PDOSDEF tdp, PTXF txfp) : TDBASE(tdp)
- {
- if ((Txfp = txfp))
- Txfp->SetTdbp(this);
-
- Lrecl = tdp->Lrecl;
- AvgLen = tdp->AvgLen;
- Ftype = tdp->Recfm;
- To_Line = NULL;
- Cardinal = -1;
- } // end of TDBDOS standard constructor
-
-TDBDOS::TDBDOS(PGLOBAL g, PTDBDOS tdbp) : TDBASE(tdbp)
- {
- Txfp = (g) ? tdbp->Txfp->Duplicate(g) : tdbp->Txfp;
- Lrecl = tdbp->Lrecl;
- AvgLen = tdbp->AvgLen;
- Ftype = tdbp->Ftype;
- To_Line = tdbp->To_Line;
- Cardinal = tdbp->Cardinal;
- } // end of TDBDOS copy constructor
-
-// Method
-PTDB TDBDOS::CopyOne(PTABS t)
- {
- PTDB tp;
- PDOSCOL cp1, cp2;
- PGLOBAL g = t->G;
-
- tp = new(g) TDBDOS(g, this);
-
- for (cp1 = (PDOSCOL)Columns; cp1; cp1 = (PDOSCOL)cp1->GetNext()) {
- cp2 = new(g) DOSCOL(cp1, tp); // Make a copy
- NewPointer(t, cp1, cp2);
- } // endfor cp1
-
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Allocate DOS column description block. */
-/***********************************************************************/
-PCOL TDBDOS::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- return new(g) DOSCOL(g, cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* Print debug information. */
-/***********************************************************************/
-void TDBDOS::PrintAM(FILE *f, char *m)
- {
- fprintf(f, "%s AM(%d): mode=%d\n", m, GetAmType(), Mode);
-
- if (Txfp->To_File)
- fprintf(f, "%s File: %s\n", m, Txfp->To_File);
-
- } // end of PrintAM
-
-/***********************************************************************/
-/* Remake the indexes after the table was modified. */
-/***********************************************************************/
-int TDBDOS::ResetTableOpt(PGLOBAL g, bool dox)
- {
- int rc = RC_OK;
-
- MaxSize = -1; // Size must be recalculated
- Cardinal = -1; // as well as Cardinality
-
- if (dox) {
- // Remake eventual indexes
- Columns = NULL; // Not used anymore
- Txfp->Reset(); // New start
- Use = USE_READY; // So the table can be reopened
- Mode = MODE_READ; // New mode
-
- if (!(PlgGetUser(g)->Check & CHK_OPT)) {
- // After the table was modified the indexes
- // are invalid and we should mark them as such...
- rc = ((PDOSDEF)To_Def)->InvalidateIndex(g);
- } else
- // ... or we should remake them.
- rc = MakeIndex(g, NULL, false);
-
- } // endif dox
-
- return rc;
- } // end of ResetTableOpt
-
-/***********************************************************************/
-/* Check whether we have to create/update permanent indexes. */
-/***********************************************************************/
-int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add)
- {
- int k, n;
- bool fixed, b = (pxdf != NULL);
- PCOL *keycols, colp;
- PIXDEF xdp, sxp = NULL;
- PKPDEF kdp;
- PDOSDEF dfp;
-//PCOLDEF cdp;
- PXINDEX x;
- PXLOAD pxp;
- PCATLG cat = PlgGetCatalog(g);
-
- Mode = MODE_READ;
- Use = USE_READY;
- dfp = (PDOSDEF)To_Def;
- fixed = Cardinality(g) >= 0;
-
- // Are we are called from CreateTable or CreateIndex?
- if (pxdf) {
- if (!add && dfp->GetIndx()) {
- strcpy(g->Message, MSG(INDX_EXIST_YET));
- return RC_FX;
- } // endif To_Indx
-
- if (add && dfp->GetIndx()) {
- for (sxp = dfp->GetIndx(); sxp; sxp = sxp->GetNext())
- if (!stricmp(sxp->GetName(), pxdf->GetName())) {
- sprintf(g->Message, MSG(INDEX_YET_ON), pxdf->GetName(), Name);
- return RC_FX;
- } else if (!sxp->GetNext())
- break;
-
- sxp->SetNext(pxdf);
-// first = false;
- } else
- dfp->SetIndx(pxdf);
-
-// pxdf->SetDef(dfp);
- } else if (!(pxdf = dfp->GetIndx()))
- return RC_INFO; // No index to make
-
- // Allocate all columns that will be used by indexes.
- // This must be done before opening the table so specific
- // column initialization can be done ( in particular by TDBVCT)
- for (n = 0, xdp = pxdf; xdp; xdp = xdp->GetNext())
- for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) {
- if (!(colp = ColDB(g, kdp->GetName(), 0))) {
- sprintf(g->Message, MSG(INDX_COL_NOTIN), kdp->GetName(), Name);
- goto err;
- } // endif colp
-
- colp->InitValue(g);
- n = max(n, xdp->GetNparts());
- } // endfor kdp
-
- keycols = (PCOL*)PlugSubAlloc(g, NULL, n * sizeof(PCOL));
-
- /*********************************************************************/
- /* Construct and save the defined indexes. */
- /*********************************************************************/
- for (xdp = pxdf; xdp; xdp = xdp->GetNext())
- if (!OpenDB(g)) {
- if (xdp->IsAuto() && fixed)
- // Auto increment key and fixed file: use an XXROW index
- continue; // XXROW index doesn't need to be made
-
- n = 0;
-
- if (sxp)
- xdp->SetID(sxp->GetID() + 1);
-
- for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext())
- keycols[n++] = ColDB(g, kdp->GetName(), 0);
-
- k = xdp->GetNparts();
-
- // Make the index and save it
- if (dfp->Huge)
- pxp = new(g) XHUGE;
- else
- pxp = new(g) XFILE;
-
- if (k == 1) // Simple index
- x = new(g) XINDXS(this, xdp, pxp, keycols);
- else // Multi-Column index
- x = new(g) XINDEX(this, xdp, pxp, keycols);
-
- if (!x->Make(g, sxp)) {
- // Retreive define values from the index
- xdp->SetMaxSame(x->GetMaxSame());
- xdp->SetOffset(x->GetDefoff());
- xdp->SetOffhigh(x->GetDefhigh());
- xdp->SetSize(x->GetSize());
-
- // store KXYCOL Mxs in KPARTDEF Mxsame
- xdp->SetMxsame(x);
-
-#if defined(TRACE)
- printf("Make done...\n");
-#endif // TRACE
-
- if (x->GetSize() > 0)
- sxp = xdp;
-
- xdp->SetInvalid(false);
- } else
- goto err;
-
- } else
- break; // Physical table does not exist yet or anymore
-
- if (Use == USE_OPEN)
- CloseDB(g);
-
- return RC_OK;
-
-err:
- if (sxp)
- sxp->SetNext(NULL);
- else
- dfp->SetIndx(NULL);
-
- return RC_FX;
- } // end of MakeIndex
-
-/***********************************************************************/
-/* DOS GetProgMax: get the max value for progress information. */
-/***********************************************************************/
-int TDBDOS::GetProgMax(PGLOBAL g)
- {
- return (To_Kindex) ? GetMaxSize(g) : GetFileLength(g);
- } // end of GetProgMax
-
-/***********************************************************************/
-/* DOS GetProgCur: get the current value for progress information. */
-/***********************************************************************/
-int TDBDOS::GetProgCur(void)
- {
- return (To_Kindex) ? To_Kindex->GetCur_K() + 1 : GetRecpos();
- } // end of GetProgCur
-
-/***********************************************************************/
-/* RowNumber: return the ordinal number of the current row. */
-/***********************************************************************/
-int TDBDOS::RowNumber(PGLOBAL g, bool b)
- {
- if (To_Kindex) {
- /*******************************************************************/
- /* Don't know how to retrieve RowID from file address. */
- /*******************************************************************/
- sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
- GetAmName(g, Txfp->GetAmType()));
- return 0;
- } else
- return Txfp->GetRowID();
-
- } // end of RowNumber
-
-/***********************************************************************/
-/* DOS 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 TDBDOS::Cardinality(PGLOBAL g)
- {
- if (!g)
- return Txfp->Cardinality(g);
-
- if (Cardinal < 0)
- Cardinal = Txfp->Cardinality(g);
-
- return Cardinal;
- } // end of Cardinality
-
-/***********************************************************************/
-/* DOS GetMaxSize: returns file size estimate in number of lines. */
-/* This function covers variable record length files. */
-/***********************************************************************/
-int TDBDOS::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize >= 0)
- return MaxSize;
-
- if (!Cardinality(NULL)) {
- int len = GetFileLength(g);
-
- if (len >= 0) {
- if (trace)
- htrc("Estimating lines len=%d ending=%d\n",
- len, ((PDOSDEF)To_Def)->Ending);
-
- /*****************************************************************/
- /* Estimate the number of lines in the table (if not known) by */
- /* dividing the file length by the minimum line length assuming */
- /* only the last column can be of variable length. This will be */
- /* a ceiling estimate (as last column is never totally absent). */
- /*****************************************************************/
- int rec = ((PDOSDEF)To_Def)->Ending; // +2: CRLF +1: LF
-
- if (AvgLen <= 0) // No given average estimate
- rec += EstimatedLength(g);
- else // A lower estimate was given for the average record length
- rec += (int)AvgLen;
-
- if (trace)
- htrc(" Filen=%d min_rec=%d\n", len, rec);
-
- MaxSize = (len + rec - 1) / rec;
-
- if (trace)
- htrc(" Estimated max_K=%d\n", MaxSize);
-
- } // endif len
-
- } else
- MaxSize = Cardinality(g);
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* DOS EstimatedLength. Returns an estimated minimum line length. */
-/***********************************************************************/
-int TDBDOS::EstimatedLength(PGLOBAL g)
- {
- int dep = 0;
- PCOLDEF cdp = To_Def->GetCols();
-
- if (!cdp->GetNext()) {
- // One column table, we are going to return a ridiculous
- // result if we set dep to 1
- dep = 1 + cdp->GetLong() / 20; // Why 20 ?????
- } else for (; cdp; cdp = cdp->GetNext())
- dep = max(dep, cdp->GetOffset());
-
- return (int)dep;
- } // end of Estimated Length
-
-/***********************************************************************/
-/* DOS tables favor the use temporary files for Update. */
-/***********************************************************************/
-bool TDBDOS::IsUsingTemp(PGLOBAL g)
- {
- USETEMP usetemp = PlgGetUser(g)->UseTemp;
-
- return (usetemp == TMP_YES || usetemp == TMP_FORCE ||
- (usetemp == TMP_AUTO && Mode == MODE_UPDATE));
- } // end of IsUsingTemp
-
-/***********************************************************************/
-/* DOS 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 TDBDOS::OpenDB(PGLOBAL g)
- {
- if (trace)
- htrc("DOS OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
- this, Tdb_No, Use, Mode);
-
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open, just replace it at its beginning. */
- /*******************************************************************/
- Txfp->Rewind(); // see comment in Work.log
-
- if (SkipHeader(g))
- return true;
-
- return false;
- } // endif use
-
- if (Txfp->Blocked && (Mode == MODE_DELETE ||
- (Mode == MODE_UPDATE && PlgGetUser(g)->UseTemp != TMP_NO))) {
- /*******************************************************************/
- /* Delete is not currently handled in block mode neither Update */
- /* when using a temporary file. */
- /*******************************************************************/
- if (Txfp->GetAmType() == TYPE_AM_MAP && Mode == MODE_DELETE)
- Txfp = new(g) MAPFAM((PDOSDEF)To_Def);
-#if defined(ZIP_SUPPORT)
- else if (Txfp->GetAmType() == TYPE_AM_ZIP)
- Txfp = new(g) ZIPFAM((PDOSDEF)To_Def);
-#endif // ZIP_SUPPORT
- else if (Txfp->GetAmType() != TYPE_AM_DOS)
- Txfp = new(g) DOSFAM((PDOSDEF)To_Def);
-
- Txfp->SetTdbp(this);
- } // endif Mode
-
- /*********************************************************************/
- /* Open according to logical input/output mode required. */
- /* Use conventionnal input/output functions. */
- /* Treat files as binary in Delete mode (for line moving) */
- /*********************************************************************/
- if (Txfp->OpenTableFile(g))
- return true;
-
- Use = USE_OPEN; // Do it now in case we are recursively called
-
- /*********************************************************************/
- /* Allocate the line buffer plus a null character. */
- /*********************************************************************/
- To_Line = (char*)PlugSubAlloc(g, NULL, Lrecl + 1);
-
- if (Mode == MODE_INSERT) {
- // Spaces between fields must be filled with blanks
- memset(To_Line, ' ', Lrecl);
- To_Line[Lrecl] = '\0';
- } else
- memset(To_Line, 0, Lrecl + 1);
-
- if (trace)
- htrc("OpenDos: R%hd mode=%d To_Line=%p\n", Tdb_No, Mode, To_Line);
-
- if (SkipHeader(g)) // When called from CSV/FMT files
- return true;
-
- /*********************************************************************/
- /* Reset statistics values. */
- /*********************************************************************/
- num_read = num_there = num_eq[0] = num_eq[1] = 0;
- return false;
- } // end of OpenDB
-
-/***********************************************************************/
-/* ReadDB: Data Base read routine for DOS access method. */
-/***********************************************************************/
-int TDBDOS::ReadDB(PGLOBAL g)
- {
- if (trace > 1)
- htrc("DOS ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p To_Line=%p\n",
- GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex, To_Line);
-
- 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;
-
- if (trace > 1)
- htrc("File position is now %d\n", GetRecpos());
-
- if (Mode == MODE_READ)
- /*************************************************************/
- /* Defer physical reading until one column setting needs it */
- /* as it can be a big saving on joins where no other column */
- /* than the keys are used, so reading is unnecessary. */
- /*************************************************************/
- if (Txfp->DeferReading())
- return RC_OK;
-
- } // endswitch recpos
-
- } // endif To_Kindex
-
- if (trace > 1)
- htrc(" ReadDB: this=%p To_Line=%p\n", this, To_Line);
-
- /*********************************************************************/
- /* Now start the reading process. */
- /*********************************************************************/
- return ReadBuffer(g);
- } // end of ReadDB
-
-/***********************************************************************/
-/* WriteDB: Data Base write routine for DOS access method. */
-/***********************************************************************/
-int TDBDOS::WriteDB(PGLOBAL g)
- {
- if (trace > 1)
- htrc("DOS WriteDB: R%d Mode=%d \n", Tdb_No, Mode);
-
- if (!Ftype && (Mode == MODE_INSERT || Txfp->GetUseTemp())) {
- char *p;
-
- /*******************************************************************/
- /* Suppress trailing blanks. */
- /* Also suppress eventual null from last line. */
- /*******************************************************************/
- for (p = To_Line + Lrecl -1; p >= To_Line; p--)
- if (*p && *p != ' ')
- break;
-
- *(++p) = '\0';
- } // endif Mode
-
- if (trace > 1)
- htrc("Write: line is='%s'\n", To_Line);
-
- // Now start the writing process
- return Txfp->WriteBuffer(g);
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for DOS (and FIX) access method. */
-/* RC_FX means delete all. Nothing to do here (was done at open). */
-/***********************************************************************/
-int TDBDOS::DeleteDB(PGLOBAL g, int irc)
- {
- return (irc == RC_FX) ? RC_OK : Txfp->DeleteRecords(g, irc);
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for DOS access method. */
-/***********************************************************************/
-void TDBDOS::CloseDB(PGLOBAL g)
- {
- if (To_Kindex) {
- To_Kindex->Close();
- To_Kindex = NULL;
- } // endif
-
- Txfp->CloseTableFile(g);
- } // end of CloseDB
-
-// ------------------------ DOSCOL functions ----------------------------
-
-/***********************************************************************/
-/* DOSCOL public constructor (also called by MAPCOL). */
-/***********************************************************************/
-DOSCOL::DOSCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am)
- : COLBLK(cdp, tp, i)
- {
- char *p;
- int prec = Format.Prec;
- PTXF txfp = ((PTDBDOS)tp)->Txfp;
-
- assert(cdp);
-
- if (cp) {
- Next = cp->GetNext();
- cp->SetNext(this);
- } else {
- Next = tp->GetColumns();
- tp->SetColumns(this);
- } // endif cprec
-
- // Set additional Dos access method information for column.
- Deplac = cdp->GetOffset();
- Long = cdp->GetLong();
- To_Val = NULL;
-
- OldVal = NULL; // Currently used only in MinMax
- Ldz = false;
- Nod = false;
- Dcm = -1;
- p = cdp->GetFmt();
-
- if (p && IsTypeNum(Buf_Type)) {
- // Formatted numeric value
- for (; p && *p && isalpha(*p); p++)
- switch (toupper(*p)) {
- case 'Z': // Have leading zeros
- Ldz = true;
- break;
- case 'N': // Have no decimal point
- Nod = true;
- break;
- } // endswitch p
-
- // Set number of decimal digits
- Dcm = (*p) ? atoi(p) : GetPrecision();
- } // endif fmt
-
- if (trace)
- htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
-
- } // end of DOSCOL constructor
-
-/***********************************************************************/
-/* DOSCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-DOSCOL::DOSCOL(DOSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- Deplac = col1->Deplac;
- Long = col1->Long;
- To_Val = col1->To_Val;
- Ldz = col1->Ldz;
- Nod = col1->Nod;
- Dcm = col1->Dcm;
- OldVal = col1->OldVal;
- Buf = col1->Buf;
- } // end of DOSCOL copy constructor
-
-/***********************************************************************/
-/* VarSize: This function tells UpdateDB whether or not the block */
-/* optimization file must be redone if this column is updated, even */
-/* it is not sorted or clustered. This applies to the last column of */
-/* a variable length table that is blocked, because if it is updated */
-/* using a temporary file, the block size may be modified. */
-/***********************************************************************/
-bool DOSCOL::VarSize(void)
- {
- PTDBDOS tdbp = (PTDBDOS)To_Tdb;
- PTXF txfp = tdbp->Txfp;
-
- if (Cdp && !Cdp->GetNext() // Must be the last column
- && tdbp->Ftype == RECFM_VAR // of a DOS variable length
- && txfp->Blocked // blocked table
- && txfp->GetUseTemp()) // using a temporary file.
- return true;
- else
- return false;
-
- } // end VarSize
-
-/***********************************************************************/
-/* SetBuffer: prepare a column block for write operation. */
-/***********************************************************************/
-bool DOSCOL::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 buffer used in WriteColumn for numeric columns
- if (IsTypeNum(Buf_Type))
- Buf = (char*)PlugSubAlloc(g, NULL, max(32, Long + Dcm + 1));
-
- // 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 last line */
-/* read from the corresponding table, extract from it the field */
-/* corresponding to this column and convert it to buffer type. */
-/***********************************************************************/
-void DOSCOL::ReadColumn(PGLOBAL g)
- {
- char *p;
- int i, rc;
- int field;
- PTDBDOS tdbp = (PTDBDOS)To_Tdb;
-
- if (trace > 1)
- htrc(
- "DOS 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;
- field = Long;
-
- switch (tdbp->Ftype) {
- case RECFM_VAR:
- /*****************************************************************/
- /* For a variable length file, check if the field exists. */
- /*****************************************************************/
- if (strlen(tdbp->To_Line) < (unsigned)Deplac)
- field = 0;
-
- case RECFM_FIX: // Fixed length text file
- case RECFM_DBF: // Fixed length DBase file
- if (Nod) switch (Buf_Type) {
- case TYPE_INT:
- case TYPE_SHORT:
- Value->SetValue_char(p, field - Dcm);
- break;
- case TYPE_FLOAT:
- Value->SetValue_char(p, field);
-
- for (i = 0; i < Dcm; i++)
- ((DFVAL*)Value)->Divide(10.0);
-
- break;
- default:
- Value->SetValue_char(p, field);
- break;
- } // endswitch Buf_Type
-
- else
- Value->SetValue_char(p, field);
-
- break;
- default:
- sprintf(g->Message, MSG(BAD_RECFM), tdbp->Ftype);
- longjmp(g->jumper[g->jump_level], 34);
- } // endswitch Ftype
-
- } // 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 DOSCOL::WriteColumn(PGLOBAL g)
- {
- char *p, *p2, fmt[32];
- int i, k, len, field;
- PTDBDOS tdbp = (PTDBDOS)To_Tdb;
-
- if (trace > 1)
- htrc("DOS WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
- Name, tdbp->GetTdb_No(), ColUse, Status);
-
- p = tdbp->To_Line + Deplac;
-
- if (trace > 1)
- htrc("Lrecl=%d deplac=%d int=%d\n", tdbp->Lrecl, Deplac, Long);
-
- field = Long;
-
- if (tdbp->Ftype == RECFM_VAR && tdbp->Mode == MODE_UPDATE) {
- len = (signed)strlen(tdbp->To_Line);
-
- if (tdbp->IsUsingTemp(g))
- // Because of eventual missing field(s) the buffer must be reset
- memset(tdbp->To_Line + len, ' ', tdbp->Lrecl - len);
- else
- // The size actually available must be recalculated
- field = min(len - Deplac, Long);
-
- } // endif Ftype
-
- if (trace > 1)
- htrc("Long=%d field=%d coltype=%d colval=%p\n",
- Long, field, Buf_Type, Value);
-
- /*********************************************************************/
- /* Get the string representation of Value according to column type. */
- /*********************************************************************/
- if (Value != To_Val)
- Value->SetValue_pval(To_Val, false); // Convert the updated value
-
- /*********************************************************************/
- /* This test is only useful for compressed(2) tables. */
- /*********************************************************************/
- if (tdbp->Ftype != RECFM_BIN) {
- if (Ldz || Nod || Dcm >= 0) {
- switch (Buf_Type) {
- case TYPE_SHORT:
- strcpy(fmt, (Ldz) ? "%0*hd" : "%*.hd");
- i = 0;
-
- if (Nod)
- for (; i < Dcm; i++)
- strcat(fmt, "0");
-
- len = sprintf(Buf, fmt, field - i, Value->GetShortValue());
- break;
- case TYPE_INT:
- strcpy(fmt, (Ldz) ? "%0*ld" : "%*.ld");
- i = 0;
-
- if (Nod)
- for (; i < Dcm; i++)
- strcat(fmt, "0");
-
- len = sprintf(Buf, fmt, field - i, Value->GetIntValue());
- break;
- case TYPE_FLOAT:
- strcpy(fmt, (Ldz) ? "%0*.*lf" : "%*.*lf");
- sprintf(Buf, fmt, field + ((Nod && Dcm) ? 1 : 0),
- Dcm, Value->GetFloatValue());
- len = strlen(Buf);
-
- if (Nod && Dcm)
- for (i = k = 0; i < len; i++, k++)
- if (Buf[i] != ' ') {
- if (Buf[i] == '.' || Buf[i] == ',')
- k++;
-
- Buf[i] = Buf[k];
- } // endif Buf(i)
-
- len = strlen(Buf);
- break;
- } // endswitch BufType
-
- p2 = Buf;
- } else // Standard PlugDB format
- p2 = Value->ShowValue(Buf, field);
-
- if (trace)
- htrc("new length(%p)=%d\n", p2, strlen(p2));
-
- if ((len = strlen(p2)) > field) {
- sprintf(g->Message, MSG(VALUE_TOO_LONG), p2, Name, field);
- longjmp(g->jumper[g->jump_level], 31);
- } // endif
-
- if (trace > 1)
- htrc("buffer=%s\n", p2);
-
- /*******************************************************************/
- /* Updating must be done only when not in checking pass. */
- /*******************************************************************/
- if (Status) {
- memset(p, ' ', field);
- memcpy(p, p2, len);
-
- if (trace > 1)
- htrc(" col write: '%.*s'\n", len, p);
-
- } // endif Use
-
- } else // BIN compressed table
- /*******************************************************************/
- /* Check if updating is Ok, meaning col value is not too long. */
- /* Updating to be done only during the second pass (Status=true) */
- /*******************************************************************/
- 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
-
- } // end of WriteColumn
-
-/***********************************************************************/
-/* Make file output of a Dos column descriptor block. */
-/***********************************************************************/
-void DOSCOL::Print(PGLOBAL g, FILE *f, uint n)
- {
- COLBLK::Print(g, f, n);
- } // end of Print
-
-/* ------------------------------------------------------------------- */
-
+/************* TabDos C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABDOS */
+/* ------------- */
+/* Version 4.8 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the DOS tables classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(WIN32)
+#include <io.h>
+#include <sys\timeb.h> // For testing only
+#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 <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. */
+/***********************************************************************/
+#include "global.h"
+#include "osutil.h"
+#include "plgdbsem.h"
+#include "catalog.h"
+//#include "reldef.h"
+#include "xindex.h"
+#include "filamap.h"
+#include "filamfix.h"
+#include "filamdbf.h"
+#if defined(ZIP_SUPPORT)
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+#include "tabdos.h"
+#include "tabfix.h"
+#include "tabmul.h"
+
+#define PLGINI "plugdb.ini" // Configuration settings file
+
+#if defined(UNIX)
+#define _fileno fileno
+#define _O_RDONLY O_RDONLY
+#endif
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+int num_read, num_there, num_eq[2]; // Statistics
+extern "C" char plgini[_MAX_PATH];
+extern "C" int trace;
+
+/***********************************************************************/
+/* Min and Max blocks contains zero ended fields (blank = false). */
+/* No conversion of block values (check = true). */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL, void *, int, int, int len = 0, int prec = 0,
+ bool check = true, bool blank = false);
+
+/* --------------------------- Class DOSDEF -------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+DOSDEF::DOSDEF(void)
+ {
+ Pseudo = 3;
+ Fn = NULL;
+ Ofn = NULL;
+ To_Indx = NULL;
+ Recfm = RECFM_VAR;
+ Mapped = false;
+ Padded = false;
+ Huge = false;
+ Accept = false;
+ Eof = false;
+ To_Pos = NULL;
+ Compressed = 0;
+ Lrecl = 0;
+ AvgLen = 0;
+ Block = 0;
+ Last = 0;
+ Blksize = 0;
+ Maxerr = 0;
+ ReadMode = 0;
+ Ending = 0;
+//Mtime = 0;
+ } // end of DOSDEF constructor
+
+/***********************************************************************/
+/* DeleteTableFile: Delete DOS/UNIX table files using platform API. */
+/* If the table file is protected (declared as read/only) we still */
+/* erase the the eventual optimize and index files but return true. */
+/***********************************************************************/
+bool DOSDEF::DeleteTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool rc = false;
+
+ // Now delete the table file itself if not protected
+ if (!IsReadOnly()) {
+ rc = Erase(filename);
+ } else
+ rc =true;
+
+ return rc; // Return true if error
+ } // end of DeleteTableFile
+
+/***********************************************************************/
+/* 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 */
+/* when the class was VCTDEF. It also minimizes the specific code. */
+/***********************************************************************/
+bool DOSDEF::Erase(char *filename)
+ {
+ bool rc;
+
+ PlugSetPath(filename, Fn, GetPath());
+#if defined(WIN32)
+ rc = !DeleteFile(filename);
+#else // UNIX
+ rc = remove(filename);
+#endif // UNIX
+
+ return rc; // Return true if error
+ } // end of Erase
+
+/***********************************************************************/
+/* DeleteIndexFile: Delete DOS/UNIX index file(s) using platform API. */
+/***********************************************************************/
+bool DOSDEF::DeleteIndexFile(PGLOBAL g, PIXDEF pxdf)
+ {
+ char *ftype;
+ char filename[_MAX_PATH];
+ bool sep, rc = false;
+
+ if (!pxdf)
+ return false; // No index
+
+ sep = Cat->GetSepIndex(); // If true indexes are in separate files
+
+ if (!sep && To_Indx) {
+ strcpy(g->Message, MSG(NO_RECOV_SPACE));
+ return true;
+ } // endif sep
+
+ switch (Recfm) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(BAD_RECFM_VAL), Recfm);
+ return true;
+ } // endswitch Ftype
+
+ /*********************************************************************/
+ /* Check for existence of an index file. */
+ /*********************************************************************/
+ if (sep) {
+ // Indexes are save in separate files
+#if !defined(UNIX)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ for (; pxdf; pxdf = pxdf->GetNext()) {
+ _splitpath(Ofn, drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), pxdf->GetName());
+ _makepath(filename, drive, direc, fname, ftype);
+ PlugSetPath(filename, filename, GetPath());
+#if defined(WIN32)
+ rc |= !DeleteFile(filename);
+#else // UNIX
+ rc |= remove(filename);
+#endif // UNIX
+ } // endfor pxdf
+
+ } else { // !sep, no more indexes or name is NULL
+ // Drop all indexes, delete the common file
+ PlugSetPath(filename, Ofn, GetPath());
+ strcat(PlugRemoveType(filename, filename), ftype);
+#if defined(WIN32)
+ rc = !DeleteFile(filename);
+#else // UNIX
+ rc = remove(filename);
+#endif // UNIX
+ } // endif sep
+
+ if (rc)
+ sprintf(g->Message, MSG(DEL_FILE_ERR), filename);
+
+ return rc; // Return true if error
+ } // end of DeleteIndexFile
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ char buf[8];
+ bool map = (am && (*am == 'M' || *am == 'm'));
+ LPCSTR dfm = (am && (*am == 'F' || *am == 'f')) ? "F"
+ : (am && (*am == 'B' || *am == 'b')) ? "B"
+ : (am && !stricmp(am, "DBF")) ? "D" : "V";
+
+ Desc = Fn = Cat->GetStringCatInfo(g, Name, "Filename", "");
+ Ofn = Cat->GetStringCatInfo(g, Name, "Optname", Fn);
+ Cat->GetCharCatInfo(Name, "Recfm", (PSZ)dfm, buf, sizeof(buf));
+ Recfm = (toupper(*buf) == 'F') ? RECFM_FIX :
+ (toupper(*buf) == 'B') ? RECFM_BIN :
+ (toupper(*buf) == 'D') ? RECFM_DBF : RECFM_VAR;
+ Lrecl = Cat->GetIntCatInfo(Name, "Lrecl", 0);
+
+ if (Recfm != RECFM_DBF)
+ Compressed = Cat->GetIntCatInfo(Name, "Compressed", 0);
+
+ Mapped = Cat->GetBoolCatInfo(Name, "Mapped", map);
+ Block = Cat->GetIntCatInfo(Name, "Blocks", 0);
+ Last = Cat->GetIntCatInfo(Name, "Last", 0);
+ Ending = Cat->GetIntCatInfo(Name, "Ending", CRLF);
+
+ if (Recfm == RECFM_FIX || Recfm == RECFM_BIN) {
+ int defhuge = (Cat->GetDefHuge()) ? 1 : 0;
+
+ Huge = (Cat->GetIntCatInfo(Name, "Huge", defhuge) != 0);
+ Padded = (Cat->GetIntCatInfo(Name, "Padded", 0) != 0);
+ Blksize = Cat->GetIntCatInfo(Name, "Blksize", 0);
+ Eof = (Cat->GetIntCatInfo(Name, "EOF", 0) != 0);
+ } else if (Recfm == RECFM_DBF) {
+ Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0);
+ Accept = (Cat->GetIntCatInfo(Name, "Accept", 0) != 0);
+ ReadMode = Cat->GetIntCatInfo(Name, "Readmode", 0);
+ } else // (Recfm == RECFM_VAR)
+ AvgLen = Cat->GetIntCatInfo(Name, "Avglen", 0);
+
+ // Ignore wrong Index definitions for catalog commands
+ return (Cat->GetIndexInfo(g, this) /*&& !Cat->GetCatFnc()*/);
+ } // end of DefineAM
+
+/***********************************************************************/
+/* InvalidateIndex: mark all indexes as invalid. */
+/***********************************************************************/
+bool DOSDEF::InvalidateIndex(PGLOBAL g)
+ {
+ if (To_Indx)
+ for (PIXDEF xp = To_Indx; xp; xp = xp->Next)
+ xp->Invalid = true;
+
+ return false;
+ } // end of InvalidateIndex
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode)
+ {
+ // Mapping not used for insert
+ USETEMP tmp = PlgGetUser(g)->UseTemp;
+ bool map = Mapped && mode != MODE_INSERT &&
+ !(tmp != TMP_NO && Recfm == RECFM_VAR
+ && mode == MODE_UPDATE) &&
+ !(tmp == TMP_FORCE &&
+ (mode == MODE_UPDATE || mode == MODE_DELETE));
+ PTXF txfp;
+ PTDBASE tdbp;
+
+ /*********************************************************************/
+ /* Allocate table and file processing class of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ if (Recfm == RECFM_DBF) {
+ if (map)
+ txfp = new(g) DBMFAM(this);
+ else
+ txfp = new(g) DBFFAM(this);
+
+ tdbp = new(g) TDBFIX(this, txfp);
+ } else if (Recfm != RECFM_VAR && Compressed < 2) {
+ if (Huge)
+ txfp = new(g) BGXFAM(this);
+ else if (map)
+ txfp = new(g) MPXFAM(this);
+#if defined(ZIP_SUPPORT)
+ else if (Compressed)
+ txfp = new(g) ZIXFAM(this);
+#endif // ZIP_SUPPORT
+ else
+ txfp = new(g) FIXFAM(this);
+
+ tdbp = new(g) TDBFIX(this, txfp);
+ } else {
+#if defined(ZIP_SUPPORT)
+ if (Compressed) {
+ if (Compressed == 1)
+ txfp = new(g) ZIPFAM(this);
+ else {
+ strcpy(g->Message, "Compress 2 not supported yet");
+// txfp = new(g) ZLBFAM(defp);
+ return NULL;
+ } // endelse
+
+ } else
+#endif // ZIP_SUPPORT
+ if (map)
+ txfp = new(g) MAPFAM(this);
+ else
+ txfp = new(g) DOSFAM(this);
+
+ // Txfp must be set even for not multiple tables because
+ // it is needed when calling Cardinality in GetBlockValues.
+ tdbp = new(g) TDBDOS(this, txfp);
+ } // endif Recfm
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+
+ return tdbp;
+ } // end of GetTable
+
+/* ------------------------ Class TDBDOS ----------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBDOS class. This is the common class that */
+/* contain all that is common between the TDBDOS and TDBMAP classes. */
+/***********************************************************************/
+TDBDOS::TDBDOS(PDOSDEF tdp, PTXF txfp) : TDBASE(tdp)
+ {
+ if ((Txfp = txfp))
+ Txfp->SetTdbp(this);
+
+ Lrecl = tdp->Lrecl;
+ AvgLen = tdp->AvgLen;
+ Ftype = tdp->Recfm;
+ To_Line = NULL;
+ Cardinal = -1;
+ } // end of TDBDOS standard constructor
+
+TDBDOS::TDBDOS(PGLOBAL g, PTDBDOS tdbp) : TDBASE(tdbp)
+ {
+ Txfp = (g) ? tdbp->Txfp->Duplicate(g) : tdbp->Txfp;
+ Lrecl = tdbp->Lrecl;
+ AvgLen = tdbp->AvgLen;
+ Ftype = tdbp->Ftype;
+ To_Line = tdbp->To_Line;
+ Cardinal = tdbp->Cardinal;
+ } // end of TDBDOS copy constructor
+
+// Method
+PTDB TDBDOS::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PDOSCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBDOS(g, this);
+
+ for (cp1 = (PDOSCOL)Columns; cp1; cp1 = (PDOSCOL)cp1->GetNext()) {
+ cp2 = new(g) DOSCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Allocate DOS column description block. */
+/***********************************************************************/
+PCOL TDBDOS::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) DOSCOL(g, cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Print debug information. */
+/***********************************************************************/
+void TDBDOS::PrintAM(FILE *f, char *m)
+ {
+ fprintf(f, "%s AM(%d): mode=%d\n", m, GetAmType(), Mode);
+
+ if (Txfp->To_File)
+ fprintf(f, "%s File: %s\n", m, Txfp->To_File);
+
+ } // end of PrintAM
+
+/***********************************************************************/
+/* Remake the indexes after the table was modified. */
+/***********************************************************************/
+int TDBDOS::ResetTableOpt(PGLOBAL g, bool dox)
+ {
+ int rc = RC_OK;
+
+ MaxSize = -1; // Size must be recalculated
+ Cardinal = -1; // as well as Cardinality
+
+ if (dox) {
+ // Remake eventual indexes
+ Columns = NULL; // Not used anymore
+ Txfp->Reset(); // New start
+ Use = USE_READY; // So the table can be reopened
+ Mode = MODE_READ; // New mode
+
+ if (!(PlgGetUser(g)->Check & CHK_OPT)) {
+ // After the table was modified the indexes
+ // are invalid and we should mark them as such...
+ rc = ((PDOSDEF)To_Def)->InvalidateIndex(g);
+ } else
+ // ... or we should remake them.
+ rc = MakeIndex(g, NULL, false);
+
+ } // endif dox
+
+ return rc;
+ } // end of ResetTableOpt
+
+/***********************************************************************/
+/* Check whether we have to create/update permanent indexes. */
+/***********************************************************************/
+int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add)
+ {
+ int k, n;
+ bool fixed, b = (pxdf != NULL);
+ PCOL *keycols, colp;
+ PIXDEF xdp, sxp = NULL;
+ PKPDEF kdp;
+ PDOSDEF dfp;
+//PCOLDEF cdp;
+ PXINDEX x;
+ PXLOAD pxp;
+ PCATLG cat = PlgGetCatalog(g);
+
+ Mode = MODE_READ;
+ Use = USE_READY;
+ dfp = (PDOSDEF)To_Def;
+ fixed = Cardinality(g) >= 0;
+
+ // Are we are called from CreateTable or CreateIndex?
+ if (pxdf) {
+ if (!add && dfp->GetIndx()) {
+ strcpy(g->Message, MSG(INDX_EXIST_YET));
+ return RC_FX;
+ } // endif To_Indx
+
+ if (add && dfp->GetIndx()) {
+ for (sxp = dfp->GetIndx(); sxp; sxp = sxp->GetNext())
+ if (!stricmp(sxp->GetName(), pxdf->GetName())) {
+ sprintf(g->Message, MSG(INDEX_YET_ON), pxdf->GetName(), Name);
+ return RC_FX;
+ } else if (!sxp->GetNext())
+ break;
+
+ sxp->SetNext(pxdf);
+// first = false;
+ } else
+ dfp->SetIndx(pxdf);
+
+// pxdf->SetDef(dfp);
+ } else if (!(pxdf = dfp->GetIndx()))
+ return RC_INFO; // No index to make
+
+ // Allocate all columns that will be used by indexes.
+ // This must be done before opening the table so specific
+ // column initialization can be done ( in particular by TDBVCT)
+ for (n = 0, xdp = pxdf; xdp; xdp = xdp->GetNext())
+ for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) {
+ if (!(colp = ColDB(g, kdp->GetName(), 0))) {
+ sprintf(g->Message, MSG(INDX_COL_NOTIN), kdp->GetName(), Name);
+ goto err;
+ } // endif colp
+
+ colp->InitValue(g);
+ n = max(n, xdp->GetNparts());
+ } // endfor kdp
+
+ keycols = (PCOL*)PlugSubAlloc(g, NULL, n * sizeof(PCOL));
+
+ /*********************************************************************/
+ /* Construct and save the defined indexes. */
+ /*********************************************************************/
+ for (xdp = pxdf; xdp; xdp = xdp->GetNext())
+ if (!OpenDB(g)) {
+ if (xdp->IsAuto() && fixed)
+ // Auto increment key and fixed file: use an XXROW index
+ continue; // XXROW index doesn't need to be made
+
+ n = 0;
+
+ if (sxp)
+ xdp->SetID(sxp->GetID() + 1);
+
+ for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext())
+ keycols[n++] = ColDB(g, kdp->GetName(), 0);
+
+ k = xdp->GetNparts();
+
+ // Make the index and save it
+ if (dfp->Huge)
+ pxp = new(g) XHUGE;
+ else
+ pxp = new(g) XFILE;
+
+ if (k == 1) // Simple index
+ x = new(g) XINDXS(this, xdp, pxp, keycols);
+ else // Multi-Column index
+ x = new(g) XINDEX(this, xdp, pxp, keycols);
+
+ if (!x->Make(g, sxp)) {
+ // Retreive define values from the index
+ xdp->SetMaxSame(x->GetMaxSame());
+ xdp->SetOffset(x->GetDefoff());
+ xdp->SetOffhigh(x->GetDefhigh());
+ xdp->SetSize(x->GetSize());
+
+ // store KXYCOL Mxs in KPARTDEF Mxsame
+ xdp->SetMxsame(x);
+
+#if defined(TRACE)
+ printf("Make done...\n");
+#endif // TRACE
+
+ if (x->GetSize() > 0)
+ sxp = xdp;
+
+ xdp->SetInvalid(false);
+ } else
+ goto err;
+
+ } else
+ break; // Physical table does not exist yet or anymore
+
+ if (Use == USE_OPEN)
+ CloseDB(g);
+
+ return RC_OK;
+
+err:
+ if (sxp)
+ sxp->SetNext(NULL);
+ else
+ dfp->SetIndx(NULL);
+
+ return RC_FX;
+ } // end of MakeIndex
+
+/***********************************************************************/
+/* DOS GetProgMax: get the max value for progress information. */
+/***********************************************************************/
+int TDBDOS::GetProgMax(PGLOBAL g)
+ {
+ return (To_Kindex) ? GetMaxSize(g) : GetFileLength(g);
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* DOS GetProgCur: get the current value for progress information. */
+/***********************************************************************/
+int TDBDOS::GetProgCur(void)
+ {
+ return (To_Kindex) ? To_Kindex->GetCur_K() + 1 : GetRecpos();
+ } // end of GetProgCur
+
+/***********************************************************************/
+/* RowNumber: return the ordinal number of the current row. */
+/***********************************************************************/
+int TDBDOS::RowNumber(PGLOBAL g, bool b)
+ {
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Don't know how to retrieve RowID from file address. */
+ /*******************************************************************/
+ sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
+ GetAmName(g, Txfp->GetAmType()));
+ return 0;
+ } else
+ return Txfp->GetRowID();
+
+ } // end of RowNumber
+
+/***********************************************************************/
+/* DOS 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 TDBDOS::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return Txfp->Cardinality(g);
+
+ if (Cardinal < 0)
+ Cardinal = Txfp->Cardinality(g);
+
+ return Cardinal;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* DOS GetMaxSize: returns file size estimate in number of lines. */
+/* This function covers variable record length files. */
+/***********************************************************************/
+int TDBDOS::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize >= 0)
+ return MaxSize;
+
+ if (!Cardinality(NULL)) {
+ int len = GetFileLength(g);
+
+ if (len >= 0) {
+ if (trace)
+ htrc("Estimating lines len=%d ending=%d\n",
+ len, ((PDOSDEF)To_Def)->Ending);
+
+ /*****************************************************************/
+ /* Estimate the number of lines in the table (if not known) by */
+ /* dividing the file length by the minimum line length assuming */
+ /* only the last column can be of variable length. This will be */
+ /* a ceiling estimate (as last column is never totally absent). */
+ /*****************************************************************/
+ int rec = ((PDOSDEF)To_Def)->Ending; // +2: CRLF +1: LF
+
+ if (AvgLen <= 0) // No given average estimate
+ rec += EstimatedLength(g);
+ else // A lower estimate was given for the average record length
+ rec += (int)AvgLen;
+
+ if (trace)
+ htrc(" Filen=%d min_rec=%d\n", len, rec);
+
+ MaxSize = (len + rec - 1) / rec;
+
+ if (trace)
+ htrc(" Estimated max_K=%d\n", MaxSize);
+
+ } // endif len
+
+ } else
+ MaxSize = Cardinality(g);
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* DOS EstimatedLength. Returns an estimated minimum line length. */
+/***********************************************************************/
+int TDBDOS::EstimatedLength(PGLOBAL g)
+ {
+ int dep = 0;
+ PCOLDEF cdp = To_Def->GetCols();
+
+ if (!cdp->GetNext()) {
+ // One column table, we are going to return a ridiculous
+ // result if we set dep to 1
+ dep = 1 + cdp->GetLong() / 20; // Why 20 ?????
+ } else for (; cdp; cdp = cdp->GetNext())
+ dep = max(dep, cdp->GetOffset());
+
+ return (int)dep;
+ } // end of Estimated Length
+
+/***********************************************************************/
+/* DOS tables favor the use temporary files for Update. */
+/***********************************************************************/
+bool TDBDOS::IsUsingTemp(PGLOBAL g)
+ {
+ USETEMP usetemp = PlgGetUser(g)->UseTemp;
+
+ return (usetemp == TMP_YES || usetemp == TMP_FORCE ||
+ (usetemp == TMP_AUTO && Mode == MODE_UPDATE));
+ } // end of IsUsingTemp
+
+/***********************************************************************/
+/* DOS 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 TDBDOS::OpenDB(PGLOBAL g)
+ {
+ if (trace)
+ htrc("DOS OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ Txfp->Rewind(); // see comment in Work.log
+
+ if (SkipHeader(g))
+ return true;
+
+ return false;
+ } // endif use
+
+ if (Txfp->Blocked && (Mode == MODE_DELETE ||
+ (Mode == MODE_UPDATE && PlgGetUser(g)->UseTemp != TMP_NO))) {
+ /*******************************************************************/
+ /* Delete is not currently handled in block mode neither Update */
+ /* when using a temporary file. */
+ /*******************************************************************/
+ if (Txfp->GetAmType() == TYPE_AM_MAP && Mode == MODE_DELETE)
+ Txfp = new(g) MAPFAM((PDOSDEF)To_Def);
+#if defined(ZIP_SUPPORT)
+ else if (Txfp->GetAmType() == TYPE_AM_ZIP)
+ Txfp = new(g) ZIPFAM((PDOSDEF)To_Def);
+#endif // ZIP_SUPPORT
+ else if (Txfp->GetAmType() != TYPE_AM_DOS)
+ Txfp = new(g) DOSFAM((PDOSDEF)To_Def);
+
+ Txfp->SetTdbp(this);
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Open according to logical input/output mode required. */
+ /* Use conventionnal input/output functions. */
+ /* Treat files as binary in Delete mode (for line moving) */
+ /*********************************************************************/
+ if (Txfp->OpenTableFile(g))
+ return true;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Allocate the line buffer plus a null character. */
+ /*********************************************************************/
+ To_Line = (char*)PlugSubAlloc(g, NULL, Lrecl + 1);
+
+ if (Mode == MODE_INSERT) {
+ // Spaces between fields must be filled with blanks
+ memset(To_Line, ' ', Lrecl);
+ To_Line[Lrecl] = '\0';
+ } else
+ memset(To_Line, 0, Lrecl + 1);
+
+ if (trace)
+ htrc("OpenDos: R%hd mode=%d To_Line=%p\n", Tdb_No, Mode, To_Line);
+
+ if (SkipHeader(g)) // When called from CSV/FMT files
+ return true;
+
+ /*********************************************************************/
+ /* Reset statistics values. */
+ /*********************************************************************/
+ num_read = num_there = num_eq[0] = num_eq[1] = 0;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for DOS access method. */
+/***********************************************************************/
+int TDBDOS::ReadDB(PGLOBAL g)
+ {
+ if (trace > 1)
+ htrc("DOS ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p To_Line=%p\n",
+ GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex, To_Line);
+
+ 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;
+
+ if (trace > 1)
+ htrc("File position is now %d\n", GetRecpos());
+
+ if (Mode == MODE_READ)
+ /*************************************************************/
+ /* Defer physical reading until one column setting needs it */
+ /* as it can be a big saving on joins where no other column */
+ /* than the keys are used, so reading is unnecessary. */
+ /*************************************************************/
+ if (Txfp->DeferReading())
+ return RC_OK;
+
+ } // endswitch recpos
+
+ } // endif To_Kindex
+
+ if (trace > 1)
+ htrc(" ReadDB: this=%p To_Line=%p\n", this, To_Line);
+
+ /*********************************************************************/
+ /* Now start the reading process. */
+ /*********************************************************************/
+ return ReadBuffer(g);
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for DOS access method. */
+/***********************************************************************/
+int TDBDOS::WriteDB(PGLOBAL g)
+ {
+ if (trace > 1)
+ htrc("DOS WriteDB: R%d Mode=%d \n", Tdb_No, Mode);
+
+ if (!Ftype && (Mode == MODE_INSERT || Txfp->GetUseTemp())) {
+ char *p;
+
+ /*******************************************************************/
+ /* Suppress trailing blanks. */
+ /* Also suppress eventual null from last line. */
+ /*******************************************************************/
+ for (p = To_Line + Lrecl -1; p >= To_Line; p--)
+ if (*p && *p != ' ')
+ break;
+
+ *(++p) = '\0';
+ } // endif Mode
+
+ if (trace > 1)
+ htrc("Write: line is='%s'\n", To_Line);
+
+ // Now start the writing process
+ return Txfp->WriteBuffer(g);
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for DOS (and FIX) access method. */
+/* RC_FX means delete all. Nothing to do here (was done at open). */
+/***********************************************************************/
+int TDBDOS::DeleteDB(PGLOBAL g, int irc)
+ {
+ return (irc == RC_FX) ? RC_OK : Txfp->DeleteRecords(g, irc);
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for DOS access method. */
+/***********************************************************************/
+void TDBDOS::CloseDB(PGLOBAL g)
+ {
+ if (To_Kindex) {
+ To_Kindex->Close();
+ To_Kindex = NULL;
+ } // endif
+
+ Txfp->CloseTableFile(g);
+ } // end of CloseDB
+
+// ------------------------ DOSCOL functions ----------------------------
+
+/***********************************************************************/
+/* DOSCOL public constructor (also called by MAPCOL). */
+/***********************************************************************/
+DOSCOL::DOSCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am)
+ : COLBLK(cdp, tp, i)
+ {
+ char *p;
+ int prec = Format.Prec;
+ PTXF txfp = ((PTDBDOS)tp)->Txfp;
+
+ assert(cdp);
+
+ if (cp) {
+ Next = cp->GetNext();
+ cp->SetNext(this);
+ } else {
+ Next = tp->GetColumns();
+ tp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional Dos access method information for column.
+ Deplac = cdp->GetOffset();
+ Long = cdp->GetLong();
+ To_Val = NULL;
+
+ OldVal = NULL; // Currently used only in MinMax
+ Ldz = false;
+ Nod = false;
+ Dcm = -1;
+ p = cdp->GetFmt();
+
+ if (p && IsTypeNum(Buf_Type)) {
+ // Formatted numeric value
+ for (; p && *p && isalpha(*p); p++)
+ switch (toupper(*p)) {
+ case 'Z': // Have leading zeros
+ Ldz = true;
+ break;
+ case 'N': // Have no decimal point
+ Nod = true;
+ break;
+ } // endswitch p
+
+ // Set number of decimal digits
+ Dcm = (*p) ? atoi(p) : GetPrecision();
+ } // endif fmt
+
+ if (trace)
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of DOSCOL constructor
+
+/***********************************************************************/
+/* DOSCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+DOSCOL::DOSCOL(DOSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Deplac = col1->Deplac;
+ Long = col1->Long;
+ To_Val = col1->To_Val;
+ Ldz = col1->Ldz;
+ Nod = col1->Nod;
+ Dcm = col1->Dcm;
+ OldVal = col1->OldVal;
+ Buf = col1->Buf;
+ } // end of DOSCOL copy constructor
+
+/***********************************************************************/
+/* VarSize: This function tells UpdateDB whether or not the block */
+/* optimization file must be redone if this column is updated, even */
+/* it is not sorted or clustered. This applies to the last column of */
+/* a variable length table that is blocked, because if it is updated */
+/* using a temporary file, the block size may be modified. */
+/***********************************************************************/
+bool DOSCOL::VarSize(void)
+ {
+ PTDBDOS tdbp = (PTDBDOS)To_Tdb;
+ PTXF txfp = tdbp->Txfp;
+
+ if (Cdp && !Cdp->GetNext() // Must be the last column
+ && tdbp->Ftype == RECFM_VAR // of a DOS variable length
+ && txfp->Blocked // blocked table
+ && txfp->GetUseTemp()) // using a temporary file.
+ return true;
+ else
+ return false;
+
+ } // end VarSize
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool DOSCOL::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 buffer used in WriteColumn for numeric columns
+ if (IsTypeNum(Buf_Type))
+ Buf = (char*)PlugSubAlloc(g, NULL, max(32, Long + Dcm + 1));
+
+ // 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 last line */
+/* read from the corresponding table, extract from it the field */
+/* corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void DOSCOL::ReadColumn(PGLOBAL g)
+ {
+ char *p;
+ int i, rc;
+ int field;
+ PTDBDOS tdbp = (PTDBDOS)To_Tdb;
+
+ if (trace > 1)
+ htrc(
+ "DOS 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;
+ field = Long;
+
+ switch (tdbp->Ftype) {
+ case RECFM_VAR:
+ /*****************************************************************/
+ /* For a variable length file, check if the field exists. */
+ /*****************************************************************/
+ if (strlen(tdbp->To_Line) < (unsigned)Deplac)
+ field = 0;
+
+ case RECFM_FIX: // Fixed length text file
+ case RECFM_DBF: // Fixed length DBase file
+ if (Nod) switch (Buf_Type) {
+ case TYPE_INT:
+ case TYPE_SHORT:
+ Value->SetValue_char(p, field - Dcm);
+ break;
+ case TYPE_FLOAT:
+ Value->SetValue_char(p, field);
+
+ for (i = 0; i < Dcm; i++)
+ ((DFVAL*)Value)->Divide(10.0);
+
+ break;
+ default:
+ Value->SetValue_char(p, field);
+ break;
+ } // endswitch Buf_Type
+
+ else
+ Value->SetValue_char(p, field);
+
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_RECFM), tdbp->Ftype);
+ longjmp(g->jumper[g->jump_level], 34);
+ } // endswitch Ftype
+
+ } // 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 DOSCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, *p2, fmt[32];
+ int i, k, len, field;
+ PTDBDOS tdbp = (PTDBDOS)To_Tdb;
+
+ if (trace > 1)
+ htrc("DOS WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status);
+
+ p = tdbp->To_Line + Deplac;
+
+ if (trace > 1)
+ htrc("Lrecl=%d deplac=%d int=%d\n", tdbp->Lrecl, Deplac, Long);
+
+ field = Long;
+
+ if (tdbp->Ftype == RECFM_VAR && tdbp->Mode == MODE_UPDATE) {
+ len = (signed)strlen(tdbp->To_Line);
+
+ if (tdbp->IsUsingTemp(g))
+ // Because of eventual missing field(s) the buffer must be reset
+ memset(tdbp->To_Line + len, ' ', tdbp->Lrecl - len);
+ else
+ // The size actually available must be recalculated
+ field = min(len - Deplac, Long);
+
+ } // endif Ftype
+
+ if (trace > 1)
+ htrc("Long=%d field=%d coltype=%d colval=%p\n",
+ Long, field, Buf_Type, Value);
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ /*********************************************************************/
+ /* This test is only useful for compressed(2) tables. */
+ /*********************************************************************/
+ if (tdbp->Ftype != RECFM_BIN) {
+ if (Ldz || Nod || Dcm >= 0) {
+ switch (Buf_Type) {
+ case TYPE_SHORT:
+ strcpy(fmt, (Ldz) ? "%0*hd" : "%*.hd");
+ i = 0;
+
+ if (Nod)
+ for (; i < Dcm; i++)
+ strcat(fmt, "0");
+
+ len = sprintf(Buf, fmt, field - i, Value->GetShortValue());
+ break;
+ case TYPE_INT:
+ strcpy(fmt, (Ldz) ? "%0*ld" : "%*.ld");
+ i = 0;
+
+ if (Nod)
+ for (; i < Dcm; i++)
+ strcat(fmt, "0");
+
+ len = sprintf(Buf, fmt, field - i, Value->GetIntValue());
+ break;
+ case TYPE_FLOAT:
+ strcpy(fmt, (Ldz) ? "%0*.*lf" : "%*.*lf");
+ sprintf(Buf, fmt, field + ((Nod && Dcm) ? 1 : 0),
+ Dcm, Value->GetFloatValue());
+ len = strlen(Buf);
+
+ if (Nod && Dcm)
+ for (i = k = 0; i < len; i++, k++)
+ if (Buf[i] != ' ') {
+ if (Buf[i] == '.' || Buf[i] == ',')
+ k++;
+
+ Buf[i] = Buf[k];
+ } // endif Buf(i)
+
+ len = strlen(Buf);
+ break;
+ } // endswitch BufType
+
+ p2 = Buf;
+ } else // Standard PlugDB format
+ p2 = Value->ShowValue(Buf, field);
+
+ if (trace)
+ htrc("new length(%p)=%d\n", p2, strlen(p2));
+
+ if ((len = strlen(p2)) > field) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p2, Name, field);
+ longjmp(g->jumper[g->jump_level], 31);
+ } // endif
+
+ if (trace > 1)
+ htrc("buffer=%s\n", p2);
+
+ /*******************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*******************************************************************/
+ if (Status) {
+ memset(p, ' ', field);
+ memcpy(p, p2, len);
+
+ if (trace > 1)
+ htrc(" col write: '%.*s'\n", len, p);
+
+ } // endif Use
+
+ } else // BIN compressed table
+ /*******************************************************************/
+ /* Check if updating is Ok, meaning col value is not too long. */
+ /* Updating to be done only during the second pass (Status=true) */
+ /*******************************************************************/
+ 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
+
+ } // end of WriteColumn
+
+/***********************************************************************/
+/* Make file output of a Dos column descriptor block. */
+/***********************************************************************/
+void DOSCOL::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ COLBLK::Print(g, f, n);
+ } // end of Print
+
+/* ------------------------------------------------------------------- */
+
diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h
index 219400c119e..a1c5b0660cd 100644
--- a/storage/connect/tabdos.h
+++ b/storage/connect/tabdos.h
@@ -1,246 +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
+/*************** 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
diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp
index 6ffcf7b0538..b3db09e1a2f 100644
--- a/storage/connect/tabfix.cpp
+++ b/storage/connect/tabfix.cpp
@@ -1,492 +1,492 @@
-/************* 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 'L': // Long Integer
- strcpy(g->Message, "Format L is deprecated, use I");
- longjmp(g->jumper[g->jump_level], 11);
- case 'I': // 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;
- longlong 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->GetBigintValue();
-
- if (n > 32767LL || n < -32768LL) {
- 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': // Tiny integer
- n = Value->GetBigintValue();
-
- if (n > 255LL || n < -256LL) {
- sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
- longjmp(g->jumper[g->jump_level], 31);
- } else if (Status)
- *p = (char)n;
-
- break;
- case 'L': // Long Integer
- strcpy(g->Message, "Format L is deprecated, use I");
- longjmp(g->jumper[g->jump_level], 11);
- case 'I': // Integer
- n = Value->GetBigintValue();
-
- if (n > INT_MAX || n < INT_MIN) {
- sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
- longjmp(g->jumper[g->jump_level], 31);
- } else if (Status)
- *(int *)p = Value->GetIntValue();
-
- break;
- case 'B': // Large (big) integer
- if (Status)
- *(longlong *)p = (longlong)Value->GetBigintValue();
-
- 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 ---------------------------- */
+/************* 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 'L': // Long Integer
+ strcpy(g->Message, "Format L is deprecated, use I");
+ longjmp(g->jumper[g->jump_level], 11);
+ case 'I': // 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;
+ longlong 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->GetBigintValue();
+
+ if (n > 32767LL || n < -32768LL) {
+ 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': // Tiny integer
+ n = Value->GetBigintValue();
+
+ if (n > 255LL || n < -256LL) {
+ sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
+ longjmp(g->jumper[g->jump_level], 31);
+ } else if (Status)
+ *p = (char)n;
+
+ break;
+ case 'L': // Long Integer
+ strcpy(g->Message, "Format L is deprecated, use I");
+ longjmp(g->jumper[g->jump_level], 11);
+ case 'I': // Integer
+ n = Value->GetBigintValue();
+
+ if (n > INT_MAX || n < INT_MIN) {
+ sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
+ longjmp(g->jumper[g->jump_level], 31);
+ } else if (Status)
+ *(int *)p = Value->GetIntValue();
+
+ break;
+ case 'B': // Large (big) integer
+ if (Status)
+ *(longlong *)p = (longlong)Value->GetBigintValue();
+
+ 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 ---------------------------- */
diff --git a/storage/connect/tabfix.h b/storage/connect/tabfix.h
index ead81833c07..0a4f9fc4872 100644
--- a/storage/connect/tabfix.h
+++ b/storage/connect/tabfix.h
@@ -1,80 +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__
+/*************** 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__
diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp
index f2efa775d5e..c62337b26d1 100644
--- a/storage/connect/tabfmt.cpp
+++ b/storage/connect/tabfmt.cpp
@@ -1,1391 +1,1391 @@
-/************* TabFmt C++ Program Source Code File (.CPP) **************/
-/* PROGRAM NAME: TABFMT */
-/* ------------- */
-/* Version 3.7 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 2001 - 2013 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the TABFMT classes DB execution routines. */
-/* The base class CSV is comma separated files. */
-/* FMT (Formatted) files are those having a complex internal record */
-/* format described in the Format keyword of their definition. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant MariaDB header file. */
-/***********************************************************************/
-#include "my_global.h"
-
-#if defined(WIN32)
-#include <io.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <locale.h>
-#if defined(__BORLANDC__)
-#define __MFC_COMPAT__ // To define min/max as macro
-#endif
-//#include <windows.h>
-#include "osutil.h"
-#else
-#if defined(UNIX)
-#include <errno.h>
-#include <unistd.h>
-#include "osutil.h"
-#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 "filamap.h"
-#if defined(ZIP_SUPPORT)
-#include "filamzip.h"
-#endif // ZIP_SUPPORT
-#include "tabfmt.h"
-#include "tabmul.h"
-#define NO_FUNC
-#include "plgcnx.h" // For DB types
-#include "resource.h"
-
-/***********************************************************************/
-/* This should be an option. */
-/***********************************************************************/
-#define MAXCOL 200 /* Default max column nb in result */
-#define TYPE_UNKNOWN 10 /* Must be greater than other types */
-
-extern "C" int trace;
-
-/***********************************************************************/
-/* CSV Catalog utility functions. */
-/***********************************************************************/
-PQRYRES PlgAllocResult(PGLOBAL, int, int, int, int *, int *,
- unsigned int *, bool blank = true, bool nonull = false);
-
-/***********************************************************************/
-/* CSVColumns: constructs the result blocks containing the description */
-/* of all the columns of a CSV file that will be retrieved by #GetData.*/
-/* Note: the algorithm to set the type is based on the internal values */
-/* of types (TYPE_STRING < TYPE_FLOAT < TYPE_INT) (1 < 2 < 7). */
-/* If these values are changed, this will have to be revisited. */
-/***********************************************************************/
-PQRYRES CSVColumns(PGLOBAL g, char *fn, char sep, char q, int hdr, int mxr)
- {
- 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[] = {6, 6, 8, 10, 10, 6};
- char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096];
- int i, imax, hmax, n, nerr, phase, blank, digit, dec, type;
- int ncol = sizeof(dbtype) / sizeof(int);
- int num_read = 0, num_max = 10000000; // Statistics
- int len[MAXCOL], typ[MAXCOL], prc[MAXCOL];
- FILE *infile;
- PQRYRES qrp;
- PCOLRES crp;
-
-// num_max = atoi(p+1); // Max num of record to test
-#if defined(WIN32)
- if (strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6))
- dechar = '.';
- else
- dechar = ',';
-#else // !WIN32
- dechar = '.';
-#endif // !WIN32
-
- if (trace)
- htrc("File %s sep=%c q=%c hdr=%d mxr=%d\n",
- SVP(fn), sep, q, hdr, mxr);
-
- if (!fn) {
- strcpy(g->Message, MSG(MISSING_FNAME));
- return NULL;
- } // endif fn
-
- imax = hmax = nerr = 0;
- mxr = max(0, mxr);
-
- for (i = 0; i < MAXCOL; i++) {
- colname[i] = NULL;
- len[i] = 0;
- typ[i] = TYPE_UNKNOWN;
- prc[i] = 0;
- } // endfor i
-
- /*********************************************************************/
- /* Open the input file. */
- /*********************************************************************/
- PlugSetPath(filename, fn, PlgGetDataPath(g));
-
- if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r")))
- return NULL;
-
- if (hdr) {
- /*******************************************************************/
- /* Make the column names from the first line. */
- /*******************************************************************/
- phase = 0;
-
- if (fgets(buf, sizeof(buf), infile)) {
- n = strlen(buf) + 1;
- buf[n - 2] = '\0';
-#if defined(UNIX)
- // The file can be imported from Windows
- if (buf[n - 3] == '\r')
- buf[n - 3] = 0;
-#endif // UNIX
- p = (char*)PlugSubAlloc(g, NULL, n);
- memcpy(p, buf, n);
-
- //skip leading blanks
- for (; *p == ' '; p++) ;
-
- if (q && *p == q) {
- // Header is quoted
- p++;
- phase = 1;
- } // endif q
-
- colname[0] = p;
- } else {
- sprintf(g->Message, MSG(FILE_IS_EMPTY), fn);
- goto err;
- } // endif's
-
- for (i = 1; *p; p++)
- if (phase == 1 && *p == q) {
- *p = '\0';
- phase = 0;
- } else if (*p == sep && !phase) {
- *p = '\0';
-
- //skip leading blanks
- for (; *(p+1) == ' '; p++) ;
-
- if (q && *(p+1) == q) {
- // Header is quoted
- p++;
- phase = 1;
- } // endif q
-
- colname[i++] = p + 1;
- } // endif sep
-
- num_read++;
- imax = hmax = i;
-
- for (i = 0; i < hmax; i++)
- length[0] = max(length[0], strlen(colname[i]));
-
- } // endif hdr
-
- for (num_read++; num_read <= num_max; num_read++) {
- /*******************************************************************/
- /* Now start the reading process. Read one line. */
- /*******************************************************************/
- if (fgets(buf, sizeof(buf), infile)) {
- n = strlen(buf);
- buf[n - 1] = '\0';
-#if defined(UNIX)
- // The file can be imported from Windows
- if (buf[n - 2] == '\r')
- buf[n - 2] = 0;
-#endif // UNIX
- } else if (feof(infile)) {
- sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1);
- break;
- } else {
- sprintf(g->Message, MSG(ERR_READING_REC), num_read, fn);
- goto err;
- } // endif's
-
- /*******************************************************************/
- /* Make the test for field lengths. */
- /*******************************************************************/
- i = n = phase = blank = digit = dec = 0;
-
- for (p = buf; *p; p++)
- if (*p == sep) {
- if (phase != 1) {
- if (i == MAXCOL - 1) {
- sprintf(g->Message, MSG(TOO_MANY_FIELDS), num_read, fn);
- goto err;
- } // endif i
-
- if (n) {
- len[i] = max(len[i], n);
- type = (digit || (dec && n == 1)) ? TYPE_STRING
- : (dec) ? TYPE_FLOAT : TYPE_INT;
- typ[i] = min(type, typ[i]);
- prc[i] = max((typ[i] == TYPE_FLOAT) ? (dec - 1) : 0, prc[i]);
- } // endif n
-
- i++;
- n = phase = blank = digit = dec = 0;
- } else // phase == 1
- n++;
-
- } else if (*p == ' ') {
- if (phase < 2)
- n++;
-
- if (blank)
- digit = 1;
-
- } else if (*p == q) {
- if (phase == 0) {
- if (blank)
- if (++nerr > mxr) {
- sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
- goto err;
- } else
- goto skip;
-
- n = 0;
- phase = digit = 1;
- } else if (phase == 1) {
- if (*(p+1) == q) {
- // This is currently not implemented for CSV tables
-// if (++nerr > mxr) {
-// sprintf(g->Message, MSG(QUOTE_IN_QUOTE), num_read);
-// goto err;
-// } else
-// goto skip;
-
- p++;
- n++;
- } else
- phase = 2;
-
- } else if (++nerr > mxr) { // phase == 2
- sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
- goto err;
- } else
- goto skip;
-
- } else {
- if (phase == 2)
- if (++nerr > mxr) {
- sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
- goto err;
- } else
- goto skip;
-
- // isdigit cannot be used here because of debug assert
- if (!strchr("0123456789", *p)) {
- if (!digit && *p == dechar)
- dec = 1; // Decimal point found
- else if (blank || !(*p == '-' || *p == '+'))
- digit = 1;
-
- } else if (dec)
- dec++; // More decimals
-
- n++;
- blank = 1;
- } // endif's *p
-
- if (phase == 1)
- if (++nerr > mxr) {
- sprintf(g->Message, MSG(UNBALANCE_QUOTE), num_read);
- goto err;
- } else
- goto skip;
-
- if (n) {
- len[i] = max(len[i], n);
- type = (digit || n == 0 || (dec && n == 1)) ? TYPE_STRING
- : (dec) ? TYPE_FLOAT : TYPE_INT;
- typ[i] = min(type, typ[i]);
- prc[i] = max((typ[i] == TYPE_FLOAT) ? (dec - 1) : 0, prc[i]);
- } // endif n
-
- imax = max(imax, i+1);
- skip: ; // Skip erroneous line
- } // endfor num_read
-
- if (trace) {
- htrc("imax=%d Lengths:", imax);
-
- for (i = 0; i < imax; i++)
- htrc(" %d", len[i]);
-
- htrc("\n");
- } // endif trace
-
- fclose(infile);
-
- if (trace)
- htrc("CSVColumns: imax=%d hmax=%d len=%d\n",
- imax, hmax, length[0]);
-
- /*********************************************************************/
- /* Allocate the structures used to refer to the result set. */
- /*********************************************************************/
- qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3,
- dbtype, buftyp, length);
- qrp->Nblin = imax;
-
- /*********************************************************************/
- /* Now get the results into blocks. */
- /*********************************************************************/
- for (i = 0; i < imax; i++) {
- if (i >= hmax) {
- sprintf(buf, "COL%.3d", i+1);
- p = buf;
- } else
- p = colname[i];
-
- if (typ[i] == TYPE_UNKNOWN) // Void column
- typ[i] = TYPE_STRING;
-
- crp = qrp->Colresp; // Column Name
- crp->Kdata->SetValue(p, i);
- crp = crp->Next; // Data Type
- crp->Kdata->SetValue(typ[i], i);
- crp = crp->Next; // Type Name
- crp->Kdata->SetValue(GetTypeName(typ[i]), i);
- crp = crp->Next; // Precision
- crp->Kdata->SetValue(len[i], i);
- crp = crp->Next; // Length
- crp->Kdata->SetValue(len[i], i);
- crp = crp->Next; // Scale (precision)
- crp->Kdata->SetValue(prc[i], i);
- } // endfor i
-
- /*********************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /*********************************************************************/
- return qrp;
-
- err:
- fclose(infile);
- return NULL;
- } // end of CSVCColumns
-
-/* --------------------------- Class CSVDEF -------------------------- */
-
-/***********************************************************************/
-/* CSVDEF constructor. */
-/***********************************************************************/
-CSVDEF::CSVDEF(void)
- {
- Fmtd = Accept = Header = false;
- Maxerr = 0;
- Quoted = -1;
- Sep = ',';
- Qot = '\0';
- } // end of CSVDEF constructor
-
-/***********************************************************************/
-/* DefineAM: define specific AM block values from XDB file. */
-/***********************************************************************/
-bool CSVDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- char buf[8];
-
- // Double check correctness of offset values
- for (PCOLDEF cdp = To_Cols; cdp; cdp = cdp->GetNext())
- if (cdp->GetOffset() < 1) {
- strcpy(g->Message, MSG(BAD_OFFSET_VAL));
- return true;
- } // endif Offset
-
- // Call DOSDEF DefineAM with am=CSV so FMT is not confused with FIX
- if (DOSDEF::DefineAM(g, "CSV", poff))
- return true;
-
- Cat->GetCharCatInfo(Name, "Separator", ",", buf, sizeof(buf));
- Sep = (strlen(buf) == 2 && buf[0] == '\\' && buf[1] == 't') ? '\t' : *buf;
- Quoted = Cat->GetIntCatInfo(Name, "Quoted", -1);
- Cat->GetCharCatInfo(Name, "Qchar", "", buf, sizeof(buf));
- Qot = *buf;
-
- if (Qot && Quoted < 0)
- Quoted = 0;
- else if (!Qot && Quoted >= 0)
- Qot = '"';
-
- Fmtd = (!Sep || (am && (*am == 'F' || *am == 'f')));
- Header = (Cat->GetIntCatInfo(Name, "Header", 0) != 0);
- Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0);
- Accept = (Cat->GetIntCatInfo(Name, "Accept", 0) != 0);
- return false;
- } // end of DefineAM
-
-/***********************************************************************/
-/* GetTable: makes a new Table Description Block. */
-/***********************************************************************/
-PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode)
- {
- USETEMP tmp = PlgGetUser(g)->UseTemp;
- bool map = Mapped && mode != MODE_INSERT &&
- !(tmp != TMP_NO && mode == MODE_UPDATE) &&
- !(tmp == TMP_FORCE &&
- (mode == MODE_UPDATE || mode == MODE_DELETE));
- PTXF txfp;
- PTDBASE tdbp;
-
- /*********************************************************************/
- /* Allocate a file processing class of the proper type. */
- /*********************************************************************/
- if (map) {
- // Should be now compatible with UNIX
- txfp = new(g) MAPFAM(this);
- } else if (Compressed) {
-#if defined(ZIP_SUPPORT)
- if (Compressed == 1)
- txfp = new(g) ZIPFAM(this);
- 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
- txfp = new(g) DOSFAM(this);
-
- /*********************************************************************/
- /* Allocate a TDB of the proper type. */
- /* Column blocks will be allocated only when needed. */
- /*********************************************************************/
- if (!Fmtd)
- tdbp = new(g) TDBCSV(this, txfp);
- else
- tdbp = new(g) TDBFMT(this, txfp);
-
- if (Multiple)
- tdbp = new(g) TDBMUL(tdbp);
-
- return tdbp;
- } // end of GetTable
-
-/* -------------------------- Class TDBCSV --------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBCSV class. */
-/***********************************************************************/
-TDBCSV::TDBCSV(PCSVDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
- {
-#if defined(_DEBUG)
- assert (tdp);
-#endif
- Field = NULL;
- Offset = NULL;
- Fldlen = NULL;
- Fields = 0;
- Nerr = 0;
- Quoted = tdp->Quoted;
- Maxerr = tdp->Maxerr;
- Accept = tdp->Accept;
- Header = tdp->Header;
- Sep = tdp->GetSep();
- Qot = tdp->GetQot();
- } // end of TDBCSV standard constructor
-
-TDBCSV::TDBCSV(PGLOBAL g, PTDBCSV tdbp) : TDBDOS(g, tdbp)
- {
- Fields = tdbp->Fields;
-
- if (Fields) {
- if (tdbp->Offset)
- Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
-
- if (tdbp->Fldlen)
- Fldlen = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
-
- Field = (PSZ *)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
-
- for (int i = 0; i < Fields; i++) {
- if (Offset)
- Offset[i] = tdbp->Offset[i];
-
- if (Fldlen)
- Fldlen[i] = tdbp->Fldlen[i];
-
- if (Field) {
- assert (Fldlen);
- Field[i] = (PSZ)PlugSubAlloc(g, NULL, Fldlen[i] + 1);
- Field[i][Fldlen[i]] = '\0';
- } // endif Field
-
- } // endfor i
-
- } else {
- Field = NULL;
- Offset = NULL;
- Fldlen = NULL;
- } // endif Fields
-
- Nerr = tdbp->Nerr;
- Maxerr = tdbp->Maxerr;
- Quoted = tdbp->Quoted;
- Accept = tdbp->Accept;
- Header = tdbp->Header;
- Sep = tdbp->Sep;
- Qot = tdbp->Qot;
- } // end of TDBCSV copy constructor
-
-// Method
-PTDB TDBCSV::CopyOne(PTABS t)
- {
- PTDB tp;
- PCSVCOL cp1, cp2;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBCSV(g, this);
-
- for (cp1 = (PCSVCOL)Columns; cp1; cp1 = (PCSVCOL)cp1->GetNext()) {
- cp2 = new(g) CSVCOL(cp1, tp); // Make a copy
- NewPointer(t, cp1, cp2);
- } // endfor cp1
-
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Allocate CSV column description block. */
-/***********************************************************************/
-PCOL TDBCSV::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- return new(g) CSVCOL(g, cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* Check whether the number of errors is greater than the maximum. */
-/***********************************************************************/
-bool TDBCSV::CheckErr(void)
- {
- return (++Nerr) > Maxerr;
- } // end of CheckErr
-
-/***********************************************************************/
-/* CSV EstimatedLength. Returns an estimated minimum line length. */
-/***********************************************************************/
-int TDBCSV::EstimatedLength(PGLOBAL g)
- {
- if (trace)
- htrc("EstimatedLength: Fields=%d Columns=%p\n", Fields, Columns);
-
- if (!Fields) {
- PCSVCOL colp;
-
- for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
- if (!colp->IsSpecial()) // Not a pseudo column
- Fields = max(Fields, (int)colp->Fldnum);
-
- if (Columns)
- Fields++; // Fldnum was 0 based
-
- } // endif Fields
-
- return (int)Fields; // Number of separators if all fields are null
- } // end of Estimated Length
-
-#if 0
-/***********************************************************************/
-/* CSV tables favor the use temporary files for Update. */
-/***********************************************************************/
-bool TDBCSV::IsUsingTemp(PGLOBAL g)
- {
- USETEMP usetemp = PlgGetUser(g)->UseTemp;
-
- return (usetemp == TMP_YES || usetemp == TMP_FORCE ||
- (usetemp == TMP_AUTO && Mode == MODE_UPDATE));
- } // end of IsUsingTemp
-#endif // 0 (Same as TDBDOS one)
-
-/***********************************************************************/
-/* CSV Access Method opening routine. */
-/* First allocate the Offset and Fldlen arrays according to the */
-/* greatest field used in that query. Then call the DOS opening fnc. */
-/***********************************************************************/
-bool TDBCSV::OpenDB(PGLOBAL g)
- {
- bool rc = false;
- PCOLDEF cdp;
- PDOSDEF tdp = (PDOSDEF)To_Def;
-
- if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) {
- // Allocate the storage used to read (or write) records
- int i, len;
- PCSVCOL colp;
-
- if (!Fields) // May have been set in TABFMT::OpenDB
- if (Mode != MODE_UPDATE && Mode != MODE_INSERT) {
- for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
- if (!colp->IsSpecial()) // Not a pseudo column
- Fields = max(Fields, (int)colp->Fldnum);
-
- if (Columns)
- Fields++; // Fldnum was 0 based
-
- } else
- for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
- Fields++;
-
- Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
- Fldlen = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
-
- if (Mode == MODE_INSERT || Mode == MODE_UPDATE) {
- Field = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
- Fldtyp = (bool*)PlugSubAlloc(g, NULL, sizeof(bool) * Fields);
- } // endif Mode
-
- for (i = 0; i < Fields; i++) {
- Offset[i] = 0;
- Fldlen[i] = 0;
-
- if (Field) {
- Field[i] = NULL;
- Fldtyp[i] = false;
- } // endif Field
-
- } // endfor i
-
- if (Field)
- // Prepare writing fields
- if (Mode != MODE_UPDATE)
- for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next) {
- i = colp->Fldnum;
- len = colp->GetLength();
- Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1);
- Field[i][len] = '\0';
- Fldlen[i] = len;
- Fldtyp[i] = IsTypeNum(colp->GetResultType());
- } // endfor colp
-
- else // MODE_UPDATE
- for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) {
- i = cdp->GetOffset() - 1;
- len = cdp->GetLength();
- Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1);
- Field[i][len] = '\0';
- Fldlen[i] = len;
- Fldtyp[i] = IsTypeNum(cdp->GetType());
- } // endfor colp
-
- } // endif Use
-
- if (Header) {
- // Check that the Lrecl is at least equal to the header line length
- int headlen = 0;
- PCOLDEF cdp;
- PDOSDEF tdp = (PDOSDEF)To_Def;
-
- for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
- headlen += strlen(cdp->GetName()) + 3; // 3 if names are quoted
-
- if (headlen > Lrecl) {
- Lrecl = headlen;
- Txfp->Lrecl = headlen;
- } // endif headlen
-
- } // endif Header
-
- Nerr = 0;
- rc = TDBDOS::OpenDB(g);
-
- if (!rc && Mode == MODE_UPDATE && To_Kindex)
- // Because KINDEX::Init is executed in mode READ, we must restore
- // the Fldlen array that was modified when reading the table file.
- for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
- Fldlen[cdp->GetOffset() - 1] = cdp->GetLength();
-
- return rc;
- } // end of OpenDB
-
-/***********************************************************************/
-/* SkipHeader: Physically skip first header line if applicable. */
-/* This is called from TDBDOS::OpenDB and must be executed before */
-/* Kindex construction if the file is accessed using an index. */
-/***********************************************************************/
-bool TDBCSV::SkipHeader(PGLOBAL g)
- {
- int len = GetFileLength(g);
- bool rc = false;
-
-#if defined(_DEBUG)
- if (len < 0)
- return true;
-#endif // _DEBUG
-
- if (Header) {
- if (Mode == MODE_INSERT) {
- if (!len) {
- // New file, the header line must be constructed and written
- int i, n = 0;
- int hlen = 0;
- bool q = Qot && Quoted > 0;
- PCOLDEF cdp;
-
- // Estimate the length of the header list
- for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
- hlen += (1 + strlen(cdp->GetName()));
- hlen += ((q) ? 2 : 0);
- n++; // Calculate the number of columns
- } // endfor cdp
-
- if (hlen > Lrecl) {
- sprintf(g->Message, MSG(LRECL_TOO_SMALL), hlen);
- return true;
- } // endif hlen
-
- // File is empty, write a header record
- memset(To_Line, 0, Lrecl);
-
- // The column order in the file is given by the offset value
- for (i = 1; i <= n; i++)
- for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
- if (cdp->GetOffset() == i) {
- if (q)
- To_Line[strlen(To_Line)] = Qot;
-
- strcat(To_Line, cdp->GetName());
-
- if (q)
- To_Line[strlen(To_Line)] = Qot;
-
- if (i < n)
- To_Line[strlen(To_Line)] = Sep;
-
- } // endif Offset
-
- rc = (Txfp->WriteBuffer(g) == RC_FX);
- } // endif !FileLength
-
- } else if (Mode == MODE_DELETE) {
- if (len)
- rc = (Txfp->SkipRecord(g, true) == RC_FX);
-
- } else if (len) // !Insert && !Delete
- rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g));
-
- } // endif Header
-
- return rc;
- } // end of SkipHeader
-
-/***********************************************************************/
-/* ReadBuffer: Physical read routine for the CSV access method. */
-/***********************************************************************/
-int TDBCSV::ReadBuffer(PGLOBAL g)
- {
- char *p1, *p2, *p = NULL;
- int i, n, len, rc = Txfp->ReadBuffer(g);
- bool bad = false;
-
- if (trace > 1)
- htrc("CSV: Row is '%s' rc=%d\n", To_Line, rc);
-
- if (rc != RC_OK || !Fields)
- return rc;
- else
- p2 = To_Line;
-
- // Find the offsets and lengths of the columns for this row
- for (i = 0; i < Fields; i++) {
- if (!bad) {
- if (Qot && *p2 == Qot) { // Quoted field
- for (n = 0, p1 = ++p2; (p = strchr(p1, Qot)); p1 = p + 2)
- if (*(p + 1) == Qot)
- n++; // Doubled internal quotes
- else
- break; // Final quote
-
- if (p) {
- len = p++ - p2;
-
-// if (Sep != ' ')
-// for (; *p == ' '; p++) ; // Skip blanks
-
- if (*p != Sep && i != Fields - 1) { // Should be the separator
- if (CheckErr()) {
- sprintf(g->Message, MSG(MISSING_FIELD),
- i+1, Name, RowNumber(g));
- return RC_FX;
- } else if (Accept)
- bad = true;
- else
- return RC_NF;
-
- } // endif p
-
- if (n) {
- int j, k;
-
- // Suppress the double of internal quotes
- for (j = k = 0; j < len; j++, k++) {
- if (p2[j] == Qot)
- j++; // skip first one
-
- p2[k] = p2[j];
- } // endfor i, j
-
- len -= n;
- } // endif n
-
- } else if (CheckErr()) {
- sprintf(g->Message, MSG(BAD_QUOTE_FIELD),
- Name, i+1, RowNumber(g));
- return RC_FX;
- } else if (Accept) {
- len = strlen(p2);
- bad = true;
- } else
- return RC_NF;
-
- } else if ((p = strchr(p2, Sep)))
- len = p - p2;
- else if (i == Fields - 1)
- len = strlen(p2);
- else if (Accept && Maxerr == 0) {
- len = strlen(p2);
- bad = true;
- } else if (CheckErr()) {
- sprintf(g->Message, MSG(MISSING_FIELD), i+1, Name, RowNumber(g));
- return RC_FX;
- } else if (Accept) {
- len = strlen(p2);
- bad = true;
- } else
- return RC_NF;
-
- } else
- len = 0;
-
- Offset[i] = p2 - To_Line;
-
- if (Mode != MODE_UPDATE)
- Fldlen[i] = len;
- else if (len > Fldlen[i]) {
- sprintf(g->Message, MSG(FIELD_TOO_LONG), i+1, RowNumber(g));
- return RC_FX;
- } else {
- strncpy(Field[i], p2, len);
- Field[i][len] = '\0';
- } // endif Mode
-
- if (p)
- p2 = p + 1;
-
- } // endfor i
-
- return rc;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* Data Base write routine CSV file access method. */
-/***********************************************************************/
-int TDBCSV::WriteDB(PGLOBAL g)
- {
- char sep[2], qot[2];
- int i, nlen, oldlen = strlen(To_Line);
-
- if (trace > 1)
- htrc("CSV WriteDB: R%d Mode=%d key=%p link=%p\n",
- Tdb_No, Mode, To_Key_Col, To_Link);
-
- // Before writing the line we must check its length
- if ((nlen = CheckWrite(g)) < 0)
- return RC_FX;
-
- // Before writing the line we must make it
- sep[0] = Sep;
- sep[1] = '\0';
- qot[0] = Qot;
- qot[1] = '\0';
- *To_Line = '\0';
-
- for (i = 0; i < Fields; i++) {
- if (i)
- strcat(To_Line, sep);
-
- if (Field[i])
- if (!strlen(Field[i])) {
- // Generally null fields are not quoted
- if (Quoted > 2)
- // Except if explicitely required
- strcat(strcat(To_Line, qot), qot);
-
- } else if (Qot && (strchr(Field[i], Sep) || *Field[i] == Qot
- || Quoted > 1 || (Quoted == 1 && !Fldtyp[i])))
- if (strchr(Field[i], Qot)) {
- // Field contains quotes that must be doubled
- int j, k = strlen(To_Line), n = strlen(Field[i]);
-
- To_Line[k++] = Qot;
-
- for (j = 0; j < n; j++) {
- if (Field[i][j] == Qot)
- To_Line[k++] = Qot;
-
- To_Line[k++] = Field[i][j];
- } // endfor j
-
- To_Line[k++] = Qot;
- To_Line[k] = '\0';
- } else
- strcat(strcat(strcat(To_Line, qot), Field[i]), qot);
-
- else
- strcat(To_Line, Field[i]);
-
- } // endfor i
-
-#if defined(_DEBUG)
- assert ((unsigned)nlen == strlen(To_Line));
-#endif
-
- if (Mode == MODE_UPDATE && nlen < oldlen
- && !((PDOSFAM)Txfp)->GetUseTemp()) {
- // In Update mode with no temp file, line length must not change
- To_Line[nlen] = Sep;
-
- for (nlen++; nlen < oldlen; nlen++)
- To_Line[nlen] = ' ';
-
- To_Line[nlen] = '\0';
- } // endif
-
- if (trace > 1)
- htrc("Write: line is=%s", To_Line);
-
- /*********************************************************************/
- /* Now start the writing process. */
- /*********************************************************************/
- return Txfp->WriteBuffer(g);
- } // end of WriteDB
-
-/***********************************************************************/
-/* Check whether a new line fit in the file lrecl size. */
-/***********************************************************************/
-int TDBCSV::CheckWrite(PGLOBAL g)
- {
- int maxlen, n, nlen = (Fields - 1);
-
- if (trace > 1)
- htrc("CheckWrite: R%d Mode=%d\n", Tdb_No, Mode);
-
- // Before writing the line we must check its length
- maxlen = (Mode == MODE_UPDATE && !Txfp->GetUseTemp())
- ? strlen(To_Line) : Lrecl;
-
- // Check whether record is too int
- for (int i = 0; i < Fields; i++)
- if (Field[i]) {
- if (!(n = strlen(Field[i])))
- n += (Quoted > 2 ? 2 : 0);
- else if (strchr(Field[i], Sep) || (Qot && *Field[i] == Qot)
- || Quoted > 1 || (Quoted == 1 && !Fldtyp[i]))
- if (!Qot) {
- sprintf(g->Message, MSG(SEP_IN_FIELD), i + 1);
- return -1;
- } else {
- // Quotes inside a quoted field must be doubled
- char *p1, *p2;
-
- for (p1 = Field[i]; (p2 = strchr(p1, Qot)); p1 = p2 + 1)
- n++;
-
- n += 2; // Outside quotes
- } // endif
-
- if ((nlen += n) > maxlen) {
- strcpy(g->Message, MSG(LINE_TOO_LONG));
- return -1;
- } // endif nlen
-
- } // endif Field
-
- return nlen;
- } // end of CheckWrite
-
-/* ------------------------------------------------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBFMT class. */
-/***********************************************************************/
-TDBFMT::TDBFMT(PGLOBAL g, PTDBFMT tdbp) : TDBCSV(g, tdbp)
- {
- FldFormat = tdbp->FldFormat;
- To_Fld = tdbp->To_Fld;
- FmtTest = tdbp->FmtTest;
- Linenum = tdbp->Linenum;
- } // end of TDBFMT copy constructor
-
-// Method
-PTDB TDBFMT::CopyOne(PTABS t)
- {
- PTDB tp;
- PCSVCOL cp1, cp2;
-//PFMTCOL cp1, cp2;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBFMT(g, this);
-
- for (cp1 = (PCSVCOL)Columns; cp1; cp1 = (PCSVCOL)cp1->GetNext()) {
-//for (cp1 = (PFMTCOL)Columns; cp1; cp1 = (PFMTCOL)cp1->GetNext()) {
- cp2 = new(g) CSVCOL(cp1, tp); // Make a copy
-// cp2 = new(g) FMTCOL(cp1, tp); // Make a copy
- NewPointer(t, cp1, cp2);
- } // endfor cp1
-
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Allocate FMT column description block. */
-/***********************************************************************/
-PCOL TDBFMT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- return new(g) CSVCOL(g, cdp, this, cprec, n);
-//return new(g) FMTCOL(cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* FMT EstimatedLength. Returns an estimated minimum line length. */
-/* The big problem here is how can we astimated that minimum ? */
-/***********************************************************************/
-int TDBFMT::EstimatedLength(PGLOBAL g)
- {
- // This is rather stupid !!!
- return ((PDOSDEF)To_Def)->GetEnding() + (int)((Lrecl / 10) + 1);
- } // end of EstimatedLength
-
-/***********************************************************************/
-/* FMT Access Method opening routine. */
-/***********************************************************************/
-bool TDBFMT::OpenDB(PGLOBAL g)
- {
- Linenum = 0;
-
- if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) {
- // Make the formats used to read records
- PSZ pfm;
- int i, n;
- PCSVCOL colp;
- PCOLDEF cdp;
- PDOSDEF tdp = (PDOSDEF)To_Def;
-
-// if (Mode != MODE_UPDATE) {
- for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
- if (!colp->IsSpecial()) // Not a pseudo column
- Fields = max(Fields, (int)colp->Fldnum);
-
- if (Columns)
- Fields++; // Fldnum was 0 based
-
-// } else
-// for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
-// Fields++;
-
- To_Fld = PlugSubAlloc(g, NULL, Lrecl + 1);
- FldFormat = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
- memset(FldFormat, 0, sizeof(PSZ) * Fields);
- FmtTest = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
- memset(FmtTest, 0, sizeof(int) * Fields);
-
- // Get the column formats
- for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
- if ((i = cdp->GetOffset() - 1) < Fields) {
- if (!(pfm = cdp->GetFmt())) {
- sprintf(g->Message, MSG(NO_FLD_FORMAT), i + 1, Name);
- return true;
- } // endif pfm
-
- // Roughly check the Fmt format
- if ((n = strlen(pfm) - 2) < 4) {
- sprintf(g->Message, MSG(BAD_FLD_FORMAT), i + 1, Name);
- return true;
- } // endif n
-
- FldFormat[i] = (PSZ)PlugSubAlloc(g, NULL, n + 5);
- strcpy(FldFormat[i], pfm);
-
- if (!strcmp(pfm + n, "%m")) {
- // This is a field that can be missing. Flag it so it can
- // be handled with special processing.
- FldFormat[i][n+1] = 'n'; // To have sscanf normal processing
- FmtTest[i] = 2;
- } else if (i+1 < Fields && strcmp(pfm + n, "%n")) {
- // There are trailing characters after the field contents
- // add a marker for the next field start position.
- strcat(FldFormat[i], "%n");
- FmtTest[i] = 1;
- } // endif's
-
- } // endif i
-
- } // endif Use
-
- return TDBCSV::OpenDB(g);
- } // end of OpenDB
-
-/***********************************************************************/
-/* ReadBuffer: Physical read routine for the FMT access method. */
-/***********************************************************************/
-int TDBFMT::ReadBuffer(PGLOBAL g)
- {
- int i, len, n, deb, fin, nwp, pos = 0, rc;
- bool bad = false;
-
- if ((rc = Txfp->ReadBuffer(g)) != RC_OK || !Fields)
- return rc;
- else
- ++Linenum;
-
- if (trace > 1)
- htrc("FMT: Row %d is '%s' rc=%d\n", Linenum, To_Line, rc);
-
- // Find the offsets and lengths of the columns for this row
- for (i = 0; i < Fields; i++) {
- if (!bad) {
- deb = fin = -1;
-
- if (!FldFormat[i]) {
- n = 0;
- } else if (FmtTest[i] == 1) {
- nwp = -1;
- n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin, &nwp);
- } else {
- n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin);
-
- if (n != 1 && (deb >= 0 || i == Fields - 1) && FmtTest[i] == 2) {
- // Missing optional field, not an error
- n = 1;
-
- if (i == Fields - 1)
- fin = deb = 0;
- else
- fin = deb;
-
- } // endif n
-
- nwp = fin;
- } // endif i
-
- if (n != 1 || deb < 0 || fin < 0 || nwp < 0) {
- // This is to avoid a very strange sscanf bug occuring
- // with fields that ends with a null character.
- // This bug causes subsequent sscanf to return in error,
- // so next lines are not parsed correctly.
- sscanf("a", "%*c"); // Seems to reset things Ok
-
- if (CheckErr()) {
- sprintf(g->Message, MSG(BAD_LINEFLD_FMT), Linenum, i + 1, Name);
- return RC_FX;
- } else if (Accept)
- bad = true;
- else
- return RC_NF;
-
- } // endif n...
-
- } // endif !bad
-
- if (!bad) {
- Offset[i] = pos + deb;
- len = fin - deb;
- } else {
- nwp = 0;
- Offset[i] = pos;
- len = 0;
- } // endif bad
-
-// if (Mode != MODE_UPDATE)
- Fldlen[i] = len;
-// else if (len > Fldlen[i]) {
-// sprintf(g->Message, MSG(FIELD_TOO_LONG), i+1, To_Tdb->RowNumber(g));
-// return RC_FX;
-// } else {
-// strncpy(Field[i], To_Line + pos, len);
-// Field[i][len] = '\0';
-// } // endif Mode
-
- pos += nwp;
- } // endfor i
-
- if (bad)
- Nerr++;
- else
- sscanf("a", "%*c"); // Seems to reset things Ok
-
- return rc;
- } // end of ReadBuffer
-
-/***********************************************************************/
-/* Data Base write routine FMT file access method. */
-/***********************************************************************/
-int TDBFMT::WriteDB(PGLOBAL g)
- {
- sprintf(g->Message, MSG(FMT_WRITE_NIY), "FMT");
- return RC_FX; // NIY
- } // end of WriteDB
-
-// ------------------------ CSVCOL functions ----------------------------
-
-/***********************************************************************/
-/* CSVCOL public constructor */
-/***********************************************************************/
-CSVCOL::CSVCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
- : DOSCOL(g, cdp, tdbp, cprec, i, "CSV")
- {
- Fldnum = Deplac - 1;
- Deplac = 0;
- } // end of CSVCOL constructor
-
-/***********************************************************************/
-/* CSVCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-CSVCOL::CSVCOL(CSVCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
- {
- Fldnum = col1->Fldnum;
- } // end of CSVCOL copy constructor
-
-/***********************************************************************/
-/* VarSize: This function tells UpdateDB whether or not the block */
-/* optimization file must be redone if this column is updated, even */
-/* it is not sorted or clustered. This applies to a blocked table, */
-/* because if it is updated using a temporary file, the block size */
-/* may be modified. */
-/***********************************************************************/
-bool CSVCOL::VarSize(void)
- {
- PTXF txfp = ((PTDBCSV)To_Tdb)->Txfp;
-
- if (txfp->IsBlocked() && txfp->GetUseTemp())
- // Blocked table using a temporary file
- return true;
- else
- return false;
-
- } // end VarSize
-
-/***********************************************************************/
-/* ReadColumn: call DOSCOL::ReadColumn after having set the offet */
-/* and length of the field to read as calculated by TDBCSV::ReadDB. */
-/***********************************************************************/
-void CSVCOL::ReadColumn(PGLOBAL g)
- {
- int rc;
- PTDBCSV tdbp = (PTDBCSV)To_Tdb;
-
- /*********************************************************************/
- /* 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], 34);
- } // endif
-
- if (tdbp->Mode != MODE_UPDATE) {
- int colen = Long; // Column length
-
- // Set the field offset and length for this row
- Deplac = tdbp->Offset[Fldnum]; // Field offset
- Long = tdbp->Fldlen[Fldnum]; // Field length
-
- if (trace > 1)
- htrc("CSV ReadColumn %s Fldnum=%d offset=%d fldlen=%d\n",
- Name, Fldnum, Deplac, Long);
-
- if (Long > colen && tdbp->CheckErr()) {
- Long = colen; // Restore column length
- sprintf(g->Message, MSG(FLD_TOO_LNG_FOR),
- Fldnum + 1, Name, To_Tdb->RowNumber(g), tdbp->GetFile(g));
- longjmp(g->jumper[g->jump_level], 34);
- } // endif Long
-
- // Now do the reading
- DOSCOL::ReadColumn(g);
-
- // Restore column length
- Long = colen;
- } else { // Mode Update
- // Field have been copied in TDB Field array
- PSZ fp = tdbp->Field[Fldnum];
-
- Value->SetValue_psz(fp);
- } // endif Mode
-
- } // end of ReadColumn
-
-/***********************************************************************/
-/* WriteColumn: The column is written in TDBCSV matching Field. */
-/***********************************************************************/
-void CSVCOL::WriteColumn(PGLOBAL g)
- {
- char *p, buf[32];
- int flen;
- PTDBCSV tdbp = (PTDBCSV)To_Tdb;
-
- if (trace > 1)
- htrc("CSV WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
- Name, tdbp->GetTdb_No(), ColUse, Status);
-
- flen = GetLength();
-
- if (trace > 1)
- htrc("Lrecl=%d Long=%d field=%d coltype=%d colval=%p\n",
- tdbp->Lrecl, Long, flen, Buf_Type, Value);
-
- /*********************************************************************/
- /* 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
-
- /*********************************************************************/
- /* Get the string representation of the column value. */
- /*********************************************************************/
- p = Value->ShowValue(buf);
-
- if (trace > 1)
- htrc("new length(%p)=%d\n", p, strlen(p));
-
- if ((signed)strlen(p) > flen) {
- sprintf(g->Message, MSG(BAD_FLD_LENGTH), Name, p, flen);
- longjmp(g->jumper[g->jump_level], 34);
- } // endif
-
- if (trace > 1)
- htrc("buffer=%s\n", p);
-
- /*********************************************************************/
- /* Updating must be done also during the first pass so writing the */
- /* updated record can be checked for acceptable record length. */
- /*********************************************************************/
- if (Fldnum < 0) {
- // This can happen for wrong offset value in XDB files
- sprintf(g->Message, MSG(BAD_FIELD_RANK), Fldnum + 1, Name);
- longjmp(g->jumper[g->jump_level], 34);
- } else
- strncpy(tdbp->Field[Fldnum], p, flen);
-
- if (trace > 1)
- htrc(" col written: '%s'\n", p);
-
- } // end of WriteColumn
-
-/* ------------------------ End of TabFmt ---------------------------- */
+/************* TabFmt C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABFMT */
+/* ------------- */
+/* Version 3.7 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2001 - 2013 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TABFMT classes DB execution routines. */
+/* The base class CSV is comma separated files. */
+/* FMT (Formatted) files are those having a complex internal record */
+/* format described in the Format keyword of their definition. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+
+#if defined(WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <locale.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#include "osutil.h"
+#else
+#if defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#include "osutil.h"
+#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 "filamap.h"
+#if defined(ZIP_SUPPORT)
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+#include "tabfmt.h"
+#include "tabmul.h"
+#define NO_FUNC
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+
+/***********************************************************************/
+/* This should be an option. */
+/***********************************************************************/
+#define MAXCOL 200 /* Default max column nb in result */
+#define TYPE_UNKNOWN 10 /* Must be greater than other types */
+
+extern "C" int trace;
+
+/***********************************************************************/
+/* CSV Catalog utility functions. */
+/***********************************************************************/
+PQRYRES PlgAllocResult(PGLOBAL, int, int, int, int *, int *,
+ unsigned int *, bool blank = true, bool nonull = false);
+
+/***********************************************************************/
+/* CSVColumns: constructs the result blocks containing the description */
+/* of all the columns of a CSV file that will be retrieved by #GetData.*/
+/* Note: the algorithm to set the type is based on the internal values */
+/* of types (TYPE_STRING < TYPE_FLOAT < TYPE_INT) (1 < 2 < 7). */
+/* If these values are changed, this will have to be revisited. */
+/***********************************************************************/
+PQRYRES CSVColumns(PGLOBAL g, char *fn, char sep, char q, int hdr, int mxr)
+ {
+ 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[] = {6, 6, 8, 10, 10, 6};
+ char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096];
+ int i, imax, hmax, n, nerr, phase, blank, digit, dec, type;
+ int ncol = sizeof(dbtype) / sizeof(int);
+ int num_read = 0, num_max = 10000000; // Statistics
+ int len[MAXCOL], typ[MAXCOL], prc[MAXCOL];
+ FILE *infile;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+// num_max = atoi(p+1); // Max num of record to test
+#if defined(WIN32)
+ if (strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6))
+ dechar = '.';
+ else
+ dechar = ',';
+#else // !WIN32
+ dechar = '.';
+#endif // !WIN32
+
+ if (trace)
+ htrc("File %s sep=%c q=%c hdr=%d mxr=%d\n",
+ SVP(fn), sep, q, hdr, mxr);
+
+ if (!fn) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return NULL;
+ } // endif fn
+
+ imax = hmax = nerr = 0;
+ mxr = max(0, mxr);
+
+ for (i = 0; i < MAXCOL; i++) {
+ colname[i] = NULL;
+ len[i] = 0;
+ typ[i] = TYPE_UNKNOWN;
+ prc[i] = 0;
+ } // endfor i
+
+ /*********************************************************************/
+ /* Open the input file. */
+ /*********************************************************************/
+ PlugSetPath(filename, fn, PlgGetDataPath(g));
+
+ if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r")))
+ return NULL;
+
+ if (hdr) {
+ /*******************************************************************/
+ /* Make the column names from the first line. */
+ /*******************************************************************/
+ phase = 0;
+
+ if (fgets(buf, sizeof(buf), infile)) {
+ n = strlen(buf) + 1;
+ buf[n - 2] = '\0';
+#if defined(UNIX)
+ // The file can be imported from Windows
+ if (buf[n - 3] == '\r')
+ buf[n - 3] = 0;
+#endif // UNIX
+ p = (char*)PlugSubAlloc(g, NULL, n);
+ memcpy(p, buf, n);
+
+ //skip leading blanks
+ for (; *p == ' '; p++) ;
+
+ if (q && *p == q) {
+ // Header is quoted
+ p++;
+ phase = 1;
+ } // endif q
+
+ colname[0] = p;
+ } else {
+ sprintf(g->Message, MSG(FILE_IS_EMPTY), fn);
+ goto err;
+ } // endif's
+
+ for (i = 1; *p; p++)
+ if (phase == 1 && *p == q) {
+ *p = '\0';
+ phase = 0;
+ } else if (*p == sep && !phase) {
+ *p = '\0';
+
+ //skip leading blanks
+ for (; *(p+1) == ' '; p++) ;
+
+ if (q && *(p+1) == q) {
+ // Header is quoted
+ p++;
+ phase = 1;
+ } // endif q
+
+ colname[i++] = p + 1;
+ } // endif sep
+
+ num_read++;
+ imax = hmax = i;
+
+ for (i = 0; i < hmax; i++)
+ length[0] = max(length[0], strlen(colname[i]));
+
+ } // endif hdr
+
+ for (num_read++; num_read <= num_max; num_read++) {
+ /*******************************************************************/
+ /* Now start the reading process. Read one line. */
+ /*******************************************************************/
+ if (fgets(buf, sizeof(buf), infile)) {
+ n = strlen(buf);
+ buf[n - 1] = '\0';
+#if defined(UNIX)
+ // The file can be imported from Windows
+ if (buf[n - 2] == '\r')
+ buf[n - 2] = 0;
+#endif // UNIX
+ } else if (feof(infile)) {
+ sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1);
+ break;
+ } else {
+ sprintf(g->Message, MSG(ERR_READING_REC), num_read, fn);
+ goto err;
+ } // endif's
+
+ /*******************************************************************/
+ /* Make the test for field lengths. */
+ /*******************************************************************/
+ i = n = phase = blank = digit = dec = 0;
+
+ for (p = buf; *p; p++)
+ if (*p == sep) {
+ if (phase != 1) {
+ if (i == MAXCOL - 1) {
+ sprintf(g->Message, MSG(TOO_MANY_FIELDS), num_read, fn);
+ goto err;
+ } // endif i
+
+ if (n) {
+ len[i] = max(len[i], n);
+ type = (digit || (dec && n == 1)) ? TYPE_STRING
+ : (dec) ? TYPE_FLOAT : TYPE_INT;
+ typ[i] = min(type, typ[i]);
+ prc[i] = max((typ[i] == TYPE_FLOAT) ? (dec - 1) : 0, prc[i]);
+ } // endif n
+
+ i++;
+ n = phase = blank = digit = dec = 0;
+ } else // phase == 1
+ n++;
+
+ } else if (*p == ' ') {
+ if (phase < 2)
+ n++;
+
+ if (blank)
+ digit = 1;
+
+ } else if (*p == q) {
+ if (phase == 0) {
+ if (blank)
+ if (++nerr > mxr) {
+ sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+
+ n = 0;
+ phase = digit = 1;
+ } else if (phase == 1) {
+ if (*(p+1) == q) {
+ // This is currently not implemented for CSV tables
+// if (++nerr > mxr) {
+// sprintf(g->Message, MSG(QUOTE_IN_QUOTE), num_read);
+// goto err;
+// } else
+// goto skip;
+
+ p++;
+ n++;
+ } else
+ phase = 2;
+
+ } else if (++nerr > mxr) { // phase == 2
+ sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+
+ } else {
+ if (phase == 2)
+ if (++nerr > mxr) {
+ sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+
+ // isdigit cannot be used here because of debug assert
+ if (!strchr("0123456789", *p)) {
+ if (!digit && *p == dechar)
+ dec = 1; // Decimal point found
+ else if (blank || !(*p == '-' || *p == '+'))
+ digit = 1;
+
+ } else if (dec)
+ dec++; // More decimals
+
+ n++;
+ blank = 1;
+ } // endif's *p
+
+ if (phase == 1)
+ if (++nerr > mxr) {
+ sprintf(g->Message, MSG(UNBALANCE_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+
+ if (n) {
+ len[i] = max(len[i], n);
+ type = (digit || n == 0 || (dec && n == 1)) ? TYPE_STRING
+ : (dec) ? TYPE_FLOAT : TYPE_INT;
+ typ[i] = min(type, typ[i]);
+ prc[i] = max((typ[i] == TYPE_FLOAT) ? (dec - 1) : 0, prc[i]);
+ } // endif n
+
+ imax = max(imax, i+1);
+ skip: ; // Skip erroneous line
+ } // endfor num_read
+
+ if (trace) {
+ htrc("imax=%d Lengths:", imax);
+
+ for (i = 0; i < imax; i++)
+ htrc(" %d", len[i]);
+
+ htrc("\n");
+ } // endif trace
+
+ fclose(infile);
+
+ if (trace)
+ htrc("CSVColumns: imax=%d hmax=%d len=%d\n",
+ imax, hmax, length[0]);
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3,
+ dbtype, buftyp, length);
+ qrp->Nblin = imax;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ for (i = 0; i < imax; i++) {
+ if (i >= hmax) {
+ sprintf(buf, "COL%.3d", i+1);
+ p = buf;
+ } else
+ p = colname[i];
+
+ if (typ[i] == TYPE_UNKNOWN) // Void column
+ typ[i] = TYPE_STRING;
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(p, i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(typ[i], i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(typ[i]), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(len[i], i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(len[i], i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(prc[i], i);
+ } // endfor i
+
+ /*********************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /*********************************************************************/
+ return qrp;
+
+ err:
+ fclose(infile);
+ return NULL;
+ } // end of CSVCColumns
+
+/* --------------------------- Class CSVDEF -------------------------- */
+
+/***********************************************************************/
+/* CSVDEF constructor. */
+/***********************************************************************/
+CSVDEF::CSVDEF(void)
+ {
+ Fmtd = Accept = Header = false;
+ Maxerr = 0;
+ Quoted = -1;
+ Sep = ',';
+ Qot = '\0';
+ } // end of CSVDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool CSVDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ char buf[8];
+
+ // Double check correctness of offset values
+ for (PCOLDEF cdp = To_Cols; cdp; cdp = cdp->GetNext())
+ if (cdp->GetOffset() < 1) {
+ strcpy(g->Message, MSG(BAD_OFFSET_VAL));
+ return true;
+ } // endif Offset
+
+ // Call DOSDEF DefineAM with am=CSV so FMT is not confused with FIX
+ if (DOSDEF::DefineAM(g, "CSV", poff))
+ return true;
+
+ Cat->GetCharCatInfo(Name, "Separator", ",", buf, sizeof(buf));
+ Sep = (strlen(buf) == 2 && buf[0] == '\\' && buf[1] == 't') ? '\t' : *buf;
+ Quoted = Cat->GetIntCatInfo(Name, "Quoted", -1);
+ Cat->GetCharCatInfo(Name, "Qchar", "", buf, sizeof(buf));
+ Qot = *buf;
+
+ if (Qot && Quoted < 0)
+ Quoted = 0;
+ else if (!Qot && Quoted >= 0)
+ Qot = '"';
+
+ Fmtd = (!Sep || (am && (*am == 'F' || *am == 'f')));
+ Header = (Cat->GetIntCatInfo(Name, "Header", 0) != 0);
+ Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0);
+ Accept = (Cat->GetIntCatInfo(Name, "Accept", 0) != 0);
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode)
+ {
+ USETEMP tmp = PlgGetUser(g)->UseTemp;
+ bool map = Mapped && mode != MODE_INSERT &&
+ !(tmp != TMP_NO && mode == MODE_UPDATE) &&
+ !(tmp == TMP_FORCE &&
+ (mode == MODE_UPDATE || mode == MODE_DELETE));
+ PTXF txfp;
+ PTDBASE tdbp;
+
+ /*********************************************************************/
+ /* Allocate a file processing class of the proper type. */
+ /*********************************************************************/
+ if (map) {
+ // Should be now compatible with UNIX
+ txfp = new(g) MAPFAM(this);
+ } else if (Compressed) {
+#if defined(ZIP_SUPPORT)
+ if (Compressed == 1)
+ txfp = new(g) ZIPFAM(this);
+ 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
+ txfp = new(g) DOSFAM(this);
+
+ /*********************************************************************/
+ /* Allocate a TDB of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ if (!Fmtd)
+ tdbp = new(g) TDBCSV(this, txfp);
+ else
+ tdbp = new(g) TDBFMT(this, txfp);
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+
+ return tdbp;
+ } // end of GetTable
+
+/* -------------------------- Class TDBCSV --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBCSV class. */
+/***********************************************************************/
+TDBCSV::TDBCSV(PCSVDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
+ {
+#if defined(_DEBUG)
+ assert (tdp);
+#endif
+ Field = NULL;
+ Offset = NULL;
+ Fldlen = NULL;
+ Fields = 0;
+ Nerr = 0;
+ Quoted = tdp->Quoted;
+ Maxerr = tdp->Maxerr;
+ Accept = tdp->Accept;
+ Header = tdp->Header;
+ Sep = tdp->GetSep();
+ Qot = tdp->GetQot();
+ } // end of TDBCSV standard constructor
+
+TDBCSV::TDBCSV(PGLOBAL g, PTDBCSV tdbp) : TDBDOS(g, tdbp)
+ {
+ Fields = tdbp->Fields;
+
+ if (Fields) {
+ if (tdbp->Offset)
+ Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+
+ if (tdbp->Fldlen)
+ Fldlen = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+
+ Field = (PSZ *)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
+
+ for (int i = 0; i < Fields; i++) {
+ if (Offset)
+ Offset[i] = tdbp->Offset[i];
+
+ if (Fldlen)
+ Fldlen[i] = tdbp->Fldlen[i];
+
+ if (Field) {
+ assert (Fldlen);
+ Field[i] = (PSZ)PlugSubAlloc(g, NULL, Fldlen[i] + 1);
+ Field[i][Fldlen[i]] = '\0';
+ } // endif Field
+
+ } // endfor i
+
+ } else {
+ Field = NULL;
+ Offset = NULL;
+ Fldlen = NULL;
+ } // endif Fields
+
+ Nerr = tdbp->Nerr;
+ Maxerr = tdbp->Maxerr;
+ Quoted = tdbp->Quoted;
+ Accept = tdbp->Accept;
+ Header = tdbp->Header;
+ Sep = tdbp->Sep;
+ Qot = tdbp->Qot;
+ } // end of TDBCSV copy constructor
+
+// Method
+PTDB TDBCSV::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PCSVCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBCSV(g, this);
+
+ for (cp1 = (PCSVCOL)Columns; cp1; cp1 = (PCSVCOL)cp1->GetNext()) {
+ cp2 = new(g) CSVCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Allocate CSV column description block. */
+/***********************************************************************/
+PCOL TDBCSV::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) CSVCOL(g, cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Check whether the number of errors is greater than the maximum. */
+/***********************************************************************/
+bool TDBCSV::CheckErr(void)
+ {
+ return (++Nerr) > Maxerr;
+ } // end of CheckErr
+
+/***********************************************************************/
+/* CSV EstimatedLength. Returns an estimated minimum line length. */
+/***********************************************************************/
+int TDBCSV::EstimatedLength(PGLOBAL g)
+ {
+ if (trace)
+ htrc("EstimatedLength: Fields=%d Columns=%p\n", Fields, Columns);
+
+ if (!Fields) {
+ PCSVCOL colp;
+
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
+ if (!colp->IsSpecial()) // Not a pseudo column
+ Fields = max(Fields, (int)colp->Fldnum);
+
+ if (Columns)
+ Fields++; // Fldnum was 0 based
+
+ } // endif Fields
+
+ return (int)Fields; // Number of separators if all fields are null
+ } // end of Estimated Length
+
+#if 0
+/***********************************************************************/
+/* CSV tables favor the use temporary files for Update. */
+/***********************************************************************/
+bool TDBCSV::IsUsingTemp(PGLOBAL g)
+ {
+ USETEMP usetemp = PlgGetUser(g)->UseTemp;
+
+ return (usetemp == TMP_YES || usetemp == TMP_FORCE ||
+ (usetemp == TMP_AUTO && Mode == MODE_UPDATE));
+ } // end of IsUsingTemp
+#endif // 0 (Same as TDBDOS one)
+
+/***********************************************************************/
+/* CSV Access Method opening routine. */
+/* First allocate the Offset and Fldlen arrays according to the */
+/* greatest field used in that query. Then call the DOS opening fnc. */
+/***********************************************************************/
+bool TDBCSV::OpenDB(PGLOBAL g)
+ {
+ bool rc = false;
+ PCOLDEF cdp;
+ PDOSDEF tdp = (PDOSDEF)To_Def;
+
+ if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) {
+ // Allocate the storage used to read (or write) records
+ int i, len;
+ PCSVCOL colp;
+
+ if (!Fields) // May have been set in TABFMT::OpenDB
+ if (Mode != MODE_UPDATE && Mode != MODE_INSERT) {
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
+ if (!colp->IsSpecial()) // Not a pseudo column
+ Fields = max(Fields, (int)colp->Fldnum);
+
+ if (Columns)
+ Fields++; // Fldnum was 0 based
+
+ } else
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ Fields++;
+
+ Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+ Fldlen = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+
+ if (Mode == MODE_INSERT || Mode == MODE_UPDATE) {
+ Field = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
+ Fldtyp = (bool*)PlugSubAlloc(g, NULL, sizeof(bool) * Fields);
+ } // endif Mode
+
+ for (i = 0; i < Fields; i++) {
+ Offset[i] = 0;
+ Fldlen[i] = 0;
+
+ if (Field) {
+ Field[i] = NULL;
+ Fldtyp[i] = false;
+ } // endif Field
+
+ } // endfor i
+
+ if (Field)
+ // Prepare writing fields
+ if (Mode != MODE_UPDATE)
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next) {
+ i = colp->Fldnum;
+ len = colp->GetLength();
+ Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1);
+ Field[i][len] = '\0';
+ Fldlen[i] = len;
+ Fldtyp[i] = IsTypeNum(colp->GetResultType());
+ } // endfor colp
+
+ else // MODE_UPDATE
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) {
+ i = cdp->GetOffset() - 1;
+ len = cdp->GetLength();
+ Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1);
+ Field[i][len] = '\0';
+ Fldlen[i] = len;
+ Fldtyp[i] = IsTypeNum(cdp->GetType());
+ } // endfor colp
+
+ } // endif Use
+
+ if (Header) {
+ // Check that the Lrecl is at least equal to the header line length
+ int headlen = 0;
+ PCOLDEF cdp;
+ PDOSDEF tdp = (PDOSDEF)To_Def;
+
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ headlen += strlen(cdp->GetName()) + 3; // 3 if names are quoted
+
+ if (headlen > Lrecl) {
+ Lrecl = headlen;
+ Txfp->Lrecl = headlen;
+ } // endif headlen
+
+ } // endif Header
+
+ Nerr = 0;
+ rc = TDBDOS::OpenDB(g);
+
+ if (!rc && Mode == MODE_UPDATE && To_Kindex)
+ // Because KINDEX::Init is executed in mode READ, we must restore
+ // the Fldlen array that was modified when reading the table file.
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ Fldlen[cdp->GetOffset() - 1] = cdp->GetLength();
+
+ return rc;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* SkipHeader: Physically skip first header line if applicable. */
+/* This is called from TDBDOS::OpenDB and must be executed before */
+/* Kindex construction if the file is accessed using an index. */
+/***********************************************************************/
+bool TDBCSV::SkipHeader(PGLOBAL g)
+ {
+ int len = GetFileLength(g);
+ bool rc = false;
+
+#if defined(_DEBUG)
+ if (len < 0)
+ return true;
+#endif // _DEBUG
+
+ if (Header) {
+ if (Mode == MODE_INSERT) {
+ if (!len) {
+ // New file, the header line must be constructed and written
+ int i, n = 0;
+ int hlen = 0;
+ bool q = Qot && Quoted > 0;
+ PCOLDEF cdp;
+
+ // Estimate the length of the header list
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
+ hlen += (1 + strlen(cdp->GetName()));
+ hlen += ((q) ? 2 : 0);
+ n++; // Calculate the number of columns
+ } // endfor cdp
+
+ if (hlen > Lrecl) {
+ sprintf(g->Message, MSG(LRECL_TOO_SMALL), hlen);
+ return true;
+ } // endif hlen
+
+ // File is empty, write a header record
+ memset(To_Line, 0, Lrecl);
+
+ // The column order in the file is given by the offset value
+ for (i = 1; i <= n; i++)
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
+ if (cdp->GetOffset() == i) {
+ if (q)
+ To_Line[strlen(To_Line)] = Qot;
+
+ strcat(To_Line, cdp->GetName());
+
+ if (q)
+ To_Line[strlen(To_Line)] = Qot;
+
+ if (i < n)
+ To_Line[strlen(To_Line)] = Sep;
+
+ } // endif Offset
+
+ rc = (Txfp->WriteBuffer(g) == RC_FX);
+ } // endif !FileLength
+
+ } else if (Mode == MODE_DELETE) {
+ if (len)
+ rc = (Txfp->SkipRecord(g, true) == RC_FX);
+
+ } else if (len) // !Insert && !Delete
+ rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g));
+
+ } // endif Header
+
+ return rc;
+ } // end of SkipHeader
+
+/***********************************************************************/
+/* ReadBuffer: Physical read routine for the CSV access method. */
+/***********************************************************************/
+int TDBCSV::ReadBuffer(PGLOBAL g)
+ {
+ char *p1, *p2, *p = NULL;
+ int i, n, len, rc = Txfp->ReadBuffer(g);
+ bool bad = false;
+
+ if (trace > 1)
+ htrc("CSV: Row is '%s' rc=%d\n", To_Line, rc);
+
+ if (rc != RC_OK || !Fields)
+ return rc;
+ else
+ p2 = To_Line;
+
+ // Find the offsets and lengths of the columns for this row
+ for (i = 0; i < Fields; i++) {
+ if (!bad) {
+ if (Qot && *p2 == Qot) { // Quoted field
+ for (n = 0, p1 = ++p2; (p = strchr(p1, Qot)); p1 = p + 2)
+ if (*(p + 1) == Qot)
+ n++; // Doubled internal quotes
+ else
+ break; // Final quote
+
+ if (p) {
+ len = p++ - p2;
+
+// if (Sep != ' ')
+// for (; *p == ' '; p++) ; // Skip blanks
+
+ if (*p != Sep && i != Fields - 1) { // Should be the separator
+ if (CheckErr()) {
+ sprintf(g->Message, MSG(MISSING_FIELD),
+ i+1, Name, RowNumber(g));
+ return RC_FX;
+ } else if (Accept)
+ bad = true;
+ else
+ return RC_NF;
+
+ } // endif p
+
+ if (n) {
+ int j, k;
+
+ // Suppress the double of internal quotes
+ for (j = k = 0; j < len; j++, k++) {
+ if (p2[j] == Qot)
+ j++; // skip first one
+
+ p2[k] = p2[j];
+ } // endfor i, j
+
+ len -= n;
+ } // endif n
+
+ } else if (CheckErr()) {
+ sprintf(g->Message, MSG(BAD_QUOTE_FIELD),
+ Name, i+1, RowNumber(g));
+ return RC_FX;
+ } else if (Accept) {
+ len = strlen(p2);
+ bad = true;
+ } else
+ return RC_NF;
+
+ } else if ((p = strchr(p2, Sep)))
+ len = p - p2;
+ else if (i == Fields - 1)
+ len = strlen(p2);
+ else if (Accept && Maxerr == 0) {
+ len = strlen(p2);
+ bad = true;
+ } else if (CheckErr()) {
+ sprintf(g->Message, MSG(MISSING_FIELD), i+1, Name, RowNumber(g));
+ return RC_FX;
+ } else if (Accept) {
+ len = strlen(p2);
+ bad = true;
+ } else
+ return RC_NF;
+
+ } else
+ len = 0;
+
+ Offset[i] = p2 - To_Line;
+
+ if (Mode != MODE_UPDATE)
+ Fldlen[i] = len;
+ else if (len > Fldlen[i]) {
+ sprintf(g->Message, MSG(FIELD_TOO_LONG), i+1, RowNumber(g));
+ return RC_FX;
+ } else {
+ strncpy(Field[i], p2, len);
+ Field[i][len] = '\0';
+ } // endif Mode
+
+ if (p)
+ p2 = p + 1;
+
+ } // endfor i
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Data Base write routine CSV file access method. */
+/***********************************************************************/
+int TDBCSV::WriteDB(PGLOBAL g)
+ {
+ char sep[2], qot[2];
+ int i, nlen, oldlen = strlen(To_Line);
+
+ if (trace > 1)
+ htrc("CSV WriteDB: R%d Mode=%d key=%p link=%p\n",
+ Tdb_No, Mode, To_Key_Col, To_Link);
+
+ // Before writing the line we must check its length
+ if ((nlen = CheckWrite(g)) < 0)
+ return RC_FX;
+
+ // Before writing the line we must make it
+ sep[0] = Sep;
+ sep[1] = '\0';
+ qot[0] = Qot;
+ qot[1] = '\0';
+ *To_Line = '\0';
+
+ for (i = 0; i < Fields; i++) {
+ if (i)
+ strcat(To_Line, sep);
+
+ if (Field[i])
+ if (!strlen(Field[i])) {
+ // Generally null fields are not quoted
+ if (Quoted > 2)
+ // Except if explicitely required
+ strcat(strcat(To_Line, qot), qot);
+
+ } else if (Qot && (strchr(Field[i], Sep) || *Field[i] == Qot
+ || Quoted > 1 || (Quoted == 1 && !Fldtyp[i])))
+ if (strchr(Field[i], Qot)) {
+ // Field contains quotes that must be doubled
+ int j, k = strlen(To_Line), n = strlen(Field[i]);
+
+ To_Line[k++] = Qot;
+
+ for (j = 0; j < n; j++) {
+ if (Field[i][j] == Qot)
+ To_Line[k++] = Qot;
+
+ To_Line[k++] = Field[i][j];
+ } // endfor j
+
+ To_Line[k++] = Qot;
+ To_Line[k] = '\0';
+ } else
+ strcat(strcat(strcat(To_Line, qot), Field[i]), qot);
+
+ else
+ strcat(To_Line, Field[i]);
+
+ } // endfor i
+
+#if defined(_DEBUG)
+ assert ((unsigned)nlen == strlen(To_Line));
+#endif
+
+ if (Mode == MODE_UPDATE && nlen < oldlen
+ && !((PDOSFAM)Txfp)->GetUseTemp()) {
+ // In Update mode with no temp file, line length must not change
+ To_Line[nlen] = Sep;
+
+ for (nlen++; nlen < oldlen; nlen++)
+ To_Line[nlen] = ' ';
+
+ To_Line[nlen] = '\0';
+ } // endif
+
+ if (trace > 1)
+ htrc("Write: line is=%s", To_Line);
+
+ /*********************************************************************/
+ /* Now start the writing process. */
+ /*********************************************************************/
+ return Txfp->WriteBuffer(g);
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Check whether a new line fit in the file lrecl size. */
+/***********************************************************************/
+int TDBCSV::CheckWrite(PGLOBAL g)
+ {
+ int maxlen, n, nlen = (Fields - 1);
+
+ if (trace > 1)
+ htrc("CheckWrite: R%d Mode=%d\n", Tdb_No, Mode);
+
+ // Before writing the line we must check its length
+ maxlen = (Mode == MODE_UPDATE && !Txfp->GetUseTemp())
+ ? strlen(To_Line) : Lrecl;
+
+ // Check whether record is too int
+ for (int i = 0; i < Fields; i++)
+ if (Field[i]) {
+ if (!(n = strlen(Field[i])))
+ n += (Quoted > 2 ? 2 : 0);
+ else if (strchr(Field[i], Sep) || (Qot && *Field[i] == Qot)
+ || Quoted > 1 || (Quoted == 1 && !Fldtyp[i]))
+ if (!Qot) {
+ sprintf(g->Message, MSG(SEP_IN_FIELD), i + 1);
+ return -1;
+ } else {
+ // Quotes inside a quoted field must be doubled
+ char *p1, *p2;
+
+ for (p1 = Field[i]; (p2 = strchr(p1, Qot)); p1 = p2 + 1)
+ n++;
+
+ n += 2; // Outside quotes
+ } // endif
+
+ if ((nlen += n) > maxlen) {
+ strcpy(g->Message, MSG(LINE_TOO_LONG));
+ return -1;
+ } // endif nlen
+
+ } // endif Field
+
+ return nlen;
+ } // end of CheckWrite
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBFMT class. */
+/***********************************************************************/
+TDBFMT::TDBFMT(PGLOBAL g, PTDBFMT tdbp) : TDBCSV(g, tdbp)
+ {
+ FldFormat = tdbp->FldFormat;
+ To_Fld = tdbp->To_Fld;
+ FmtTest = tdbp->FmtTest;
+ Linenum = tdbp->Linenum;
+ } // end of TDBFMT copy constructor
+
+// Method
+PTDB TDBFMT::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PCSVCOL cp1, cp2;
+//PFMTCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBFMT(g, this);
+
+ for (cp1 = (PCSVCOL)Columns; cp1; cp1 = (PCSVCOL)cp1->GetNext()) {
+//for (cp1 = (PFMTCOL)Columns; cp1; cp1 = (PFMTCOL)cp1->GetNext()) {
+ cp2 = new(g) CSVCOL(cp1, tp); // Make a copy
+// cp2 = new(g) FMTCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Allocate FMT column description block. */
+/***********************************************************************/
+PCOL TDBFMT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) CSVCOL(g, cdp, this, cprec, n);
+//return new(g) FMTCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* FMT EstimatedLength. Returns an estimated minimum line length. */
+/* The big problem here is how can we astimated that minimum ? */
+/***********************************************************************/
+int TDBFMT::EstimatedLength(PGLOBAL g)
+ {
+ // This is rather stupid !!!
+ return ((PDOSDEF)To_Def)->GetEnding() + (int)((Lrecl / 10) + 1);
+ } // end of EstimatedLength
+
+/***********************************************************************/
+/* FMT Access Method opening routine. */
+/***********************************************************************/
+bool TDBFMT::OpenDB(PGLOBAL g)
+ {
+ Linenum = 0;
+
+ if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) {
+ // Make the formats used to read records
+ PSZ pfm;
+ int i, n;
+ PCSVCOL colp;
+ PCOLDEF cdp;
+ PDOSDEF tdp = (PDOSDEF)To_Def;
+
+// if (Mode != MODE_UPDATE) {
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
+ if (!colp->IsSpecial()) // Not a pseudo column
+ Fields = max(Fields, (int)colp->Fldnum);
+
+ if (Columns)
+ Fields++; // Fldnum was 0 based
+
+// } else
+// for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+// Fields++;
+
+ To_Fld = PlugSubAlloc(g, NULL, Lrecl + 1);
+ FldFormat = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
+ memset(FldFormat, 0, sizeof(PSZ) * Fields);
+ FmtTest = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+ memset(FmtTest, 0, sizeof(int) * Fields);
+
+ // Get the column formats
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ if ((i = cdp->GetOffset() - 1) < Fields) {
+ if (!(pfm = cdp->GetFmt())) {
+ sprintf(g->Message, MSG(NO_FLD_FORMAT), i + 1, Name);
+ return true;
+ } // endif pfm
+
+ // Roughly check the Fmt format
+ if ((n = strlen(pfm) - 2) < 4) {
+ sprintf(g->Message, MSG(BAD_FLD_FORMAT), i + 1, Name);
+ return true;
+ } // endif n
+
+ FldFormat[i] = (PSZ)PlugSubAlloc(g, NULL, n + 5);
+ strcpy(FldFormat[i], pfm);
+
+ if (!strcmp(pfm + n, "%m")) {
+ // This is a field that can be missing. Flag it so it can
+ // be handled with special processing.
+ FldFormat[i][n+1] = 'n'; // To have sscanf normal processing
+ FmtTest[i] = 2;
+ } else if (i+1 < Fields && strcmp(pfm + n, "%n")) {
+ // There are trailing characters after the field contents
+ // add a marker for the next field start position.
+ strcat(FldFormat[i], "%n");
+ FmtTest[i] = 1;
+ } // endif's
+
+ } // endif i
+
+ } // endif Use
+
+ return TDBCSV::OpenDB(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadBuffer: Physical read routine for the FMT access method. */
+/***********************************************************************/
+int TDBFMT::ReadBuffer(PGLOBAL g)
+ {
+ int i, len, n, deb, fin, nwp, pos = 0, rc;
+ bool bad = false;
+
+ if ((rc = Txfp->ReadBuffer(g)) != RC_OK || !Fields)
+ return rc;
+ else
+ ++Linenum;
+
+ if (trace > 1)
+ htrc("FMT: Row %d is '%s' rc=%d\n", Linenum, To_Line, rc);
+
+ // Find the offsets and lengths of the columns for this row
+ for (i = 0; i < Fields; i++) {
+ if (!bad) {
+ deb = fin = -1;
+
+ if (!FldFormat[i]) {
+ n = 0;
+ } else if (FmtTest[i] == 1) {
+ nwp = -1;
+ n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin, &nwp);
+ } else {
+ n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin);
+
+ if (n != 1 && (deb >= 0 || i == Fields - 1) && FmtTest[i] == 2) {
+ // Missing optional field, not an error
+ n = 1;
+
+ if (i == Fields - 1)
+ fin = deb = 0;
+ else
+ fin = deb;
+
+ } // endif n
+
+ nwp = fin;
+ } // endif i
+
+ if (n != 1 || deb < 0 || fin < 0 || nwp < 0) {
+ // This is to avoid a very strange sscanf bug occuring
+ // with fields that ends with a null character.
+ // This bug causes subsequent sscanf to return in error,
+ // so next lines are not parsed correctly.
+ sscanf("a", "%*c"); // Seems to reset things Ok
+
+ if (CheckErr()) {
+ sprintf(g->Message, MSG(BAD_LINEFLD_FMT), Linenum, i + 1, Name);
+ return RC_FX;
+ } else if (Accept)
+ bad = true;
+ else
+ return RC_NF;
+
+ } // endif n...
+
+ } // endif !bad
+
+ if (!bad) {
+ Offset[i] = pos + deb;
+ len = fin - deb;
+ } else {
+ nwp = 0;
+ Offset[i] = pos;
+ len = 0;
+ } // endif bad
+
+// if (Mode != MODE_UPDATE)
+ Fldlen[i] = len;
+// else if (len > Fldlen[i]) {
+// sprintf(g->Message, MSG(FIELD_TOO_LONG), i+1, To_Tdb->RowNumber(g));
+// return RC_FX;
+// } else {
+// strncpy(Field[i], To_Line + pos, len);
+// Field[i][len] = '\0';
+// } // endif Mode
+
+ pos += nwp;
+ } // endfor i
+
+ if (bad)
+ Nerr++;
+ else
+ sscanf("a", "%*c"); // Seems to reset things Ok
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Data Base write routine FMT file access method. */
+/***********************************************************************/
+int TDBFMT::WriteDB(PGLOBAL g)
+ {
+ sprintf(g->Message, MSG(FMT_WRITE_NIY), "FMT");
+ return RC_FX; // NIY
+ } // end of WriteDB
+
+// ------------------------ CSVCOL functions ----------------------------
+
+/***********************************************************************/
+/* CSVCOL public constructor */
+/***********************************************************************/
+CSVCOL::CSVCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : DOSCOL(g, cdp, tdbp, cprec, i, "CSV")
+ {
+ Fldnum = Deplac - 1;
+ Deplac = 0;
+ } // end of CSVCOL constructor
+
+/***********************************************************************/
+/* CSVCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+CSVCOL::CSVCOL(CSVCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
+ {
+ Fldnum = col1->Fldnum;
+ } // end of CSVCOL copy constructor
+
+/***********************************************************************/
+/* VarSize: This function tells UpdateDB whether or not the block */
+/* optimization file must be redone if this column is updated, even */
+/* it is not sorted or clustered. This applies to a blocked table, */
+/* because if it is updated using a temporary file, the block size */
+/* may be modified. */
+/***********************************************************************/
+bool CSVCOL::VarSize(void)
+ {
+ PTXF txfp = ((PTDBCSV)To_Tdb)->Txfp;
+
+ if (txfp->IsBlocked() && txfp->GetUseTemp())
+ // Blocked table using a temporary file
+ return true;
+ else
+ return false;
+
+ } // end VarSize
+
+/***********************************************************************/
+/* ReadColumn: call DOSCOL::ReadColumn after having set the offet */
+/* and length of the field to read as calculated by TDBCSV::ReadDB. */
+/***********************************************************************/
+void CSVCOL::ReadColumn(PGLOBAL g)
+ {
+ int rc;
+ PTDBCSV tdbp = (PTDBCSV)To_Tdb;
+
+ /*********************************************************************/
+ /* 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], 34);
+ } // endif
+
+ if (tdbp->Mode != MODE_UPDATE) {
+ int colen = Long; // Column length
+
+ // Set the field offset and length for this row
+ Deplac = tdbp->Offset[Fldnum]; // Field offset
+ Long = tdbp->Fldlen[Fldnum]; // Field length
+
+ if (trace > 1)
+ htrc("CSV ReadColumn %s Fldnum=%d offset=%d fldlen=%d\n",
+ Name, Fldnum, Deplac, Long);
+
+ if (Long > colen && tdbp->CheckErr()) {
+ Long = colen; // Restore column length
+ sprintf(g->Message, MSG(FLD_TOO_LNG_FOR),
+ Fldnum + 1, Name, To_Tdb->RowNumber(g), tdbp->GetFile(g));
+ longjmp(g->jumper[g->jump_level], 34);
+ } // endif Long
+
+ // Now do the reading
+ DOSCOL::ReadColumn(g);
+
+ // Restore column length
+ Long = colen;
+ } else { // Mode Update
+ // Field have been copied in TDB Field array
+ PSZ fp = tdbp->Field[Fldnum];
+
+ Value->SetValue_psz(fp);
+ } // endif Mode
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: The column is written in TDBCSV matching Field. */
+/***********************************************************************/
+void CSVCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, buf[32];
+ int flen;
+ PTDBCSV tdbp = (PTDBCSV)To_Tdb;
+
+ if (trace > 1)
+ htrc("CSV WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status);
+
+ flen = GetLength();
+
+ if (trace > 1)
+ htrc("Lrecl=%d Long=%d field=%d coltype=%d colval=%p\n",
+ tdbp->Lrecl, Long, flen, Buf_Type, Value);
+
+ /*********************************************************************/
+ /* 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
+
+ /*********************************************************************/
+ /* Get the string representation of the column value. */
+ /*********************************************************************/
+ p = Value->ShowValue(buf);
+
+ if (trace > 1)
+ htrc("new length(%p)=%d\n", p, strlen(p));
+
+ if ((signed)strlen(p) > flen) {
+ sprintf(g->Message, MSG(BAD_FLD_LENGTH), Name, p, flen);
+ longjmp(g->jumper[g->jump_level], 34);
+ } // endif
+
+ if (trace > 1)
+ htrc("buffer=%s\n", p);
+
+ /*********************************************************************/
+ /* Updating must be done also during the first pass so writing the */
+ /* updated record can be checked for acceptable record length. */
+ /*********************************************************************/
+ if (Fldnum < 0) {
+ // This can happen for wrong offset value in XDB files
+ sprintf(g->Message, MSG(BAD_FIELD_RANK), Fldnum + 1, Name);
+ longjmp(g->jumper[g->jump_level], 34);
+ } else
+ strncpy(tdbp->Field[Fldnum], p, flen);
+
+ if (trace > 1)
+ htrc(" col written: '%s'\n", p);
+
+ } // end of WriteColumn
+
+/* ------------------------ End of TabFmt ---------------------------- */
diff --git a/storage/connect/tabfmt.h b/storage/connect/tabfmt.h
index 7da36372377..80ad1a6ae63 100644
--- a/storage/connect/tabfmt.h
+++ b/storage/connect/tabfmt.h
@@ -1,164 +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 ------------------------- */
+/*************** 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 ------------------------- */
diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp
index db603513458..77c2fd4df3b 100644
--- a/storage/connect/table.cpp
+++ b/storage/connect/table.cpp
@@ -1,427 +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
+/************** 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
diff --git a/storage/connect/tabmac.cpp b/storage/connect/tabmac.cpp
index 65cb21eb62d..f072465ced5 100644
--- a/storage/connect/tabmac.cpp
+++ b/storage/connect/tabmac.cpp
@@ -1,458 +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
+/***********************************************************************/
+/* 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
diff --git a/storage/connect/tabmac.h b/storage/connect/tabmac.h
index 1d6cb4d5aa4..cfdf842cdc8 100644
--- a/storage/connect/tabmac.h
+++ b/storage/connect/tabmac.h
@@ -1,107 +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
+// 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
diff --git a/storage/connect/tabmul.cpp b/storage/connect/tabmul.cpp
index 1b272196e0f..eddc6afa08b 100644
--- a/storage/connect/tabmul.cpp
+++ b/storage/connect/tabmul.cpp
@@ -1,1474 +1,1474 @@
-/************* TabMul C++ Program Source Code File (.CPP) **************/
-/* PROGRAM NAME: TABMUL */
-/* ------------- */
-/* Version 1.7 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to PlugDB Software Development 2003 - 2012 */
-/* Author: Olivier BERTRAND */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the TDBMUL class DB routines. */
-/* */
-/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
-/* -------------------------------------- */
-/* */
-/* REQUIRED FILES: */
-/* --------------- */
-/* TABMUL.CPP - Source code */
-/* PLGDBSEM.H - DB application declaration file */
-/* TABDOS.H - TABDOS classes declaration file */
-/* TABMUL.H - TABFIX classes declaration file */
-/* GLOBAL.H - Global declaration file */
-/* */
-/* REQUIRED LIBRARIES: */
-/* ------------------- */
-/* Large model C library */
-/* */
-/* REQUIRED PROGRAMS: */
-/* ------------------ */
-/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
-/* */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant section of system dependant header files. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-#include <stdlib.h>
-#include <stdio.h>
-#if defined(__BORLANDC__)
-#define __MFC_COMPAT__ // To define min/max as macro
-#endif
-//#include <windows.h>
-#else
-#if defined(UNIX)
-#include <fnmatch.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "osutil.h"
-#else
-//#include <io.h>
-#endif
-//#include <fcntl.h>
-#endif
-
-/***********************************************************************/
-/* Include application header files: */
-/***********************************************************************/
-#include "global.h" // global declarations
-#include "plgdbsem.h" // DB application declarations
-#include "reldef.h" // DB definition declares
-#include "filamtxt.h"
-#include "tabdos.h" // TDBDOS and DOSCOL class dcls
-#include "tabmul.h" // TDBMUL and MULCOL classes dcls
-
-/* ------------------------- Class TDBMUL ---------------------------- */
-
-/***********************************************************************/
-/* TABMUL constructors. */
-/***********************************************************************/
-TDBMUL::TDBMUL(PTDBASE tdbp) : TDBASE(tdbp->GetDef())
- {
- Tdbp = tdbp;
- Filenames = NULL;
- Rows = 0;
- Mul = tdbp->GetDef()->GetMultiple();
- NumFiles = 0;
- iFile = 0;
- } // end of TDBMUL standard constructor
-
-TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp)
- {
- Tdbp = tdbp->Tdbp;
- Filenames = tdbp->Filenames;
- Rows = tdbp->Rows;
- Mul = tdbp->Mul;
- NumFiles = tdbp->NumFiles;
- iFile = tdbp->iFile;
- } // end of TDBMUL copy constructor
-
-// Method
-PTDB TDBMUL::CopyOne(PTABS t)
- {
- PTDBMUL tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBMUL(this);
- tp->Tdbp = (PTDBASE)Tdbp->CopyOne(t);
- tp->Columns = tp->Tdbp->GetColumns();
- return tp;
- } // end of CopyOne
-
-PTDB TDBMUL::Duplicate(PGLOBAL g)
- {
- PTDBMUL tmup = new(g) TDBMUL(this);
-
- tmup->Tdbp = (PTDBASE)Tdbp->Duplicate(g);
- return tmup;
- } // end of Duplicate
-
-/***********************************************************************/
-/* Initializes the table filename list. */
-/* Note: tables created by concatenating the file components without */
-/* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
-/* have a LRECL that is the sum of the lengths of all components. */
-/* This is why we use a big filename array to take care of that. */
-/***********************************************************************/
-bool TDBMUL::InitFileNames(PGLOBAL g)
- {
-#define PFNZ 8192
- char *pfn[PFNZ], filename[_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT];
- int rc, n = 0;
-
- // The sub table may need to refer to the Table original block
- Tdbp->SetTable(To_Table); // Was not set at construction
-
- PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
-
- if (Mul == 1) {
- /*******************************************************************/
- /* To_File is a multiple name with special characters */
- /*******************************************************************/
-#if defined(WIN32)
- char drive[_MAX_DRIVE], direc[_MAX_DIR];
- WIN32_FIND_DATA FileData;
- HANDLE hSearch;
-
- _splitpath(filename, drive, direc, NULL, NULL);
-
- // Start searching files in the target directory.
- hSearch = FindFirstFile(filename, &FileData);
-
- if (hSearch == INVALID_HANDLE_VALUE) {
- rc = GetLastError();
-
- if (rc != ERROR_FILE_NOT_FOUND) {
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(), 0,
- (LPTSTR)&filename, sizeof(filename), NULL);
- sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
- return true;
- } // endif rc
-
- goto suite;
- } // endif hSearch
-
- while (n < PFNZ) {
- strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName);
- pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
- strcpy(pfn[n++], filename);
-
- if (!FindNextFile(hSearch, &FileData)) {
- rc = GetLastError();
-
- if (rc != ERROR_NO_MORE_FILES) {
- sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
- FindClose(hSearch);
- return true;
- } // endif rc
-
- break;
- } // endif FindNextFile
-
- } // endwhile n
-
- // Close the search handle.
- if (!FindClose(hSearch)) {
- strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
- return true;
- } // endif FindClose
-
-#else // !WIN32
- struct stat fileinfo;
- char fn[PATH_MAX], direc[PATH_MAX], pattern[256], ftype[8];
- DIR *dir;
- struct dirent *entry;
-
- _splitpath(filename, NULL, direc, pattern, ftype);
- strcat(pattern, ftype);
-
- // Start searching files in the target directory.
- if (!(dir = opendir(direc))) {
- sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno));
- return true;
- } // endif dir
-
- while ((entry = readdir(dir)) && n < PFNZ) {
- strcat(strcpy(fn, direc), entry->d_name);
-
- if (lstat(fn, &fileinfo) < 0) {
- sprintf(g->Message, "%s: %s", fn, strerror(errno));
- return true;
- } else if (!S_ISREG(fileinfo.st_mode))
- continue; // Not a regular file (should test for links)
-
- /*******************************************************************/
- /* Test whether the file name matches the table name filter. */
- /*******************************************************************/
- if (fnmatch(pattern, entry->d_name, 0))
- continue; // Not a match
-
- strcat(strcpy(filename, direc), entry->d_name);
- pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
- strcpy(pfn[n++], filename);
- } // endwhile readdir
-
- // Close the dir handle.
- closedir(dir);
-#endif // !WIN32
-
- } else {
- /*******************************************************************/
- /* To_File is the name of a file containing the file name list */
- /*******************************************************************/
- char *p;
- FILE *stream;
-
- if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r")))
- return true;
-
- while (n < PFNZ) {
- if (!fgets(filename, sizeof(filename), stream)) {
- fclose(stream);
- break;
- } // endif fgets
-
- p = filename + strlen(filename) - 1;
-
-#if defined(UNIX)
- // Data files can be imported from Windows (having CRLF)
- if (*p == '\n' || *p == '\r') {
- // is this enough for Unix ???
- *p--; // Eliminate ending CR or LF character
-
- if (p >= filename)
- // is this enough for Unix ???
- if (*p == '\n' || *p == '\r')
- *p--; // Eliminate ending CR or LF character
-
- } // endif p
-
-#else
- if (*p == '\n')
- p--; // Eliminate ending new-line character
-#endif
- // Trim rightmost blanks
- for (; p >= filename && *p == ' '; p--) ;
-
- *(++p) = '\0';
-
- // Suballocate the file name
- pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
- strcpy(pfn[n++], filename);
- } // endfor n
-
- } // endif Mul
-
- suite:
- if (n) {
- Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
-
- for (int i = 0; i < n; i++)
- Filenames[i] = pfn[i];
-
- } else {
- Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
- Filenames[0] = NULL;
- } // endif n
-
- NumFiles = n;
- return false;
- } // end of InitFileNames
-
-/***********************************************************************/
-/* The table column list is the sub-table column list. */
-/***********************************************************************/
-PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num)
- {
- PCOL cp;
-
- /*********************************************************************/
- /* Because special columns are directly added to the MUL block, */
- /* make sure that the sub-table has the same column list, before */
- /* and after the call to the ColDB function. */
- /*********************************************************************/
- Tdbp->SetColumns(Columns);
- cp = Tdbp->ColDB(g, name, num);
- Columns = Tdbp->GetColumns();
- return cp;
-} // end of ColDB
-
-/***********************************************************************/
-/* MUL GetProgMax: get the max value for progress information. */
-/***********************************************************************/
-int TDBMUL::GetProgMax(PGLOBAL g)
- {
- if (!Filenames && InitFileNames(g))
- return -1;
-
- return NumFiles; // This is a temporary setting
- } // end of GetProgMax
-
-/***********************************************************************/
-/* MUL GetProgCur: get the current value for progress information. */
-/***********************************************************************/
-int TDBMUL::GetProgCur(void)
- {
- return iFile; // This is a temporary setting
- } // end of GetProgMax
-
-/***********************************************************************/
-/* MUL Cardinality: returns table cardinality in number of rows. */
-/* This function can be called with a null argument to test the */
-/* availability of Cardinality implementation (1 yes, 0 no). */
-/* Can be used on Multiple FIX table only. */
-/***********************************************************************/
-int TDBMUL::Cardinality(PGLOBAL g)
- {
- if (!g)
- return Tdbp->Cardinality(g);
-
- if (!Filenames && InitFileNames(g))
- return -1;
-
- int n, card = 0;
-
- for (int i = 0; i < NumFiles; i++) {
- Tdbp->SetFile(g, Filenames[i]);
- Tdbp->ResetSize();
-
- if ((n = Tdbp->Cardinality(g)) < 0) {
-// strcpy(g->Message, MSG(BAD_CARDINALITY));
- return -1;
- } // endif n
-
- card += n;
- } // endfor i
-
- return card;
- } // end of Cardinality
-
-/***********************************************************************/
-/* Sum up the sizes of all sub-tables. */
-/***********************************************************************/
-int TDBMUL::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0) {
- int i;
- int mxsz;
-
- if (!Filenames && InitFileNames(g))
- return -1;
-
- if (Use == USE_OPEN) {
- strcpy(g->Message, MSG(MAXSIZE_ERROR));
- return -1;
- } else
- MaxSize = 0;
-
- for (i = 0; i < NumFiles; i++) {
- Tdbp->SetFile(g, Filenames[i]);
- Tdbp->ResetSize();
-
- if ((mxsz = Tdbp->GetMaxSize(g)) < 0) {
- MaxSize = -1;
- return mxsz;
- } // endif mxsz
-
- MaxSize += mxsz;
- } // endfor i
-
- } // endif MaxSize
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* Reset read/write position values. */
-/***********************************************************************/
-void TDBMUL::ResetDB(void)
- {
- for (PCOL colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_FILID)
- colp->COLBLK::Reset();
-
- Tdbp->ResetDB();
- } // end of ResetDB
-
-/***********************************************************************/
-/* Returns RowId if b is false or Rownum if b is true. */
-/***********************************************************************/
-int TDBMUL::RowNumber(PGLOBAL g, bool b)
- {
- return ((b) ? 0 : Rows)
- + ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1);
- } // end of RowNumber
-
-/***********************************************************************/
-/* MUL Access Method opening routine. */
-/* Open first file, other will be opened sequencially when reading. */
-/***********************************************************************/
-bool TDBMUL::OpenDB(PGLOBAL g)
- {
-#ifdef DEBTRACE
- htrc("MUL 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, replace it at its beginning. */
- /*******************************************************************/
- if (Filenames[iFile = 0]) {
- Tdbp->CloseDB(g);
- Tdbp->SetUse(USE_READY);
- Tdbp->SetFile(g, Filenames[iFile = 0]);
- Tdbp->ResetSize();
- Rows = 0;
- ResetDB();
- return Tdbp->OpenDB(g); // Re-open with new file name
- } else
- return false;
-
- } // endif use
-
- /*********************************************************************/
- /* We need to calculate MaxSize before opening the query. */
- /*********************************************************************/
- if (GetMaxSize(g) < 0)
- return true;
-
- /*********************************************************************/
- /* Open the first table file of the list. */
- /*********************************************************************/
-//if (!Filenames && InitFileNames(g)) done in GetMaxSize
-// return true;
-
- if (Filenames[iFile = 0]) {
- Tdbp->SetFile(g, Filenames[0]);
- Tdbp->SetMode(Mode);
- Tdbp->ResetDB();
- Tdbp->ResetSize();
-
- if (Tdbp->OpenDB(g))
- return true;
-
- } // endif *Filenames
-
- Use = USE_OPEN;
- return false;
- } // end of OpenDB
-
-/***********************************************************************/
-/* ReadDB: Data Base read routine for MUL access method. */
-/***********************************************************************/
-int TDBMUL::ReadDB(PGLOBAL g)
- {
- int rc;
-
- if (NumFiles == 0)
- return RC_EF;
- else if (To_Kindex) {
- /*******************************************************************/
- /* Reading is by an index table. */
- /*******************************************************************/
- strcpy(g->Message, MSG(NO_INDEX_READ));
- rc = RC_FX;
- } else {
- /*******************************************************************/
- /* Now start the reading process. */
- /*******************************************************************/
- retry:
- rc = Tdbp->ReadDB(g);
-
- if (rc == RC_EF) {
- if (Tdbp->GetDef()->GetPseudo() & 1)
- // Total number of rows met so far
- Rows += Tdbp->RowNumber(g) - 1;
-
- if (++iFile < NumFiles) {
- /***************************************************************/
- /* Continue reading from next table file. */
- /***************************************************************/
- Tdbp->CloseDB(g);
- Tdbp->SetUse(USE_READY);
- Tdbp->SetFile(g, Filenames[iFile]);
- Tdbp->ResetSize();
- ResetDB();
-
- if (Tdbp->OpenDB(g)) // Re-open with new file name
- return RC_FX;
-
- goto retry;
- } // endif iFile
-
- } else if (rc == RC_FX)
- strcat(strcat(strcat(g->Message, " ("), Tdbp->GetFile(g)), ")");
-
- } // endif To_Kindex
-
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* Data Base write routine for MUL access method. */
-/***********************************************************************/
-int TDBMUL::WriteDB(PGLOBAL g)
- {
- return Tdbp->WriteDB(g);
-// strcpy(g->Message, MSG(TABMUL_READONLY));
-// return RC_FX; // NIY
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for MUL access method. */
-/***********************************************************************/
-int TDBMUL::DeleteDB(PGLOBAL g, int irc)
- {
- // When implementing DELETE_MODE InitFileNames must be updated to
- // eliminate CRLF under Windows if the file is read in binary.
- strcpy(g->Message, MSG(TABMUL_READONLY));
- return RC_FX; // NIY
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for MUL access method. */
-/***********************************************************************/
-void TDBMUL::CloseDB(PGLOBAL g)
- {
- if (NumFiles > 0) {
- Tdbp->CloseDB(g);
- iFile = NumFiles;
- } // endif NumFiles
-
- } // end of CloseDB
-
-/* --------------------------- Class DIRDEF -------------------------- */
-
-/***********************************************************************/
-/* DefineAM: define specific AM block values from XDB file. */
-/***********************************************************************/
-bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- Desc = Fn = Cat->GetStringCatInfo(g, Name, "Filename", "");
- Incl = (Cat->GetIntCatInfo(Name, "Subdir", 0) != 0);
- Huge = (Cat->GetIntCatInfo(Name, "Huge", 0) != 0);
- return false;
- } // end of DefineAM
-
-/***********************************************************************/
-/* GetTable: makes a new Table Description Block. */
-/***********************************************************************/
-PTDB DIRDEF::GetTable(PGLOBAL g, MODE m)
- {
-#if 0
- if (Huge)
- return new(g) TDBDHR(this); // Not implemented yet
- else
-#endif
- if (Incl)
- return new(g) TDBSDR(this); // Including sub-directory files
- else
- return new(g) TDBDIR(this); // Not Including sub-directory files
-
- } // end of GetTable
-
-/* ------------------------- Class TDBDIR ---------------------------- */
-
-/***********************************************************************/
-/* TABDIR constructors. */
-/***********************************************************************/
-TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
- {
- To_File = tdp->Fn;
- iFile = 0;
-#if defined(WIN32)
- memset(&FileData, 0, sizeof(_finddata_t));
- Hsearch = -1;
- *Drive = '\0';
-#else // !WIN32
- memset(&Fileinfo, 0, sizeof(struct stat));
- Entry = NULL;
- Dir = NULL;
- Done = false;
- *Pattern = '\0';
-#endif // !WIN32
- *Fpath = '\0';
- *Direc = '\0';
- *Fname = '\0';
- *Ftype = '\0';
- } // end of TDBDIR standard constructor
-
-TDBDIR::TDBDIR(PTDBDIR tdbp) : TDBASE(tdbp)
- {
- To_File = tdbp->To_File;
- iFile = tdbp->iFile;
-#if defined(WIN32)
- FileData = tdbp->FileData;
- Hsearch = tdbp->Hsearch;
- strcpy(Drive, tdbp->Drive);
-#else // !WIN32
- Fileinfo = tdbp->Fileinfo;
- Entry = tdbp->Entry;
- Dir = tdbp->Dir;
- Done = tdbp->Done;
- strcpy(Pattern, tdbp->Pattern);
-#endif // !WIN32
- strcpy(Direc, tdbp->Direc);
- strcpy(Fname, tdbp->Fname);
- strcpy(Ftype, tdbp->Ftype);
- } // end of TDBDIR copy constructor
-
-// Method
-PTDB TDBDIR::CopyOne(PTABS t)
- {
- PTDB tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBDIR(this);
- tp->SetColumns(Columns);
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Initialize/get the components of the search file pattern. */
-/***********************************************************************/
-char* TDBDIR::Path(PGLOBAL g)
- {
- PCATLG cat = PlgGetCatalog(g);
-
-#if defined(WIN32)
- if (!*Drive) {
- PlugSetPath(Fpath, To_File, cat->GetDataPath());
- _splitpath(Fpath, Drive, Direc, Fname, Ftype);
- } else
- _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull ???
-
- return Fpath;
-#else // !WIN32
- if (!Done) {
- PlugSetPath(Fpath, To_File, cat->GetDataPath());
- _splitpath(Fpath, NULL, Direc, Fname, Ftype);
- strcat(strcpy(Pattern, Fname), Ftype);
- Done = true;
- } // endif Done
-
- return Pattern;
-#endif // !WIN32
- } // end of Path
-
-/***********************************************************************/
-/* Allocate DIR column description block. */
-/***********************************************************************/
-PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- return new(g) DIRCOL(cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* DIR GetMaxSize: returns the number of retrieved files. */
-/***********************************************************************/
-int TDBDIR::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0) {
- int n = -1;
-#if defined(WIN32)
- int h;
-
- // Start searching files in the target directory.
- h = _findfirst(Path(g), &FileData);
-
- if (h != -1) {
- for (n = 1;; n++)
- if (_findnext(h, &FileData))
- break;
-
- // Close the search handle.
- _findclose(h);
- } else
- n = 0;
-
-#else // !WIN32
- Path(g);
-
- // Start searching files in the target directory.
- if (!(Dir = opendir(Direc))) {
- sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
- return -1;
- } // endif dir
-
- while ((Entry = readdir(Dir))) {
- strcat(strcpy(Fpath, Direc), Entry->d_name);
-
- if (lstat(Fpath, &Fileinfo) < 0) {
- sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
- return -1;
- } else if (S_ISREG(Fileinfo.st_mode))
- // Test whether the file name matches the table name filter
- if (!fnmatch(Pattern, Entry->d_name, 0))
- n++; // We have a match
-
- } // endwhile Entry
-
- // Close the DIR handle.
- closedir(Dir);
-#endif // !WIN32
- MaxSize = n;
- } // endif MaxSize
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* DIR Access Method opening routine. */
-/* Open first file, other will be opened sequencially when reading. */
-/***********************************************************************/
-bool TDBDIR::OpenDB(PGLOBAL g)
- {
-#ifdef DEBTRACE
- htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
- this, Tdb_No, Use, Mode);
-#endif
-
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open, reopen it. */
- /*******************************************************************/
- CloseDB(g);
- SetUse(USE_READY);
- } // endif use
-
- Use = USE_OPEN;
-#if !defined(WIN32)
- Path(g); // Be sure it is done
- Dir = NULL; // For ReadDB
-#endif // !WIN32
- return false;
- } // end of OpenDB
-
-/***********************************************************************/
-/* Data Base read routine for DIR access method. */
-/***********************************************************************/
-int TDBDIR::ReadDB(PGLOBAL g)
- {
- int rc = RC_OK;
-
-#if defined(WIN32)
- if (Hsearch == -1) {
- /*******************************************************************/
- /* Start searching files in the target directory. The use of the */
- /* Path function is required when called from TDBSDR. */
- /*******************************************************************/
- Hsearch = _findfirst(Path(g), &FileData);
-
- if (Hsearch == -1)
- rc = RC_EF;
- else
- iFile++;
-
- } else {
- if (_findnext(Hsearch, &FileData)) {
- // Restore file name and type pattern
- _splitpath(To_File, NULL, NULL, Fname, Ftype);
- rc = RC_EF;
- } else
- iFile++;
-
- } // endif Hsearch
-
- if (rc == RC_OK)
- _splitpath(FileData.name, NULL, NULL, Fname, Ftype);
-
-#else // !Win32
- rc = RC_NF;
-
- if (!Dir)
- // Start searching files in the target directory.
- if (!(Dir = opendir(Direc))) {
- sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
- rc = RC_FX;
- } // endif dir
-
- while (rc == RC_NF)
- if ((Entry = readdir(Dir))) {
- // We need the Fileinfo structure to get info about the file
- strcat(strcpy(Fpath, Direc), Entry->d_name);
-
- if (lstat(Fpath, &Fileinfo) < 0) {
- sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
- rc = RC_FX;
- } else if (S_ISREG(Fileinfo.st_mode))
- // Test whether the file name matches the table name filter
- if (!fnmatch(Pattern, Entry->d_name, 0)) {
- iFile++; // We have a match
- _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
- rc = RC_OK;
- } // endif fnmatch
-
- } else {
- // Restore file name and type pattern
- _splitpath(To_File, NULL, NULL, Fname, Ftype);
- rc = RC_EF;
- } // endif Entry
-
-#endif // !WIN32
-
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* Data Base write routine for DIR access method. */
-/***********************************************************************/
-int TDBDIR::WriteDB(PGLOBAL g)
- {
- strcpy(g->Message, MSG(TABDIR_READONLY));
- return RC_FX; // NIY
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for DIR access method. */
-/***********************************************************************/
-int TDBDIR::DeleteDB(PGLOBAL g, int irc)
- {
- strcpy(g->Message, MSG(TABDIR_READONLY));
- return RC_FX; // NIY
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for MUL access method. */
-/***********************************************************************/
-void TDBDIR::CloseDB(PGLOBAL g)
- {
-#if defined(WIN32)
- // Close the search handle.
- _findclose(Hsearch);
- Hsearch = -1;
-#else // !WIN32
- // Close the DIR handle.
- closedir(Dir);
- Dir = NULL;
-#endif // !WIN32
- iFile = 0;
- } // end of CloseDB
-
-// ------------------------ DIRCOL functions ----------------------------
-
-/***********************************************************************/
-/* DIRCOL public constructor. */
-/***********************************************************************/
-DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
- : COLBLK(cdp, tdbp, i)
- {
- if (cprec) {
- Next = cprec->GetNext();
- cprec->SetNext(this);
- } else {
- Next = tdbp->GetColumns();
- tdbp->SetColumns(this);
- } // endif cprec
-
- // Set additional DIR access method information for column.
- N = cdp->GetOffset();
- } // end of DIRCOL constructor
-
-/***********************************************************************/
-/* DIRCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- N = col1->N;
- } // end of DIRCOL copy constructor
-
-/***********************************************************************/
-/* ReadColumn: what this routine does is to access the information */
-/* corresponding to this column and convert it to buffer type. */
-/***********************************************************************/
-void DIRCOL::ReadColumn(PGLOBAL g)
- {
- PTDBDIR tdbp = (PTDBDIR)To_Tdb;
-
-#ifdef DEBTRACE
- fprintf(debug,
- "DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
- Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
-#endif
-
- /*********************************************************************/
- /* Retrieve the information corresponding to the column number. */
- /*********************************************************************/
- switch (N) {
-#if defined(WIN32)
- case 0: Value->SetValue_psz(tdbp->Drive); break;
-#endif // WIN32
- case 1: Value->SetValue_psz(tdbp->Direc); break;
- case 2: Value->SetValue_psz(tdbp->Fname); break;
- case 3: Value->SetValue_psz(tdbp->Ftype); break;
-#if defined(WIN32)
- case 4: Value->SetValue((int)tdbp->FileData.attrib); break;
- case 5: Value->SetValue((int)tdbp->FileData.size); break;
- case 6: Value->SetValue((int)tdbp->FileData.time_write); break;
- case 7: Value->SetValue((int)tdbp->FileData.time_create); break;
- case 8: Value->SetValue((int)tdbp->FileData.time_access); break;
-#else // !WIN32
- case 4: Value->SetValue((int)tdbp->Fileinfo.st_mode); break;
- case 5: Value->SetValue((int)tdbp->Fileinfo.st_size); break;
- case 6: Value->SetValue((int)tdbp->Fileinfo.st_mtime); break;
- case 7: Value->SetValue((int)tdbp->Fileinfo.st_ctime); break;
- case 8: Value->SetValue((int)tdbp->Fileinfo.st_atime); break;
- case 9: Value->SetValue((int)tdbp->Fileinfo.st_uid); break;
- case 10: Value->SetValue((int)tdbp->Fileinfo.st_gid); break;
-#endif // !WIN32
- default:
- sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
- longjmp(g->jumper[g->jump_level], GetAmType());
- } // endswitch N
-
- } // end of ReadColumn
-
-/* ------------------------- Class TDBSDR ---------------------------- */
-
-/***********************************************************************/
-/* TABSDR copy constructors. */
-/***********************************************************************/
-TDBSDR::TDBSDR(PTDBSDR tdbp) : TDBDIR(tdbp)
- {
- Sub = tdbp->Sub;
- } // end of TDBSDR copy constructor
-
-// Method
-PTDB TDBSDR::CopyOne(PTABS t)
- {
- PTDB tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBSDR(this);
- tp->SetColumns(Columns);
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* SDR GetMaxSize: returns the number of retrieved files. */
-/***********************************************************************/
-int TDBSDR::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0) {
- Path(g);
- MaxSize = FindInDir(g);
- } // endif MaxSize
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* SDR GetMaxSize: returns the number of retrieved files. */
-/***********************************************************************/
-int TDBSDR::FindInDir(PGLOBAL g)
- {
- int n = 0;
- size_t m = strlen(Direc);
-
- // Start searching files in the target directory.
-#if defined(WIN32)
- int h = _findfirst(Path(g), &FileData);
-
- if (h != -1) {
- for (n = 1;; n++)
- if (_findnext(h, &FileData))
- break;
-
- // Close the search handle.
- _findclose(h);
- } // endif h
-
- // Now search files in sub-directories.
- _makepath(Fpath, Drive, Direc, "*", "");
- h = _findfirst(Fpath, &FileData);
-
- if (h != -1) {
- while (true) {
- if (FileData.attrib & _A_SUBDIR && *FileData.name != '.') {
- // Look in the name sub-directory
- strcat(strcat(Direc, FileData.name), "\\");
- n += FindInDir(g);
- Direc[m] = '\0'; // Restore path
- } // endif SUBDIR
-
- if (_findnext(h, &FileData))
- break;
-
- } // endwhile
-
- // Close the search handle.
- _findclose(h);
- } // endif h
-#else // !WIN32
- int k;
- DIR *dir = opendir(Direc);
-
- if (!dir) {
- sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
- return -1;
- } // endif dir
-
- while ((Entry = readdir(dir))) {
- strcat(strcpy(Fpath, Direc), Entry->d_name);
-
- if (lstat(Fpath, &Fileinfo) < 0) {
- sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
- return -1;
- } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
- // Look in the name sub-directory
- strcat(strcat(Direc, Entry->d_name), "/");
-
- if ((k = FindInDir(g)) < 0)
- return k;
- else
- n += k;
-
- Direc[m] = '\0'; // Restore path
- } else if (S_ISREG(Fileinfo.st_mode))
- // Test whether the file name matches the table name filter
- if (!fnmatch(Pattern, Entry->d_name, 0))
- n++; // We have a match
-
- } // endwhile readdir
-
- // Close the DIR handle.
- closedir(dir);
-#endif // !WIN32
-
- return n;
- } // end of FindInDir
-
-/***********************************************************************/
-/* DIR Access Method opening routine. */
-/* Open first file, other will be opened sequencially when reading. */
-/***********************************************************************/
-bool TDBSDR::OpenDB(PGLOBAL g)
- {
- if (!Sub) {
- Path(g);
- Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
- Sub->Next = NULL;
- Sub->Prev = NULL;
-#if defined(WIN32)
- Sub->H = -1;
- Sub->Len = strlen(Direc);
-#else // !WIN32
- Sub->D = NULL;
- Sub->Len = 0;
-#endif // !WIN32
- } // endif To_Sub
-
- return TDBDIR::OpenDB(g);
- } // end of OpenDB
-
-/***********************************************************************/
-/* Data Base read routine for SDR access method. */
-/***********************************************************************/
-int TDBSDR::ReadDB(PGLOBAL g)
- {
- int rc;
-
-#if defined(WIN32)
- again:
- rc = TDBDIR::ReadDB(g);
-
- if (rc == RC_EF) {
- // Are there more files in sub-directories
- retry:
- do {
- if (Sub->H == -1) {
- _makepath(Fpath, Drive, Direc, "*", "");
- Sub->H = _findfirst(Fpath, &FileData);
- } else if (_findnext(Sub->H, &FileData)) {
- _findclose(Sub->H);
- Sub->H = -1;
- *FileData.name = '\0';
- } // endif findnext
-
- } while(*FileData.name == '.');
-
- if (Sub->H == -1) {
- // No more sub-directories. Are we in a sub-directory?
- if (!Sub->Prev)
- return rc; // No, all is finished
-
- // here we must continue in the parent directory
- Sub = Sub->Prev;
- goto retry;
- } else {
- // Search next sub-directory
- Direc[Sub->Len] = '\0';
-
- if (!Sub->Next) {
- PSUBDIR sup;
-
- sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
- sup->Next = NULL;
- sup->Prev = Sub;
- sup->H = -1;
- Sub->Next = sup;
- } // endif Next
-
- Sub = Sub->Next;
- strcat(strcat(Direc, FileData.name), "\\");
- Sub->Len = strlen(Direc);
-
- // Reset Hsearch used by TDBDIR::ReadDB
- _findclose(Hsearch);
- Hsearch = -1;
- goto again;
- } // endif H
-
- } // endif rc
-#else // !WIN32
- rc = RC_NF;
-
- again:
- if (!Sub->D)
- // Start searching files in the target directory.
- if (!(Sub->D = opendir(Direc))) {
- sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
- rc = RC_FX;
- } // endif dir
-
- while (rc == RC_NF)
- if ((Entry = readdir(Sub->D))) {
- // We need the Fileinfo structure to get info about the file
- strcat(strcpy(Fpath, Direc), Entry->d_name);
-
- if (lstat(Fpath, &Fileinfo) < 0) {
- sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
- rc = RC_FX;
- } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
- // Look in the name sub-directory
- if (!Sub->Next) {
- PSUBDIR sup;
-
- sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
- sup->Next = NULL;
- sup->Prev = Sub;
- Sub->Next = sup;
- } // endif Next
-
- Sub = Sub->Next;
- Sub->D = NULL;
- Sub->Len = strlen(Direc);
- strcat(strcat(Direc, Entry->d_name), "/");
- goto again;
- } else if (S_ISREG(Fileinfo.st_mode))
- // Test whether the file name matches the table name filter
- if (!fnmatch(Pattern, Entry->d_name, 0)) {
- iFile++; // We have a match
- _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
- rc = RC_OK;
- } // endif fnmatch
-
- } else {
- // No more files. Close the DIR handle.
- closedir(Sub->D);
-
- // Are we in a sub-directory?
- if (Sub->Prev) {
- // Yes, we must continue in the parent directory
- Direc[Sub->Len] = '\0';
- Sub = Sub->Prev;
- } else
- rc = RC_EF; // No, all is finished
-
- } // endif Entry
-
-#endif // !WIN32
-
- return rc;
- } // end of ReadDB
-
-#if 0
-/* ------------------------- Class TDBDHR ---------------------------- */
-
-/***********************************************************************/
-/* TABDHR constructors. */
-/***********************************************************************/
-TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
- {
- memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
- Hsearch = INVALID_HANDLE_VALUE;
- iFile = 0;
- *Drive = '\0';
- *Direc = '\0';
- *Fname = '\0';
- *Ftype = '\0';
- } // end of TDBDHR standard constructor
-
-TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
- {
- FileData = tdbp->FileData;
- Hsearch = tdbp->Hsearch;
- iFile = tdbp->iFile;
- strcpy(Drive, tdbp->Drive);
- strcpy(Direc, tdbp->Direc);
- strcpy(Fname, tdbp->Fname);
- strcpy(Ftype, tdbp->Ftype);
- } // end of TDBDHR copy constructor
-
-// Method
-PTDB TDBDHR::CopyOne(PTABS t)
- {
- PTDB tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBDHR(this);
- tp->Columns = Columns;
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Allocate DHR column description block. */
-/***********************************************************************/
-PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- return new(g) DHRCOL(cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* DHR GetMaxSize: returns the number of retrieved files. */
-/***********************************************************************/
-int TDBDHR::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0) {
- char filename[_MAX_PATH];
- int i, rc;
- int n = -1;
- HANDLE h;
- PDBUSER dup = PlgGetUser(g);
-
- PlugSetPath(filename, To_File, dup->Path);
-
- // Start searching files in the target directory.
- h = FindFirstFile(filename, &FileData);
-
- if (h == INVALID_HANDLE_VALUE) {
- switch (rc = GetLastError()) {
- case ERROR_NO_MORE_FILES:
- case ERROR_FILE_NOT_FOUND:
- n = 0;
- break;
- default:
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, rc, 0,
- (LPTSTR)&filename, sizeof(filename), NULL);
- sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
- } // endswitch rc
-
- } else {
- for (n = 1;; n++)
- if (!FindNextFile(h, &FileData)) {
- rc = GetLastError();
-
- if (rc != ERROR_NO_MORE_FILES) {
- sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
- n = -1;
- } // endif rc
-
- break;
- } // endif FindNextFile
-
- // Close the search handle.
- if (!FindClose(h) && n != -1)
- strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
-
- } // endif Hsearch
-
- MaxSize = n;
- } // endif MaxSize
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* DHR Access Method opening routine. */
-/* Open first file, other will be opened sequencially when reading. */
-/***********************************************************************/
-bool TDBDHR::OpenDB(PGLOBAL g)
- {
-#ifdef DEBTRACE
- htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
- this, Tdb_No, Use, Mode);
-#endif
-
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open, reopen it. */
- /*******************************************************************/
- CloseDB(g);
- SetUse(USE_READY);
- } // endif use
-
- /*********************************************************************/
- /* Direct access needed for join or sorting. */
- /*********************************************************************/
- if (NeedIndexing(g)) {
- // Direct access of DHR tables is not implemented yet
- sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
- return true;
- } // endif NeedIndexing
-
- Use = USE_OPEN;
- return false;
- } // end of OpenDB
-
-/***********************************************************************/
-/* Data Base read routine for DHR access method. */
-/***********************************************************************/
-int TDBDHR::ReadDB(PGLOBAL g)
- {
- int rc = RC_OK;
- DWORD erc;
-
- if (Hsearch == INVALID_HANDLE_VALUE) {
- char *filename[_MAX_PATH];
- PDBUSER dup = PlgGetUser(g);
-
- PlugSetPath(filename, To_File, dup->Path);
- _splitpath(filename, Drive, Direc, NULL, NULL);
-
- /*******************************************************************/
- /* Start searching files in the target directory. */
- /*******************************************************************/
- Hsearch = FindFirstFile(filename, &FileData);
-
- if (Hsearch != INVALID_HANDLE_VALUE)
- iFile = 1;
- else switch (erc = GetLastError()) {
- case ERROR_NO_MORE_FILES:
- case ERROR_FILE_NOT_FOUND:
-// case ERROR_PATH_NOT_FOUND: ???????
- rc = RC_EF;
- break;
- default:
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, erc, 0,
- (LPTSTR)&filename, sizeof(filename), NULL);
- sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
- rc = RC_FX;
- } // endswitch erc
-
- } else {
- if (!FindNextFile(Hsearch, &FileData)) {
- DWORD erc = GetLastError();
-
- if (erc != ERROR_NO_MORE_FILES) {
- sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
- FindClose(Hsearch);
- rc = RC_FX;
- } else
- rc = RC_EF;
-
- } else
- iFile++;
-
- } // endif Hsearch
-
- if (rc == RC_OK)
- _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
-
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* Data Base close routine for MUL access method. */
-/***********************************************************************/
-void TDBDHR::CloseDB(PGLOBAL g)
- {
- // Close the search handle.
- if (!FindClose(Hsearch)) {
- strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
- longjmp(g->jumper[g->jump_level], GetAmType());
- } // endif FindClose
-
- iFile = 0;
- Hsearch = INVALID_HANDLE_VALUE;
- } // end of CloseDB
-
-// ------------------------ DHRCOL functions ----------------------------
-
-/***********************************************************************/
-/* DHRCOL public constructor. */
-/***********************************************************************/
-DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
- : COLBLK(cdp, tdbp, i)
- {
- if (cprec) {
- Next = cprec->GetNext();
- cprec->SetNext(this);
- } else {
- Next = tdbp->GetColumns();
- tdbp->SetColumns(this);
- } // endif cprec
-
- // Set additional DHR access method information for column.
- N = cdp->GetOffset();
- } // end of DOSCOL constructor
-
-/***********************************************************************/
-/* DHRCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- N = col1->N;
- } // end of DHRCOL copy constructor
-
-/***********************************************************************/
-/* ReadColumn: what this routine does is to access the information */
-/* corresponding to this column and convert it to buffer type. */
-/***********************************************************************/
-void DHRCOL::ReadColumn(PGLOBAL g)
- {
- int rc;
- PTDBDHR tdbp = (PTDBDHR)To_Tdb;
-
-#ifdef DEBTRACE
- fprintf(debug,
- "DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
- Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
-#endif
-
- /*********************************************************************/
- /* Retrieve the information corresponding to the column number. */
- /*********************************************************************/
- switch (N) {
- case 0: // Drive
- Value->SetValue(Drive, _MAX_DRIVE);
- break;
- case 1: // Path
- Value->SetValue(Direc, _MAX_DHR);
- break;
- case 2: // Name
- Value->SetValue(Fname, _MAX_FNAME);
- break;
- case 3: // Extention
- Value->SetValue(Ftype, _MAX_EXT);
- break;
- case 4: // Extention
- Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
- break;
- case 5:
- Value->SetValue(tdbp->FileData.dwFileAttributes);
- break;
- case 6:
- Value->SetValue(..................
- } // end of ReadColumn
-#endif // 0
-
+/************* TabMul C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABMUL */
+/* ------------- */
+/* Version 1.7 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to PlugDB Software Development 2003 - 2012 */
+/* Author: Olivier BERTRAND */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TDBMUL class DB routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABMUL.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABDOS.H - TABDOS classes declaration file */
+/* TABMUL.H - TABFIX classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(WIN32)
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+#else
+//#include <io.h>
+#endif
+//#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h" // global declarations
+#include "plgdbsem.h" // DB application declarations
+#include "reldef.h" // DB definition declares
+#include "filamtxt.h"
+#include "tabdos.h" // TDBDOS and DOSCOL class dcls
+#include "tabmul.h" // TDBMUL and MULCOL classes dcls
+
+/* ------------------------- Class TDBMUL ---------------------------- */
+
+/***********************************************************************/
+/* TABMUL constructors. */
+/***********************************************************************/
+TDBMUL::TDBMUL(PTDBASE tdbp) : TDBASE(tdbp->GetDef())
+ {
+ Tdbp = tdbp;
+ Filenames = NULL;
+ Rows = 0;
+ Mul = tdbp->GetDef()->GetMultiple();
+ NumFiles = 0;
+ iFile = 0;
+ } // end of TDBMUL standard constructor
+
+TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp)
+ {
+ Tdbp = tdbp->Tdbp;
+ Filenames = tdbp->Filenames;
+ Rows = tdbp->Rows;
+ Mul = tdbp->Mul;
+ NumFiles = tdbp->NumFiles;
+ iFile = tdbp->iFile;
+ } // end of TDBMUL copy constructor
+
+// Method
+PTDB TDBMUL::CopyOne(PTABS t)
+ {
+ PTDBMUL tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBMUL(this);
+ tp->Tdbp = (PTDBASE)Tdbp->CopyOne(t);
+ tp->Columns = tp->Tdbp->GetColumns();
+ return tp;
+ } // end of CopyOne
+
+PTDB TDBMUL::Duplicate(PGLOBAL g)
+ {
+ PTDBMUL tmup = new(g) TDBMUL(this);
+
+ tmup->Tdbp = (PTDBASE)Tdbp->Duplicate(g);
+ return tmup;
+ } // end of Duplicate
+
+/***********************************************************************/
+/* Initializes the table filename list. */
+/* Note: tables created by concatenating the file components without */
+/* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
+/* have a LRECL that is the sum of the lengths of all components. */
+/* This is why we use a big filename array to take care of that. */
+/***********************************************************************/
+bool TDBMUL::InitFileNames(PGLOBAL g)
+ {
+#define PFNZ 8192
+ char *pfn[PFNZ], filename[_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT];
+ int rc, n = 0;
+
+ // The sub table may need to refer to the Table original block
+ Tdbp->SetTable(To_Table); // Was not set at construction
+
+ PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
+
+ if (Mul == 1) {
+ /*******************************************************************/
+ /* To_File is a multiple name with special characters */
+ /*******************************************************************/
+#if defined(WIN32)
+ char drive[_MAX_DRIVE], direc[_MAX_DIR];
+ WIN32_FIND_DATA FileData;
+ HANDLE hSearch;
+
+ _splitpath(filename, drive, direc, NULL, NULL);
+
+ // Start searching files in the target directory.
+ hSearch = FindFirstFile(filename, &FileData);
+
+ if (hSearch == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+
+ if (rc != ERROR_FILE_NOT_FOUND) {
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0,
+ (LPTSTR)&filename, sizeof(filename), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
+ return true;
+ } // endif rc
+
+ goto suite;
+ } // endif hSearch
+
+ while (n < PFNZ) {
+ strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName);
+ pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
+ strcpy(pfn[n++], filename);
+
+ if (!FindNextFile(hSearch, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ FindClose(hSearch);
+ return true;
+ } // endif rc
+
+ break;
+ } // endif FindNextFile
+
+ } // endwhile n
+
+ // Close the search handle.
+ if (!FindClose(hSearch)) {
+ strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
+ return true;
+ } // endif FindClose
+
+#else // !WIN32
+ struct stat fileinfo;
+ char fn[PATH_MAX], direc[PATH_MAX], pattern[256], ftype[8];
+ DIR *dir;
+ struct dirent *entry;
+
+ _splitpath(filename, NULL, direc, pattern, ftype);
+ strcat(pattern, ftype);
+
+ // Start searching files in the target directory.
+ if (!(dir = opendir(direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno));
+ return true;
+ } // endif dir
+
+ while ((entry = readdir(dir)) && n < PFNZ) {
+ strcat(strcpy(fn, direc), entry->d_name);
+
+ if (lstat(fn, &fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", fn, strerror(errno));
+ return true;
+ } else if (!S_ISREG(fileinfo.st_mode))
+ continue; // Not a regular file (should test for links)
+
+ /*******************************************************************/
+ /* Test whether the file name matches the table name filter. */
+ /*******************************************************************/
+ if (fnmatch(pattern, entry->d_name, 0))
+ continue; // Not a match
+
+ strcat(strcpy(filename, direc), entry->d_name);
+ pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
+ strcpy(pfn[n++], filename);
+ } // endwhile readdir
+
+ // Close the dir handle.
+ closedir(dir);
+#endif // !WIN32
+
+ } else {
+ /*******************************************************************/
+ /* To_File is the name of a file containing the file name list */
+ /*******************************************************************/
+ char *p;
+ FILE *stream;
+
+ if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r")))
+ return true;
+
+ while (n < PFNZ) {
+ if (!fgets(filename, sizeof(filename), stream)) {
+ fclose(stream);
+ break;
+ } // endif fgets
+
+ p = filename + strlen(filename) - 1;
+
+#if defined(UNIX)
+ // Data files can be imported from Windows (having CRLF)
+ if (*p == '\n' || *p == '\r') {
+ // is this enough for Unix ???
+ *p--; // Eliminate ending CR or LF character
+
+ if (p >= filename)
+ // is this enough for Unix ???
+ if (*p == '\n' || *p == '\r')
+ *p--; // Eliminate ending CR or LF character
+
+ } // endif p
+
+#else
+ if (*p == '\n')
+ p--; // Eliminate ending new-line character
+#endif
+ // Trim rightmost blanks
+ for (; p >= filename && *p == ' '; p--) ;
+
+ *(++p) = '\0';
+
+ // Suballocate the file name
+ pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
+ strcpy(pfn[n++], filename);
+ } // endfor n
+
+ } // endif Mul
+
+ suite:
+ if (n) {
+ Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
+
+ for (int i = 0; i < n; i++)
+ Filenames[i] = pfn[i];
+
+ } else {
+ Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
+ Filenames[0] = NULL;
+ } // endif n
+
+ NumFiles = n;
+ return false;
+ } // end of InitFileNames
+
+/***********************************************************************/
+/* The table column list is the sub-table column list. */
+/***********************************************************************/
+PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num)
+ {
+ PCOL cp;
+
+ /*********************************************************************/
+ /* Because special columns are directly added to the MUL block, */
+ /* make sure that the sub-table has the same column list, before */
+ /* and after the call to the ColDB function. */
+ /*********************************************************************/
+ Tdbp->SetColumns(Columns);
+ cp = Tdbp->ColDB(g, name, num);
+ Columns = Tdbp->GetColumns();
+ return cp;
+} // end of ColDB
+
+/***********************************************************************/
+/* MUL GetProgMax: get the max value for progress information. */
+/***********************************************************************/
+int TDBMUL::GetProgMax(PGLOBAL g)
+ {
+ if (!Filenames && InitFileNames(g))
+ return -1;
+
+ return NumFiles; // This is a temporary setting
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* MUL GetProgCur: get the current value for progress information. */
+/***********************************************************************/
+int TDBMUL::GetProgCur(void)
+ {
+ return iFile; // This is a temporary setting
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* MUL Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/* Can be used on Multiple FIX table only. */
+/***********************************************************************/
+int TDBMUL::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return Tdbp->Cardinality(g);
+
+ if (!Filenames && InitFileNames(g))
+ return -1;
+
+ int n, card = 0;
+
+ for (int i = 0; i < NumFiles; i++) {
+ Tdbp->SetFile(g, Filenames[i]);
+ Tdbp->ResetSize();
+
+ if ((n = Tdbp->Cardinality(g)) < 0) {
+// strcpy(g->Message, MSG(BAD_CARDINALITY));
+ return -1;
+ } // endif n
+
+ card += n;
+ } // endfor i
+
+ return card;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Sum up the sizes of all sub-tables. */
+/***********************************************************************/
+int TDBMUL::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ int i;
+ int mxsz;
+
+ if (!Filenames && InitFileNames(g))
+ return -1;
+
+ if (Use == USE_OPEN) {
+ strcpy(g->Message, MSG(MAXSIZE_ERROR));
+ return -1;
+ } else
+ MaxSize = 0;
+
+ for (i = 0; i < NumFiles; i++) {
+ Tdbp->SetFile(g, Filenames[i]);
+ Tdbp->ResetSize();
+
+ if ((mxsz = Tdbp->GetMaxSize(g)) < 0) {
+ MaxSize = -1;
+ return mxsz;
+ } // endif mxsz
+
+ MaxSize += mxsz;
+ } // endfor i
+
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void TDBMUL::ResetDB(void)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_FILID)
+ colp->COLBLK::Reset();
+
+ Tdbp->ResetDB();
+ } // end of ResetDB
+
+/***********************************************************************/
+/* Returns RowId if b is false or Rownum if b is true. */
+/***********************************************************************/
+int TDBMUL::RowNumber(PGLOBAL g, bool b)
+ {
+ return ((b) ? 0 : Rows)
+ + ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* MUL Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBMUL::OpenDB(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ htrc("MUL 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, replace it at its beginning. */
+ /*******************************************************************/
+ if (Filenames[iFile = 0]) {
+ Tdbp->CloseDB(g);
+ Tdbp->SetUse(USE_READY);
+ Tdbp->SetFile(g, Filenames[iFile = 0]);
+ Tdbp->ResetSize();
+ Rows = 0;
+ ResetDB();
+ return Tdbp->OpenDB(g); // Re-open with new file name
+ } else
+ return false;
+
+ } // endif use
+
+ /*********************************************************************/
+ /* We need to calculate MaxSize before opening the query. */
+ /*********************************************************************/
+ if (GetMaxSize(g) < 0)
+ return true;
+
+ /*********************************************************************/
+ /* Open the first table file of the list. */
+ /*********************************************************************/
+//if (!Filenames && InitFileNames(g)) done in GetMaxSize
+// return true;
+
+ if (Filenames[iFile = 0]) {
+ Tdbp->SetFile(g, Filenames[0]);
+ Tdbp->SetMode(Mode);
+ Tdbp->ResetDB();
+ Tdbp->ResetSize();
+
+ if (Tdbp->OpenDB(g))
+ return true;
+
+ } // endif *Filenames
+
+ Use = USE_OPEN;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for MUL access method. */
+/***********************************************************************/
+int TDBMUL::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (NumFiles == 0)
+ return RC_EF;
+ else if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ strcpy(g->Message, MSG(NO_INDEX_READ));
+ rc = RC_FX;
+ } else {
+ /*******************************************************************/
+ /* Now start the reading process. */
+ /*******************************************************************/
+ retry:
+ rc = Tdbp->ReadDB(g);
+
+ if (rc == RC_EF) {
+ if (Tdbp->GetDef()->GetPseudo() & 1)
+ // Total number of rows met so far
+ Rows += Tdbp->RowNumber(g) - 1;
+
+ if (++iFile < NumFiles) {
+ /***************************************************************/
+ /* Continue reading from next table file. */
+ /***************************************************************/
+ Tdbp->CloseDB(g);
+ Tdbp->SetUse(USE_READY);
+ Tdbp->SetFile(g, Filenames[iFile]);
+ Tdbp->ResetSize();
+ ResetDB();
+
+ if (Tdbp->OpenDB(g)) // Re-open with new file name
+ return RC_FX;
+
+ goto retry;
+ } // endif iFile
+
+ } else if (rc == RC_FX)
+ strcat(strcat(strcat(g->Message, " ("), Tdbp->GetFile(g)), ")");
+
+ } // endif To_Kindex
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Data Base write routine for MUL access method. */
+/***********************************************************************/
+int TDBMUL::WriteDB(PGLOBAL g)
+ {
+ return Tdbp->WriteDB(g);
+// strcpy(g->Message, MSG(TABMUL_READONLY));
+// return RC_FX; // NIY
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for MUL access method. */
+/***********************************************************************/
+int TDBMUL::DeleteDB(PGLOBAL g, int irc)
+ {
+ // When implementing DELETE_MODE InitFileNames must be updated to
+ // eliminate CRLF under Windows if the file is read in binary.
+ strcpy(g->Message, MSG(TABMUL_READONLY));
+ return RC_FX; // NIY
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for MUL access method. */
+/***********************************************************************/
+void TDBMUL::CloseDB(PGLOBAL g)
+ {
+ if (NumFiles > 0) {
+ Tdbp->CloseDB(g);
+ iFile = NumFiles;
+ } // endif NumFiles
+
+ } // end of CloseDB
+
+/* --------------------------- Class DIRDEF -------------------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ Desc = Fn = Cat->GetStringCatInfo(g, Name, "Filename", "");
+ Incl = (Cat->GetIntCatInfo(Name, "Subdir", 0) != 0);
+ Huge = (Cat->GetIntCatInfo(Name, "Huge", 0) != 0);
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB DIRDEF::GetTable(PGLOBAL g, MODE m)
+ {
+#if 0
+ if (Huge)
+ return new(g) TDBDHR(this); // Not implemented yet
+ else
+#endif
+ if (Incl)
+ return new(g) TDBSDR(this); // Including sub-directory files
+ else
+ return new(g) TDBDIR(this); // Not Including sub-directory files
+
+ } // end of GetTable
+
+/* ------------------------- Class TDBDIR ---------------------------- */
+
+/***********************************************************************/
+/* TABDIR constructors. */
+/***********************************************************************/
+TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
+ {
+ To_File = tdp->Fn;
+ iFile = 0;
+#if defined(WIN32)
+ memset(&FileData, 0, sizeof(_finddata_t));
+ Hsearch = -1;
+ *Drive = '\0';
+#else // !WIN32
+ memset(&Fileinfo, 0, sizeof(struct stat));
+ Entry = NULL;
+ Dir = NULL;
+ Done = false;
+ *Pattern = '\0';
+#endif // !WIN32
+ *Fpath = '\0';
+ *Direc = '\0';
+ *Fname = '\0';
+ *Ftype = '\0';
+ } // end of TDBDIR standard constructor
+
+TDBDIR::TDBDIR(PTDBDIR tdbp) : TDBASE(tdbp)
+ {
+ To_File = tdbp->To_File;
+ iFile = tdbp->iFile;
+#if defined(WIN32)
+ FileData = tdbp->FileData;
+ Hsearch = tdbp->Hsearch;
+ strcpy(Drive, tdbp->Drive);
+#else // !WIN32
+ Fileinfo = tdbp->Fileinfo;
+ Entry = tdbp->Entry;
+ Dir = tdbp->Dir;
+ Done = tdbp->Done;
+ strcpy(Pattern, tdbp->Pattern);
+#endif // !WIN32
+ strcpy(Direc, tdbp->Direc);
+ strcpy(Fname, tdbp->Fname);
+ strcpy(Ftype, tdbp->Ftype);
+ } // end of TDBDIR copy constructor
+
+// Method
+PTDB TDBDIR::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBDIR(this);
+ tp->SetColumns(Columns);
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Initialize/get the components of the search file pattern. */
+/***********************************************************************/
+char* TDBDIR::Path(PGLOBAL g)
+ {
+ PCATLG cat = PlgGetCatalog(g);
+
+#if defined(WIN32)
+ if (!*Drive) {
+ PlugSetPath(Fpath, To_File, cat->GetDataPath());
+ _splitpath(Fpath, Drive, Direc, Fname, Ftype);
+ } else
+ _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull ???
+
+ return Fpath;
+#else // !WIN32
+ if (!Done) {
+ PlugSetPath(Fpath, To_File, cat->GetDataPath());
+ _splitpath(Fpath, NULL, Direc, Fname, Ftype);
+ strcat(strcpy(Pattern, Fname), Ftype);
+ Done = true;
+ } // endif Done
+
+ return Pattern;
+#endif // !WIN32
+ } // end of Path
+
+/***********************************************************************/
+/* Allocate DIR column description block. */
+/***********************************************************************/
+PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) DIRCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* DIR GetMaxSize: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBDIR::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ int n = -1;
+#if defined(WIN32)
+ int h;
+
+ // Start searching files in the target directory.
+ h = _findfirst(Path(g), &FileData);
+
+ if (h != -1) {
+ for (n = 1;; n++)
+ if (_findnext(h, &FileData))
+ break;
+
+ // Close the search handle.
+ _findclose(h);
+ } else
+ n = 0;
+
+#else // !WIN32
+ Path(g);
+
+ // Start searching files in the target directory.
+ if (!(Dir = opendir(Direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ return -1;
+ } // endif dir
+
+ while ((Entry = readdir(Dir))) {
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ return -1;
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0))
+ n++; // We have a match
+
+ } // endwhile Entry
+
+ // Close the DIR handle.
+ closedir(Dir);
+#endif // !WIN32
+ MaxSize = n;
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* DIR Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBDIR::OpenDB(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+#endif
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, reopen it. */
+ /*******************************************************************/
+ CloseDB(g);
+ SetUse(USE_READY);
+ } // endif use
+
+ Use = USE_OPEN;
+#if !defined(WIN32)
+ Path(g); // Be sure it is done
+ Dir = NULL; // For ReadDB
+#endif // !WIN32
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for DIR access method. */
+/***********************************************************************/
+int TDBDIR::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+
+#if defined(WIN32)
+ if (Hsearch == -1) {
+ /*******************************************************************/
+ /* Start searching files in the target directory. The use of the */
+ /* Path function is required when called from TDBSDR. */
+ /*******************************************************************/
+ Hsearch = _findfirst(Path(g), &FileData);
+
+ if (Hsearch == -1)
+ rc = RC_EF;
+ else
+ iFile++;
+
+ } else {
+ if (_findnext(Hsearch, &FileData)) {
+ // Restore file name and type pattern
+ _splitpath(To_File, NULL, NULL, Fname, Ftype);
+ rc = RC_EF;
+ } else
+ iFile++;
+
+ } // endif Hsearch
+
+ if (rc == RC_OK)
+ _splitpath(FileData.name, NULL, NULL, Fname, Ftype);
+
+#else // !Win32
+ rc = RC_NF;
+
+ if (!Dir)
+ // Start searching files in the target directory.
+ if (!(Dir = opendir(Direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ rc = RC_FX;
+ } // endif dir
+
+ while (rc == RC_NF)
+ if ((Entry = readdir(Dir))) {
+ // We need the Fileinfo structure to get info about the file
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ rc = RC_FX;
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0)) {
+ iFile++; // We have a match
+ _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
+ rc = RC_OK;
+ } // endif fnmatch
+
+ } else {
+ // Restore file name and type pattern
+ _splitpath(To_File, NULL, NULL, Fname, Ftype);
+ rc = RC_EF;
+ } // endif Entry
+
+#endif // !WIN32
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Data Base write routine for DIR access method. */
+/***********************************************************************/
+int TDBDIR::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, MSG(TABDIR_READONLY));
+ return RC_FX; // NIY
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for DIR access method. */
+/***********************************************************************/
+int TDBDIR::DeleteDB(PGLOBAL g, int irc)
+ {
+ strcpy(g->Message, MSG(TABDIR_READONLY));
+ return RC_FX; // NIY
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for MUL access method. */
+/***********************************************************************/
+void TDBDIR::CloseDB(PGLOBAL g)
+ {
+#if defined(WIN32)
+ // Close the search handle.
+ _findclose(Hsearch);
+ Hsearch = -1;
+#else // !WIN32
+ // Close the DIR handle.
+ closedir(Dir);
+ Dir = NULL;
+#endif // !WIN32
+ iFile = 0;
+ } // end of CloseDB
+
+// ------------------------ DIRCOL functions ----------------------------
+
+/***********************************************************************/
+/* DIRCOL public constructor. */
+/***********************************************************************/
+DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional DIR access method information for column.
+ N = cdp->GetOffset();
+ } // end of DIRCOL constructor
+
+/***********************************************************************/
+/* DIRCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ N = col1->N;
+ } // end of DIRCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the information */
+/* corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void DIRCOL::ReadColumn(PGLOBAL g)
+ {
+ PTDBDIR tdbp = (PTDBDIR)To_Tdb;
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ "DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
+#endif
+
+ /*********************************************************************/
+ /* Retrieve the information corresponding to the column number. */
+ /*********************************************************************/
+ switch (N) {
+#if defined(WIN32)
+ case 0: Value->SetValue_psz(tdbp->Drive); break;
+#endif // WIN32
+ case 1: Value->SetValue_psz(tdbp->Direc); break;
+ case 2: Value->SetValue_psz(tdbp->Fname); break;
+ case 3: Value->SetValue_psz(tdbp->Ftype); break;
+#if defined(WIN32)
+ case 4: Value->SetValue((int)tdbp->FileData.attrib); break;
+ case 5: Value->SetValue((int)tdbp->FileData.size); break;
+ case 6: Value->SetValue((int)tdbp->FileData.time_write); break;
+ case 7: Value->SetValue((int)tdbp->FileData.time_create); break;
+ case 8: Value->SetValue((int)tdbp->FileData.time_access); break;
+#else // !WIN32
+ case 4: Value->SetValue((int)tdbp->Fileinfo.st_mode); break;
+ case 5: Value->SetValue((int)tdbp->Fileinfo.st_size); break;
+ case 6: Value->SetValue((int)tdbp->Fileinfo.st_mtime); break;
+ case 7: Value->SetValue((int)tdbp->Fileinfo.st_ctime); break;
+ case 8: Value->SetValue((int)tdbp->Fileinfo.st_atime); break;
+ case 9: Value->SetValue((int)tdbp->Fileinfo.st_uid); break;
+ case 10: Value->SetValue((int)tdbp->Fileinfo.st_gid); break;
+#endif // !WIN32
+ default:
+ sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
+ longjmp(g->jumper[g->jump_level], GetAmType());
+ } // endswitch N
+
+ } // end of ReadColumn
+
+/* ------------------------- Class TDBSDR ---------------------------- */
+
+/***********************************************************************/
+/* TABSDR copy constructors. */
+/***********************************************************************/
+TDBSDR::TDBSDR(PTDBSDR tdbp) : TDBDIR(tdbp)
+ {
+ Sub = tdbp->Sub;
+ } // end of TDBSDR copy constructor
+
+// Method
+PTDB TDBSDR::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBSDR(this);
+ tp->SetColumns(Columns);
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* SDR GetMaxSize: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBSDR::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ Path(g);
+ MaxSize = FindInDir(g);
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* SDR GetMaxSize: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBSDR::FindInDir(PGLOBAL g)
+ {
+ int n = 0;
+ size_t m = strlen(Direc);
+
+ // Start searching files in the target directory.
+#if defined(WIN32)
+ int h = _findfirst(Path(g), &FileData);
+
+ if (h != -1) {
+ for (n = 1;; n++)
+ if (_findnext(h, &FileData))
+ break;
+
+ // Close the search handle.
+ _findclose(h);
+ } // endif h
+
+ // Now search files in sub-directories.
+ _makepath(Fpath, Drive, Direc, "*", "");
+ h = _findfirst(Fpath, &FileData);
+
+ if (h != -1) {
+ while (true) {
+ if (FileData.attrib & _A_SUBDIR && *FileData.name != '.') {
+ // Look in the name sub-directory
+ strcat(strcat(Direc, FileData.name), "\\");
+ n += FindInDir(g);
+ Direc[m] = '\0'; // Restore path
+ } // endif SUBDIR
+
+ if (_findnext(h, &FileData))
+ break;
+
+ } // endwhile
+
+ // Close the search handle.
+ _findclose(h);
+ } // endif h
+#else // !WIN32
+ int k;
+ DIR *dir = opendir(Direc);
+
+ if (!dir) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ return -1;
+ } // endif dir
+
+ while ((Entry = readdir(dir))) {
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ return -1;
+ } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
+ // Look in the name sub-directory
+ strcat(strcat(Direc, Entry->d_name), "/");
+
+ if ((k = FindInDir(g)) < 0)
+ return k;
+ else
+ n += k;
+
+ Direc[m] = '\0'; // Restore path
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0))
+ n++; // We have a match
+
+ } // endwhile readdir
+
+ // Close the DIR handle.
+ closedir(dir);
+#endif // !WIN32
+
+ return n;
+ } // end of FindInDir
+
+/***********************************************************************/
+/* DIR Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBSDR::OpenDB(PGLOBAL g)
+ {
+ if (!Sub) {
+ Path(g);
+ Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
+ Sub->Next = NULL;
+ Sub->Prev = NULL;
+#if defined(WIN32)
+ Sub->H = -1;
+ Sub->Len = strlen(Direc);
+#else // !WIN32
+ Sub->D = NULL;
+ Sub->Len = 0;
+#endif // !WIN32
+ } // endif To_Sub
+
+ return TDBDIR::OpenDB(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for SDR access method. */
+/***********************************************************************/
+int TDBSDR::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+#if defined(WIN32)
+ again:
+ rc = TDBDIR::ReadDB(g);
+
+ if (rc == RC_EF) {
+ // Are there more files in sub-directories
+ retry:
+ do {
+ if (Sub->H == -1) {
+ _makepath(Fpath, Drive, Direc, "*", "");
+ Sub->H = _findfirst(Fpath, &FileData);
+ } else if (_findnext(Sub->H, &FileData)) {
+ _findclose(Sub->H);
+ Sub->H = -1;
+ *FileData.name = '\0';
+ } // endif findnext
+
+ } while(*FileData.name == '.');
+
+ if (Sub->H == -1) {
+ // No more sub-directories. Are we in a sub-directory?
+ if (!Sub->Prev)
+ return rc; // No, all is finished
+
+ // here we must continue in the parent directory
+ Sub = Sub->Prev;
+ goto retry;
+ } else {
+ // Search next sub-directory
+ Direc[Sub->Len] = '\0';
+
+ if (!Sub->Next) {
+ PSUBDIR sup;
+
+ sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
+ sup->Next = NULL;
+ sup->Prev = Sub;
+ sup->H = -1;
+ Sub->Next = sup;
+ } // endif Next
+
+ Sub = Sub->Next;
+ strcat(strcat(Direc, FileData.name), "\\");
+ Sub->Len = strlen(Direc);
+
+ // Reset Hsearch used by TDBDIR::ReadDB
+ _findclose(Hsearch);
+ Hsearch = -1;
+ goto again;
+ } // endif H
+
+ } // endif rc
+#else // !WIN32
+ rc = RC_NF;
+
+ again:
+ if (!Sub->D)
+ // Start searching files in the target directory.
+ if (!(Sub->D = opendir(Direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ rc = RC_FX;
+ } // endif dir
+
+ while (rc == RC_NF)
+ if ((Entry = readdir(Sub->D))) {
+ // We need the Fileinfo structure to get info about the file
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ rc = RC_FX;
+ } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
+ // Look in the name sub-directory
+ if (!Sub->Next) {
+ PSUBDIR sup;
+
+ sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
+ sup->Next = NULL;
+ sup->Prev = Sub;
+ Sub->Next = sup;
+ } // endif Next
+
+ Sub = Sub->Next;
+ Sub->D = NULL;
+ Sub->Len = strlen(Direc);
+ strcat(strcat(Direc, Entry->d_name), "/");
+ goto again;
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0)) {
+ iFile++; // We have a match
+ _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
+ rc = RC_OK;
+ } // endif fnmatch
+
+ } else {
+ // No more files. Close the DIR handle.
+ closedir(Sub->D);
+
+ // Are we in a sub-directory?
+ if (Sub->Prev) {
+ // Yes, we must continue in the parent directory
+ Direc[Sub->Len] = '\0';
+ Sub = Sub->Prev;
+ } else
+ rc = RC_EF; // No, all is finished
+
+ } // endif Entry
+
+#endif // !WIN32
+
+ return rc;
+ } // end of ReadDB
+
+#if 0
+/* ------------------------- Class TDBDHR ---------------------------- */
+
+/***********************************************************************/
+/* TABDHR constructors. */
+/***********************************************************************/
+TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
+ {
+ memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
+ Hsearch = INVALID_HANDLE_VALUE;
+ iFile = 0;
+ *Drive = '\0';
+ *Direc = '\0';
+ *Fname = '\0';
+ *Ftype = '\0';
+ } // end of TDBDHR standard constructor
+
+TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
+ {
+ FileData = tdbp->FileData;
+ Hsearch = tdbp->Hsearch;
+ iFile = tdbp->iFile;
+ strcpy(Drive, tdbp->Drive);
+ strcpy(Direc, tdbp->Direc);
+ strcpy(Fname, tdbp->Fname);
+ strcpy(Ftype, tdbp->Ftype);
+ } // end of TDBDHR copy constructor
+
+// Method
+PTDB TDBDHR::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBDHR(this);
+ tp->Columns = Columns;
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Allocate DHR column description block. */
+/***********************************************************************/
+PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) DHRCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* DHR GetMaxSize: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBDHR::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ char filename[_MAX_PATH];
+ int i, rc;
+ int n = -1;
+ HANDLE h;
+ PDBUSER dup = PlgGetUser(g);
+
+ PlugSetPath(filename, To_File, dup->Path);
+
+ // Start searching files in the target directory.
+ h = FindFirstFile(filename, &FileData);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ switch (rc = GetLastError()) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+ n = 0;
+ break;
+ default:
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, rc, 0,
+ (LPTSTR)&filename, sizeof(filename), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
+ } // endswitch rc
+
+ } else {
+ for (n = 1;; n++)
+ if (!FindNextFile(h, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ n = -1;
+ } // endif rc
+
+ break;
+ } // endif FindNextFile
+
+ // Close the search handle.
+ if (!FindClose(h) && n != -1)
+ strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
+
+ } // endif Hsearch
+
+ MaxSize = n;
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* DHR Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBDHR::OpenDB(PGLOBAL g)
+ {
+#ifdef DEBTRACE
+ htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+#endif
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, reopen it. */
+ /*******************************************************************/
+ CloseDB(g);
+ SetUse(USE_READY);
+ } // endif use
+
+ /*********************************************************************/
+ /* Direct access needed for join or sorting. */
+ /*********************************************************************/
+ if (NeedIndexing(g)) {
+ // Direct access of DHR tables is not implemented yet
+ sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
+ return true;
+ } // endif NeedIndexing
+
+ Use = USE_OPEN;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for DHR access method. */
+/***********************************************************************/
+int TDBDHR::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+ DWORD erc;
+
+ if (Hsearch == INVALID_HANDLE_VALUE) {
+ char *filename[_MAX_PATH];
+ PDBUSER dup = PlgGetUser(g);
+
+ PlugSetPath(filename, To_File, dup->Path);
+ _splitpath(filename, Drive, Direc, NULL, NULL);
+
+ /*******************************************************************/
+ /* Start searching files in the target directory. */
+ /*******************************************************************/
+ Hsearch = FindFirstFile(filename, &FileData);
+
+ if (Hsearch != INVALID_HANDLE_VALUE)
+ iFile = 1;
+ else switch (erc = GetLastError()) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+// case ERROR_PATH_NOT_FOUND: ???????
+ rc = RC_EF;
+ break;
+ default:
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, erc, 0,
+ (LPTSTR)&filename, sizeof(filename), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
+ rc = RC_FX;
+ } // endswitch erc
+
+ } else {
+ if (!FindNextFile(Hsearch, &FileData)) {
+ DWORD erc = GetLastError();
+
+ if (erc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
+ FindClose(Hsearch);
+ rc = RC_FX;
+ } else
+ rc = RC_EF;
+
+ } else
+ iFile++;
+
+ } // endif Hsearch
+
+ if (rc == RC_OK)
+ _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Data Base close routine for MUL access method. */
+/***********************************************************************/
+void TDBDHR::CloseDB(PGLOBAL g)
+ {
+ // Close the search handle.
+ if (!FindClose(Hsearch)) {
+ strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
+ longjmp(g->jumper[g->jump_level], GetAmType());
+ } // endif FindClose
+
+ iFile = 0;
+ Hsearch = INVALID_HANDLE_VALUE;
+ } // end of CloseDB
+
+// ------------------------ DHRCOL functions ----------------------------
+
+/***********************************************************************/
+/* DHRCOL public constructor. */
+/***********************************************************************/
+DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional DHR access method information for column.
+ N = cdp->GetOffset();
+ } // end of DOSCOL constructor
+
+/***********************************************************************/
+/* DHRCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ N = col1->N;
+ } // end of DHRCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the information */
+/* corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void DHRCOL::ReadColumn(PGLOBAL g)
+ {
+ int rc;
+ PTDBDHR tdbp = (PTDBDHR)To_Tdb;
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ "DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
+#endif
+
+ /*********************************************************************/
+ /* Retrieve the information corresponding to the column number. */
+ /*********************************************************************/
+ switch (N) {
+ case 0: // Drive
+ Value->SetValue(Drive, _MAX_DRIVE);
+ break;
+ case 1: // Path
+ Value->SetValue(Direc, _MAX_DHR);
+ break;
+ case 2: // Name
+ Value->SetValue(Fname, _MAX_FNAME);
+ break;
+ case 3: // Extention
+ Value->SetValue(Ftype, _MAX_EXT);
+ break;
+ case 4: // Extention
+ Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
+ break;
+ case 5:
+ Value->SetValue(tdbp->FileData.dwFileAttributes);
+ break;
+ case 6:
+ Value->SetValue(..................
+ } // end of ReadColumn
+#endif // 0
+
diff --git a/storage/connect/tabmul.h b/storage/connect/tabmul.h
index 205d2d6f0c5..052b4e7d33e 100644
--- a/storage/connect/tabmul.h
+++ b/storage/connect/tabmul.h
@@ -1,220 +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
+/*************** 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
diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp
index 859989fae34..d2394b09b7b 100644
--- a/storage/connect/tabmysql.cpp
+++ b/storage/connect/tabmysql.cpp
@@ -1,1105 +1,1105 @@
-/************* TabMySQL C++ Program Source Code File (.CPP) *************/
-/* PROGRAM NAME: TABMYSQL */
-/* ------------- */
-/* Version 1.5 */
-/* */
-/* AUTHOR: */
-/* ------- */
-/* Olivier BERTRAND 2007-2013 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* Implements a table type that are MySQL tables. */
-/* It can optionally use the embedded MySQL library. */
-/* */
-/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
-/* -------------------------------------- */
-/* */
-/* REQUIRED FILES: */
-/* --------------- */
-/* TABMYSQL.CPP - Source code */
-/* PLGDBSEM.H - DB application declaration file */
-/* TABMYSQL.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 "my_global.h"
-#if defined(WIN32)
-//#include <windows.h>
-#else // !WIN32
-//#include <fnmatch.h>
-//#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "osutil.h"
-//#include <io.h>
-//#include <fcntl.h>
-#endif // !WIN32
-
-/***********************************************************************/
-/* Include application header files: */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "xtable.h"
-#include "tabcol.h"
-#include "colblk.h"
-//#include "xindex.h"
-#include "reldef.h"
-#include "tabmysql.h"
-#include "valblk.h"
-#include "plgcnx.h" // For DB types
-#include "resource.h"
-
-#if defined(_CONSOLE)
-void PrintResult(PGLOBAL, PSEM, PQRYRES);
-#endif // _CONSOLE
-
-extern "C" int trace;
-
-/**************************************************************************/
-/* Allocate the result structure that will contain result data. */
-/**************************************************************************/
-PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
- int *dbtype, int *buftyp, unsigned int *length,
- bool blank = true, bool nonull = true);
-
-/************************************************************************/
-/* MyColumns: constructs the result blocks containing all columns */
-/* of a MySQL table that will be retrieved by GetData commands. */
-/* key = TRUE when called from Create Table to get key informations. */
-/************************************************************************/
-PQRYRES MyColumns(PGLOBAL g, char *host, char *db, char *user, char *pwd,
- char *table, char *colpat, int port, bool key)
- {
- static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR, DB_INT,
- DB_INT, DB_SHORT, DB_CHAR, DB_CHAR};
- static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
- TYPE_INT, TYPE_SHORT, TYPE_STRING, TYPE_STRING};
- static unsigned int length[] = {0, 4, 16, 4, 4, 4, 0, 0};
- char *fld, *fmt, cmd[128];
- int i, n, nf, ncol = sizeof(dbtype) / sizeof(int);
- int len, type, prec, rc, k = 0;
- PQRYRES qrp;
- PCOLRES crp;
- MYSQLC myc;
-
- /**********************************************************************/
- /* Open the connection with the MySQL server. */
- /**********************************************************************/
- if (myc.Open(g, host, db, user, pwd, port))
- return NULL;
-
- /**********************************************************************/
- /* Do an evaluation of the result size. */
- /**********************************************************************/
- sprintf(cmd, "SHOW FULL COLUMNS FROM %s", table);
- strcat(strcat(cmd, " FROM "), (db) ? db : PlgGetUser(g)->DBName);
-
- if (colpat)
- strcat(strcat(cmd, " LIKE "), colpat);
-
- if (trace)
- htrc("MyColumns: cmd='%s'\n", cmd);
-
- if ((n = myc.GetResultSize(g, cmd)) < 0) {
- myc.Close();
- return NULL;
- } // endif n
-
- /**********************************************************************/
- /* Get the size of the name columns. */
- /* Note that because the length is 0 for the last 2 columns (comment */
- /* and date format) they will be STRBLK instead of CHRBLK. */
- /**********************************************************************/
- length[0] = myc.GetFieldLength(0);
-
- if (!key) // We are not called from Create table
- ncol--; // No date format column
-
- /**********************************************************************/
- /* Allocate the structures used to refer to the result set. */
- /**********************************************************************/
- qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
- dbtype, buftyp, length);
-
- /**********************************************************************/
- /* Now get the results into blocks. */
- /**********************************************************************/
- for (i = 0; i < n; i++) {
- if ((rc = myc.Fetch(g, -1) == RC_FX))
- return NULL;
- else if (rc == RC_NF)
- break;
-
- // Get column name
- fld = myc.GetCharField(0);
- crp = qrp->Colresp;
- crp->Kdata->SetValue(fld, i);
-
- // Get type, type name, and precision
- fld = myc.GetCharField(1);
- prec = 0;
- len = 256; // Default for text or blob
-
- if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) {
- sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
- return NULL;
- } else
- qrp->Nblin++;
-
- if ((type = MYSQLtoPLG(cmd)) == TYPE_ERROR) {
- sprintf(g->Message, "Unsupported column type %s", cmd);
- return NULL;
- } // endif type
-
- crp = crp->Next;
- crp->Kdata->SetValue(type, i);
- crp = crp->Next;
- crp->Kdata->SetValue(cmd, i);
-
- if (key && type == TYPE_DATE) {
- // When creating tables we do need info about date columns
- fmt = MyDateFmt(cmd);
- len = strlen(fmt);
- } else
- fmt = NULL;
-
- crp = crp->Next;
- crp->Name = "Length";
- crp->Kdata->SetValue(len, i);
- crp = crp->Next;
- crp->Name = "Key";
-
- if (key) {
- // Creating a table, we need key info
- fld = myc.GetCharField(4);
- crp->Kdata->SetValue((stricmp(fld, "PRI")) ? 0 : ++k, i);
- } else
- crp->Kdata->SetValue(len, i);
-
- crp = crp->Next;
- crp->Name = "Prec";
- crp->Kdata->SetValue(prec, i);
-
- // Get comment field
- crp = crp->Next;
- crp->Name = "Comment";
- fld = myc.GetCharField(8);
-
- if (fld && strlen(fld))
- crp->Kdata->SetValue(fld, i);
- else
- crp->Kdata->Reset(i);
-
- if (key) {
- crp = crp->Next;
- crp->Name = "Date_Fmt";
-
- if (fmt)
- crp->Kdata->SetValue(fmt, i);
- else
- crp->Kdata->Reset(i);
-
- } // endif key
-
- } // endfor i
-
- if (k > 1) {
- // Multicolumn primary key
- PVBLK vbp = qrp->Colresp->Next->Next->Next->Next->Kdata;
-
- for (i = 0; i < n; i++)
- if (vbp->GetIntValue(i))
- vbp->SetValue(k, i);
-
- } // endif k
-
- /**********************************************************************/
- /* Close MySQL connection. */
- /**********************************************************************/
- myc.Close();
-
- /**********************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /**********************************************************************/
- return qrp;
- } // end of MyColumns
-
-#if 0
-/**************************************************************************/
-/* SemMySQLColumns: analyze a MySQL table for column format. */
-/**************************************************************************/
-void SemMySQLColumns(PGLOBAL g, PSEM semp)
- {
- PQRYRES qrp;
- PPARM pp, parmp = semp->Parmp;
-
- /*********************************************************************/
- /* Test passed parameters. */
- /*********************************************************************/
- sprintf(g->Message, MSG(BAD_PARAMETERS), semp->Name);
- semp->Value = g->Message;
- semp->Type = TYPE_ERROR;
-
- if (!parmp || parmp->Type != TYPE_LIST)
- return;
-
- /*********************************************************************/
- /* Analyze the table specifications. */
- /*********************************************************************/
- PSZ host, db, user, pwd, table;
- int port = 0;
-
- host = db = user = pwd = table = NULL;
-
- for (pp = (PPARM)parmp->Value; pp; pp = pp->Next)
- switch (pp->Type) {
- case TYPE_STRING:
- switch (pp->Domain) {
- case 5: table = (PSZ)pp->Value; break;
- case 7: db = (PSZ)pp->Value; break;
- case 30: host = (PSZ)pp->Value; break;
- case 31: user = (PSZ)pp->Value; break;
- case 32: pwd = (PSZ)pp->Value; break;
- default:
- return;
- } // endswitch Domain
-
- break;
- case TYPE_INT:
- if (pp->Domain == 33)
- port = (int)*(int*)pp->Value;
- else
- return;
-
- break;
- default:
- return;
- } // endswitch Type
-
- /************************************************************************/
- /* Get and store the result pointer for use by GetData routines. */
- /************************************************************************/
- if (!(qrp = MyColumns(g, host, db, user, pwd, table, NULL, port, TRUE)))
- return; // Error in MyColumns
-
- PlgGetUser(g)->Result = qrp;
-
-#if defined(_CONSOLE)
- PrintResult(g, semp, qrp);
-#else
- /************************************************************************/
- /* Make as result the qryresult description block. */
- /************************************************************************/
- semp->Type = TYPE_QRYRES;
- semp->Domain = 0;
- semp->Value = qrp;
-#endif // _CONSOLE
- } // end of SemMySQLColumns
-#endif // 0
-
-/* -------------- Implementation of the MYSQLDEF class --------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-MYSQLDEF::MYSQLDEF(void)
- {
- Pseudo = 2; // SERVID is Ok but not ROWID
- Hostname = NULL;
- Database = NULL;
- Tabname = NULL;
- Username = NULL;
- Password = NULL;
- Portnumber = 0;
- Bind = FALSE;
- Delayed = FALSE;
- } // end of MYSQLDEF constructor
-
-/***********************************************************************/
-/* DefineAM: define specific AM block values from XCV file. */
-/***********************************************************************/
-bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- Desc = "MySQL Table";
- Hostname = Cat->GetStringCatInfo(g, Name, "Host", "localhost");
- Database = Cat->GetStringCatInfo(g, Name, "Database", "*");
- Tabname = Cat->GetStringCatInfo(g, Name, "Name", Name); // Deprecated
- Tabname = Cat->GetStringCatInfo(g, Name, "Tabname", Tabname);
- Username = Cat->GetStringCatInfo(g, Name, "User", "root");
- Password = Cat->GetStringCatInfo(g, Name, "Password", NULL);
- Portnumber = Cat->GetIntCatInfo(Name, "Port", MYSQL_PORT);
- Bind = !!Cat->GetIntCatInfo(Name, "Bind", 0);
- Delayed = !!Cat->GetIntCatInfo(Name, "Delayed", 0);
- return FALSE;
- } // end of DefineAM
-
-/***********************************************************************/
-/* GetTable: makes a new TDB of the proper type. */
-/***********************************************************************/
-PTDB MYSQLDEF::GetTable(PGLOBAL g, MODE m)
- {
- return new(g) TDBMYSQL(this);
- } // end of GetTable
-
-/* ------------------------------------------------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBMYSQL class. */
-/***********************************************************************/
-TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp)
- {
- if (tdp) {
- Host = tdp->GetHostname();
- Database = tdp->GetDatabase();
- Tabname = tdp->GetTabname();
- User = tdp->GetUsername();
- Pwd = tdp->GetPassword();
- Port = tdp->GetPortnumber();
- Prep = tdp->Bind;
- Delayed = tdp->Delayed;
- } else {
- Host = NULL;
- Database = NULL;
- Tabname = NULL;
- User = NULL;
- Pwd = NULL;
- Port = 0;
- Prep = FALSE;
- Delayed = FALSE;
- } // endif tdp
-
- Bind = NULL;
- Query = NULL;
- Qbuf = NULL;
- Fetched = FALSE;
- m_Rc = RC_FX;
- AftRows = 0;
- N = -1;
- Nparm = 0;
- } // end of TDBMYSQL constructor
-
-TDBMYSQL::TDBMYSQL(PGLOBAL g, PTDBMY tdbp) : TDBASE(tdbp)
- {
- Host = tdbp->Host;
- Database = tdbp->Database;
- Tabname = tdbp->Tabname;
- User = tdbp->User;
- Pwd = tdbp->Pwd;
- Port = tdbp->Port;
- Prep = tdbp->Prep;
- Delayed = tdbp->Delayed;
- Bind = NULL;
- Query = tdbp->Query;
- Qbuf = NULL;
- Fetched = tdbp->Fetched;
- m_Rc = tdbp->m_Rc;
- AftRows = tdbp->AftRows;
- N = tdbp->N;
- Nparm = tdbp->Nparm;
- } // end of TDBMYSQL copy constructor
-
-// Is this really useful ???
-PTDB TDBMYSQL::CopyOne(PTABS t)
- {
- PTDB tp;
- PCOL cp1, cp2;
- PGLOBAL g = t->G;
-
- tp = new(g) TDBMYSQL(g, this);
-
- for (cp1 = Columns; cp1; cp1 = cp1->GetNext()) {
- cp2 = new(g) MYSQLCOL((PMYCOL)cp1, tp);
-
- NewPointer(t, cp1, cp2);
- } // endfor cp1
-
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Allocate MYSQL column description block. */
-/***********************************************************************/
-PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- return new(g) MYSQLCOL(cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* MakeSelect: make the Select statement use with MySQL connection. */
-/* Note: when implementing EOM filtering, column only used in local */
-/* filter should be removed from column list. */
-/***********************************************************************/
-bool TDBMYSQL::MakeSelect(PGLOBAL g)
- {
- char *colist;
- char *tk = "`";
- int len = 0, ncol = 0, rank = 0;
- bool b = FALSE;
- PCOL colp;
- PDBUSER dup = PlgGetUser(g);
-
- if (Query)
- return FALSE; // already done
-
- for (colp = Columns; colp; colp = colp->GetNext())
- ncol++;
-
- if (ncol) {
- colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol);
- *colist = '\0';
-
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->IsSpecial()) {
- strcpy(g->Message, MSG(NO_SPEC_COL));
- return TRUE;
- } else {
- if (b)
- strcat(colist, ", ");
- else
- b = TRUE;
-
- strcat(strcat(strcat(colist, tk), colp->GetName()), tk);
- ((PMYCOL)colp)->Rank = rank++;
- } // endif colp
-
- } else {
- // ncol == 0 can occur for queries such as Query count(*) from...
- // for which we will count the rows from Query '*' from...
- // (the use of a char constant minimize the result storage)
- colist = (char*)PlugSubAlloc(g, NULL, 2);
- strcpy(colist, "'*'");
- } // endif ncol
-
- // Below 32 is space to contain extra stuff
- len += (strlen(colist) + strlen(Tabname) + 32);
- len += (To_Filter ? strlen(To_Filter) + 7 : 0);
- Query = (char*)PlugSubAlloc(g, NULL, len);
- strcat(strcpy(Query, "SELECT "), colist);
- strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk);
-
- if (To_Filter)
- strcat(strcat(Query, " WHERE "), To_Filter);
-
- return FALSE;
- } // end of MakeSelect
-
-/***********************************************************************/
-/* MakeInsert: make the Insert statement used with MySQL connection. */
-/***********************************************************************/
-bool TDBMYSQL::MakeInsert(PGLOBAL g)
- {
- char *colist, *valist = NULL;
- char *tk = "`";
- int len = 0, qlen = 0;
- bool b = FALSE;
- PCOL colp;
-
- if (Query)
- return FALSE; // already done
-
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->IsSpecial()) {
- strcpy(g->Message, MSG(NO_SPEC_COL));
- return TRUE;
- } else {
- len += (strlen(colp->GetName()) + 4);
- ((PMYCOL)colp)->Rank = Nparm++;
- } // endif colp
-
- colist = (char*)PlugSubAlloc(g, NULL, len);
- *colist = '\0';
-
- if (Prep) {
- valist = (char*)PlugSubAlloc(g, NULL, 2 * Nparm);
- *valist = '\0';
- } // endif Prep
-
- for (colp = Columns; colp; colp = colp->GetNext()) {
- if (b) {
- strcat(colist, ", ");
- if (Prep) strcat(valist, ",");
- } else
- b = TRUE;
-
- strcat(strcat(strcat(colist, tk), colp->GetName()), tk);
-
- // Parameter marker
- if (!Prep) {
- if (colp->GetResultType() == TYPE_DATE)
- qlen += 20;
- else
- qlen += colp->GetLength();
-
- } // endif Prep
-
- if (Prep)
- strcat(valist, "?");
-
- } // endfor colp
-
- // Below 40 is enough to contain the fixed part of the query
- len = (strlen(Tabname) + strlen(colist)
- + ((Prep) ? strlen(valist) : 0) + 40);
- Query = (char*)PlugSubAlloc(g, NULL, len);
-
- if (Delayed)
- strcpy(Query, "INSERT DELAYED INTO ");
- else
- strcpy(Query, "INSERT INTO ");
-
- strcat(strcat(strcat(Query, tk), Tabname), tk);
- strcat(strcat(strcat(Query, " ("), colist), ") VALUES (");
-
- if (Prep)
- strcat(strcat(Query, valist), ")");
- else {
- qlen += (strlen(Query) + Nparm);
- Qbuf = (char *)PlugSubAlloc(g, NULL, qlen);
- } // endelse Prep
-
- return FALSE;
- } // end of MakeInsert
-
-#if 0
-/***********************************************************************/
-/* MakeUpdate: make the Update statement use with MySQL connection. */
-/* Note: currently limited to local values and filtering. */
-/***********************************************************************/
-bool TDBMYSQL::MakeUpdate(PGLOBAL g, PSELECT selist)
- {
- char *setlist, *colname, *where = NULL, *tk = "`";
- int len = 0, nset = 0;
- bool b = FALSE;
- PXOB xp;
- PSELECT selp;
-
- if (Query)
- return FALSE; // already done
-
- if (To_Filter)
- if (To_Filter->CheckLocal(this)) {
- where = (char*)PlugSubAlloc(g, NULL, 512); // Should be enough
- *where = '\0';
-
- if (!PlugRephraseSQL(g, where, To_Filter, TYPE_FILTER, tk))
- return TRUE;
-
- To_Filter = NULL;
- len = strlen(where);
- } else {
- strcpy(g->Message, MSG(NO_REF_UPDATE));
- return TRUE;
- } // endif Local
-
- for (selp = selist; selp; selp = selp->GetNext_Proj())
- nset++;
-
- assert(nset);
-
- // Allocate a pretty big buffer
- setlist = (char*)PlugSubAlloc(g, NULL, 256 * nset);
- *setlist = '\0';
-
- for (selp = selist; selp; selp = selp->GetNext_Proj()) {
- if (selp->GetSetType() == TYPE_COLBLK) {
- colname = selp->GetSetCol()->GetName();
- } else if (selp->GetSetType() == TYPE_COLUMN) {
- colname = (char*)((PCOLUMN)selp->GetSetCol())->GetName();
- } else {
- sprintf(g->Message, MSG(BAD_SET_TYPE), selp->GetSetType());
- return TRUE;
- } // endif Type
-
- if (b)
- strcat(setlist, ", ");
- else
- b = TRUE;
-
- strcat(strcat(strcat(strcat(setlist, tk), colname), tk), " = ");
-
- xp = selp->GetObject();
-
- if (!xp->CheckLocal(this)) {
- strcpy(g->Message, MSG(NO_REF_UPDATE));
- return TRUE;
- } else if (xp->GetType() == TYPE_SUBQ)
- // Cannot be correlated because CheckLocal would have failed
- xp = new(g) CONSTANT(xp->GetValue());
-
- if (!PlugRephraseSQL(g, setlist + strlen(setlist),
- xp, TYPE_XOBJECT, tk))
- return TRUE;
-
- } // endfor selp
-
- // Below 16 is enough to take care of the fixed part of the query
- len += (strlen(setlist) + strlen(Tabname) + 16);
- Query = (char*)PlugSubAlloc(g, NULL, len);
- strcat(strcat(strcat(strcpy(Query, "UPDATE "), tk), Tabname), tk);
- strcat(strcat(Query, " SET "), setlist);
-
- if (where)
- strcat(Query, where);
-
- return FALSE;
- } // end of MakeUpdate
-
-/***********************************************************************/
-/* MakeDelete: make the Delete statement use with MySQL connection. */
-/* If no filtering Truncate is used because it is faster than Delete. */
-/* However, the number of deleted lines is not returned by MySQL. */
-/* Note: currently limited to local filtering. */
-/***********************************************************************/
-bool TDBMYSQL::MakeDelete(PGLOBAL g)
- {
- char *tk = "`";
- int len = 0;
-
- if (Query)
- return FALSE; // already done
-
- if (!To_Filter)
- AftRows = -1; // Means "all lines deleted"
-
- // Below 16 is more than length of 'delete from ' + 3
- len += (strlen(Tabname) + 16);
- len += (To_Filter ? strlen(To_Filter) + 7 : 0);
- Query = (char*)PlugSubAlloc(g, NULL, len);
- strcpy(Query, (To_Filter) ? "DELETE FROM " : "TRUNCATE ");
- strcat(strcat(strcat(Query, tk), Tabname), tk);
-
- if (To_Filter)
- strcat(strcat(Query, " WHERE "), To_Filter);
-
- return FALSE;
- } // end of MakeDelete
-#endif // 0
-
-/***********************************************************************/
-/* XCV GetMaxSize: returns the maximum number of rows in the table. */
-/***********************************************************************/
-int TDBMYSQL::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0) {
-#if 0
- if (MakeSelect(g))
- return -2;
-
- if (!Myc.Connected()) {
- if (Myc.Open(g, Host, Database, User, Pwd, Port))
- return -1;
-
- } // endif connected
-
- if ((MaxSize = Myc.GetResultSize(g, Query)) < 0) {
- Myc.Close();
- return -3;
- } // endif MaxSize
-
- // FIXME: Columns should be known when Info calls GetMaxSize
- if (!Columns)
- Query = NULL; // Must be remade when columns are known
-#endif // 0
-
- MaxSize = 0;
- } // endif MaxSize
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* This a fake routine as ROWID does not exist in MySQL. */
-/***********************************************************************/
-int TDBMYSQL::RowNumber(PGLOBAL g, bool b)
- {
- return N;
- } // end of RowNumber
-
-/***********************************************************************/
-/* Return 0 in mode DELETE to tell that the delete is done. */
-/***********************************************************************/
-int TDBMYSQL::GetProgMax(PGLOBAL g)
- {
- return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0
- : GetMaxSize(g);
- } // end of GetProgMax
-
-/***********************************************************************/
-/* MySQL Bind Parameter function. */
-/***********************************************************************/
-int TDBMYSQL::BindColumns(PGLOBAL g)
- {
- if (Prep) {
- Bind = (MYSQL_BIND*)PlugSubAlloc(g, NULL, Nparm * sizeof(MYSQL_BIND));
-
- for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
- colp->InitBind(g);
-
- return Myc.BindParams(g, Bind);
- } else {
- for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
- if (colp->Buf_Type == TYPE_DATE)
- // Format must match DATETIME MySQL type
- ((DTVAL*)colp->GetValue())->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
-
- return RC_OK;
- } // endif Prep
-
- } // end of BindColumns
-
-/***********************************************************************/
-/* MySQL Access Method opening routine. */
-/***********************************************************************/
-bool TDBMYSQL::OpenDB(PGLOBAL g)
- {
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open, just replace it at its beginning. */
- /*******************************************************************/
- Myc.Rewind();
- return FALSE;
- } // endif use
-
- /*********************************************************************/
- /* Open a MySQL 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 server */
- /* and if so to allocate just a new result set. But this only for */
- /* servers allowing concurency in getting results ??? */
- /*********************************************************************/
- if (!Myc.Connected()) {
- if (Myc.Open(g, Host, Database, User, Pwd, Port))
- return TRUE;
-
- } // endif Connected
-
- /*********************************************************************/
- /* Allocate whatever is used for getting results. */
- /*********************************************************************/
- if (Mode == MODE_READ) {
- if (!MakeSelect(g))
- m_Rc = Myc.ExecSQL(g, Query);
-
- } else if (Mode == MODE_INSERT) {
- if (!MakeInsert(g)) {
- int n = (Prep) ? Myc.PrepareSQL(g, Query) : Nparm;
-
- if (Nparm != n) {
- if (n >= 0) // Other errors return negative values
- strcpy(g->Message, MSG(BAD_PARM_COUNT));
-
- } else
- m_Rc = BindColumns(g);
-
- } // endif MakeInsert
-
- if (m_Rc != RC_FX) {
- char cmd[64];
- int w;
-
- sprintf(cmd, "ALTER TABLE `%s` DISABLE KEYS", Tabname);
- m_Rc = Myc.ExecSQL(g, cmd, &w);
- } // endif m_Rc
-
-#if 0
- } else if (Next) {
- strcpy(g->Message, MSG(NO_JOIN_UPDEL));
- } else if (Mode == MODE_DELETE) {
- strcpy(g->Message, "MySQL table delete not implemented yet\n");
- bool rc = MakeDelete(g);
-
- if (!rc && Myc.ExecSQL(g, Query) == RC_NF) {
- if (!AftRows)
- AftRows = Myc.GetRows();
-
- m_Rc = RC_OK;
- } // endif ExecSQL
-#endif // 0
-
- } else {
-// bool rc = MakeUpdate(g, sqlp->GetProj());
- strcpy(g->Message, "MySQL table delete/update not implemented yet\n");
- } // endelse
-
- if (m_Rc == RC_FX) {
- Myc.Close();
- return TRUE;
- } // endif rc
-
- Use = USE_OPEN; // Do it now in case we are recursively called
- return FALSE;
- } // end of OpenDB
-
-/***********************************************************************/
-/* Data Base read routine for MYSQL access method. */
-/***********************************************************************/
-int TDBMYSQL::ReadDB(PGLOBAL g)
- {
- int rc;
-
- if (trace > 1)
- htrc("MySQL ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
- GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
-
- /*********************************************************************/
- /* Now start the reading process. */
- /* Here is the place to fetch the line. */
- /*********************************************************************/
- N++;
- Fetched = ((rc = Myc.Fetch(g, -1)) == RC_OK);
-
- if (trace > 1)
- htrc(" Read: rc=%d\n", rc);
-
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* WriteDB: Data Base write routine for MYSQL access methods. */
-/***********************************************************************/
-int TDBMYSQL::WriteDB(PGLOBAL g)
- {
- if (Prep)
- return Myc.ExecStmt(g);
-
- // Statement was not prepared, we must construct and execute
- // an insert query for each line to insert
- int rc;
- char buf[32];
-
- strcpy(Qbuf, Query);
-
- // Make the Insert command value list
- for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
- if (colp->GetResultType() == TYPE_STRING ||
- colp->GetResultType() == TYPE_DATE)
- strcat(Qbuf, "'");
-
- strcat(Qbuf, colp->GetValue()->GetCharString(buf));
-
- if (colp->GetResultType() == TYPE_STRING ||
- colp->GetResultType() == TYPE_DATE)
- strcat(Qbuf, "'");
-
- strcat(Qbuf, (colp->GetNext()) ? "," : ")");
- } // endfor colp
-
- Myc.m_Rows = -1; // To execute the query
- rc = Myc.ExecSQL(g, Qbuf);
- return (rc == RC_NF) ? RC_OK : rc; // RC_NF is Ok
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for MYSQL access methods. */
-/***********************************************************************/
-int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
- {
- strcpy(g->Message, MSG(NO_MYSQL_DELETE));
- return RC_FX;
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for MySQL access method. */
-/***********************************************************************/
-void TDBMYSQL::CloseDB(PGLOBAL g)
- {
- if (Mode == MODE_INSERT) {
- char cmd[64];
- int w;
- PDBUSER dup = PlgGetUser(g);
-
- dup->Step = "Enabling indexes";
- sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", Tabname);
- Myc.m_Rows = -1; // To execute the query
- m_Rc = Myc.ExecSQL(g, cmd, &w);
- } // endif m_Rc
-
- Myc.Close();
-
- if (trace)
- htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
-
- } // end of CloseDB
-
-// ------------------------ MYSQLCOL functions --------------------------
-
-/***********************************************************************/
-/* MYSQLCOL public constructor. */
-/***********************************************************************/
-MYSQLCOL::MYSQLCOL(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();
- Bind = NULL;
- To_Val = NULL;
- Slen = 0;
- Rank = -1; // Not known yet
-
- if (trace)
- htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
-
- } // end of MYSQLCOL constructor
-
-/***********************************************************************/
-/* MYSQLCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-MYSQLCOL::MYSQLCOL(MYSQLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- Long = col1->Long;
- Bind = NULL;
- To_Val = NULL;
- Slen = col1->Slen;
- Rank = col1->Rank;
- } // end of MYSQLCOL copy constructor
-
-/***********************************************************************/
-/* SetBuffer: prepare a column block for write operation. */
-/***********************************************************************/
-bool MYSQLCOL::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
-
-/***********************************************************************/
-/* InitBind: Initialize the bind structure according to type. */
-/***********************************************************************/
-void MYSQLCOL::InitBind(PGLOBAL g)
- {
- PTDBMY tdbp = (PTDBMY)To_Tdb;
-
- assert(tdbp->Bind && Rank < tdbp->Nparm);
-
- Bind = &tdbp->Bind[Rank];
- memset(Bind, 0, sizeof(MYSQL_BIND));
-
- if (Buf_Type == TYPE_DATE) {
- // Default format must match DATETIME MySQL type
-// if (!((DTVAL*)Value)->IsFormatted())
- ((DTVAL*)Value)->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
-
- Bind->buffer_type = PLGtoMYSQL(TYPE_STRING);
- Bind->buffer = (char *)PlugSubAlloc(g,NULL, 20);
- Bind->buffer_length = 20;
- Bind->length = &Slen;
- } else {
- Bind->buffer_type = PLGtoMYSQL(Buf_Type);
- Bind->buffer = (char *)Value->GetTo_Val();
- Bind->buffer_length = Value->GetClen();
- Bind->length = (IsTypeChar(Buf_Type)) ? &Slen : NULL;
- } // endif Buf_Type
-
- } // end of InitBind
-
-/***********************************************************************/
-/* ReadColumn: */
-/***********************************************************************/
-void MYSQLCOL::ReadColumn(PGLOBAL g)
- {
- char *buf;
- int rc;
- PTDBMY tdbp = (PTDBMY)To_Tdb;
-
- if (trace)
- htrc("MySQL ReadColumn: name=%s\n", Name);
-
- assert (Rank >= 0);
-
- /*********************************************************************/
- /* If physical fetching of the line was deferred, do it now. */
- /*********************************************************************/
- if (!tdbp->Fetched)
- if ((rc = tdbp->Myc.Fetch(g, tdbp->N)) != RC_OK) {
- if (rc == RC_EF)
- sprintf(g->Message, MSG(INV_DEF_READ), rc);
-
- longjmp(g->jumper[g->jump_level], 11);
- } else
- tdbp->Fetched = TRUE;
-
- if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank)))
- Value->SetValue_char(buf, Long);
- else
- Value->Reset(); // Null value
-
- } // end of ReadColumn
-
-/***********************************************************************/
-/* WriteColumn: make sure the bind buffer is updated. */
-/***********************************************************************/
-void MYSQLCOL::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 (((PTDBMY)To_Tdb)->Prep) {
- if (Buf_Type == TYPE_DATE) {
- Value->ShowValue((char *)Bind->buffer, (int)*Bind->length);
- Slen = strlen((char *)Bind->buffer);
- } else if (IsTypeChar(Buf_Type))
- Slen = strlen(Value->GetCharValue());
-
- } // endif Prep
-
- } // end of WriteColumn
+/************* TabMySQL C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: TABMYSQL */
+/* ------------- */
+/* Version 1.5 */
+/* */
+/* AUTHOR: */
+/* ------- */
+/* Olivier BERTRAND 2007-2013 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* Implements a table type that are MySQL tables. */
+/* It can optionally use the embedded MySQL library. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABMYSQL.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABMYSQL.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 "my_global.h"
+#if defined(WIN32)
+//#include <windows.h>
+#else // !WIN32
+//#include <fnmatch.h>
+//#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+//#include <io.h>
+//#include <fcntl.h>
+#endif // !WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabcol.h"
+#include "colblk.h"
+//#include "xindex.h"
+#include "reldef.h"
+#include "tabmysql.h"
+#include "valblk.h"
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+
+#if defined(_CONSOLE)
+void PrintResult(PGLOBAL, PSEM, PQRYRES);
+#endif // _CONSOLE
+
+extern "C" int trace;
+
+/**************************************************************************/
+/* Allocate the result structure that will contain result data. */
+/**************************************************************************/
+PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
+ int *dbtype, int *buftyp, unsigned int *length,
+ bool blank = true, bool nonull = true);
+
+/************************************************************************/
+/* MyColumns: constructs the result blocks containing all columns */
+/* of a MySQL table that will be retrieved by GetData commands. */
+/* key = TRUE when called from Create Table to get key informations. */
+/************************************************************************/
+PQRYRES MyColumns(PGLOBAL g, char *host, char *db, char *user, char *pwd,
+ char *table, char *colpat, int port, bool key)
+ {
+ static int dbtype[] = {DB_CHAR, DB_SHORT, DB_CHAR, DB_INT,
+ DB_INT, DB_SHORT, DB_CHAR, DB_CHAR};
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ TYPE_INT, TYPE_SHORT, TYPE_STRING, TYPE_STRING};
+ static unsigned int length[] = {0, 4, 16, 4, 4, 4, 0, 0};
+ char *fld, *fmt, cmd[128];
+ int i, n, nf, ncol = sizeof(dbtype) / sizeof(int);
+ int len, type, prec, rc, k = 0;
+ PQRYRES qrp;
+ PCOLRES crp;
+ MYSQLC myc;
+
+ /**********************************************************************/
+ /* Open the connection with the MySQL server. */
+ /**********************************************************************/
+ if (myc.Open(g, host, db, user, pwd, port))
+ return NULL;
+
+ /**********************************************************************/
+ /* Do an evaluation of the result size. */
+ /**********************************************************************/
+ sprintf(cmd, "SHOW FULL COLUMNS FROM %s", table);
+ strcat(strcat(cmd, " FROM "), (db) ? db : PlgGetUser(g)->DBName);
+
+ if (colpat)
+ strcat(strcat(cmd, " LIKE "), colpat);
+
+ if (trace)
+ htrc("MyColumns: cmd='%s'\n", cmd);
+
+ if ((n = myc.GetResultSize(g, cmd)) < 0) {
+ myc.Close();
+ return NULL;
+ } // endif n
+
+ /**********************************************************************/
+ /* Get the size of the name columns. */
+ /* Note that because the length is 0 for the last 2 columns (comment */
+ /* and date format) they will be STRBLK instead of CHRBLK. */
+ /**********************************************************************/
+ length[0] = myc.GetFieldLength(0);
+
+ if (!key) // We are not called from Create table
+ ncol--; // No date format column
+
+ /**********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /**********************************************************************/
+ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ dbtype, buftyp, length);
+
+ /**********************************************************************/
+ /* Now get the results into blocks. */
+ /**********************************************************************/
+ for (i = 0; i < n; i++) {
+ if ((rc = myc.Fetch(g, -1) == RC_FX))
+ return NULL;
+ else if (rc == RC_NF)
+ break;
+
+ // Get column name
+ fld = myc.GetCharField(0);
+ crp = qrp->Colresp;
+ crp->Kdata->SetValue(fld, i);
+
+ // Get type, type name, and precision
+ fld = myc.GetCharField(1);
+ prec = 0;
+ len = 256; // Default for text or blob
+
+ if ((nf = sscanf(fld, "%[^(](%d,%d", cmd, &len, &prec)) < 1) {
+ sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
+ return NULL;
+ } else
+ qrp->Nblin++;
+
+ if ((type = MYSQLtoPLG(cmd)) == TYPE_ERROR) {
+ sprintf(g->Message, "Unsupported column type %s", cmd);
+ return NULL;
+ } // endif type
+
+ crp = crp->Next;
+ crp->Kdata->SetValue(type, i);
+ crp = crp->Next;
+ crp->Kdata->SetValue(cmd, i);
+
+ if (key && type == TYPE_DATE) {
+ // When creating tables we do need info about date columns
+ fmt = MyDateFmt(cmd);
+ len = strlen(fmt);
+ } else
+ fmt = NULL;
+
+ crp = crp->Next;
+ crp->Name = "Length";
+ crp->Kdata->SetValue(len, i);
+ crp = crp->Next;
+ crp->Name = "Key";
+
+ if (key) {
+ // Creating a table, we need key info
+ fld = myc.GetCharField(4);
+ crp->Kdata->SetValue((stricmp(fld, "PRI")) ? 0 : ++k, i);
+ } else
+ crp->Kdata->SetValue(len, i);
+
+ crp = crp->Next;
+ crp->Name = "Prec";
+ crp->Kdata->SetValue(prec, i);
+
+ // Get comment field
+ crp = crp->Next;
+ crp->Name = "Comment";
+ fld = myc.GetCharField(8);
+
+ if (fld && strlen(fld))
+ crp->Kdata->SetValue(fld, i);
+ else
+ crp->Kdata->Reset(i);
+
+ if (key) {
+ crp = crp->Next;
+ crp->Name = "Date_Fmt";
+
+ if (fmt)
+ crp->Kdata->SetValue(fmt, i);
+ else
+ crp->Kdata->Reset(i);
+
+ } // endif key
+
+ } // endfor i
+
+ if (k > 1) {
+ // Multicolumn primary key
+ PVBLK vbp = qrp->Colresp->Next->Next->Next->Next->Kdata;
+
+ for (i = 0; i < n; i++)
+ if (vbp->GetIntValue(i))
+ vbp->SetValue(k, i);
+
+ } // endif k
+
+ /**********************************************************************/
+ /* Close MySQL connection. */
+ /**********************************************************************/
+ myc.Close();
+
+ /**********************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /**********************************************************************/
+ return qrp;
+ } // end of MyColumns
+
+#if 0
+/**************************************************************************/
+/* SemMySQLColumns: analyze a MySQL table for column format. */
+/**************************************************************************/
+void SemMySQLColumns(PGLOBAL g, PSEM semp)
+ {
+ PQRYRES qrp;
+ PPARM pp, parmp = semp->Parmp;
+
+ /*********************************************************************/
+ /* Test passed parameters. */
+ /*********************************************************************/
+ sprintf(g->Message, MSG(BAD_PARAMETERS), semp->Name);
+ semp->Value = g->Message;
+ semp->Type = TYPE_ERROR;
+
+ if (!parmp || parmp->Type != TYPE_LIST)
+ return;
+
+ /*********************************************************************/
+ /* Analyze the table specifications. */
+ /*********************************************************************/
+ PSZ host, db, user, pwd, table;
+ int port = 0;
+
+ host = db = user = pwd = table = NULL;
+
+ for (pp = (PPARM)parmp->Value; pp; pp = pp->Next)
+ switch (pp->Type) {
+ case TYPE_STRING:
+ switch (pp->Domain) {
+ case 5: table = (PSZ)pp->Value; break;
+ case 7: db = (PSZ)pp->Value; break;
+ case 30: host = (PSZ)pp->Value; break;
+ case 31: user = (PSZ)pp->Value; break;
+ case 32: pwd = (PSZ)pp->Value; break;
+ default:
+ return;
+ } // endswitch Domain
+
+ break;
+ case TYPE_INT:
+ if (pp->Domain == 33)
+ port = (int)*(int*)pp->Value;
+ else
+ return;
+
+ break;
+ default:
+ return;
+ } // endswitch Type
+
+ /************************************************************************/
+ /* Get and store the result pointer for use by GetData routines. */
+ /************************************************************************/
+ if (!(qrp = MyColumns(g, host, db, user, pwd, table, NULL, port, TRUE)))
+ return; // Error in MyColumns
+
+ PlgGetUser(g)->Result = qrp;
+
+#if defined(_CONSOLE)
+ PrintResult(g, semp, qrp);
+#else
+ /************************************************************************/
+ /* Make as result the qryresult description block. */
+ /************************************************************************/
+ semp->Type = TYPE_QRYRES;
+ semp->Domain = 0;
+ semp->Value = qrp;
+#endif // _CONSOLE
+ } // end of SemMySQLColumns
+#endif // 0
+
+/* -------------- Implementation of the MYSQLDEF class --------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+MYSQLDEF::MYSQLDEF(void)
+ {
+ Pseudo = 2; // SERVID is Ok but not ROWID
+ Hostname = NULL;
+ Database = NULL;
+ Tabname = NULL;
+ Username = NULL;
+ Password = NULL;
+ Portnumber = 0;
+ Bind = FALSE;
+ Delayed = FALSE;
+ } // end of MYSQLDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XCV file. */
+/***********************************************************************/
+bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ Desc = "MySQL Table";
+ Hostname = Cat->GetStringCatInfo(g, Name, "Host", "localhost");
+ Database = Cat->GetStringCatInfo(g, Name, "Database", "*");
+ Tabname = Cat->GetStringCatInfo(g, Name, "Name", Name); // Deprecated
+ Tabname = Cat->GetStringCatInfo(g, Name, "Tabname", Tabname);
+ Username = Cat->GetStringCatInfo(g, Name, "User", "root");
+ Password = Cat->GetStringCatInfo(g, Name, "Password", NULL);
+ Portnumber = Cat->GetIntCatInfo(Name, "Port", MYSQL_PORT);
+ Bind = !!Cat->GetIntCatInfo(Name, "Bind", 0);
+ Delayed = !!Cat->GetIntCatInfo(Name, "Delayed", 0);
+ return FALSE;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB MYSQLDEF::GetTable(PGLOBAL g, MODE m)
+ {
+ return new(g) TDBMYSQL(this);
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBMYSQL class. */
+/***********************************************************************/
+TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp)
+ {
+ if (tdp) {
+ Host = tdp->GetHostname();
+ Database = tdp->GetDatabase();
+ Tabname = tdp->GetTabname();
+ User = tdp->GetUsername();
+ Pwd = tdp->GetPassword();
+ Port = tdp->GetPortnumber();
+ Prep = tdp->Bind;
+ Delayed = tdp->Delayed;
+ } else {
+ Host = NULL;
+ Database = NULL;
+ Tabname = NULL;
+ User = NULL;
+ Pwd = NULL;
+ Port = 0;
+ Prep = FALSE;
+ Delayed = FALSE;
+ } // endif tdp
+
+ Bind = NULL;
+ Query = NULL;
+ Qbuf = NULL;
+ Fetched = FALSE;
+ m_Rc = RC_FX;
+ AftRows = 0;
+ N = -1;
+ Nparm = 0;
+ } // end of TDBMYSQL constructor
+
+TDBMYSQL::TDBMYSQL(PGLOBAL g, PTDBMY tdbp) : TDBASE(tdbp)
+ {
+ Host = tdbp->Host;
+ Database = tdbp->Database;
+ Tabname = tdbp->Tabname;
+ User = tdbp->User;
+ Pwd = tdbp->Pwd;
+ Port = tdbp->Port;
+ Prep = tdbp->Prep;
+ Delayed = tdbp->Delayed;
+ Bind = NULL;
+ Query = tdbp->Query;
+ Qbuf = NULL;
+ Fetched = tdbp->Fetched;
+ m_Rc = tdbp->m_Rc;
+ AftRows = tdbp->AftRows;
+ N = tdbp->N;
+ Nparm = tdbp->Nparm;
+ } // end of TDBMYSQL copy constructor
+
+// Is this really useful ???
+PTDB TDBMYSQL::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBMYSQL(g, this);
+
+ for (cp1 = Columns; cp1; cp1 = cp1->GetNext()) {
+ cp2 = new(g) MYSQLCOL((PMYCOL)cp1, tp);
+
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Allocate MYSQL column description block. */
+/***********************************************************************/
+PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) MYSQLCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* MakeSelect: make the Select statement use with MySQL connection. */
+/* Note: when implementing EOM filtering, column only used in local */
+/* filter should be removed from column list. */
+/***********************************************************************/
+bool TDBMYSQL::MakeSelect(PGLOBAL g)
+ {
+ char *colist;
+ char *tk = "`";
+ int len = 0, ncol = 0, rank = 0;
+ bool b = FALSE;
+ PCOL colp;
+ PDBUSER dup = PlgGetUser(g);
+
+ if (Query)
+ return FALSE; // already done
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ ncol++;
+
+ if (ncol) {
+ colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol);
+ *colist = '\0';
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->IsSpecial()) {
+ strcpy(g->Message, MSG(NO_SPEC_COL));
+ return TRUE;
+ } else {
+ if (b)
+ strcat(colist, ", ");
+ else
+ b = TRUE;
+
+ strcat(strcat(strcat(colist, tk), colp->GetName()), tk);
+ ((PMYCOL)colp)->Rank = rank++;
+ } // endif colp
+
+ } else {
+ // ncol == 0 can occur for queries such as Query count(*) from...
+ // for which we will count the rows from Query '*' from...
+ // (the use of a char constant minimize the result storage)
+ colist = (char*)PlugSubAlloc(g, NULL, 2);
+ strcpy(colist, "'*'");
+ } // endif ncol
+
+ // Below 32 is space to contain extra stuff
+ len += (strlen(colist) + strlen(Tabname) + 32);
+ len += (To_Filter ? strlen(To_Filter) + 7 : 0);
+ Query = (char*)PlugSubAlloc(g, NULL, len);
+ strcat(strcpy(Query, "SELECT "), colist);
+ strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk);
+
+ if (To_Filter)
+ strcat(strcat(Query, " WHERE "), To_Filter);
+
+ return FALSE;
+ } // end of MakeSelect
+
+/***********************************************************************/
+/* MakeInsert: make the Insert statement used with MySQL connection. */
+/***********************************************************************/
+bool TDBMYSQL::MakeInsert(PGLOBAL g)
+ {
+ char *colist, *valist = NULL;
+ char *tk = "`";
+ int len = 0, qlen = 0;
+ bool b = FALSE;
+ PCOL colp;
+
+ if (Query)
+ return FALSE; // already done
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->IsSpecial()) {
+ strcpy(g->Message, MSG(NO_SPEC_COL));
+ return TRUE;
+ } else {
+ len += (strlen(colp->GetName()) + 4);
+ ((PMYCOL)colp)->Rank = Nparm++;
+ } // endif colp
+
+ colist = (char*)PlugSubAlloc(g, NULL, len);
+ *colist = '\0';
+
+ if (Prep) {
+ valist = (char*)PlugSubAlloc(g, NULL, 2 * Nparm);
+ *valist = '\0';
+ } // endif Prep
+
+ for (colp = Columns; colp; colp = colp->GetNext()) {
+ if (b) {
+ strcat(colist, ", ");
+ if (Prep) strcat(valist, ",");
+ } else
+ b = TRUE;
+
+ strcat(strcat(strcat(colist, tk), colp->GetName()), tk);
+
+ // Parameter marker
+ if (!Prep) {
+ if (colp->GetResultType() == TYPE_DATE)
+ qlen += 20;
+ else
+ qlen += colp->GetLength();
+
+ } // endif Prep
+
+ if (Prep)
+ strcat(valist, "?");
+
+ } // endfor colp
+
+ // Below 40 is enough to contain the fixed part of the query
+ len = (strlen(Tabname) + strlen(colist)
+ + ((Prep) ? strlen(valist) : 0) + 40);
+ Query = (char*)PlugSubAlloc(g, NULL, len);
+
+ if (Delayed)
+ strcpy(Query, "INSERT DELAYED INTO ");
+ else
+ strcpy(Query, "INSERT INTO ");
+
+ strcat(strcat(strcat(Query, tk), Tabname), tk);
+ strcat(strcat(strcat(Query, " ("), colist), ") VALUES (");
+
+ if (Prep)
+ strcat(strcat(Query, valist), ")");
+ else {
+ qlen += (strlen(Query) + Nparm);
+ Qbuf = (char *)PlugSubAlloc(g, NULL, qlen);
+ } // endelse Prep
+
+ return FALSE;
+ } // end of MakeInsert
+
+#if 0
+/***********************************************************************/
+/* MakeUpdate: make the Update statement use with MySQL connection. */
+/* Note: currently limited to local values and filtering. */
+/***********************************************************************/
+bool TDBMYSQL::MakeUpdate(PGLOBAL g, PSELECT selist)
+ {
+ char *setlist, *colname, *where = NULL, *tk = "`";
+ int len = 0, nset = 0;
+ bool b = FALSE;
+ PXOB xp;
+ PSELECT selp;
+
+ if (Query)
+ return FALSE; // already done
+
+ if (To_Filter)
+ if (To_Filter->CheckLocal(this)) {
+ where = (char*)PlugSubAlloc(g, NULL, 512); // Should be enough
+ *where = '\0';
+
+ if (!PlugRephraseSQL(g, where, To_Filter, TYPE_FILTER, tk))
+ return TRUE;
+
+ To_Filter = NULL;
+ len = strlen(where);
+ } else {
+ strcpy(g->Message, MSG(NO_REF_UPDATE));
+ return TRUE;
+ } // endif Local
+
+ for (selp = selist; selp; selp = selp->GetNext_Proj())
+ nset++;
+
+ assert(nset);
+
+ // Allocate a pretty big buffer
+ setlist = (char*)PlugSubAlloc(g, NULL, 256 * nset);
+ *setlist = '\0';
+
+ for (selp = selist; selp; selp = selp->GetNext_Proj()) {
+ if (selp->GetSetType() == TYPE_COLBLK) {
+ colname = selp->GetSetCol()->GetName();
+ } else if (selp->GetSetType() == TYPE_COLUMN) {
+ colname = (char*)((PCOLUMN)selp->GetSetCol())->GetName();
+ } else {
+ sprintf(g->Message, MSG(BAD_SET_TYPE), selp->GetSetType());
+ return TRUE;
+ } // endif Type
+
+ if (b)
+ strcat(setlist, ", ");
+ else
+ b = TRUE;
+
+ strcat(strcat(strcat(strcat(setlist, tk), colname), tk), " = ");
+
+ xp = selp->GetObject();
+
+ if (!xp->CheckLocal(this)) {
+ strcpy(g->Message, MSG(NO_REF_UPDATE));
+ return TRUE;
+ } else if (xp->GetType() == TYPE_SUBQ)
+ // Cannot be correlated because CheckLocal would have failed
+ xp = new(g) CONSTANT(xp->GetValue());
+
+ if (!PlugRephraseSQL(g, setlist + strlen(setlist),
+ xp, TYPE_XOBJECT, tk))
+ return TRUE;
+
+ } // endfor selp
+
+ // Below 16 is enough to take care of the fixed part of the query
+ len += (strlen(setlist) + strlen(Tabname) + 16);
+ Query = (char*)PlugSubAlloc(g, NULL, len);
+ strcat(strcat(strcat(strcpy(Query, "UPDATE "), tk), Tabname), tk);
+ strcat(strcat(Query, " SET "), setlist);
+
+ if (where)
+ strcat(Query, where);
+
+ return FALSE;
+ } // end of MakeUpdate
+
+/***********************************************************************/
+/* MakeDelete: make the Delete statement use with MySQL connection. */
+/* If no filtering Truncate is used because it is faster than Delete. */
+/* However, the number of deleted lines is not returned by MySQL. */
+/* Note: currently limited to local filtering. */
+/***********************************************************************/
+bool TDBMYSQL::MakeDelete(PGLOBAL g)
+ {
+ char *tk = "`";
+ int len = 0;
+
+ if (Query)
+ return FALSE; // already done
+
+ if (!To_Filter)
+ AftRows = -1; // Means "all lines deleted"
+
+ // Below 16 is more than length of 'delete from ' + 3
+ len += (strlen(Tabname) + 16);
+ len += (To_Filter ? strlen(To_Filter) + 7 : 0);
+ Query = (char*)PlugSubAlloc(g, NULL, len);
+ strcpy(Query, (To_Filter) ? "DELETE FROM " : "TRUNCATE ");
+ strcat(strcat(strcat(Query, tk), Tabname), tk);
+
+ if (To_Filter)
+ strcat(strcat(Query, " WHERE "), To_Filter);
+
+ return FALSE;
+ } // end of MakeDelete
+#endif // 0
+
+/***********************************************************************/
+/* XCV GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBMYSQL::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+#if 0
+ if (MakeSelect(g))
+ return -2;
+
+ if (!Myc.Connected()) {
+ if (Myc.Open(g, Host, Database, User, Pwd, Port))
+ return -1;
+
+ } // endif connected
+
+ if ((MaxSize = Myc.GetResultSize(g, Query)) < 0) {
+ Myc.Close();
+ return -3;
+ } // endif MaxSize
+
+ // FIXME: Columns should be known when Info calls GetMaxSize
+ if (!Columns)
+ Query = NULL; // Must be remade when columns are known
+#endif // 0
+
+ MaxSize = 0;
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* This a fake routine as ROWID does not exist in MySQL. */
+/***********************************************************************/
+int TDBMYSQL::RowNumber(PGLOBAL g, bool b)
+ {
+ return N;
+ } // end of RowNumber
+
+/***********************************************************************/
+/* Return 0 in mode DELETE to tell that the delete is done. */
+/***********************************************************************/
+int TDBMYSQL::GetProgMax(PGLOBAL g)
+ {
+ return (Mode == MODE_DELETE || Mode == MODE_UPDATE) ? 0
+ : GetMaxSize(g);
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* MySQL Bind Parameter function. */
+/***********************************************************************/
+int TDBMYSQL::BindColumns(PGLOBAL g)
+ {
+ if (Prep) {
+ Bind = (MYSQL_BIND*)PlugSubAlloc(g, NULL, Nparm * sizeof(MYSQL_BIND));
+
+ for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
+ colp->InitBind(g);
+
+ return Myc.BindParams(g, Bind);
+ } else {
+ for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
+ if (colp->Buf_Type == TYPE_DATE)
+ // Format must match DATETIME MySQL type
+ ((DTVAL*)colp->GetValue())->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
+
+ return RC_OK;
+ } // endif Prep
+
+ } // end of BindColumns
+
+/***********************************************************************/
+/* MySQL Access Method opening routine. */
+/***********************************************************************/
+bool TDBMYSQL::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ Myc.Rewind();
+ return FALSE;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open a MySQL 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 server */
+ /* and if so to allocate just a new result set. But this only for */
+ /* servers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Myc.Connected()) {
+ if (Myc.Open(g, Host, Database, User, Pwd, Port))
+ return TRUE;
+
+ } // endif Connected
+
+ /*********************************************************************/
+ /* Allocate whatever is used for getting results. */
+ /*********************************************************************/
+ if (Mode == MODE_READ) {
+ if (!MakeSelect(g))
+ m_Rc = Myc.ExecSQL(g, Query);
+
+ } else if (Mode == MODE_INSERT) {
+ if (!MakeInsert(g)) {
+ int n = (Prep) ? Myc.PrepareSQL(g, Query) : Nparm;
+
+ if (Nparm != n) {
+ if (n >= 0) // Other errors return negative values
+ strcpy(g->Message, MSG(BAD_PARM_COUNT));
+
+ } else
+ m_Rc = BindColumns(g);
+
+ } // endif MakeInsert
+
+ if (m_Rc != RC_FX) {
+ char cmd[64];
+ int w;
+
+ sprintf(cmd, "ALTER TABLE `%s` DISABLE KEYS", Tabname);
+ m_Rc = Myc.ExecSQL(g, cmd, &w);
+ } // endif m_Rc
+
+#if 0
+ } else if (Next) {
+ strcpy(g->Message, MSG(NO_JOIN_UPDEL));
+ } else if (Mode == MODE_DELETE) {
+ strcpy(g->Message, "MySQL table delete not implemented yet\n");
+ bool rc = MakeDelete(g);
+
+ if (!rc && Myc.ExecSQL(g, Query) == RC_NF) {
+ if (!AftRows)
+ AftRows = Myc.GetRows();
+
+ m_Rc = RC_OK;
+ } // endif ExecSQL
+#endif // 0
+
+ } else {
+// bool rc = MakeUpdate(g, sqlp->GetProj());
+ strcpy(g->Message, "MySQL table delete/update not implemented yet\n");
+ } // endelse
+
+ if (m_Rc == RC_FX) {
+ Myc.Close();
+ return TRUE;
+ } // endif rc
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for MYSQL access method. */
+/***********************************************************************/
+int TDBMYSQL::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (trace > 1)
+ htrc("MySQL ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p\n",
+ GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
+
+ /*********************************************************************/
+ /* Now start the reading process. */
+ /* Here is the place to fetch the line. */
+ /*********************************************************************/
+ N++;
+ Fetched = ((rc = Myc.Fetch(g, -1)) == RC_OK);
+
+ if (trace > 1)
+ htrc(" Read: rc=%d\n", rc);
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for MYSQL access methods. */
+/***********************************************************************/
+int TDBMYSQL::WriteDB(PGLOBAL g)
+ {
+ if (Prep)
+ return Myc.ExecStmt(g);
+
+ // Statement was not prepared, we must construct and execute
+ // an insert query for each line to insert
+ int rc;
+ char buf[32];
+
+ strcpy(Qbuf, Query);
+
+ // Make the Insert command value list
+ for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
+ if (colp->GetResultType() == TYPE_STRING ||
+ colp->GetResultType() == TYPE_DATE)
+ strcat(Qbuf, "'");
+
+ strcat(Qbuf, colp->GetValue()->GetCharString(buf));
+
+ if (colp->GetResultType() == TYPE_STRING ||
+ colp->GetResultType() == TYPE_DATE)
+ strcat(Qbuf, "'");
+
+ strcat(Qbuf, (colp->GetNext()) ? "," : ")");
+ } // endfor colp
+
+ Myc.m_Rows = -1; // To execute the query
+ rc = Myc.ExecSQL(g, Qbuf);
+ return (rc == RC_NF) ? RC_OK : rc; // RC_NF is Ok
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for MYSQL access methods. */
+/***********************************************************************/
+int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
+ {
+ strcpy(g->Message, MSG(NO_MYSQL_DELETE));
+ return RC_FX;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for MySQL access method. */
+/***********************************************************************/
+void TDBMYSQL::CloseDB(PGLOBAL g)
+ {
+ if (Mode == MODE_INSERT) {
+ char cmd[64];
+ int w;
+ PDBUSER dup = PlgGetUser(g);
+
+ dup->Step = "Enabling indexes";
+ sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", Tabname);
+ Myc.m_Rows = -1; // To execute the query
+ m_Rc = Myc.ExecSQL(g, cmd, &w);
+ } // endif m_Rc
+
+ Myc.Close();
+
+ if (trace)
+ htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
+
+ } // end of CloseDB
+
+// ------------------------ MYSQLCOL functions --------------------------
+
+/***********************************************************************/
+/* MYSQLCOL public constructor. */
+/***********************************************************************/
+MYSQLCOL::MYSQLCOL(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();
+ Bind = NULL;
+ To_Val = NULL;
+ Slen = 0;
+ Rank = -1; // Not known yet
+
+ if (trace)
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of MYSQLCOL constructor
+
+/***********************************************************************/
+/* MYSQLCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+MYSQLCOL::MYSQLCOL(MYSQLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Long = col1->Long;
+ Bind = NULL;
+ To_Val = NULL;
+ Slen = col1->Slen;
+ Rank = col1->Rank;
+ } // end of MYSQLCOL copy constructor
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool MYSQLCOL::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
+
+/***********************************************************************/
+/* InitBind: Initialize the bind structure according to type. */
+/***********************************************************************/
+void MYSQLCOL::InitBind(PGLOBAL g)
+ {
+ PTDBMY tdbp = (PTDBMY)To_Tdb;
+
+ assert(tdbp->Bind && Rank < tdbp->Nparm);
+
+ Bind = &tdbp->Bind[Rank];
+ memset(Bind, 0, sizeof(MYSQL_BIND));
+
+ if (Buf_Type == TYPE_DATE) {
+ // Default format must match DATETIME MySQL type
+// if (!((DTVAL*)Value)->IsFormatted())
+ ((DTVAL*)Value)->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
+
+ Bind->buffer_type = PLGtoMYSQL(TYPE_STRING);
+ Bind->buffer = (char *)PlugSubAlloc(g,NULL, 20);
+ Bind->buffer_length = 20;
+ Bind->length = &Slen;
+ } else {
+ Bind->buffer_type = PLGtoMYSQL(Buf_Type);
+ Bind->buffer = (char *)Value->GetTo_Val();
+ Bind->buffer_length = Value->GetClen();
+ Bind->length = (IsTypeChar(Buf_Type)) ? &Slen : NULL;
+ } // endif Buf_Type
+
+ } // end of InitBind
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void MYSQLCOL::ReadColumn(PGLOBAL g)
+ {
+ char *buf;
+ int rc;
+ PTDBMY tdbp = (PTDBMY)To_Tdb;
+
+ if (trace)
+ htrc("MySQL ReadColumn: name=%s\n", Name);
+
+ assert (Rank >= 0);
+
+ /*********************************************************************/
+ /* If physical fetching of the line was deferred, do it now. */
+ /*********************************************************************/
+ if (!tdbp->Fetched)
+ if ((rc = tdbp->Myc.Fetch(g, tdbp->N)) != RC_OK) {
+ if (rc == RC_EF)
+ sprintf(g->Message, MSG(INV_DEF_READ), rc);
+
+ longjmp(g->jumper[g->jump_level], 11);
+ } else
+ tdbp->Fetched = TRUE;
+
+ if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank)))
+ Value->SetValue_char(buf, Long);
+ else
+ Value->Reset(); // Null value
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: make sure the bind buffer is updated. */
+/***********************************************************************/
+void MYSQLCOL::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 (((PTDBMY)To_Tdb)->Prep) {
+ if (Buf_Type == TYPE_DATE) {
+ Value->ShowValue((char *)Bind->buffer, (int)*Bind->length);
+ Slen = strlen((char *)Bind->buffer);
+ } else if (IsTypeChar(Buf_Type))
+ Slen = strlen(Value->GetCharValue());
+
+ } // endif Prep
+
+ } // end of WriteColumn
diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h
index 7507e3889fd..bdd4a80377a 100644
--- a/storage/connect/tabmysql.h
+++ b/storage/connect/tabmysql.h
@@ -1,139 +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
-
+// 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
+
diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp
index c58091a32fb..948d6cda53e 100644
--- a/storage/connect/tabodbc.cpp
+++ b/storage/connect/tabodbc.cpp
@@ -1,1079 +1,1079 @@
-/************* Tabodbc C++ Program Source Code File (.CPP) *************/
-/* PROGRAM NAME: TABODBC */
-/* ------------- */
-/* Version 2.4 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
-/* */
-/* 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>
-#define NODW
-#include "osutil.h"
-#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. */
-/* 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"
-
-#include "sql_string.h"
-
-PQRYRES ODBCDataSources(PGLOBAL g);
-
-/***********************************************************************/
-/* 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 -------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-ODBCDEF::ODBCDEF(void)
- {
- Connect = Tabname = Tabowner = Tabqual = Qchar = NULL;
- Catver = Options = 0;
- Info = false;
- } // end of ODBCDEF constructor
-
-/***********************************************************************/
-/* 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
- Info = Cat->GetBoolCatInfo(Name, "Info", false);
- 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. */
- /*********************************************************************/
- if (!Info) {
- tdbp = new(g) TDBODBC(this);
-
- if (Multiple == 1)
- tdbp = new(g) TDBMUL(tdbp);
- else if (Multiple == 2)
- strcpy(g->Message, MSG(NO_ODBC_MUL));
-
- } else
- tdbp = new(g) TDBOIF(this);
-
- 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
-
-
-/******************************************************************/
-/* Convert an UTF-8 string to latin characters. */
-/******************************************************************/
-int TDBODBC::Decode(char *txt, char *buf, size_t n)
-{
- uint dummy_errors;
- uint32 len= copy_and_convert(buf, n, &my_charset_latin1,
- txt, strlen(txt),
- &my_charset_utf8_general_ci,
- &dummy_errors);
- buf[len]= '\0';
- return 0;
-} // end of Decode
-
-
-/***********************************************************************/
-/* 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 (!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(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(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 (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
-
-/* ---------------------------TDBOIF class --------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBOIF class. */
-/***********************************************************************/
-TDBOIF::TDBOIF(PODEF tdp) : TDBASE(tdp)
- {
- Qrp = NULL;
- Init = false;
- N = -1;
- } // end of TDBOIF constructor
-
-/***********************************************************************/
-/* Allocate OIF column description block. */
-/***********************************************************************/
-PCOL TDBOIF::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- POIFCOL colp;
-
- colp = (POIFCOL)new(g) OIFCOL(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, "Name"))
- colp->Flag = 1;
- else if (!stricmp(colp->Name, "Description"))
- colp->Flag = 2;
-
- } // endif Flag
-
- return colp;
- } // end of MakeCol
-
-/***********************************************************************/
-/* Initialize: Get the list of ODBC data sources. */
-/***********************************************************************/
-bool TDBOIF::Initialize(PGLOBAL g)
- {
- if (Init)
- return false;
-
- if (!(Qrp = ODBCDataSources(g)))
- return true;
-
- Init = true;
- return false;
- } // end of Initialize
-
-/***********************************************************************/
-/* OIF: Get the number of properties. */
-/***********************************************************************/
-int TDBOIF::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0) {
- if (Initialize(g))
- return -1;
-
- MaxSize = Qrp->Nblin;
- } // endif MaxSize
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* OIF Access Method opening routine. */
-/***********************************************************************/
-bool TDBOIF::OpenDB(PGLOBAL g)
- {
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open. */
- /*******************************************************************/
- N = -1;
- return false;
- } // endif use
-
- if (Mode != MODE_READ) {
- /*******************************************************************/
- /* ODBC Info tables cannot be modified. */
- /*******************************************************************/
- strcpy(g->Message, "OIF tables are read only");
- return true;
- } // endif Mode
-
- /*********************************************************************/
- /* Initialize the ODBC processing. */
- /*********************************************************************/
- if (Initialize(g))
- return true;
-
- return InitCol(g);
- } // end of OpenDB
-
-/***********************************************************************/
-/* Initialize columns. */
-/***********************************************************************/
-bool TDBOIF::InitCol(PGLOBAL g)
- {
- POIFCOL colp;
-
- for (colp = (POIFCOL)Columns; colp; colp = (POIFCOL)colp->GetNext())
- switch (colp->Flag) {
- case 1:
- colp->Crp = Qrp->Colresp;
- break;
- case 2:
- colp->Crp = Qrp->Colresp->Next;
- break;
- default:
- strcpy(g->Message, "Invalid column name or flag");
- return true;
- } // endswitch Flag
-
- return false;
- } // end of InitCol
-
-/***********************************************************************/
-/* Data Base read routine for OIF access method. */
-/***********************************************************************/
-int TDBOIF::ReadDB(PGLOBAL g)
- {
- return (++N < Qrp->Nblin) ? RC_OK : RC_EF;
- } // end of ReadDB
-
-/***********************************************************************/
-/* WriteDB: Data Base write routine for OIF access methods. */
-/***********************************************************************/
-int TDBOIF::WriteDB(PGLOBAL g)
- {
- strcpy(g->Message, "OIF tables are read only");
- return RC_FX;
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for OIF access methods. */
-/***********************************************************************/
-int TDBOIF::DeleteDB(PGLOBAL g, int irc)
- {
- strcpy(g->Message, "Delete not enabled for OIF tables");
- return RC_FX;
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for WMI access method. */
-/***********************************************************************/
-void TDBOIF::CloseDB(PGLOBAL g)
- {
- // Nothing to do
- } // end of CloseDB
-
-// ------------------------ OIFCOL functions ----------------------------
-
-/***********************************************************************/
-/* OIFCOL public constructor. */
-/***********************************************************************/
-OIFCOL::OIFCOL(PCOLDEF cdp, PTDB tdbp, int n)
- : COLBLK(cdp, tdbp, n)
- {
- Tdbp = (PTDBOIF)tdbp;
- Crp = NULL;
- Flag = cdp->GetOffset();
- } // end of WMICOL constructor
-
-/***********************************************************************/
-/* Read the next Data Source elements. */
-/***********************************************************************/
-void OIFCOL::ReadColumn(PGLOBAL g)
- {
- // Get the value of the Name or Description property
- Value->SetValue_psz(Crp->Kdata->GetCharValue(Tdbp->N));
- } // end of ReadColumn
-
-/* ------------------------ End of Tabodbc --------------------------- */
+/************* Tabodbc C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: TABODBC */
+/* ------------- */
+/* Version 2.4 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
+/* */
+/* 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>
+#define NODW
+#include "osutil.h"
+#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. */
+/* 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"
+
+#include "sql_string.h"
+
+PQRYRES ODBCDataSources(PGLOBAL g);
+
+/***********************************************************************/
+/* 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 -------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+ODBCDEF::ODBCDEF(void)
+ {
+ Connect = Tabname = Tabowner = Tabqual = Qchar = NULL;
+ Catver = Options = 0;
+ Info = false;
+ } // end of ODBCDEF constructor
+
+/***********************************************************************/
+/* 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
+ Info = Cat->GetBoolCatInfo(Name, "Info", false);
+ 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. */
+ /*********************************************************************/
+ if (!Info) {
+ tdbp = new(g) TDBODBC(this);
+
+ if (Multiple == 1)
+ tdbp = new(g) TDBMUL(tdbp);
+ else if (Multiple == 2)
+ strcpy(g->Message, MSG(NO_ODBC_MUL));
+
+ } else
+ tdbp = new(g) TDBOIF(this);
+
+ 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
+
+
+/******************************************************************/
+/* Convert an UTF-8 string to latin characters. */
+/******************************************************************/
+int TDBODBC::Decode(char *txt, char *buf, size_t n)
+{
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, n, &my_charset_latin1,
+ txt, strlen(txt),
+ &my_charset_utf8_general_ci,
+ &dummy_errors);
+ buf[len]= '\0';
+ return 0;
+} // end of Decode
+
+
+/***********************************************************************/
+/* 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 (!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(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(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 (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
+
+/* ---------------------------TDBOIF class --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBOIF class. */
+/***********************************************************************/
+TDBOIF::TDBOIF(PODEF tdp) : TDBASE(tdp)
+ {
+ Qrp = NULL;
+ Init = false;
+ N = -1;
+ } // end of TDBOIF constructor
+
+/***********************************************************************/
+/* Allocate OIF column description block. */
+/***********************************************************************/
+PCOL TDBOIF::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ POIFCOL colp;
+
+ colp = (POIFCOL)new(g) OIFCOL(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, "Name"))
+ colp->Flag = 1;
+ else if (!stricmp(colp->Name, "Description"))
+ colp->Flag = 2;
+
+ } // endif Flag
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Initialize: Get the list of ODBC data sources. */
+/***********************************************************************/
+bool TDBOIF::Initialize(PGLOBAL g)
+ {
+ if (Init)
+ return false;
+
+ if (!(Qrp = ODBCDataSources(g)))
+ return true;
+
+ Init = true;
+ return false;
+ } // end of Initialize
+
+/***********************************************************************/
+/* OIF: Get the number of properties. */
+/***********************************************************************/
+int TDBOIF::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ if (Initialize(g))
+ return -1;
+
+ MaxSize = Qrp->Nblin;
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* OIF Access Method opening routine. */
+/***********************************************************************/
+bool TDBOIF::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open. */
+ /*******************************************************************/
+ N = -1;
+ return false;
+ } // endif use
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* ODBC Info tables cannot be modified. */
+ /*******************************************************************/
+ strcpy(g->Message, "OIF tables are read only");
+ return true;
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Initialize the ODBC processing. */
+ /*********************************************************************/
+ if (Initialize(g))
+ return true;
+
+ return InitCol(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Initialize columns. */
+/***********************************************************************/
+bool TDBOIF::InitCol(PGLOBAL g)
+ {
+ POIFCOL colp;
+
+ for (colp = (POIFCOL)Columns; colp; colp = (POIFCOL)colp->GetNext())
+ switch (colp->Flag) {
+ case 1:
+ colp->Crp = Qrp->Colresp;
+ break;
+ case 2:
+ colp->Crp = Qrp->Colresp->Next;
+ break;
+ default:
+ strcpy(g->Message, "Invalid column name or flag");
+ return true;
+ } // endswitch Flag
+
+ return false;
+ } // end of InitCol
+
+/***********************************************************************/
+/* Data Base read routine for OIF access method. */
+/***********************************************************************/
+int TDBOIF::ReadDB(PGLOBAL g)
+ {
+ return (++N < Qrp->Nblin) ? RC_OK : RC_EF;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for OIF access methods. */
+/***********************************************************************/
+int TDBOIF::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, "OIF tables are read only");
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for OIF access methods. */
+/***********************************************************************/
+int TDBOIF::DeleteDB(PGLOBAL g, int irc)
+ {
+ strcpy(g->Message, "Delete not enabled for OIF tables");
+ return RC_FX;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for WMI access method. */
+/***********************************************************************/
+void TDBOIF::CloseDB(PGLOBAL g)
+ {
+ // Nothing to do
+ } // end of CloseDB
+
+// ------------------------ OIFCOL functions ----------------------------
+
+/***********************************************************************/
+/* OIFCOL public constructor. */
+/***********************************************************************/
+OIFCOL::OIFCOL(PCOLDEF cdp, PTDB tdbp, int n)
+ : COLBLK(cdp, tdbp, n)
+ {
+ Tdbp = (PTDBOIF)tdbp;
+ Crp = NULL;
+ Flag = cdp->GetOffset();
+ } // end of WMICOL constructor
+
+/***********************************************************************/
+/* Read the next Data Source elements. */
+/***********************************************************************/
+void OIFCOL::ReadColumn(PGLOBAL g)
+ {
+ // Get the value of the Name or Description property
+ Value->SetValue_psz(Crp->Kdata->GetCharValue(Tdbp->N));
+ } // end of ReadColumn
+
+/* ------------------------ End of Tabodbc --------------------------- */
diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h
index 5509d3df679..70edd337c8c 100644
--- a/storage/connect/tabodbc.h
+++ b/storage/connect/tabodbc.h
@@ -1,225 +1,225 @@
-/*************** Tabodbc H Declares Source Code File (.H) **************/
-/* Name: TABODBC.H Version 1.5 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
-/* */
-/* This file contains the TDBODBC classes declares. */
-/***********************************************************************/
-#include "colblk.h"
-
-typedef class ODBCDEF *PODEF;
-typedef class TDBODBC *PTDBODBC;
-typedef class ODBCCOL *PODBCCOL;
-typedef class TDBOIF *PTDBOIF;
-typedef class OIFCOL *POIFCOL;
-
-/***********************************************************************/
-/* ODBC table. */
-/***********************************************************************/
-class DllExport ODBCDEF : public TABDEF { /* Logical table description */
- public:
- // Constructor
- ODBCDEF(void);
-
- // 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 */
- bool Info; /* true if getting data sources */
- }; // 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
- int Decode(char *utf, char *buf, size_t n);
- 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
-
-/***********************************************************************/
-/* This is the class declaration for the ODBC info table. */
-/***********************************************************************/
-class TDBOIF : public TDBASE {
- friend class OIFCOL;
- public:
- // Constructor
- TDBOIF(PODEF tdp);
-
- // Implementation
- virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
-
- // 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);
- bool InitCol(PGLOBAL g);
-
- // Members
- PQRYRES Qrp;
- int N; // Row number
- bool Init;
- }; // end of class TDBOIF
-
-/***********************************************************************/
-/* Class OIFCOL: ODBC info column. */
-/***********************************************************************/
-class OIFCOL : public COLBLK {
- friend class TDBOIF;
- public:
- // Constructors
- OIFCOL(PCOLDEF cdp, PTDB tdbp, int n);
-
- // Implementation
- virtual int GetAmType(void) {return TYPE_AM_ODBC;}
-
- // Methods
- virtual void ReadColumn(PGLOBAL g);
-
- protected:
- OIFCOL(void) {} // Default constructor not to be used
-
- // Members
- PTDBOIF Tdbp; // Points to ODBC table block
- PCOLRES Crp; // The column data array
- int Flag;
- }; // end of class OIFCOL
-#endif // !NODBC
-
+/*************** Tabodbc H Declares Source Code File (.H) **************/
+/* Name: TABODBC.H Version 1.5 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
+/* */
+/* This file contains the TDBODBC classes declares. */
+/***********************************************************************/
+#include "colblk.h"
+
+typedef class ODBCDEF *PODEF;
+typedef class TDBODBC *PTDBODBC;
+typedef class ODBCCOL *PODBCCOL;
+typedef class TDBOIF *PTDBOIF;
+typedef class OIFCOL *POIFCOL;
+
+/***********************************************************************/
+/* ODBC table. */
+/***********************************************************************/
+class DllExport ODBCDEF : public TABDEF { /* Logical table description */
+ public:
+ // Constructor
+ ODBCDEF(void);
+
+ // 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 */
+ bool Info; /* true if getting data sources */
+ }; // 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
+ int Decode(char *utf, char *buf, size_t n);
+ 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
+
+/***********************************************************************/
+/* This is the class declaration for the ODBC info table. */
+/***********************************************************************/
+class TDBOIF : public TDBASE {
+ friend class OIFCOL;
+ public:
+ // Constructor
+ TDBOIF(PODEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
+
+ // 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);
+ bool InitCol(PGLOBAL g);
+
+ // Members
+ PQRYRES Qrp;
+ int N; // Row number
+ bool Init;
+ }; // end of class TDBOIF
+
+/***********************************************************************/
+/* Class OIFCOL: ODBC info column. */
+/***********************************************************************/
+class OIFCOL : public COLBLK {
+ friend class TDBOIF;
+ public:
+ // Constructors
+ OIFCOL(PCOLDEF cdp, PTDB tdbp, int n);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_ODBC;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ OIFCOL(void) {} // Default constructor not to be used
+
+ // Members
+ PTDBOIF Tdbp; // Points to ODBC table block
+ PCOLRES Crp; // The column data array
+ int Flag;
+ }; // end of class OIFCOL
+#endif // !NODBC
+
diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp
index 3e5b7c0e117..fccd8338d8a 100644
--- a/storage/connect/tabpivot.cpp
+++ b/storage/connect/tabpivot.cpp
@@ -1,1202 +1,1202 @@
-/************ TabPivot C++ Program Source Code File (.CPP) *************/
-/* PROGRAM NAME: TABPIVOT */
-/* ------------- */
-/* Version 1.3 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the PIVOT classes DB execution routines. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant sections of the operating system header file. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-#if defined(__BORLANDC__)
-#define __MFC_COMPAT__ // To define min/max as macro
-#endif
-//#include <windows.h>
-#elif defined(UNIX)
-#include <errno.h>
-#include <unistd.h>
-#include "osutil.h"
-#else
-#include <io.h>
-#endif
-
-/***********************************************************************/
-/* Include application header files: */
-/* global.h is header containing all global declarations. */
-/* plgdbsem.h is header containing the DB application declarations. */
-/***********************************************************************/
-#define FRM_VER 6
-#include "table.h" // MySQL table definitions
-#include "sql_const.h"
-#include "field.h"
-#include "global.h"
-#include "plgdbsem.h"
-#include "xtable.h"
-#include "xindex.h"
-#include "colblk.h"
-#include "tabmysql.h"
-#include "csort.h"
-#include "tabpivot.h"
-#include "valblk.h"
-#include "ha_connect.h"
-#include "mycat.h" // For GetHandler
-
-extern "C" int trace;
-
-/* --------------- Implementation of the PIVOT classes --------------- */
-
-/***********************************************************************/
-/* DefineAM: define specific AM block values from PIVOT table. */
-/***********************************************************************/
-bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- char *p1, *p2;
- PHC hc = ((MYCAT*)Cat)->GetHandler();
-
- Host = Cat->GetStringCatInfo(g, Name, "Host", "localhost");
- User = Cat->GetStringCatInfo(g, Name, "User", "root");
- Pwd = Cat->GetStringCatInfo(g, Name, "Password", NULL);
- DB = Cat->GetStringCatInfo(g, Name, "Database", (PSZ)hc->GetDBName(NULL));
- Tabsrc = Cat->GetStringCatInfo(g, Name, "SrcDef", NULL);
- Tabname = Cat->GetStringCatInfo(g, Name, "Name", NULL);
- Picol = Cat->GetStringCatInfo(g, Name, "PivotCol", NULL);
- Fncol = Cat->GetStringCatInfo(g, Name, "FncCol", NULL);
-
- // If fncol is like avg(colname), separate Fncol and Function
- if (Fncol && (p1 = strchr(Fncol, '(')) && (p2 = strchr(p1, ')')) &&
- (*Fncol != '"') && (!*(p2+1))) {
- *p1++ = '\0'; *p2 = '\0';
- Function = Fncol;
- Fncol = p1;
- } else
- Function = Cat->GetStringCatInfo(g, Name, "Function", "SUM");
-
- GBdone = Cat->GetIntCatInfo(Name, "Groupby", 0) ? TRUE : FALSE;
- Port = Cat->GetIntCatInfo(Name, "Port", 3306);
- Desc = (*Tabname) ? Tabname : Tabsrc;
- return FALSE;
- } // end of DefineAM
-
-/***********************************************************************/
-/* GetTable: makes a new TDB of the proper type. */
-/***********************************************************************/
-PTDB PIVOTDEF::GetTable(PGLOBAL g, MODE m)
- {
- return new(g) TDBPIVOT(this);
- } // end of GetTable
-
-/* ------------------------------------------------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBPIVOT class. */
-/***********************************************************************/
-TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBASE(tdp), CSORT(FALSE)
- {
- Tqrp = NULL;
- Host = tdp->Host;
- Database = tdp->DB;
- User = tdp->User;
- Pwd = tdp->Pwd;
- Port = tdp->Port;
- Qryp = NULL;
- Tabname = tdp->Tabname; // Name of source table
- Tabsrc = tdp->Tabsrc; // SQL description of source table
- Picol = tdp->Picol; // Pivot column name
- Fncol = tdp->Fncol; // Function column name
- Function = tdp->Function; // Aggregate function name
- Xcolp = NULL; // To the FNCCOL column
-//Xresp = NULL; // To the pivot result column
-//Rblkp = NULL; // The value block of the pivot column
- Fcolp = NULL; // To the function column
- GBdone = tdp->GBdone;
- Mult = -1; // Estimated table size
- N = 0; // The current table index
- M = 0; // The occurence rank
- FileStatus = 0; // Logical End-of-File
- RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
- } // end of TDBPIVOT constructor
-
-#if 0
-TDBPIVOT::TDBPIVOT(PTDBPIVOT tdbp) : TDBASE(tdbp), CSORT(FALSE)
- {
- Tdbp = tdbp->Tdbp;
- Sqlp = tdbp->Sqlp;
- Qryp = tdbp->Qryp;
- Tabname = tdbp->Tabname;
- Tabsrc = tdbp->Tabsrc;
- Picol = tdbp->Picol;
- Fncol = tdbp->Fncol;
- Function = tdbp->Function;
- Xcolp = tdbp->Xcolp;
- Xresp = tdbp->Xresp;
- Rblkp = tdbp->Rblkp;
- Fcolp = tdbp->Fcolp;
- Mult = tdbp->Mult;
- N = tdbp->N;
- M = tdbp->M;
- FileStatus = tdbp->FileStatus;
- RowFlag = tdbp->RowFlag;
- } // end of TDBPIVOT copy constructor
-
-// Is this really useful ???
-PTDB TDBPIVOT::CopyOne(PTABS t)
- {
- PTDB tp = new(t->G) TDBPIVOT(this);
-
- tp->SetColumns(Columns);
- return tp;
- } // end of CopyOne
-#endif // 0
-
-/***********************************************************************/
-/* Prepare the source table Query. */
-/***********************************************************************/
-PQRYRES TDBPIVOT::GetSourceTable(PGLOBAL g)
- {
- if (Qryp)
- return Qryp; // Already done
-
- if (!Tabsrc && Tabname) {
- char *def, *colist;
- size_t len = 0;
- PCOL colp;
- PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- // Evaluate the length of the column list
- for (colp = Columns; colp; colp = colp->GetNext())
- len += (strlen(colp->GetName()) + 2);
-
- *(colist = (char*)PlugSubAlloc(g, NULL, len)) = 0;
-
- // Locate the suballocated string (size is not known yet)
- def = (char*)PlugSubAlloc(g, NULL, 0);
- strcpy(def, "SELECT ");
-
- if (!Fncol) {
- for (colp = Columns; colp; colp = colp->GetNext())
- if (!Picol || stricmp(Picol, colp->GetName()))
- Fncol = colp->GetName();
-
- if (!Fncol) {
- strcpy(g->Message, MSG(NO_DEF_FNCCOL));
- return NULL;
- } // endif Fncol
-
- } else if (!(ColDB(g, Fncol, 0))) {
- // Function column not found in table
- sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname);
- return NULL;
- } // endif Fcolp
-
- if (!Picol) {
- // Find default Picol as the last one not equal to Fncol
- for (colp = Columns; colp; colp = colp->GetNext())
- if (!Fncol || stricmp(Fncol, colp->GetName()))
- Picol = colp->GetName();
-
- if (!Picol) {
- strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
- return NULL;
- } // endif Picol
-
- } else if (!(ColDB(g, Picol, 0))) {
- // Pivot column not found in table
- sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname);
- return NULL;
- } // endif Xcolp
-
- // Make the other column list
- for (colp = Columns; colp; colp = colp->GetNext())
- if (stricmp(Picol, colp->GetName()) &&
- stricmp(Fncol, colp->GetName()))
- strcat(strcat(colist, colp->GetName()), ", ");
-
- // Add the Pivot column at the end of the list
- strcat(strcat(def, strcat(colist, Picol)), ", ");
-
- // Continue making the definition
- if (!GBdone) {
- // Make it suitable for Pivot by doing the group by
- strcat(strcat(def, Function), "(");
- strcat(strcat(strcat(def, Fncol), ") "), Fncol);
- strcat(strcat(def, " FROM "), Tabname);
- strcat(strcat(def, " GROUP BY "), colist);
- } else // Gbdone
- strcat(strcat(strcat(def, Fncol), " FROM "), Tabname);
-
- // Now we know how much was suballocated
- Tabsrc = (char*)PlugSubAlloc(g, NULL, strlen(def));
- } else {
- strcpy(g->Message, MSG(SRC_TABLE_UNDEF));
- return NULL;
- } // endif Tabsrc
-
- int w;
-
- // Open a MySQL connection for this table
- if (Myc.Open(g, Host, Database, User, Pwd, Port))
- return NULL;
-
- // Send the source command to MySQL
- if (Myc.ExecSQL(g, Tabsrc, &w) == RC_FX) {
- Myc.Close();
- return NULL;
- } // endif Exec
-
- // We must have a storage query to get pivot column values
- Qryp = Myc.GetResult(g);
- Myc.Close();
- Tqrp = new(g) TDBQRS(Qryp);
- Tqrp->OpenDB(g);
-
- if (MakePivotColumns(g) < 0)
- return NULL;
-
- return Qryp;
- } // end of GetSourceTable
-
-/***********************************************************************/
-/* Allocate PIVOT columns description block. */
-/***********************************************************************/
-int TDBPIVOT::MakePivotColumns(PGLOBAL g)
- {
- if (Mult < 0) {
- int ndif, n = 0, nblin = Qryp->Nblin;
- PVAL valp;
- PCOL cp;
- PSRCCOL colp;
- PFNCCOL cfnp;
-
- // Allocate all the source columns
- Tqrp->ColDB(g, NULL, 0);
- Columns = NULL; // Discard dummy columns blocks
-
- for (cp = Tqrp->GetColumns(); cp; cp = cp->GetNext()) {
- if (cp->InitValue(g))
- return -1;
-
- if (!stricmp(cp->GetName(), Picol)) {
- Xcolp = (PQRSCOL)cp;
- Xresp = Xcolp->GetCrp();
- Rblkp = Xresp->Kdata;
- } else if (!stricmp(cp->GetName(), Fncol)) {
- Fcolp = (PQRSCOL)cp;
- } else
- if ((colp = new(g) SRCCOL(cp, this, ++n))->Init(g, this))
- return -1;
-
- } // endfor cp
-
- if (!Xcolp) {
- sprintf(g->Message, MSG(COL_ISNOT_TABLE),
- Picol, Tabname ? Tabname : "TabSrc");
- return -1;
- } else if (!Fcolp) {
- sprintf(g->Message, MSG(COL_ISNOT_TABLE),
- Fncol, Tabname ? Tabname : "TabSrc");
- return -1;
- } // endif Fcolp
-
- // Before calling sort, initialize all
- Index.Size = nblin * sizeof(int);
- Index.Sub = TRUE; // Should be small enough
-
- if (!PlgDBalloc(g, NULL, Index))
- return -1;
-
- Offset.Size = (nblin + 1) * sizeof(int);
- Offset.Sub = TRUE; // Should be small enough
-
- if (!PlgDBalloc(g, NULL, Offset))
- return -2;
-
- ndif = Qsort(g, nblin);
-
- if (ndif < 0) { // error
- return -3;
- } else
- Ncol = ndif;
-
- // Now make the functional columns
- for (int i = 0; i < Ncol; i++) {
- // Allocate the Value used to retieve column names
- if (!(valp = AllocateValue(g, Xcolp->GetResultType(),
- Xcolp->GetLengthEx(), Xcolp->GetPrecision(),
- Xcolp->GetDomain(), Xcolp->GetTo_Tdb()->GetCat())))
- return -4;
-
- // Get the value that will be the generated column name
- valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]);
-
- // Copy the functional column with new Name and new Value
- cfnp = (PFNCCOL)new(g) FNCCOL(Fcolp, this);
-
- // Initialize the generated column
- if (cfnp->InitColumn(g, valp))
- return -5;
-
- } // endfor i
-
- // Fields must be updated for ha_connect
-// if (UpdateTableFields(g, n + Ncol))
-// return -6;
-
- // This should be refined later
- Mult = nblin;
- } // endif Mult
-
- return Mult;
- } // end of MakePivotColumns
-
-#if 0
-/***********************************************************************/
-/* Update fields in the MySQL table structure */
-/* Note: this does not work. Indeed the new rows are correctly made */
-/* but the final result still specify the unmodified table and the */
-/* returned table only contains the original column values. */
-/* In addition, a new query on the table, when it is into the cache, */
-/* specifies all the new columns and fails because they do not belong */
-/* to the original table. */
-/***********************************************************************/
-bool TDBPIVOT::UpdateTableFields(PGLOBAL g, int n)
- {
- uchar *trec, *srec, *tptr, *sptr;
- int i = 0, k = 0;
- uint len;
- uint32 nmp, lwm;
- size_t buffsize;
- PCOL colp;
- PHC hc = ((MYCAT*)((PIVOTDEF*)To_Def)->Cat)->GetHandler();
- TABLE *table = hc->GetTable();
- st_mem_root *tmr = &table->mem_root;
- st_mem_root *smr = &table->s->mem_root;
- Field* *field;
- Field *fp, *tfncp, *sfncp;
- Field* *ntf;
- Field* *nsf;
-//my_bitmap_map *org_bitmap;
- const MY_BITMAP *map;
-
- // When sorting read_set selects all columns, so we use def_read_set
- map= (const MY_BITMAP *)&table->def_read_set;
-
- // Find the function field
- for (field= table->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(fp->field_name, Fncol)) {
- tfncp = fp;
- break;
- } // endif Name
-
- } // endfor field
-
- for (field= table->s->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(fp->field_name, Fncol)) {
- sfncp = fp;
- break;
- } // endif Name
-
- } // endfor field
-
- // Calculate the new buffer size
- len = tfncp->max_data_length();
- buffsize = table->s->rec_buff_length + len * Ncol;
-
- // Allocate the new record space
- if (!(tptr = trec = (uchar*)alloc_root(tmr, 2 * buffsize)))
- return TRUE;
-
- if (!(sptr = srec = (uchar*)alloc_root(smr, 2 * buffsize)))
- return TRUE;
-
-
- // Allocate the array of all new table field pointers
- if (!(ntf = (Field**)alloc_root(tmr, (uint)((n+1) * sizeof(Field*)))))
- return TRUE;
-
- // Allocate the array of all new table share field pointers
- if (!(nsf = (Field**)alloc_root(smr, (uint)((n+1) * sizeof(Field*)))))
- return TRUE;
-
- // First fields are the the ones of the source columns
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_SRC) {
- for (field= table->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(colp->GetName(), fp->field_name)) {
- ntf[i] = fp;
- fp->field_index = i++;
- fp->ptr = tptr;
- tptr += fp->max_data_length();
- break;
- } // endif Name
-
- } // endfor field
-
- for (field= table->s->field; *field; field++) {
- fp= *field;
-
- if (bitmap_is_set(map, fp->field_index))
- if (!stricmp(colp->GetName(), fp->field_name)) {
- nsf[k] = fp;
- fp->field_index = k++;
- fp->ptr = srec;
- srec += fp->max_data_length();
- break;
- } // endif Name
-
- } // endfor field
-
- } // endif AmType
-
- // Now add the pivot generated columns
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_FNC) {
- if ((fp = (Field*)memdup_root(tmr, (char*)tfncp, tfncp->size_of()))) {
- ntf[i] = fp;
- fp->ptr = tptr;
- fp->field_name = colp->GetName();
- fp->field_index = i++;
- fp->vcol_info = NULL;
- fp->stored_in_db = TRUE;
- tptr += len;
- } else
- return TRUE;
-
- if ((fp = (Field*)memdup_root(smr, (char*)sfncp, sfncp->size_of()))) {
- nsf[i] = fp;
- fp->ptr = sptr;
- fp->field_name = colp->GetName();
- fp->field_index = k++;
- fp->vcol_info = NULL;
- fp->stored_in_db = TRUE;
- sptr += len;
- } else
- return TRUE;
-
- } // endif AM_FNC
-
- // Mark end of the list
- ntf[i] = NULL;
- nsf[k] = NULL;
-
- // Update the table fields
- nmp = (uint32)((1<<i) - 1);
- lwm = (uint32)((-1)<<i);
- table->field = ntf;
- table->used_fields = i;
- table->record[0] = trec;
- table->record[1] = trec + buffsize;
- *table->def_read_set.bitmap = nmp;
- *table->def_read_set.last_word_ptr = nmp;
- table->def_read_set.last_word_mask = lwm;
- table->def_read_set.n_bits = i;
- *table->read_set->bitmap = nmp;
- *table->read_set->last_word_ptr = nmp;
- table->read_set->last_word_mask = lwm;
- table->read_set->n_bits = i;
- table->write_set->n_bits = i;
- *table->vcol_set->bitmap = 0;
- table->vcol_set->n_bits = i;
-
- // and the share fields
- table->s->field = nsf;
- table->s->reclength = sptr - srec;
- table->s->stored_rec_length = sptr - srec;
- table->s->fields = k;
- table->s->stored_fields = k;
- table->s->rec_buff_length = buffsize;
-//table->s->varchar_fields = ???;
-//table->s->db_record_offset = ???;
-//table->s->null_field_first = ???;
- return FALSE;
- } // end of UpdateTableFields
-#endif // 0
-
-/***********************************************************************/
-/* Allocate source column description block. */
-/***********************************************************************/
-PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- PCOL colp = NULL;
-
-//if (stricmp(cdp->GetName(), Picol) && stricmp(cdp->GetName(), Fncol)) {
- colp = new(g) COLBLK(cdp, this, n);
-
-// if (((PSRCCOL)colp)->Init(g, this))
-// return NULL;
-
-//} else {
-// sprintf(g->Message, MSG(NO_MORE_COL), cdp->GetName());
-// return NULL;
-//} // endif Name
-
- if (cprec) {
- colp->SetNext(cprec->GetNext());
- cprec->SetNext(colp);
- } else {
- colp->SetNext(Columns);
- Columns = colp;
- } // endif cprec
-
- return colp;
- } // end of MakeCol
-
-/***********************************************************************/
-/* PIVOT GetMaxSize: returns the maximum number of rows in the table. */
-/***********************************************************************/
-int TDBPIVOT::GetMaxSize(PGLOBAL g)
- {
-#if 0
- if (MaxSize < 0)
- MaxSize = MakePivotColumns(g);
-
- return MaxSize;
-#endif // 0
- return 0;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* In this sample, ROWID will be the (virtual) row number, */
-/* while ROWNUM will be the occurence rank in the multiple column. */
-/***********************************************************************/
-int TDBPIVOT::RowNumber(PGLOBAL g, bool b)
- {
- return (b) ? M : N;
- } // end of RowNumber
-
-/***********************************************************************/
-/* PIVOT Access Method opening routine. */
-/***********************************************************************/
-bool TDBPIVOT::OpenDB(PGLOBAL g)
- {
-//PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open, just replace it at its beginning. */
- /*******************************************************************/
- N = M = 0;
- RowFlag = 0;
- FileStatus = 0;
- return FALSE;
- } // endif use
-
- /*********************************************************************/
- /* Do it here if not done yet (should not be the case). */
- /*********************************************************************/
-//if (MakePivotColumns(g) < 0)
- if (!(Qryp = GetSourceTable(g)))
- return TRUE;
-
- if (Mode != MODE_READ) {
- /*******************************************************************/
- /* Currently PIVOT tables cannot be modified. */
- /*******************************************************************/
- sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
- return TRUE;
- } // endif Mode
-
- if (To_Key_Col || To_Kindex) {
- /*******************************************************************/
- /* Direct access of PIVOT tables is not implemented yet. */
- /*******************************************************************/
- strcpy(g->Message, MSG(NO_PIV_DIR_ACC));
- return TRUE;
- } // endif To_Key_Col
-
- return FALSE;
- } // end of OpenDB
-
-/***********************************************************************/
-/* Data Base read routine for PIVOT access method. */
-/***********************************************************************/
-int TDBPIVOT::ReadDB(PGLOBAL g)
- {
- int rc = RC_OK;
- bool newrow = FALSE;
- PCOL colp;
- PVAL vp1, vp2;
-
- if (FileStatus == 2)
- return RC_EF;
-
- if (FileStatus)
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_SRC)
- ((PSRCCOL)colp)->SetColumn();
-
- // New row, reset all function column values
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_FNC)
- colp->GetValue()->Reset();
-
- /*********************************************************************/
- /* Now start the multi reading process. */
- /*********************************************************************/
- do {
- if (RowFlag != 1) {
- if ((rc = Tqrp->ReadDB(g)) != RC_OK) {
- if (FileStatus && rc == RC_EF) {
- // A prepared row remains to be sent
- FileStatus = 2;
- rc = RC_OK;
- } // endif FileStatus
-
- break;
- } // endif rc
-
- for (colp = Tqrp->GetColumns(); colp; colp = colp->GetNext())
- colp->ReadColumn(g);
-
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_SRC)
- if (FileStatus) {
- if (((PSRCCOL)colp)->CompareColumn())
- newrow = (RowFlag) ? TRUE : FALSE;
-
- } else
- ((PSRCCOL)colp)->SetColumn();
-
- FileStatus = 1;
- } // endif RowFlag
-
- if (newrow) {
- RowFlag = 1;
- break;
- } else
- RowFlag = 2;
-
- vp1 = Xcolp->GetValue();
-
- // Look for the column having this header
- for (colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_FNC) {
- vp2 = ((PFNCCOL)colp)->Hval;
-
- if (!vp1->CompareValue(vp2))
- break;
-
- } // endif AmType
-
- if (!colp) {
- strcpy(g->Message, MSG(NO_MATCH_COL));
- return RC_FX;
- } // endif colp
-
- // Set the value of the matching column from the fonction value
- colp->GetValue()->SetValue_pval(Fcolp->GetValue());
- } while (RowFlag == 2);
-
- N++;
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* WriteDB: Data Base write routine for PIVOT access methods. */
-/***********************************************************************/
-int TDBPIVOT::WriteDB(PGLOBAL g)
- {
- sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
- return RC_FX;
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for PIVOT access methods. */
-/***********************************************************************/
-int TDBPIVOT::DeleteDB(PGLOBAL g, int irc)
- {
- sprintf(g->Message, MSG(NO_TABLE_DEL), "PIVOT");
- return RC_FX;
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for PIVOT access method. */
-/***********************************************************************/
-void TDBPIVOT::CloseDB(PGLOBAL g)
- {
-//Tdbp->CloseDB(g);
- } // end of CloseDB
-
-/***********************************************************************/
-/* TDBPIVOT: Compare routine for sorting pivot column values. */
-/***********************************************************************/
-int TDBPIVOT::Qcompare(int *i1, int *i2)
- {
- // TODO: the actual comparison between pivot column result values.
- return Rblkp->CompVal(*i1, *i2);
- } // end of Qcompare
-
-// ------------------------ FNCCOL functions ----------------------------
-
-/***********************************************************************/
-/* FNCCOL public constructor. */
-/***********************************************************************/
-FNCCOL::FNCCOL(PCOL col1, PTDBPIVOT tdbp)
- : COLBLK(col1, tdbp)
- {
- Value = NULL; // We'll get a new one later
- Hval = NULL; // The unconverted header value
- } // end of FNCCOL constructor
-
-/***********************************************************************/
-/* FNCCOL initialization function. */
-/***********************************************************************/
-bool FNCCOL::InitColumn(PGLOBAL g, PVAL valp)
-{
- char *p, buf[128];
- int len;
-
- // Must have its own value block
- if (InitValue(g))
- return TRUE;
-
- // Convert header value to a null terminated character string
- Hval = valp;
- p = Hval->GetCharString(buf);
- len = strlen(p) + 1;
-
- if (len > (signed)sizeof(buf)) {
- strcpy(g->Message, MSG(COLNAM_TOO_LONG));
- return TRUE;
- } // endif buf
-
- // Set the name of the functional pivot column
- Name = (PSZ)PlugSubAlloc(g, NULL, len);
- strcpy(Name, p);
- AddStatus(BUF_READ); // All is done here
- return FALSE;
-} // end of InitColumn
-
-// ------------------------ SRCCOL functions ----------------------------
-
-#if 0
-/***********************************************************************/
-/* SRCCOL public constructor. */
-/***********************************************************************/
-SRCCOL::SRCCOL(PCOLDEF cdp, PTDBPIVOT tdbp, int n)
- : COLBLK(cdp, tdbp, n)
- {
- // Set additional SRC access method information for column.
- Colp = NULL;
- Cnval = NULL;
- } // end of SRCCOL constructor
-#endif // 0
-
-/***********************************************************************/
-/* SRCCOL public constructor. */
-/***********************************************************************/
-SRCCOL::SRCCOL(PCOL cp, PTDBPIVOT tdbp, int n)
- : COLBLK(cp, tdbp)
- {
- Index = n;
-
- // Set additional SRC access method information for column.
- Colp = (PQRSCOL)cp;
-
- // Don't share Value with the source column so we can compare
- Cnval = Value = NULL;
- } // end of SRCCOL constructor
-
-#if 0
-/***********************************************************************/
-/* SRCCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-SRCCOL::SRCCOL(SRCCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- Colp = col1->Colp;
- } // end of SRCCOL copy constructor
-#endif // 0
-
-/***********************************************************************/
-/* Initialize the column as pointing to the source column. */
-/***********************************************************************/
-bool SRCCOL::Init(PGLOBAL g, PTDBPIVOT tdbp)
- {
- // Currently we ignore the type of the create table column
- bool conv = FALSE;
-
-#if 0
- if (!Colp) {
- // Column was defined in the Create Table statement
- if (!(Colp = tdbp->ColDB(g, Name, 0)))
- return TRUE;
-
- // We can have a conversion problem converting from numeric to
- // character because GetCharValue does not exist for numeric types.
- conv = (IsTypeChar(Buf_Type) && IsTypeNum(Colp->GetResultType()));
- } else
-#endif // 0
- conv = FALSE;
-
- if (InitValue(g))
- return TRUE;
-
-//if (conv)
-// Cnval = AllocateValue(g, Colp->GetValue());
-//else
- Cnval = Value;
-
- AddStatus(BUF_READ); // All is done here
- return FALSE;
- } // end of SRCCOL constructor
-
-/***********************************************************************/
-/* SetColumn: have the column value set from the source column. */
-/***********************************************************************/
-void SRCCOL::SetColumn(void)
- {
-#if defined(_DEBUG)
- Cnval->SetValue_pval(Colp->GetValue(), TRUE);
-#else
- Cnval->SetValue_pval(Colp->GetValue());
-#endif // _DEBUG
-
- if (Value != Cnval)
- // Convert value
- Value->SetValue_pval(Cnval);
-
- } // end of SetColumn
-
-/***********************************************************************/
-/* SetColumn: Compare column value with source column value. */
-/***********************************************************************/
-bool SRCCOL::CompareColumn(void)
- {
- // Compare the unconverted values
- return Cnval->CompareValue(Colp->GetValue());
- } // end of CompareColumn
-
-
-/* ------------------------------------------------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBQRS class. */
-/***********************************************************************/
-TDBQRS::TDBQRS(PTDBQRS tdbp) : TDBASE(tdbp)
- {
- Qrp = tdbp->Qrp;
- CurPos = tdbp->CurPos;
- } // end of TDBQRS copy constructor
-
-// Method
-PTDB TDBQRS::CopyOne(PTABS t)
- {
- PTDB tp;
- PQRSCOL cp1, cp2;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBQRS(this);
-
- for (cp1 = (PQRSCOL)Columns; cp1; cp1 = (PQRSCOL)cp1->GetNext()) {
- cp2 = new(g) QRSCOL(cp1, tp); // Make a copy
- NewPointer(t, cp1, cp2);
- } // endfor cp1
-
- return tp;
- } // end of CopyOne
-
-#if 0 // The TDBASE functions return NULL when To_Def is NULL
-/***********************************************************************/
-/* Return the pointer on the DB catalog this table belongs to. */
-/***********************************************************************/
-PCATLG TDBQRS::GetCat(void)
- {
- // To_Def is null for QRYRES tables
- return NULL;
- } // end of GetCat
-
-/***********************************************************************/
-/* Return the datapath of the DB this table belongs to. */
-/***********************************************************************/
-PSZ TDBQRS::GetPath(void)
- {
- // To_Def is null for QRYRES tables
- return NULL;
- } // end of GetPath
-#endif // 0
-
-/***********************************************************************/
-/* Initialize QRS column description block construction. */
-/* name is used to call columns by name. */
-/* num is used by LNA to construct columns by index number. */
-/* Note: name=Null and num=0 for constructing all columns (select *) */
-/***********************************************************************/
-PCOL TDBQRS::ColDB(PGLOBAL g, PSZ name, int num)
- {
- int i;
- PCOLRES crp;
- PCOL cp, colp = NULL, cprec = NULL;
-
- if (trace)
- htrc("QRS ColDB: colname=%s tabname=%s num=%d\n",
- SVP(name), Name, num);
-
- for (crp = Qrp->Colresp, i = 1; crp; crp = crp->Next, i++)
- if ((!name && !num) ||
- (name && !stricmp(crp->Name, 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) {
- if (cp)
- htrc("cp(%d).Name=%s cp=%p\n", i, cp->GetName(), cp);
- else
- htrc("cp(%d) cp=%p\n", i, cp);
- } // endif trace
-
- // Now take care of Column Description Block
- if (cp)
- colp = cp;
- else
- colp = new(g) QRSCOL(g, crp, this, cprec, i);
-
- if (name || num)
- break;
- else
- cprec = colp;
-
- } // endif Name
-
- return (colp);
- } // end of ColDB
-
-/***********************************************************************/
-/* QRS GetMaxSize: returns maximum table size in number of lines. */
-/***********************************************************************/
-int TDBQRS::GetMaxSize(PGLOBAL g)
- {
- MaxSize = Qrp->Maxsize;
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* RowNumber: returns the current row ordinal number. */
-/***********************************************************************/
-int TDBQRS::RowNumber(PGLOBAL g, BOOL b)
- {
- return (CurPos + 1);
- } // end of RowNumber
-
-/***********************************************************************/
-/* QRS 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 TDBQRS::OpenDB(PGLOBAL g)
- {
- if (trace)
- htrc("QRS OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
- this, Tdb_No, Use, To_Key_Col, Mode);
-
- if (Mode != MODE_READ) {
- sprintf(g->Message, MSG(BAD_QUERY_OPEN), Mode);
- return TRUE;
- } // endif Mode
-
- CurPos = -1;
-
- 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();
-
- return FALSE;
- } // endif use
-
- /*********************************************************************/
- /* Open (retrieve data from) the query if not already open. */
- /*********************************************************************/
- Use = USE_OPEN; // Do it now in case we are recursively called
-
- return FALSE;
- } // end of OpenDB
-
-/***********************************************************************/
-/* GetRecpos: returns current position of next sequential read. */
-/***********************************************************************/
-int TDBQRS::GetRecpos(void)
- {
- return (CurPos);
- } // end of GetRecpos
-
-/***********************************************************************/
-/* ReadDB: Data Base read routine for QRS access method. */
-/***********************************************************************/
-int TDBQRS::ReadDB(PGLOBAL g)
- {
- int rc = RC_OK;
-
- if (trace)
- htrc("QRS ReadDB: R%d CurPos=%d key=%p link=%p Kindex=%p\n",
- GetTdb_No(), CurPos, To_Key_Col, To_Link, To_Kindex);
-
- if (To_Kindex) {
- /*******************************************************************/
- /* Reading is by an index table. */
- /*******************************************************************/
- int recpos = To_Kindex->Fetch(g);
-
- switch (recpos) {
- case -1: // End of file reached
- rc = RC_EF;
- break;
- case -2: // No match for join
- rc = RC_NF;
- break;
- case -3: // Same record as last non null one
- rc = RC_OK;
- break;
- default:
- /***************************************************************/
- /* Set the file position according to record to read. */
- /***************************************************************/
- CurPos = recpos;
- } // endswitch recpos
-
- if (trace)
- htrc("Position is now %d\n", CurPos);
-
- } else
- /*******************************************************************/
- /* !To_Kindex ---> sequential reading */
- /*******************************************************************/
- rc = (++CurPos < Qrp->Nblin) ? RC_OK : RC_EF;
-
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* Dummy WriteDB: just send back an error return. */
-/***********************************************************************/
-int TDBQRS::WriteDB(PGLOBAL g)
- {
- strcpy(g->Message, MSG(QRY_READ_ONLY));
- return RC_FX;
- } // end of WriteDB
-
-/***********************************************************************/
-/* Dummy DeleteDB routine, just returns an error code. */
-/***********************************************************************/
-int TDBQRS::DeleteDB(PGLOBAL g, int irc)
- {
- strcpy(g->Message, MSG(NO_QRY_DELETE));
- return RC_FX;
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for QRS access method. */
-/***********************************************************************/
-void TDBQRS::CloseDB(PGLOBAL g)
- {
- if (To_Kindex) {
- To_Kindex->Close();
- To_Kindex = NULL;
- } // endif
-
- if (trace)
- htrc("Qryres CloseDB");
-
-//Qryp->Sqlp->CloseDB();
- } // end of CloseDB
-
-// ------------------------ QRSCOL functions ----------------------------
-
-/***********************************************************************/
-/* QRSCOL public constructor. */
-/***********************************************************************/
-QRSCOL::QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i)
- : COLBLK(NULL, tdbp, i)
- {
- if (cprec) {
- Next = cprec->GetNext();
- cprec->SetNext(this);
- } else {
- Next = tdbp->GetColumns();
- tdbp->SetColumns(this);
- } // endif cprec
-
- // Set additional QRS access method information for column.
- Crp = crp;
- Name = Crp->Name;
- Long = Crp->Clen;
- Buf_Type = crp->Type;
- strcpy(Format.Type, GetFormatType(Buf_Type));
- Format.Length = (SHORT)Long;
- Format.Prec = (SHORT)Crp->Prec;
-
- if (trace) {
- htrc("Making new QRSCOL C%d %s at %p\n", Index, Name, this);
- htrc(" BufType=%d Long=%d length=%d clen=%d\n",
- Buf_Type, Long, Format.Length, Crp->Clen);
- } // endif trace
-
- } // end of QRSCOL constructor
-
-/***********************************************************************/
-/* QRSCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-QRSCOL::QRSCOL(QRSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- Crp = col1->Crp;
- } // end of QRSCOL copy constructor
-
-/***********************************************************************/
-/* ReadColumn: what this routine does is to extract the RESCOL block */
-/* current value and convert it to the column buffer type. */
-/***********************************************************************/
-void QRSCOL::ReadColumn(PGLOBAL g)
- {
- PTDBQRS tdbp = (PTDBQRS)To_Tdb;
-
- if (trace)
- htrc("QRS RC: col %s R%d type=%d CurPos=%d Len=%d\n",
- Name, tdbp->GetTdb_No(), Buf_Type, tdbp->CurPos, Crp->Clen);
-
- if (Crp->Kdata)
- Value->SetValue_pvblk(Crp->Kdata, tdbp->CurPos);
- else
- Value->Reset();
-
- } // end of ReadColumn
-
-/***********************************************************************/
-/* Make file output of a Dos column descriptor block. */
-/***********************************************************************/
-void QRSCOL::Print(PGLOBAL g, FILE *f, UINT n)
- {
- COLBLK::Print(g, f, n);
-
- fprintf(f, " Crp=%p\n", Crp);
- } // end of Print
-
-/* --------------------- End of TabPivot/TabQrs ---------------------- */
+/************ TabPivot C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: TABPIVOT */
+/* ------------- */
+/* Version 1.3 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the PIVOT classes DB execution routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the operating system header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(WIN32)
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#elif defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#include "osutil.h"
+#else
+#include <io.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/***********************************************************************/
+#define FRM_VER 6
+#include "table.h" // MySQL table definitions
+#include "sql_const.h"
+#include "field.h"
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "xindex.h"
+#include "colblk.h"
+#include "tabmysql.h"
+#include "csort.h"
+#include "tabpivot.h"
+#include "valblk.h"
+#include "ha_connect.h"
+#include "mycat.h" // For GetHandler
+
+extern "C" int trace;
+
+/* --------------- Implementation of the PIVOT classes --------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from PIVOT table. */
+/***********************************************************************/
+bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ char *p1, *p2;
+ PHC hc = ((MYCAT*)Cat)->GetHandler();
+
+ Host = Cat->GetStringCatInfo(g, Name, "Host", "localhost");
+ User = Cat->GetStringCatInfo(g, Name, "User", "root");
+ Pwd = Cat->GetStringCatInfo(g, Name, "Password", NULL);
+ DB = Cat->GetStringCatInfo(g, Name, "Database", (PSZ)hc->GetDBName(NULL));
+ Tabsrc = Cat->GetStringCatInfo(g, Name, "SrcDef", NULL);
+ Tabname = Cat->GetStringCatInfo(g, Name, "Name", NULL);
+ Picol = Cat->GetStringCatInfo(g, Name, "PivotCol", NULL);
+ Fncol = Cat->GetStringCatInfo(g, Name, "FncCol", NULL);
+
+ // If fncol is like avg(colname), separate Fncol and Function
+ if (Fncol && (p1 = strchr(Fncol, '(')) && (p2 = strchr(p1, ')')) &&
+ (*Fncol != '"') && (!*(p2+1))) {
+ *p1++ = '\0'; *p2 = '\0';
+ Function = Fncol;
+ Fncol = p1;
+ } else
+ Function = Cat->GetStringCatInfo(g, Name, "Function", "SUM");
+
+ GBdone = Cat->GetIntCatInfo(Name, "Groupby", 0) ? TRUE : FALSE;
+ Port = Cat->GetIntCatInfo(Name, "Port", 3306);
+ Desc = (*Tabname) ? Tabname : Tabsrc;
+ return FALSE;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB PIVOTDEF::GetTable(PGLOBAL g, MODE m)
+ {
+ return new(g) TDBPIVOT(this);
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBPIVOT class. */
+/***********************************************************************/
+TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBASE(tdp), CSORT(FALSE)
+ {
+ Tqrp = NULL;
+ Host = tdp->Host;
+ Database = tdp->DB;
+ User = tdp->User;
+ Pwd = tdp->Pwd;
+ Port = tdp->Port;
+ Qryp = NULL;
+ Tabname = tdp->Tabname; // Name of source table
+ Tabsrc = tdp->Tabsrc; // SQL description of source table
+ Picol = tdp->Picol; // Pivot column name
+ Fncol = tdp->Fncol; // Function column name
+ Function = tdp->Function; // Aggregate function name
+ Xcolp = NULL; // To the FNCCOL column
+//Xresp = NULL; // To the pivot result column
+//Rblkp = NULL; // The value block of the pivot column
+ Fcolp = NULL; // To the function column
+ GBdone = tdp->GBdone;
+ Mult = -1; // Estimated table size
+ N = 0; // The current table index
+ M = 0; // The occurence rank
+ FileStatus = 0; // Logical End-of-File
+ RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
+ } // end of TDBPIVOT constructor
+
+#if 0
+TDBPIVOT::TDBPIVOT(PTDBPIVOT tdbp) : TDBASE(tdbp), CSORT(FALSE)
+ {
+ Tdbp = tdbp->Tdbp;
+ Sqlp = tdbp->Sqlp;
+ Qryp = tdbp->Qryp;
+ Tabname = tdbp->Tabname;
+ Tabsrc = tdbp->Tabsrc;
+ Picol = tdbp->Picol;
+ Fncol = tdbp->Fncol;
+ Function = tdbp->Function;
+ Xcolp = tdbp->Xcolp;
+ Xresp = tdbp->Xresp;
+ Rblkp = tdbp->Rblkp;
+ Fcolp = tdbp->Fcolp;
+ Mult = tdbp->Mult;
+ N = tdbp->N;
+ M = tdbp->M;
+ FileStatus = tdbp->FileStatus;
+ RowFlag = tdbp->RowFlag;
+ } // end of TDBPIVOT copy constructor
+
+// Is this really useful ???
+PTDB TDBPIVOT::CopyOne(PTABS t)
+ {
+ PTDB tp = new(t->G) TDBPIVOT(this);
+
+ tp->SetColumns(Columns);
+ return tp;
+ } // end of CopyOne
+#endif // 0
+
+/***********************************************************************/
+/* Prepare the source table Query. */
+/***********************************************************************/
+PQRYRES TDBPIVOT::GetSourceTable(PGLOBAL g)
+ {
+ if (Qryp)
+ return Qryp; // Already done
+
+ if (!Tabsrc && Tabname) {
+ char *def, *colist;
+ size_t len = 0;
+ PCOL colp;
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ // Evaluate the length of the column list
+ for (colp = Columns; colp; colp = colp->GetNext())
+ len += (strlen(colp->GetName()) + 2);
+
+ *(colist = (char*)PlugSubAlloc(g, NULL, len)) = 0;
+
+ // Locate the suballocated string (size is not known yet)
+ def = (char*)PlugSubAlloc(g, NULL, 0);
+ strcpy(def, "SELECT ");
+
+ if (!Fncol) {
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!Picol || stricmp(Picol, colp->GetName()))
+ Fncol = colp->GetName();
+
+ if (!Fncol) {
+ strcpy(g->Message, MSG(NO_DEF_FNCCOL));
+ return NULL;
+ } // endif Fncol
+
+ } else if (!(ColDB(g, Fncol, 0))) {
+ // Function column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname);
+ return NULL;
+ } // endif Fcolp
+
+ if (!Picol) {
+ // Find default Picol as the last one not equal to Fncol
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!Fncol || stricmp(Fncol, colp->GetName()))
+ Picol = colp->GetName();
+
+ if (!Picol) {
+ strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
+ return NULL;
+ } // endif Picol
+
+ } else if (!(ColDB(g, Picol, 0))) {
+ // Pivot column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname);
+ return NULL;
+ } // endif Xcolp
+
+ // Make the other column list
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (stricmp(Picol, colp->GetName()) &&
+ stricmp(Fncol, colp->GetName()))
+ strcat(strcat(colist, colp->GetName()), ", ");
+
+ // Add the Pivot column at the end of the list
+ strcat(strcat(def, strcat(colist, Picol)), ", ");
+
+ // Continue making the definition
+ if (!GBdone) {
+ // Make it suitable for Pivot by doing the group by
+ strcat(strcat(def, Function), "(");
+ strcat(strcat(strcat(def, Fncol), ") "), Fncol);
+ strcat(strcat(def, " FROM "), Tabname);
+ strcat(strcat(def, " GROUP BY "), colist);
+ } else // Gbdone
+ strcat(strcat(strcat(def, Fncol), " FROM "), Tabname);
+
+ // Now we know how much was suballocated
+ Tabsrc = (char*)PlugSubAlloc(g, NULL, strlen(def));
+ } else {
+ strcpy(g->Message, MSG(SRC_TABLE_UNDEF));
+ return NULL;
+ } // endif Tabsrc
+
+ int w;
+
+ // Open a MySQL connection for this table
+ if (Myc.Open(g, Host, Database, User, Pwd, Port))
+ return NULL;
+
+ // Send the source command to MySQL
+ if (Myc.ExecSQL(g, Tabsrc, &w) == RC_FX) {
+ Myc.Close();
+ return NULL;
+ } // endif Exec
+
+ // We must have a storage query to get pivot column values
+ Qryp = Myc.GetResult(g);
+ Myc.Close();
+ Tqrp = new(g) TDBQRS(Qryp);
+ Tqrp->OpenDB(g);
+
+ if (MakePivotColumns(g) < 0)
+ return NULL;
+
+ return Qryp;
+ } // end of GetSourceTable
+
+/***********************************************************************/
+/* Allocate PIVOT columns description block. */
+/***********************************************************************/
+int TDBPIVOT::MakePivotColumns(PGLOBAL g)
+ {
+ if (Mult < 0) {
+ int ndif, n = 0, nblin = Qryp->Nblin;
+ PVAL valp;
+ PCOL cp;
+ PSRCCOL colp;
+ PFNCCOL cfnp;
+
+ // Allocate all the source columns
+ Tqrp->ColDB(g, NULL, 0);
+ Columns = NULL; // Discard dummy columns blocks
+
+ for (cp = Tqrp->GetColumns(); cp; cp = cp->GetNext()) {
+ if (cp->InitValue(g))
+ return -1;
+
+ if (!stricmp(cp->GetName(), Picol)) {
+ Xcolp = (PQRSCOL)cp;
+ Xresp = Xcolp->GetCrp();
+ Rblkp = Xresp->Kdata;
+ } else if (!stricmp(cp->GetName(), Fncol)) {
+ Fcolp = (PQRSCOL)cp;
+ } else
+ if ((colp = new(g) SRCCOL(cp, this, ++n))->Init(g, this))
+ return -1;
+
+ } // endfor cp
+
+ if (!Xcolp) {
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE),
+ Picol, Tabname ? Tabname : "TabSrc");
+ return -1;
+ } else if (!Fcolp) {
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE),
+ Fncol, Tabname ? Tabname : "TabSrc");
+ return -1;
+ } // endif Fcolp
+
+ // Before calling sort, initialize all
+ Index.Size = nblin * sizeof(int);
+ Index.Sub = TRUE; // Should be small enough
+
+ if (!PlgDBalloc(g, NULL, Index))
+ return -1;
+
+ Offset.Size = (nblin + 1) * sizeof(int);
+ Offset.Sub = TRUE; // Should be small enough
+
+ if (!PlgDBalloc(g, NULL, Offset))
+ return -2;
+
+ ndif = Qsort(g, nblin);
+
+ if (ndif < 0) { // error
+ return -3;
+ } else
+ Ncol = ndif;
+
+ // Now make the functional columns
+ for (int i = 0; i < Ncol; i++) {
+ // Allocate the Value used to retieve column names
+ if (!(valp = AllocateValue(g, Xcolp->GetResultType(),
+ Xcolp->GetLengthEx(), Xcolp->GetPrecision(),
+ Xcolp->GetDomain(), Xcolp->GetTo_Tdb()->GetCat())))
+ return -4;
+
+ // Get the value that will be the generated column name
+ valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]);
+
+ // Copy the functional column with new Name and new Value
+ cfnp = (PFNCCOL)new(g) FNCCOL(Fcolp, this);
+
+ // Initialize the generated column
+ if (cfnp->InitColumn(g, valp))
+ return -5;
+
+ } // endfor i
+
+ // Fields must be updated for ha_connect
+// if (UpdateTableFields(g, n + Ncol))
+// return -6;
+
+ // This should be refined later
+ Mult = nblin;
+ } // endif Mult
+
+ return Mult;
+ } // end of MakePivotColumns
+
+#if 0
+/***********************************************************************/
+/* Update fields in the MySQL table structure */
+/* Note: this does not work. Indeed the new rows are correctly made */
+/* but the final result still specify the unmodified table and the */
+/* returned table only contains the original column values. */
+/* In addition, a new query on the table, when it is into the cache, */
+/* specifies all the new columns and fails because they do not belong */
+/* to the original table. */
+/***********************************************************************/
+bool TDBPIVOT::UpdateTableFields(PGLOBAL g, int n)
+ {
+ uchar *trec, *srec, *tptr, *sptr;
+ int i = 0, k = 0;
+ uint len;
+ uint32 nmp, lwm;
+ size_t buffsize;
+ PCOL colp;
+ PHC hc = ((MYCAT*)((PIVOTDEF*)To_Def)->Cat)->GetHandler();
+ TABLE *table = hc->GetTable();
+ st_mem_root *tmr = &table->mem_root;
+ st_mem_root *smr = &table->s->mem_root;
+ Field* *field;
+ Field *fp, *tfncp, *sfncp;
+ Field* *ntf;
+ Field* *nsf;
+//my_bitmap_map *org_bitmap;
+ const MY_BITMAP *map;
+
+ // When sorting read_set selects all columns, so we use def_read_set
+ map= (const MY_BITMAP *)&table->def_read_set;
+
+ // Find the function field
+ for (field= table->field; *field; field++) {
+ fp= *field;
+
+ if (bitmap_is_set(map, fp->field_index))
+ if (!stricmp(fp->field_name, Fncol)) {
+ tfncp = fp;
+ break;
+ } // endif Name
+
+ } // endfor field
+
+ for (field= table->s->field; *field; field++) {
+ fp= *field;
+
+ if (bitmap_is_set(map, fp->field_index))
+ if (!stricmp(fp->field_name, Fncol)) {
+ sfncp = fp;
+ break;
+ } // endif Name
+
+ } // endfor field
+
+ // Calculate the new buffer size
+ len = tfncp->max_data_length();
+ buffsize = table->s->rec_buff_length + len * Ncol;
+
+ // Allocate the new record space
+ if (!(tptr = trec = (uchar*)alloc_root(tmr, 2 * buffsize)))
+ return TRUE;
+
+ if (!(sptr = srec = (uchar*)alloc_root(smr, 2 * buffsize)))
+ return TRUE;
+
+
+ // Allocate the array of all new table field pointers
+ if (!(ntf = (Field**)alloc_root(tmr, (uint)((n+1) * sizeof(Field*)))))
+ return TRUE;
+
+ // Allocate the array of all new table share field pointers
+ if (!(nsf = (Field**)alloc_root(smr, (uint)((n+1) * sizeof(Field*)))))
+ return TRUE;
+
+ // First fields are the the ones of the source columns
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_SRC) {
+ for (field= table->field; *field; field++) {
+ fp= *field;
+
+ if (bitmap_is_set(map, fp->field_index))
+ if (!stricmp(colp->GetName(), fp->field_name)) {
+ ntf[i] = fp;
+ fp->field_index = i++;
+ fp->ptr = tptr;
+ tptr += fp->max_data_length();
+ break;
+ } // endif Name
+
+ } // endfor field
+
+ for (field= table->s->field; *field; field++) {
+ fp= *field;
+
+ if (bitmap_is_set(map, fp->field_index))
+ if (!stricmp(colp->GetName(), fp->field_name)) {
+ nsf[k] = fp;
+ fp->field_index = k++;
+ fp->ptr = srec;
+ srec += fp->max_data_length();
+ break;
+ } // endif Name
+
+ } // endfor field
+
+ } // endif AmType
+
+ // Now add the pivot generated columns
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_FNC) {
+ if ((fp = (Field*)memdup_root(tmr, (char*)tfncp, tfncp->size_of()))) {
+ ntf[i] = fp;
+ fp->ptr = tptr;
+ fp->field_name = colp->GetName();
+ fp->field_index = i++;
+ fp->vcol_info = NULL;
+ fp->stored_in_db = TRUE;
+ tptr += len;
+ } else
+ return TRUE;
+
+ if ((fp = (Field*)memdup_root(smr, (char*)sfncp, sfncp->size_of()))) {
+ nsf[i] = fp;
+ fp->ptr = sptr;
+ fp->field_name = colp->GetName();
+ fp->field_index = k++;
+ fp->vcol_info = NULL;
+ fp->stored_in_db = TRUE;
+ sptr += len;
+ } else
+ return TRUE;
+
+ } // endif AM_FNC
+
+ // Mark end of the list
+ ntf[i] = NULL;
+ nsf[k] = NULL;
+
+ // Update the table fields
+ nmp = (uint32)((1<<i) - 1);
+ lwm = (uint32)((-1)<<i);
+ table->field = ntf;
+ table->used_fields = i;
+ table->record[0] = trec;
+ table->record[1] = trec + buffsize;
+ *table->def_read_set.bitmap = nmp;
+ *table->def_read_set.last_word_ptr = nmp;
+ table->def_read_set.last_word_mask = lwm;
+ table->def_read_set.n_bits = i;
+ *table->read_set->bitmap = nmp;
+ *table->read_set->last_word_ptr = nmp;
+ table->read_set->last_word_mask = lwm;
+ table->read_set->n_bits = i;
+ table->write_set->n_bits = i;
+ *table->vcol_set->bitmap = 0;
+ table->vcol_set->n_bits = i;
+
+ // and the share fields
+ table->s->field = nsf;
+ table->s->reclength = sptr - srec;
+ table->s->stored_rec_length = sptr - srec;
+ table->s->fields = k;
+ table->s->stored_fields = k;
+ table->s->rec_buff_length = buffsize;
+//table->s->varchar_fields = ???;
+//table->s->db_record_offset = ???;
+//table->s->null_field_first = ???;
+ return FALSE;
+ } // end of UpdateTableFields
+#endif // 0
+
+/***********************************************************************/
+/* Allocate source column description block. */
+/***********************************************************************/
+PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCOL colp = NULL;
+
+//if (stricmp(cdp->GetName(), Picol) && stricmp(cdp->GetName(), Fncol)) {
+ colp = new(g) COLBLK(cdp, this, n);
+
+// if (((PSRCCOL)colp)->Init(g, this))
+// return NULL;
+
+//} else {
+// sprintf(g->Message, MSG(NO_MORE_COL), cdp->GetName());
+// return NULL;
+//} // endif Name
+
+ if (cprec) {
+ colp->SetNext(cprec->GetNext());
+ cprec->SetNext(colp);
+ } else {
+ colp->SetNext(Columns);
+ Columns = colp;
+ } // endif cprec
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* PIVOT GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBPIVOT::GetMaxSize(PGLOBAL g)
+ {
+#if 0
+ if (MaxSize < 0)
+ MaxSize = MakePivotColumns(g);
+
+ return MaxSize;
+#endif // 0
+ return 0;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* In this sample, ROWID will be the (virtual) row number, */
+/* while ROWNUM will be the occurence rank in the multiple column. */
+/***********************************************************************/
+int TDBPIVOT::RowNumber(PGLOBAL g, bool b)
+ {
+ return (b) ? M : N;
+ } // end of RowNumber
+
+/***********************************************************************/
+/* PIVOT Access Method opening routine. */
+/***********************************************************************/
+bool TDBPIVOT::OpenDB(PGLOBAL g)
+ {
+//PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ N = M = 0;
+ RowFlag = 0;
+ FileStatus = 0;
+ return FALSE;
+ } // endif use
+
+ /*********************************************************************/
+ /* Do it here if not done yet (should not be the case). */
+ /*********************************************************************/
+//if (MakePivotColumns(g) < 0)
+ if (!(Qryp = GetSourceTable(g)))
+ return TRUE;
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* Currently PIVOT tables cannot be modified. */
+ /*******************************************************************/
+ sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
+ return TRUE;
+ } // endif Mode
+
+ if (To_Key_Col || To_Kindex) {
+ /*******************************************************************/
+ /* Direct access of PIVOT tables is not implemented yet. */
+ /*******************************************************************/
+ strcpy(g->Message, MSG(NO_PIV_DIR_ACC));
+ return TRUE;
+ } // endif To_Key_Col
+
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for PIVOT access method. */
+/***********************************************************************/
+int TDBPIVOT::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+ bool newrow = FALSE;
+ PCOL colp;
+ PVAL vp1, vp2;
+
+ if (FileStatus == 2)
+ return RC_EF;
+
+ if (FileStatus)
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_SRC)
+ ((PSRCCOL)colp)->SetColumn();
+
+ // New row, reset all function column values
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_FNC)
+ colp->GetValue()->Reset();
+
+ /*********************************************************************/
+ /* Now start the multi reading process. */
+ /*********************************************************************/
+ do {
+ if (RowFlag != 1) {
+ if ((rc = Tqrp->ReadDB(g)) != RC_OK) {
+ if (FileStatus && rc == RC_EF) {
+ // A prepared row remains to be sent
+ FileStatus = 2;
+ rc = RC_OK;
+ } // endif FileStatus
+
+ break;
+ } // endif rc
+
+ for (colp = Tqrp->GetColumns(); colp; colp = colp->GetNext())
+ colp->ReadColumn(g);
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_SRC)
+ if (FileStatus) {
+ if (((PSRCCOL)colp)->CompareColumn())
+ newrow = (RowFlag) ? TRUE : FALSE;
+
+ } else
+ ((PSRCCOL)colp)->SetColumn();
+
+ FileStatus = 1;
+ } // endif RowFlag
+
+ if (newrow) {
+ RowFlag = 1;
+ break;
+ } else
+ RowFlag = 2;
+
+ vp1 = Xcolp->GetValue();
+
+ // Look for the column having this header
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_FNC) {
+ vp2 = ((PFNCCOL)colp)->Hval;
+
+ if (!vp1->CompareValue(vp2))
+ break;
+
+ } // endif AmType
+
+ if (!colp) {
+ strcpy(g->Message, MSG(NO_MATCH_COL));
+ return RC_FX;
+ } // endif colp
+
+ // Set the value of the matching column from the fonction value
+ colp->GetValue()->SetValue_pval(Fcolp->GetValue());
+ } while (RowFlag == 2);
+
+ N++;
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for PIVOT access methods. */
+/***********************************************************************/
+int TDBPIVOT::WriteDB(PGLOBAL g)
+ {
+ sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for PIVOT access methods. */
+/***********************************************************************/
+int TDBPIVOT::DeleteDB(PGLOBAL g, int irc)
+ {
+ sprintf(g->Message, MSG(NO_TABLE_DEL), "PIVOT");
+ return RC_FX;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for PIVOT access method. */
+/***********************************************************************/
+void TDBPIVOT::CloseDB(PGLOBAL g)
+ {
+//Tdbp->CloseDB(g);
+ } // end of CloseDB
+
+/***********************************************************************/
+/* TDBPIVOT: Compare routine for sorting pivot column values. */
+/***********************************************************************/
+int TDBPIVOT::Qcompare(int *i1, int *i2)
+ {
+ // TODO: the actual comparison between pivot column result values.
+ return Rblkp->CompVal(*i1, *i2);
+ } // end of Qcompare
+
+// ------------------------ FNCCOL functions ----------------------------
+
+/***********************************************************************/
+/* FNCCOL public constructor. */
+/***********************************************************************/
+FNCCOL::FNCCOL(PCOL col1, PTDBPIVOT tdbp)
+ : COLBLK(col1, tdbp)
+ {
+ Value = NULL; // We'll get a new one later
+ Hval = NULL; // The unconverted header value
+ } // end of FNCCOL constructor
+
+/***********************************************************************/
+/* FNCCOL initialization function. */
+/***********************************************************************/
+bool FNCCOL::InitColumn(PGLOBAL g, PVAL valp)
+{
+ char *p, buf[128];
+ int len;
+
+ // Must have its own value block
+ if (InitValue(g))
+ return TRUE;
+
+ // Convert header value to a null terminated character string
+ Hval = valp;
+ p = Hval->GetCharString(buf);
+ len = strlen(p) + 1;
+
+ if (len > (signed)sizeof(buf)) {
+ strcpy(g->Message, MSG(COLNAM_TOO_LONG));
+ return TRUE;
+ } // endif buf
+
+ // Set the name of the functional pivot column
+ Name = (PSZ)PlugSubAlloc(g, NULL, len);
+ strcpy(Name, p);
+ AddStatus(BUF_READ); // All is done here
+ return FALSE;
+} // end of InitColumn
+
+// ------------------------ SRCCOL functions ----------------------------
+
+#if 0
+/***********************************************************************/
+/* SRCCOL public constructor. */
+/***********************************************************************/
+SRCCOL::SRCCOL(PCOLDEF cdp, PTDBPIVOT tdbp, int n)
+ : COLBLK(cdp, tdbp, n)
+ {
+ // Set additional SRC access method information for column.
+ Colp = NULL;
+ Cnval = NULL;
+ } // end of SRCCOL constructor
+#endif // 0
+
+/***********************************************************************/
+/* SRCCOL public constructor. */
+/***********************************************************************/
+SRCCOL::SRCCOL(PCOL cp, PTDBPIVOT tdbp, int n)
+ : COLBLK(cp, tdbp)
+ {
+ Index = n;
+
+ // Set additional SRC access method information for column.
+ Colp = (PQRSCOL)cp;
+
+ // Don't share Value with the source column so we can compare
+ Cnval = Value = NULL;
+ } // end of SRCCOL constructor
+
+#if 0
+/***********************************************************************/
+/* SRCCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+SRCCOL::SRCCOL(SRCCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Colp = col1->Colp;
+ } // end of SRCCOL copy constructor
+#endif // 0
+
+/***********************************************************************/
+/* Initialize the column as pointing to the source column. */
+/***********************************************************************/
+bool SRCCOL::Init(PGLOBAL g, PTDBPIVOT tdbp)
+ {
+ // Currently we ignore the type of the create table column
+ bool conv = FALSE;
+
+#if 0
+ if (!Colp) {
+ // Column was defined in the Create Table statement
+ if (!(Colp = tdbp->ColDB(g, Name, 0)))
+ return TRUE;
+
+ // We can have a conversion problem converting from numeric to
+ // character because GetCharValue does not exist for numeric types.
+ conv = (IsTypeChar(Buf_Type) && IsTypeNum(Colp->GetResultType()));
+ } else
+#endif // 0
+ conv = FALSE;
+
+ if (InitValue(g))
+ return TRUE;
+
+//if (conv)
+// Cnval = AllocateValue(g, Colp->GetValue());
+//else
+ Cnval = Value;
+
+ AddStatus(BUF_READ); // All is done here
+ return FALSE;
+ } // end of SRCCOL constructor
+
+/***********************************************************************/
+/* SetColumn: have the column value set from the source column. */
+/***********************************************************************/
+void SRCCOL::SetColumn(void)
+ {
+#if defined(_DEBUG)
+ Cnval->SetValue_pval(Colp->GetValue(), TRUE);
+#else
+ Cnval->SetValue_pval(Colp->GetValue());
+#endif // _DEBUG
+
+ if (Value != Cnval)
+ // Convert value
+ Value->SetValue_pval(Cnval);
+
+ } // end of SetColumn
+
+/***********************************************************************/
+/* SetColumn: Compare column value with source column value. */
+/***********************************************************************/
+bool SRCCOL::CompareColumn(void)
+ {
+ // Compare the unconverted values
+ return Cnval->CompareValue(Colp->GetValue());
+ } // end of CompareColumn
+
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBQRS class. */
+/***********************************************************************/
+TDBQRS::TDBQRS(PTDBQRS tdbp) : TDBASE(tdbp)
+ {
+ Qrp = tdbp->Qrp;
+ CurPos = tdbp->CurPos;
+ } // end of TDBQRS copy constructor
+
+// Method
+PTDB TDBQRS::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PQRSCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBQRS(this);
+
+ for (cp1 = (PQRSCOL)Columns; cp1; cp1 = (PQRSCOL)cp1->GetNext()) {
+ cp2 = new(g) QRSCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of CopyOne
+
+#if 0 // The TDBASE functions return NULL when To_Def is NULL
+/***********************************************************************/
+/* Return the pointer on the DB catalog this table belongs to. */
+/***********************************************************************/
+PCATLG TDBQRS::GetCat(void)
+ {
+ // To_Def is null for QRYRES tables
+ return NULL;
+ } // end of GetCat
+
+/***********************************************************************/
+/* Return the datapath of the DB this table belongs to. */
+/***********************************************************************/
+PSZ TDBQRS::GetPath(void)
+ {
+ // To_Def is null for QRYRES tables
+ return NULL;
+ } // end of GetPath
+#endif // 0
+
+/***********************************************************************/
+/* Initialize QRS column description block construction. */
+/* name is used to call columns by name. */
+/* num is used by LNA to construct columns by index number. */
+/* Note: name=Null and num=0 for constructing all columns (select *) */
+/***********************************************************************/
+PCOL TDBQRS::ColDB(PGLOBAL g, PSZ name, int num)
+ {
+ int i;
+ PCOLRES crp;
+ PCOL cp, colp = NULL, cprec = NULL;
+
+ if (trace)
+ htrc("QRS ColDB: colname=%s tabname=%s num=%d\n",
+ SVP(name), Name, num);
+
+ for (crp = Qrp->Colresp, i = 1; crp; crp = crp->Next, i++)
+ if ((!name && !num) ||
+ (name && !stricmp(crp->Name, 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) {
+ if (cp)
+ htrc("cp(%d).Name=%s cp=%p\n", i, cp->GetName(), cp);
+ else
+ htrc("cp(%d) cp=%p\n", i, cp);
+ } // endif trace
+
+ // Now take care of Column Description Block
+ if (cp)
+ colp = cp;
+ else
+ colp = new(g) QRSCOL(g, crp, this, cprec, i);
+
+ if (name || num)
+ break;
+ else
+ cprec = colp;
+
+ } // endif Name
+
+ return (colp);
+ } // end of ColDB
+
+/***********************************************************************/
+/* QRS GetMaxSize: returns maximum table size in number of lines. */
+/***********************************************************************/
+int TDBQRS::GetMaxSize(PGLOBAL g)
+ {
+ MaxSize = Qrp->Maxsize;
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* RowNumber: returns the current row ordinal number. */
+/***********************************************************************/
+int TDBQRS::RowNumber(PGLOBAL g, BOOL b)
+ {
+ return (CurPos + 1);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* QRS 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 TDBQRS::OpenDB(PGLOBAL g)
+ {
+ if (trace)
+ htrc("QRS OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+
+ if (Mode != MODE_READ) {
+ sprintf(g->Message, MSG(BAD_QUERY_OPEN), Mode);
+ return TRUE;
+ } // endif Mode
+
+ CurPos = -1;
+
+ 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();
+
+ return FALSE;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open (retrieve data from) the query if not already open. */
+ /*********************************************************************/
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* GetRecpos: returns current position of next sequential read. */
+/***********************************************************************/
+int TDBQRS::GetRecpos(void)
+ {
+ return (CurPos);
+ } // end of GetRecpos
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for QRS access method. */
+/***********************************************************************/
+int TDBQRS::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+
+ if (trace)
+ htrc("QRS ReadDB: R%d CurPos=%d key=%p link=%p Kindex=%p\n",
+ GetTdb_No(), CurPos, To_Key_Col, To_Link, To_Kindex);
+
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ int recpos = To_Kindex->Fetch(g);
+
+ switch (recpos) {
+ case -1: // End of file reached
+ rc = RC_EF;
+ break;
+ case -2: // No match for join
+ rc = RC_NF;
+ break;
+ case -3: // Same record as last non null one
+ rc = RC_OK;
+ break;
+ default:
+ /***************************************************************/
+ /* Set the file position according to record to read. */
+ /***************************************************************/
+ CurPos = recpos;
+ } // endswitch recpos
+
+ if (trace)
+ htrc("Position is now %d\n", CurPos);
+
+ } else
+ /*******************************************************************/
+ /* !To_Kindex ---> sequential reading */
+ /*******************************************************************/
+ rc = (++CurPos < Qrp->Nblin) ? RC_OK : RC_EF;
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Dummy WriteDB: just send back an error return. */
+/***********************************************************************/
+int TDBQRS::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, MSG(QRY_READ_ONLY));
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Dummy DeleteDB routine, just returns an error code. */
+/***********************************************************************/
+int TDBQRS::DeleteDB(PGLOBAL g, int irc)
+ {
+ strcpy(g->Message, MSG(NO_QRY_DELETE));
+ return RC_FX;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for QRS access method. */
+/***********************************************************************/
+void TDBQRS::CloseDB(PGLOBAL g)
+ {
+ if (To_Kindex) {
+ To_Kindex->Close();
+ To_Kindex = NULL;
+ } // endif
+
+ if (trace)
+ htrc("Qryres CloseDB");
+
+//Qryp->Sqlp->CloseDB();
+ } // end of CloseDB
+
+// ------------------------ QRSCOL functions ----------------------------
+
+/***********************************************************************/
+/* QRSCOL public constructor. */
+/***********************************************************************/
+QRSCOL::QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i)
+ : COLBLK(NULL, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional QRS access method information for column.
+ Crp = crp;
+ Name = Crp->Name;
+ Long = Crp->Clen;
+ Buf_Type = crp->Type;
+ strcpy(Format.Type, GetFormatType(Buf_Type));
+ Format.Length = (SHORT)Long;
+ Format.Prec = (SHORT)Crp->Prec;
+
+ if (trace) {
+ htrc("Making new QRSCOL C%d %s at %p\n", Index, Name, this);
+ htrc(" BufType=%d Long=%d length=%d clen=%d\n",
+ Buf_Type, Long, Format.Length, Crp->Clen);
+ } // endif trace
+
+ } // end of QRSCOL constructor
+
+/***********************************************************************/
+/* QRSCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+QRSCOL::QRSCOL(QRSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Crp = col1->Crp;
+ } // end of QRSCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to extract the RESCOL block */
+/* current value and convert it to the column buffer type. */
+/***********************************************************************/
+void QRSCOL::ReadColumn(PGLOBAL g)
+ {
+ PTDBQRS tdbp = (PTDBQRS)To_Tdb;
+
+ if (trace)
+ htrc("QRS RC: col %s R%d type=%d CurPos=%d Len=%d\n",
+ Name, tdbp->GetTdb_No(), Buf_Type, tdbp->CurPos, Crp->Clen);
+
+ if (Crp->Kdata)
+ Value->SetValue_pvblk(Crp->Kdata, tdbp->CurPos);
+ else
+ Value->Reset();
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* Make file output of a Dos column descriptor block. */
+/***********************************************************************/
+void QRSCOL::Print(PGLOBAL g, FILE *f, UINT n)
+ {
+ COLBLK::Print(g, f, n);
+
+ fprintf(f, " Crp=%p\n", Crp);
+ } // end of Print
+
+/* --------------------- End of TabPivot/TabQrs ---------------------- */
diff --git a/storage/connect/tabpivot.h b/storage/connect/tabpivot.h
index 11af4d69bc6..fb480b9abbf 100644
--- a/storage/connect/tabpivot.h
+++ b/storage/connect/tabpivot.h
@@ -1,241 +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
-
+/************** 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
+
diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp
index 75bc32a9d2e..1ac101f02be 100644
--- a/storage/connect/tabsys.cpp
+++ b/storage/connect/tabsys.cpp
@@ -1,877 +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 ---------------------------- */
-
-
+/************* 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 ---------------------------- */
+
+
diff --git a/storage/connect/tabsys.h b/storage/connect/tabsys.h
index b56dd4a4ca3..52e8d2196cf 100644
--- a/storage/connect/tabsys.h
+++ b/storage/connect/tabsys.h
@@ -1,184 +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
+
+/*************** 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
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp
index 9f4bb8a05a8..4abdb7aa681 100644
--- a/storage/connect/tabtbl.cpp
+++ b/storage/connect/tabtbl.cpp
@@ -1,777 +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
-
-/* ------------------------------------------------------------------- */
+/************* 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
+
+/* ------------------------------------------------------------------- */
diff --git a/storage/connect/tabtbl.h b/storage/connect/tabtbl.h
index 76733f56cc1..07a20bb2867 100644
--- a/storage/connect/tabtbl.h
+++ b/storage/connect/tabtbl.h
@@ -1,162 +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
+/*************** 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
diff --git a/storage/connect/tabvct.cpp b/storage/connect/tabvct.cpp
index ca59fcc81c6..c06f7bbead1 100644
--- a/storage/connect/tabvct.cpp
+++ b/storage/connect/tabvct.cpp
@@ -1,563 +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 ---------------------------- */
+/************* 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 ---------------------------- */
diff --git a/storage/connect/tabvct.h b/storage/connect/tabvct.h
index d248244bde8..4049b4f7683 100644
--- a/storage/connect/tabvct.h
+++ b/storage/connect/tabvct.h
@@ -1,123 +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__
-
+/*************** 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__
+
diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp
index 5d33e06ff76..fd7e6eb345d 100644
--- a/storage/connect/tabwmi.cpp
+++ b/storage/connect/tabwmi.cpp
@@ -1,1153 +1,1153 @@
-/***********************************************************************/
-/* TABWMI: Author Olivier Bertrand -- PlugDB -- 2012 - 2013 */
-/* 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"
-
-extern "C" int trace;
-
-/**************************************************************************/
-/* Allocate the result structure that will contain result data. */
-/**************************************************************************/
-PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
- int *dbtype, int *buftyp, unsigned int *length,
- bool blank = true, bool nonull = true);
-
-/* ------------------- Functions WMI Column info --------------------- */
-
-/***********************************************************************/
-/* Structure used by WMI column info functions. */
-/***********************************************************************/
-typedef struct _WMIutil {
- IWbemServices *Svc;
- IWbemClassObject *Cobj;
-} WMIUTIL, *PWMIUT;
-
-/***********************************************************************/
-/* Initialize WMI operations. */
-/***********************************************************************/
-PWMIUT InitWMI(PGLOBAL g, char *nsp, char *classname)
-{
- IWbemLocator *loc;
- char *p;
- HRESULT res;
- PWMIUT wp = (PWMIUT)PlugSubAlloc(g, NULL, sizeof(WMIUTIL));
-
- if (trace)
- htrc("WMIColumns class %s space %s\n", SVP(classname), SVP(nsp));
-
- /*********************************************************************/
- /* Set default values for the namespace and class name. */
- /*********************************************************************/
- if (!nsp)
- nsp = "root\\cimv2";
-
- if (!classname) {
- if (!stricmp(nsp, "root\\cimv2"))
- classname = "ComputerSystemProduct";
- else if (!stricmp(nsp, "root\\cli"))
- classname = "Msft_CliAlias";
- else {
- strcpy(g->Message, "Missing class name");
- return NULL;
- } // endif classname
-
- } // endif classname
-
- /*********************************************************************/
- /* Initialize WMI. */
- /*********************************************************************/
-//res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
- res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
-
- if (FAILED(res)) {
- sprintf(g->Message, "Failed to initialize COM library. "
- "Error code = %p", res);
- return NULL;
- } // endif res
-
-#if 0 // irrelevant for a DLL
- res = CoInitializeSecurity(NULL, -1, NULL, NULL,
- RPC_C_AUTHN_LEVEL_CONNECT,
- RPC_C_IMP_LEVEL_IMPERSONATE,
- NULL, EOAC_NONE, NULL);
-
- if (res != RPC_E_TOO_LATE && FAILED(res)) {
- sprintf(g->Message, "Failed to initialize security. "
- "Error code = %p", res);
- CoUninitialize();
- return NULL;
- } // endif Res
-#endif // 0
-
- res = CoCreateInstance(CLSID_WbemLocator, NULL,
- CLSCTX_INPROC_SERVER, IID_IWbemLocator,
- (void**) &loc);
- if (FAILED(res)) {
- sprintf(g->Message, "Failed to create Locator. "
- "Error code = %p", res);
- CoUninitialize();
- return NULL;
- } // endif res
-
- res = loc->ConnectServer(_bstr_t(nsp),
- NULL, NULL, NULL, 0, NULL, NULL, &wp->Svc);
-
- if (FAILED(res)) {
- sprintf(g->Message, "Could not connect. Error code = %p", res);
- loc->Release();
- CoUninitialize();
- return NULL;
- } // endif res
-
- loc->Release();
-
- if (trace)
- htrc("Successfully connected to namespace.\n");
-
- /*********************************************************************/
- /* Perform a full class object retrieval. */
- /*********************************************************************/
- p = (char*)PlugSubAlloc(g, NULL, strlen(classname) + 7);
-
- if (strchr(classname, '_'))
- strcpy(p, classname);
- else
- strcat(strcpy(p, "Win32_"), classname);
-
- res = wp->Svc->GetObject(bstr_t(p), 0, 0, &wp->Cobj, 0);
-
- if (FAILED(res)) {
- sprintf(g->Message, "failed GetObject %s in %s\n", classname, nsp);
- wp->Svc->Release();
- wp->Svc = NULL; // MUST be set to NULL (why?)
- return NULL;
- } // endif res
-
- return wp;
-} // end of InitWMI
-
-/***********************************************************************/
-/* WMIColumns: constructs the result blocks containing the description */
-/* of all the columns of a WMI table of a specified class. */
-/***********************************************************************/
-PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *classname, PWMIUT wp)
- {
- 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 len, length[] = {0, 6, 8, 10, 10, 6};
- int i = 0, n = 0, ncol = sizeof(dbtype) / sizeof(int);
- int lng, typ, prec;
- LONG low, upp;
- BOOL b1, b2 = TRUE;
- BSTR propname;
- VARIANT val;
- CIMTYPE type;
- HRESULT res;
- SAFEARRAY *prnlist = NULL;
- PQRYRES qrp = NULL;
- PCOLRES crp;
-
- /*********************************************************************/
- /* Initialize WMI if not done yet. */
- /*********************************************************************/
- if ((b1 = !wp) && !(wp = InitWMI(g, nsp, classname)))
- return NULL;
-
- /*********************************************************************/
- /* Get the number of properties to return. */
- /*********************************************************************/
- res = wp->Cobj->Get(bstr_t("__Property_Count"), 0, &val, NULL, NULL);
-
- if (FAILED(res)) {
- sprintf(g->Message, "failed Get(__Property_Count) res=%d\n", res);
- goto err;
- } // endif res
-
- if (!(n = val.lVal)) {
- sprintf(g->Message, "Class %s in %s has no properties\n",
- classname, nsp);
- goto err;
- } // endif res
-
- /*********************************************************************/
- /* Get max property name length. */
- /*********************************************************************/
- res = wp->Cobj->GetNames(NULL,
- WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY,
- NULL, &prnlist);
-
- if (FAILED(res)) {
- sprintf(g->Message, "failed GetNames res=%d\n", res);
- goto err;
- } // endif res
-
- res = SafeArrayGetLBound(prnlist, 1, &low);
- res = SafeArrayGetUBound(prnlist, 1, &upp);
-
- for (long i = low; i <= upp; i++) {
- // Get this property name.
- res = SafeArrayGetElement(prnlist, &i, &propname);
-
- if (FAILED(res)) {
- sprintf(g->Message, "failed GetArrayElement res=%d\n", res);
- goto err;
- } // endif res
-
- len = (unsigned)SysStringLen(propname);
- length[0] = max(length[0], len);
- } // enfor i
-
- res = SafeArrayDestroy(prnlist);
-
- /*********************************************************************/
- /* Allocate the structures used to refer to the result set. */
- /*********************************************************************/
- qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
- dbtype, buftyp, length);
-
- /*********************************************************************/
- /* Now get the results into blocks. */
- /*********************************************************************/
- res = wp->Cobj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
-
- if (FAILED(res)) {
- sprintf(g->Message, "failed BeginEnumeration hr=%d\n", res);
- qrp = NULL;
- goto err;
- } // endif hr
-
- while (TRUE) {
- res = wp->Cobj->Next(0, &propname, &val, &type, NULL);
-
- if (FAILED(res)) {
- sprintf(g->Message, "failed getting Next hr=%d\n", res);
- qrp = NULL;
- goto err;
- } else if (res == WBEM_S_NO_MORE_DATA) {
- VariantClear(&val);
- break;
- } // endif res
-
- if (i >= n)
- break; // Should never happen
- else
- 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:
- qrp->BadLines++;
- goto suite;
- } // endswitch type
-
- crp = qrp->Colresp; // Column Name
- crp->Kdata->SetValue(_com_util::ConvertBSTRToString(propname), i);
- crp = crp->Next; // Data Type
- crp->Kdata->SetValue(typ, i);
- crp = crp->Next; // Type Name
- crp->Kdata->SetValue(GetTypeName(typ), i);
- crp = crp->Next; // Precision
- crp->Kdata->SetValue(lng, i);
- crp = crp->Next; // Length
- crp->Kdata->SetValue(lng, i);
- crp = crp->Next; // Scale (precision)
- crp->Kdata->SetValue(prec, i);
- i++;
-
- suite:
- SysFreeString(propname);
- VariantClear(&val);
- } // endfor i
-
- qrp->Nblin = i;
- b2 = b1;
-
- err:
- if (b2) {
- // Cleanup
- wp->Cobj->Release();
- wp->Svc->Release();
- wp->Svc = NULL; // MUST be set to NULL (why?)
- CoUninitialize();
- } // endif b
-
- /*********************************************************************/
- /* Return the result pointer for use by GetData routines. */
- /*********************************************************************/
- return qrp;
- } // end of WMIColumns
-
-/* -------------- 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
+/***********************************************************************/
+/* TABWMI: Author Olivier Bertrand -- PlugDB -- 2012 - 2013 */
+/* 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"
+
+extern "C" int trace;
+
+/**************************************************************************/
+/* Allocate the result structure that will contain result data. */
+/**************************************************************************/
+PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
+ int *dbtype, int *buftyp, unsigned int *length,
+ bool blank = true, bool nonull = true);
+
+/* ------------------- Functions WMI Column info --------------------- */
+
+/***********************************************************************/
+/* Structure used by WMI column info functions. */
+/***********************************************************************/
+typedef struct _WMIutil {
+ IWbemServices *Svc;
+ IWbemClassObject *Cobj;
+} WMIUTIL, *PWMIUT;
+
+/***********************************************************************/
+/* Initialize WMI operations. */
+/***********************************************************************/
+PWMIUT InitWMI(PGLOBAL g, char *nsp, char *classname)
+{
+ IWbemLocator *loc;
+ char *p;
+ HRESULT res;
+ PWMIUT wp = (PWMIUT)PlugSubAlloc(g, NULL, sizeof(WMIUTIL));
+
+ if (trace)
+ htrc("WMIColumns class %s space %s\n", SVP(classname), SVP(nsp));
+
+ /*********************************************************************/
+ /* Set default values for the namespace and class name. */
+ /*********************************************************************/
+ if (!nsp)
+ nsp = "root\\cimv2";
+
+ if (!classname) {
+ if (!stricmp(nsp, "root\\cimv2"))
+ classname = "ComputerSystemProduct";
+ else if (!stricmp(nsp, "root\\cli"))
+ classname = "Msft_CliAlias";
+ else {
+ strcpy(g->Message, "Missing class name");
+ return NULL;
+ } // endif classname
+
+ } // endif classname
+
+ /*********************************************************************/
+ /* Initialize WMI. */
+ /*********************************************************************/
+//res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "Failed to initialize COM library. "
+ "Error code = %p", res);
+ return NULL;
+ } // endif res
+
+#if 0 // irrelevant for a DLL
+ res = CoInitializeSecurity(NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL, EOAC_NONE, NULL);
+
+ if (res != RPC_E_TOO_LATE && FAILED(res)) {
+ sprintf(g->Message, "Failed to initialize security. "
+ "Error code = %p", res);
+ CoUninitialize();
+ return NULL;
+ } // endif Res
+#endif // 0
+
+ res = CoCreateInstance(CLSID_WbemLocator, NULL,
+ CLSCTX_INPROC_SERVER, IID_IWbemLocator,
+ (void**) &loc);
+ if (FAILED(res)) {
+ sprintf(g->Message, "Failed to create Locator. "
+ "Error code = %p", res);
+ CoUninitialize();
+ return NULL;
+ } // endif res
+
+ res = loc->ConnectServer(_bstr_t(nsp),
+ NULL, NULL, NULL, 0, NULL, NULL, &wp->Svc);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "Could not connect. Error code = %p", res);
+ loc->Release();
+ CoUninitialize();
+ return NULL;
+ } // endif res
+
+ loc->Release();
+
+ if (trace)
+ htrc("Successfully connected to namespace.\n");
+
+ /*********************************************************************/
+ /* Perform a full class object retrieval. */
+ /*********************************************************************/
+ p = (char*)PlugSubAlloc(g, NULL, strlen(classname) + 7);
+
+ if (strchr(classname, '_'))
+ strcpy(p, classname);
+ else
+ strcat(strcpy(p, "Win32_"), classname);
+
+ res = wp->Svc->GetObject(bstr_t(p), 0, 0, &wp->Cobj, 0);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed GetObject %s in %s\n", classname, nsp);
+ wp->Svc->Release();
+ wp->Svc = NULL; // MUST be set to NULL (why?)
+ return NULL;
+ } // endif res
+
+ return wp;
+} // end of InitWMI
+
+/***********************************************************************/
+/* WMIColumns: constructs the result blocks containing the description */
+/* of all the columns of a WMI table of a specified class. */
+/***********************************************************************/
+PQRYRES WMIColumns(PGLOBAL g, char *nsp, char *classname, PWMIUT wp)
+ {
+ 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 len, length[] = {0, 6, 8, 10, 10, 6};
+ int i = 0, n = 0, ncol = sizeof(dbtype) / sizeof(int);
+ int lng, typ, prec;
+ LONG low, upp;
+ BOOL b1, b2 = TRUE;
+ BSTR propname;
+ VARIANT val;
+ CIMTYPE type;
+ HRESULT res;
+ SAFEARRAY *prnlist = NULL;
+ PQRYRES qrp = NULL;
+ PCOLRES crp;
+
+ /*********************************************************************/
+ /* Initialize WMI if not done yet. */
+ /*********************************************************************/
+ if ((b1 = !wp) && !(wp = InitWMI(g, nsp, classname)))
+ return NULL;
+
+ /*********************************************************************/
+ /* Get the number of properties to return. */
+ /*********************************************************************/
+ res = wp->Cobj->Get(bstr_t("__Property_Count"), 0, &val, NULL, NULL);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed Get(__Property_Count) res=%d\n", res);
+ goto err;
+ } // endif res
+
+ if (!(n = val.lVal)) {
+ sprintf(g->Message, "Class %s in %s has no properties\n",
+ classname, nsp);
+ goto err;
+ } // endif res
+
+ /*********************************************************************/
+ /* Get max property name length. */
+ /*********************************************************************/
+ res = wp->Cobj->GetNames(NULL,
+ WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY,
+ NULL, &prnlist);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed GetNames res=%d\n", res);
+ goto err;
+ } // endif res
+
+ res = SafeArrayGetLBound(prnlist, 1, &low);
+ res = SafeArrayGetUBound(prnlist, 1, &upp);
+
+ for (long i = low; i <= upp; i++) {
+ // Get this property name.
+ res = SafeArrayGetElement(prnlist, &i, &propname);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed GetArrayElement res=%d\n", res);
+ goto err;
+ } // endif res
+
+ len = (unsigned)SysStringLen(propname);
+ length[0] = max(length[0], len);
+ } // enfor i
+
+ res = SafeArrayDestroy(prnlist);
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ dbtype, buftyp, length);
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ res = wp->Cobj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed BeginEnumeration hr=%d\n", res);
+ qrp = NULL;
+ goto err;
+ } // endif hr
+
+ while (TRUE) {
+ res = wp->Cobj->Next(0, &propname, &val, &type, NULL);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed getting Next hr=%d\n", res);
+ qrp = NULL;
+ goto err;
+ } else if (res == WBEM_S_NO_MORE_DATA) {
+ VariantClear(&val);
+ break;
+ } // endif res
+
+ if (i >= n)
+ break; // Should never happen
+ else
+ 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:
+ qrp->BadLines++;
+ goto suite;
+ } // endswitch type
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(_com_util::ConvertBSTRToString(propname), i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(typ, i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(typ), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(lng, i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(lng, i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(prec, i);
+ i++;
+
+ suite:
+ SysFreeString(propname);
+ VariantClear(&val);
+ } // endfor i
+
+ qrp->Nblin = i;
+ b2 = b1;
+
+ err:
+ if (b2) {
+ // Cleanup
+ wp->Cobj->Release();
+ wp->Svc->Release();
+ wp->Svc = NULL; // MUST be set to NULL (why?)
+ CoUninitialize();
+ } // endif b
+
+ /*********************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /*********************************************************************/
+ return qrp;
+ } // end of WMIColumns
+
+/* -------------- 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
diff --git a/storage/connect/tabwmi.h b/storage/connect/tabwmi.h
index ede84896166..cff9f8eb716 100644
--- a/storage/connect/tabwmi.h
+++ b/storage/connect/tabwmi.h
@@ -1,191 +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
+// 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
diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp
index 5a465687521..68d1846d388 100644
--- a/storage/connect/tabxml.cpp
+++ b/storage/connect/tabxml.cpp
@@ -1,1712 +1,1712 @@
-/************* Tabxml C++ Program Source Code File (.CPP) **************/
-/* PROGRAM NAME: TABXML */
-/* ------------- */
-/* Version 2.6 */
-/* */
-/* Author Olivier BERTRAND 2007 - 2013 */
-/* */
-/* This program are the XML tables classes using MS-DOM or libxml2. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include required compiler header files. */
-/***********************************************************************/
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#if defined(WIN32)
-#include <io.h>
-#include <winsock2.h>
-//#include <windows.h>
-#include <comdef.h>
-#else // !WIN32
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <unistd.h>
-//#include <ctype.h>
-#include "osutil.h"
-#define _O_RDONLY O_RDONLY
-#endif // !WIN32
-#include "my_global.h"
-
-#define INCLUDE_TDBXML
-#define NODE_TYPE_LIST
-
-/***********************************************************************/
-/* 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 "xtable.h"
-#include "colblk.h"
-#include "xindex.h"
-#include "plgxml.h"
-#include "tabxml.h"
-
-extern "C" {
-extern char version[];
-extern int trace;
-} // "C"
-
-#if defined(WIN32) && defined(DOMDOC_SUPPORT)
-#define XMLSUP "MS-DOM"
-#else // !WIN32
-#define XMLSUP "libxml2"
-#endif // !WIN32
-
-bool PushWarning(PGLOBAL g, PTDBASE tdbp);
-
-/* -------------- Implementation of the XMLDEF class ---------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-XMLDEF::XMLDEF(void)
- {
- Pseudo = 3;
- Fn = NULL;
- Encoding = NULL;
- Tabname = NULL;
- Rowname = NULL;
- Colname = NULL;
- Mulnode = NULL;
- XmlDB = NULL;
- Nslist = NULL;
- DefNs = NULL;
- Attrib = NULL;
- Hdattr = NULL;
- Limit = 0;
- Xpand = false;
- Usedom = false;
- Skipnull = false;
- } // end of XMLDEF constructor
-
-/***********************************************************************/
-/* DefineAM: define specific AM block values from XDB file. */
-/***********************************************************************/
-bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- char *defrow, *defcol, buf[10];
-//void *memp = Cat->GetDescp();
-//PSZ dbfile = Cat->GetDescFile();
-
- Fn = Cat->GetStringCatInfo(g, Name, "Filename", "?");
- Encoding = Cat->GetStringCatInfo(g, Name, "Encoding", "UTF-8");
-
- if (*Fn == '?') {
- strcpy(g->Message, MSG(MISSING_FNAME));
- return true;
- } // endif fn
-
- if ((signed)Cat->GetIntCatInfo(Name, "Flag", -1) != -1) {
- strcpy(g->Message, MSG(DEPREC_FLAG));
- return true;
- } // endif flag
-
- defrow = defcol = "";
- Cat->GetCharCatInfo(Name, "Coltype", "", buf, sizeof(buf));
-
- switch (toupper(*buf)) {
- case 'A': // Attribute
- case '@':
- case '0':
- Coltype = 0;
- break;
- case '\0': // Default
- case 'T': // Tag
- case 'N': // Node
- case '1':
- Coltype = 1;
- break;
- case 'C': // Column
- case 'P': // Position
- case 'H': // HTML
- case '2':
- Coltype = 2;
- defrow = "TR";
- defcol = "TD";
- break;
- default:
- sprintf(g->Message, MSG(INV_COL_TYPE), buf);
- return true;
- } // endswitch typname
-
- Tabname = Cat->GetStringCatInfo(g, Name, "Name", Name); // Deprecated
- Tabname = Cat->GetStringCatInfo(g, Name, "Table_name", Tabname);
- Rowname = Cat->GetStringCatInfo(g, Name, "Rownode", defrow);
- Colname = Cat->GetStringCatInfo(g, Name, "Colnode", defcol);
- Mulnode = Cat->GetStringCatInfo(g, Name, "Mulnode", "");
- XmlDB = Cat->GetStringCatInfo(g, Name, "XmlDB", "");
- Nslist = Cat->GetStringCatInfo(g, Name, "Nslist", "");
- DefNs = Cat->GetStringCatInfo(g, Name, "DefNs", "");
- Limit = Cat->GetIntCatInfo(Name, "Limit", 2);
- Xpand = (Cat->GetIntCatInfo(Name, "Expand", 0) != 0);
- Skipnull = (Cat->GetIntCatInfo(Name, "Skipnull", 0) != 0);
- Header = Cat->GetIntCatInfo(Name, "Header", 0);
- Cat->GetCharCatInfo(Name, "Xmlsup", "*", buf, sizeof(buf));
-
- if (*buf == '*') // Try the old (deprecated) option
- Cat->GetCharCatInfo(Name, "Method", "*", buf, sizeof(buf));
-
- if (*buf == '*') // Is there a default for the database?
- Cat->GetCharCatInfo("Database", "Defxml", XMLSUP,
- buf, sizeof(buf));
-
- // Note that if no support is specified, the default is MS-DOM
- Usedom = (toupper(*buf) == 'M' || toupper(*buf) == 'D');
-
- // Get eventual table node attribute
- Attrib = Cat->GetStringCatInfo(g, Name, "Attribute", "");
- Hdattr = Cat->GetStringCatInfo(g, Name, "HeadAttr", "");
-
- return false;
- } // end of DefineAM
-
-/***********************************************************************/
-/* GetTable: makes a new TDB of the proper type. */
-/***********************************************************************/
-PTDB XMLDEF::GetTable(PGLOBAL g, MODE m)
- {
- return new(g) TDBXML(this);
- } // end of GetTable
-
-/***********************************************************************/
-/* DeleteTableFile: Delete XML table files using platform API. */
-/***********************************************************************/
-bool XMLDEF::DeleteTableFile(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- bool rc;
-
- // Delete the XML table file if not protected
- if (!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
-
-/* ------------------------- TDBXML Class ---------------------------- */
-
-/***********************************************************************/
-/* Implementation of the TDBXML constuctor. */
-/***********************************************************************/
-TDBXML::TDBXML(PXMLDEF tdp) : TDBASE(tdp)
- {
- Docp = NULL;
- Root = NULL;
- Curp = NULL;
- DBnode = NULL;
- TabNode = NULL;
- RowNode = NULL;
- ColNode = NULL;
- Nlist = NULL;
- Clist = NULL;
- To_Xb = NULL;
- Colp = NULL;
- Xfile = tdp->Fn;
- Enc = tdp->Encoding;
- Tabname = tdp->Tabname;
- Rowname = (*tdp->Rowname) ? tdp->Rowname : NULL;
- Colname = (*tdp->Colname) ? tdp->Colname : NULL;
- Mulnode = (*tdp->Mulnode) ? tdp->Mulnode : NULL;
- XmlDB = (*tdp->XmlDB) ? tdp->XmlDB : NULL;
- Nslist = (*tdp->Nslist) ? tdp->Nslist : NULL;
- DefNs = (*tdp->DefNs) ? tdp->DefNs : NULL;
- Attrib = (*tdp->Attrib) ? tdp->Attrib : NULL;
- Hdattr = (*tdp->Hdattr) ? tdp->Hdattr : NULL;
- Coltype = tdp->Coltype;
- Limit = tdp->Limit;
- Xpand = tdp->Xpand;
- Skipnull = tdp->Skipnull;
- Changed = false;
- Checked = false;
- NextSame = false;
- NewRow = false;
- Hasnod = false;
- Write = false;
- Bufdone = false;
- Nodedone = false;
- Void = false;
- Usedom = tdp->Usedom;
- Header = tdp->Header;
- Nrow = -1;
- Irow = Header - 1;
- Nsub = 0;
- N = 0;
- } // end of TDBXML constructor
-
-TDBXML::TDBXML(PTDBXML tdbp) : TDBASE(tdbp)
- {
- Docp = tdbp->Docp;
- Root = tdbp->Root;
- Curp = tdbp->Curp;
- DBnode = tdbp->DBnode;
- TabNode = tdbp->TabNode;
- RowNode = tdbp->RowNode;
- ColNode = tdbp->ColNode;
- Nlist = tdbp->Nlist;
- Clist = tdbp->Clist;
- To_Xb = tdbp->To_Xb;
- Colp = tdbp->Colp;
- Xfile = tdbp->Xfile;
- Enc = tdbp->Enc;
- Tabname = tdbp->Tabname;
- Rowname = tdbp->Rowname;
- Colname = tdbp->Colname;
- Mulnode = tdbp->Mulnode;
- XmlDB = tdbp->XmlDB;
- Nslist = tdbp->Nslist;
- DefNs = tdbp->DefNs;
- Attrib = tdbp->Attrib;
- Hdattr = tdbp->Hdattr;
- Coltype = tdbp->Coltype;
- Limit = tdbp->Limit;
- Xpand = tdbp->Xpand;
- Skipnull = tdbp->Skipnull;
- Changed = tdbp->Changed;
- Checked = tdbp->Checked;
- NextSame = tdbp->NextSame;
- NewRow = tdbp->NewRow;
- Hasnod = tdbp->Hasnod;
- Write = tdbp->Write;
- Void = tdbp->Void;
- Usedom = tdbp->Usedom;
- Header = tdbp->Header;
- Nrow = tdbp->Nrow;
- Irow = tdbp->Irow;
- Nsub = tdbp->Nsub;
- N = tdbp->N;
- } // end of TDBXML copy constructor
-
-// Used for update
-PTDB TDBXML::CopyOne(PTABS t)
- {
- PTDB tp;
- PXMLCOL cp1, cp2;
- PGLOBAL g = t->G;
-
- tp = new(g) TDBXML(this);
-
- for (cp1 = (PXMLCOL)Columns; cp1; cp1 = (PXMLCOL)cp1->GetNext()) {
- cp2 = new(g) XMLCOL(cp1, tp); // Make a copy
- NewPointer(t, cp1, cp2);
- } // endfor cp1
-
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Allocate XML column description block. */
-/***********************************************************************/
-PCOL TDBXML::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- if (trace)
- htrc("TDBXML: MakeCol %s n=%d\n", (cdp) ? cdp->GetName() : "<null>", n);
-
- return new(g) XMLCOL(cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* InsertSpecialColumn: Put a special column ahead of the column list.*/
-/***********************************************************************/
-PCOL TDBXML::InsertSpecialColumn(PGLOBAL g, PCOL colp)
- {
- if (!colp->IsSpecial())
- return NULL;
-
-//if (Xpand && ((SPCBLK*)colp)->GetRnm())
-// colp->SetKey(0); // Rownum is no more a key
-
- colp->SetNext(Columns);
- Columns = colp;
- return colp;
- } // end of InsertSpecialColumn
-
-/***********************************************************************/
-/* LoadTableFile: Load and parse an XML file. */
-/***********************************************************************/
-int TDBXML::LoadTableFile(PGLOBAL g)
- {
- char filename[_MAX_PATH];
- int rc = RC_OK, type = (Usedom) ? TYPE_FB_XML : TYPE_FB_XML2;
- PFBLOCK fp = NULL;
- PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- /*********************************************************************/
- /* We used the file name relative to recorded datapath. */
- /*********************************************************************/
- PlugSetPath(filename, Xfile, GetPath());
-
- if (trace)
- htrc("TDBXML: loading %s\n", filename);
-
- /*********************************************************************/
- /* Firstly we check whether this file have been already loaded. */
- /*********************************************************************/
- if (Mode == MODE_READ)
- for (fp = dup->Openlist; fp; fp = fp->Next)
- if (fp->Type == type && fp->Length && fp->Count)
- if (!stricmp(fp->Fname, filename))
- break;
-
- if (fp) {
- /*******************************************************************/
- /* File already loaded. Just increment use count and get pointer. */
- /*******************************************************************/
- fp->Count++;
- Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc, fp)
- : GetLibxmlDoc(g, Nslist, DefNs, Enc, fp);
- } else {
- /*******************************************************************/
- /* Parse the XML file. */
- /*******************************************************************/
- if (!(Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc)
- : GetLibxmlDoc(g, Nslist, DefNs, Enc)))
- return RC_FX;
-
- // Initialize the implementation
- if (Docp->Initialize(g)) {
- sprintf(g->Message, MSG(INIT_FAILED), (Usedom) ? "DOM" : "libxml2");
- return RC_FX;
- } // endif init
-
- if (trace)
- htrc("TDBXML: parsing %s rc=%d\n", filename, rc);
-
- // Parse the XML file
- if (Docp->ParseFile(filename)) {
- // Does the file exist?
- int h= global_open(g, MSGID_NONE, filename, _O_RDONLY);
-
- rc = (h == -1 && errno == ENOENT) ? RC_NF : RC_INFO;
- if (h != -1) close(h);
- return rc;
- } // endif Docp
-
- /*******************************************************************/
- /* Link a Xblock. This make possible to reuse already opened docs */
- /* and also to automatically close them in case of error g->jump. */
- /*******************************************************************/
- fp = Docp->LinkXblock(g, Mode, rc, filename);
- } // endif xp
-
- To_Xb = fp; // Useful when closing
- return rc;
- } // end of LoadTableFile
-
-/***********************************************************************/
-/* Initialize the processing of the XML file. */
-/* Note: this function can be called several times, eventally before */
-/* the columns are known (from TBL for instance) */
-/***********************************************************************/
-bool TDBXML::Initialize(PGLOBAL g)
- {
- char tabpath[64];
- int rc;
- PXMLCOL colp;
-
- if (Void)
- return false;
-
- if (Columns && !Bufdone) {
- // Allocate the buffers that will contain node values
- for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
- if (!colp->IsSpecial()) // Not a pseudo column
- if (colp->AllocBuf(g, Mode == MODE_INSERT))
- return true;
-
- Bufdone = true;
- } // endif Bufdone
-
-#if !defined(UNIX)
- if (!Root) try {
-#else
- if (!Root) {
-#endif
- // Load or re-use the table file
- rc = LoadTableFile(g);
-
- if (rc == RC_OK) {
- // Get root node
- if (!(Root = Docp->GetRoot(g))) {
- // This should never happen as load should have failed
- strcpy(g->Message, MSG(EMPTY_DOC));
- goto error;
- } // endif Root
-
- // If tabname is not an Xpath,
- // construct one that will find it anywhere
- if (!strchr(Tabname, '/'))
- strcat(strcpy(tabpath, "//"), Tabname);
- else
- strcpy(tabpath, Tabname);
-
- // Evaluate table xpath
- if ((TabNode = Root->SelectSingleNode(g, tabpath))) {
- if (TabNode->GetType() != XML_ELEMENT_NODE) {
- sprintf(g->Message, MSG(BAD_NODE_TYPE), TabNode->GetType());
- goto error;
- } // endif Type
-
- } else if (Mode == MODE_INSERT && XmlDB) {
- // We are adding a new table to a multi-table file
-
- // If XmlDB is not an Xpath,
- // construct one that will find it anywhere
- if (!strchr(XmlDB, '/'))
- strcat(strcpy(tabpath, "//"), XmlDB);
- else
- strcpy(tabpath, XmlDB);
-
- if (!(DBnode = Root->SelectSingleNode(g, tabpath))) {
- // DB node does not exist yet; we cannot create it
- // because we don't know where it should be placed
- sprintf(g->Message, MSG(MISSING_NODE), XmlDB, Xfile);
- goto error;
- } // endif DBnode
-
- if (!(TabNode = DBnode->AddChildNode(g, Tabname))) {
- sprintf(g->Message, MSG(FAIL_ADD_NODE), Tabname);
- goto error;
- } // endif TabNode
-
- DBnode->AddText(g, "\n");
- } else
- TabNode = Root; // Try this ?
-
- } else if (rc == RC_NF) {
- // The XML file does not exist
- if (Mode == MODE_INSERT) {
- // New Document
- char buf[64];
-
- // Create the XML node
- if (Docp->NewDoc(g, "1.0")) {
- strcpy(g->Message, MSG(NEW_DOC_FAILED));
- goto error;
- } // endif NewDoc
-
- // Add a PlugDB comment node
- sprintf(buf, MSG(CREATED_PLUGDB), version);
- Docp->AddComment(g, buf);
-
- if (XmlDB) {
- // This is a multi-table file
- DBnode = Root = Docp->NewRoot(g, XmlDB);
- DBnode->AddText(g, "\n");
- TabNode = DBnode->AddChildNode(g, Tabname);
- DBnode->AddText(g, "\n");
- } else
- TabNode = Root = Docp->NewRoot(g, Tabname);
-
- if (TabNode == NULL || Root == NULL) {
- strcpy(g->Message, MSG(XML_INIT_ERROR));
- goto error;
- } else if (SetTabNode(g))
- goto error;
-
- } else {
- sprintf(g->Message, MSG(FILE_UNFOUND), Xfile);
-
- if (Mode == MODE_READ) {
- PushWarning(g, this);
- Void = true;
- } // endif Mode
-
- goto error;
- } // endif Mode
-
- } else if (rc == RC_INFO) {
- // Loading failed
- sprintf(g->Message, MSG(LOADING_FAILED), Xfile);
- goto error;
- } else // (rc == RC_FX)
- goto error;
-
- // Get row node list
- if (Rowname)
- Nlist = TabNode->SelectNodes(g, Rowname);
- else
- Nlist = TabNode->GetChildElements(g);
-
-#if defined(WIN32)
- } catch(_com_error e) {
- // We come here if a DOM command threw an error
- char buf[128];
-
- rc = WideCharToMultiByte(CP_ACP, 0, e.Description(), -1,
- buf, sizeof(buf), NULL, NULL);
-
- if (rc)
- sprintf(g->Message, "%s: %s", MSG(COM_ERROR), buf);
- else
- sprintf(g->Message, "%s hr=%p", MSG(COM_ERROR), e.Error());
-
- goto error;
-#endif // WIN32
-#if !defined(UNIX)
- } catch(...) {
- // Other errors
- strcpy(g->Message, MSG(XMLTAB_INIT_ERR));
- goto error;
-#endif
- } // end of try-catches
-
- if (Root && Columns && !Nodedone) {
- // Allocate class nodes to avoid dynamic allocation
- for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
- if (!colp->IsSpecial()) // Not a pseudo column
- colp->AllocNodes(g, Docp);
-
- Nodedone = true;
- } // endif Nodedone
-
- if (Nrow < 0)
- Nrow = (Nlist) ? Nlist->GetLength() : 0;
-
- // Init is Ok
- return false;
-
-error:
- if (Docp)
- Docp->CloseDoc(g, To_Xb);
-
- return !Void;
-} // end of Initialize
-
-/***********************************************************************/
-/* Set TabNode attributes or header. */
-/***********************************************************************/
-bool TDBXML::SetTabNode(PGLOBAL g)
- {
- assert(Mode == MODE_INSERT);
-
- if (Attrib)
- SetNodeAttr(g, Attrib, TabNode);
-
- if (Header) {
- PCOLDEF cdp;
- PXNODE rn, cn;
-
- if (Rowname) {
- TabNode->AddText(g, "\n\t");
- rn = TabNode->AddChildNode(g, Rowname, NULL);
- } else {
- strcpy(g->Message, MSG(NO_ROW_NODE));
- return true;
- } // endif Rowname
-
- if (Hdattr)
- SetNodeAttr(g, Hdattr, rn);
-
- for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
- rn->AddText(g, "\n\t\t");
- cn = rn->AddChildNode(g, "TH", NULL);
- cn->SetContent(g, (char *)cdp->GetName(),
- strlen(cdp->GetName()) + 1);
- } // endfor cdp
-
- rn->AddText(g, "\n\t");
- } // endif ColType
-
- return false;
- } // end of SetTabNode
-
-/***********************************************************************/
-/* Set attributes of a table or header node. */
-/***********************************************************************/
-void TDBXML::SetNodeAttr(PGLOBAL g, char *attr, PXNODE node)
- {
- char *p, *pa, *pn = attr;
- PXATTR an;
-
- do {
- if ((p = strchr(pn, '='))) {
- pa = pn;
- *p++ = 0;
-
- if ((pn = strchr(p, ';')))
- *pn++ = 0;
-
- an = node->AddProperty(g, pa, NULL);
- an->SetText(g, p, strlen(p) + 1);
- } else
- break;
-
- } while (pn);
-
- } // end of SetNodeAttr
-
-/***********************************************************************/
-/* XML 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 TDBXML::Cardinality(PGLOBAL g)
- {
- if (!g)
- return (Xpand || Coltype == 2) ? 0 : 1;
-
- if (Nrow < 0)
- if (Initialize(g))
- return -1;
-
- return (Void) ? 0 : Nrow - Header;
- } // end of Cardinality
-
-/***********************************************************************/
-/* XML GetMaxSize: returns the number of tables in the database. */
-/***********************************************************************/
-int TDBXML::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0)
- MaxSize = Cardinality(g) * ((Xpand) ? Limit : 1);
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* Return the position in the table. */
-/***********************************************************************/
-int TDBXML::GetRecpos(void)
- {
- union {
- uint Rpos;
- BYTE Spos[4];
- };
-
- Rpos = htonl(Irow);
- Spos[0] = (BYTE)Nsub;
- return Rpos;
- } // end of GetRecpos
-
-/***********************************************************************/
-/* RowNumber: return the ordinal number of the current row. */
-/***********************************************************************/
-int TDBXML::RowNumber(PGLOBAL g, bool b)
- {
- if (To_Kindex && (Xpand || Coltype == 2) && !b) {
- /*******************************************************************/
- /* Don't know how to retrieve RowID for expanded XML tables. */
- /*******************************************************************/
- sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
- GetAmName(g, GetAmType()));
- return 0; // Means error
- } else
- return (b || !(Xpand || Coltype == 2)) ? Irow - Header + 1 : N;
-
- } // end of RowNumber
-
-/***********************************************************************/
-/* XML Access Method opening routine. */
-/***********************************************************************/
-bool TDBXML::OpenDB(PGLOBAL g)
- {
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open replace it at its beginning. */
- /*******************************************************************/
- if (!To_Kindex) {
- Irow = Header - 1;
- Nsub = 0;
- } else
- /*****************************************************************/
- /* Table is to be accessed through a sorted index table. */
- /*****************************************************************/
- To_Kindex->Reset();
-
- return false;
- } // endif use
-
- /*********************************************************************/
- /* OpenDB: initialize the XML file processing. */
- /*********************************************************************/
- Write = (Mode == MODE_INSERT || Mode == MODE_UPDATE);
- Skipnull = (Skipnull && Mode == MODE_INSERT);
-
- if (Initialize(g))
- return true;
-
- NewRow = (Mode == MODE_INSERT);
- Nsub = 0;
- Use = USE_OPEN; // Do it now in case we are recursively called
-
- return false;
- } // end of OpenDB
-
-/***********************************************************************/
-/* Data Base read routine for XML access method. */
-/***********************************************************************/
-int TDBXML::ReadDB(PGLOBAL g)
- {
- bool same;
-
- if (Void)
- return RC_EF;
-
- /*********************************************************************/
- /* Now start the pseudo reading process. */
- /*********************************************************************/
- if (To_Kindex) {
- /*******************************************************************/
- /* Reading is by an index table. */
- /*******************************************************************/
- union {
- uint Rpos;
- BYTE Spos[4];
- };
-
- 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
- same = true;
- return RC_OK;
- default:
- Rpos = recpos;
- Nsub = Spos[0];
- Spos[0] = 0;
-
- if (Irow != (signed)ntohl(Rpos)) {
- Irow = ntohl(Rpos);
- same = false;
- } else
- same = true;
-
- } // endswitch recpos
-
- } else {
- if (trace)
- htrc("TDBXML ReadDB: Irow=%d Nrow=%d\n", Irow, Nrow);
-
- // This is to force the table to be expanded when constructing
- // an index for which the expand column is not specified.
- if (Colp && Irow >= Header) {
- Colp->Eval(g);
- Colp->Reset();
- } // endif Colp
-
- if (!NextSame) {
- if (++Irow == Nrow)
- return RC_EF;
-
- same = false;
- Nsub = 0;
- } else {
- // Not sure the multiple column read will be called
- NextSame = false;
- same = true;
- Nsub++;
- } // endif NextSame
-
- N++; // RowID
- } // endif To_Kindex
-
- if (!same) {
- if (trace > 1)
- htrc("TDBXML ReadDB: Irow=%d RowNode=%p\n", Irow, RowNode);
-
- // Get the new row node
- if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
- sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
- return RC_FX;
- } // endif RowNode
-
- if (Colname && Coltype == 2)
- Clist = RowNode->SelectNodes(g, Colname, Clist);
-
- } // endif same
-
- return RC_OK;
- } // end of ReadDB
-
-/***********************************************************************/
-/* CheckRow: called On Insert and Update. Must create the Row node */
-/* if it does not exist (Insert) and update the Clist if called by */
-/* a column having an Xpath because it can use an existing node that */
-/* was added while inserting or Updating this row. */
-/***********************************************************************/
-bool TDBXML::CheckRow(PGLOBAL g, bool b)
- {
- if (NewRow && Mode == MODE_INSERT)
- if (Rowname) {
- TabNode->AddText(g, "\n\t");
- RowNode = TabNode->AddChildNode(g, Rowname, RowNode);
- } else {
- strcpy(g->Message, MSG(NO_ROW_NODE));
- return true;
- } // endif Rowname
-
- if (Colname && (NewRow || b))
- Clist = RowNode->SelectNodes(g, Colname, Clist);
-
- return NewRow = false;
- } // end of CheckRow
-
-/***********************************************************************/
-/* WriteDB: Data Base write routine for XDB access methods. */
-/***********************************************************************/
-int TDBXML::WriteDB(PGLOBAL g)
- {
- if (Mode == MODE_INSERT) {
- if (Hasnod)
- RowNode->AddText(g, "\n\t");
-
- NewRow = true;
- } // endif Mode
-
- // Something was changed in the document
- Changed = true;
- return RC_OK;
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for XDB access methods. */
-/***********************************************************************/
-int TDBXML::DeleteDB(PGLOBAL g, int irc)
- {
- if (irc == RC_FX) {
- // Delete all rows
- for (Irow = 0; Irow < Nrow; Irow++)
- if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
- sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
- return RC_FX;
- } else
- TabNode->DeleteChild(g, RowNode);
-
- Changed = true;
- } else if (irc != RC_EF) {
- TabNode->DeleteChild(g, RowNode);
- Changed = true;
- } // endif's irc
-
- return RC_OK;
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for XDB access methods. */
-/***********************************************************************/
-void TDBXML::CloseDB(PGLOBAL g)
- {
- if (Docp) {
- if (Changed) {
- char filename[_MAX_PATH];
-// PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- // We used the file name relative to recorded datapath
- PlugSetPath(filename, Xfile, GetPath());
-
- if (Mode == MODE_INSERT)
- TabNode->AddText(g, "\n");
-
- // Save the modified document
- int rc = Docp->DumpDoc(g, filename);
- } // endif Changed
-
- // Free the document and terminate XML processing
- Docp->CloseDoc(g, To_Xb);
- } // endif docp
-
- } // end of CloseDB
-
-// ------------------------ XMLCOL functions ----------------------------
-
-/***********************************************************************/
-/* XMLCOL public constructor. */
-/***********************************************************************/
-XMLCOL::XMLCOL(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 XML access method information for column.
- Tdbp = (PTDBXML)tdbp;
- Nl = NULL;
- Nlx = NULL;
- ColNode = NULL;
- ValNode = NULL;
- Cxnp = NULL;
- Vxnp = NULL;
- Vxap = NULL;
- AttNode = NULL;
- Nodes = NULL;
- Nod = 0;
- Inod = -1;
- Mul = false;
- Checked = false;
- Xname = cdp->GetFmt();
- Long = cdp->GetLong();
- Rank = cdp->GetOffset();
- Type = Tdbp->Coltype;
- Nx = -1;
- Sx = -1;
- Valbuf = NULL;
- To_Val = NULL;
- } // end of XMLCOL constructor
-
-/***********************************************************************/
-/* XMLCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- Tdbp = col1->Tdbp;
- Nl = col1->Nl;
- Nlx = col1->Nlx;
- ColNode = col1->ColNode;
- ValNode = col1->ValNode;
- Cxnp = col1->Cxnp;
- Vxnp = col1->Vxnp;
- Vxap = col1->Vxap;
- AttNode = col1->AttNode;
- Nodes = col1->Nodes;
- Nod = col1->Nod;
- Inod = col1->Inod;
- Mul = col1->Mul;
- Checked = col1->Checked;
- Xname = col1->Xname;
- Valbuf = col1->Valbuf;
- Long = col1->Long;
- Rank = col1->Rank;
- Nx = col1->Nx;
- Sx = col1->Sx;
- Type = col1->Type;
- To_Val = col1->To_Val;
- } // end of XMLCOL copy constructor
-
-/***********************************************************************/
-/* Allocate a buffer of the proper size. */
-/***********************************************************************/
-bool XMLCOL::AllocBuf(PGLOBAL g, bool mode)
- {
- if (Valbuf)
- return false; // Already done
-
- Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1);
- Valbuf[Long] = '\0';
- return ParseXpath(g, mode);
- } // end of AllocBuf
-
-/***********************************************************************/
-/* Parse the eventual passed Xpath information. */
-/* This information can be specified in the Xpath (or Fieldfmt) */
-/* column option when creating the table. It permits to indicate the */
-/* position of the node corresponding to that column in a Xpath-like */
-/* language (but not a truly compliant one). */
-/***********************************************************************/
-bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
- {
- char *p, *p2, *pbuf = NULL;
- int i, len = strlen(Name);
-
- len += ((Tdbp->Colname) ? strlen(Tdbp->Colname) : 0);
- len += ((Xname) ? strlen(Xname) : 0);
- pbuf = (char*)PlugSubAlloc(g, NULL, len + 3);
- *pbuf = '\0';
-
- if (!mode)
- // Take care of an eventual extra column node a la html
- if (Tdbp->Colname) {
- sprintf(pbuf, Tdbp->Colname, Rank + ((Tdbp->Usedom) ? 0 : 1));
- strcat(pbuf, "/");
- } // endif Colname
-
- if (Xname) {
- if (Type == 2) {
- sprintf(g->Message, MSG(BAD_COL_XPATH), Name, Tdbp->Name);
- return true;
- } else
- strcat(pbuf, Xname);
-
- if (trace)
- htrc("XMLCOL: pbuf=%s\n", pbuf);
-
- // For Update or Insert the Xpath must be analyzed
- if (mode) {
- for (i = 0, p = pbuf; (p = strchr(p, '/')); i++, p++)
- Nod++; // One path node found
-
- if (Nod)
- Nodes = (char**)PlugSubAlloc(g, NULL, Nod * sizeof(char*));
-
- } // endif mode
-
- // Analyze the Xpath for this column
- for (i = 0, p = pbuf; (p2 = strchr(p, '/')); i++, p = p2 + 1) {
- if (Tdbp->Mulnode && !strncmp(p, Tdbp->Mulnode, p2 - p))
- if (!Tdbp->Xpand && mode) {
- strcpy(g->Message, MSG(CONCAT_SUBNODE));
- return true;
- } else
- Inod = i; // Index of multiple node
-
- if (mode) {
- // For Update or Insert the Xpath must be explicit
- if (strchr("@/.*", *p)) {
- sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
- return true;
- } else
- Nodes[i] = p;
-
- *p2 = '\0';
- } // endif mode
-
- } // endfor i, p
-
- if (*p == '/' || *p == '.') {
- sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
- return true;
- } else if (*p == '@') {
- p++; // Remove the @ if mode
- Type = 0; // Column is an attribute
- } else
- Type = 1; // Column is a node
-
- if (!*p)
- strcpy(p, Name); // Xname is column name
-
- if (Type && Tdbp->Mulnode && !strcmp(p, Tdbp->Mulnode))
- Inod = Nod; // Index of multiple node
-
- if (mode) // Prepare Xname
- pbuf = p;
-
- } else if (Type == 2) {
- // HTML like table, columns are retrieved by position
- new(this) XPOSCOL(Value); // Change the class of this column
- Tdbp->Hasnod = true;
- return false;
- } else if (Type == 0 && !mode) {
- strcat(strcat(pbuf, "@"), Name);
- } else { // Type == 1
- if (Tdbp->Mulnode && !strcmp(Name, Tdbp->Mulnode))
- Inod = 0; // Nod
-
- strcat(pbuf, Name);
- } // endif,s
-
- if (Inod >= 0) {
- Tdbp->Colp = this; // To force expand
- new(this) XMULCOL(Value); // Change the class of this column
- } // endif Inod
-
- if (Type || Nod)
- Tdbp->Hasnod = true;
-
- if (trace)
- htrc("XMLCOL: Xname=%s\n", pbuf);
-
- // Save the calculated Xpath
- Xname = pbuf;
- return false;
- } // end of ParseXpath
-
-/***********************************************************************/
-/* SetBuffer: prepare a column block for write operation. */
-/***********************************************************************/
-bool XMLCOL::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();
- Tdbp = (PTDBXML)To_Tdb; // Specific of XMLCOL
-
- // Allocate the XML buffer
- if (AllocBuf(g, true)) // In Write mode
- return true;
-
- } // endif GetOrig
-
- // Set the Column
- Status = (ok) ? BUF_EMPTY : BUF_NO;
- return false;
- } // end of SetBuffer
-
-/***********************************************************************/
-/* Alloc the nodes that will be used during the whole process. */
-/***********************************************************************/
-void XMLCOL::AllocNodes(PGLOBAL g, PXDOC dp)
-{
- Cxnp = dp->NewPnode(g);
- Vxnp = dp->NewPnode(g);
- Vxap = dp->NewPattr(g);
-} // end of AllocNodes
-
-/***********************************************************************/
-/* ReadColumn: what this routine does is to access the column node */
-/* from the corresponding table, extract from it the node text and */
-/* convert it to the column type. */
-/***********************************************************************/
-void XMLCOL::ReadColumn(PGLOBAL g)
- {
- if (Nx == Tdbp->Irow)
- return; // Same row than the last read
-
- ValNode = Tdbp->RowNode->SelectSingleNode(g, Xname, Vxnp);
-
- if (ValNode) {
- if (ValNode->GetType() != XML_ELEMENT_NODE &&
- ValNode->GetType() != XML_ATTRIBUTE_NODE) {
- sprintf(g->Message, MSG(BAD_VALNODE), Name, ValNode->GetType());
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif type
-
- // Get the Xname value from the XML file
- ValNode->GetText(Valbuf, Long);
- } else
- *Valbuf = '\0';
-
- Value->SetValue_psz(Valbuf);
- Nx = Tdbp->Irow;
- } // end of ReadColumn
-
-/***********************************************************************/
-/* WriteColumn: what this routine does is to access the last row of */
-/* the corresponding table, and rewrite the content corresponding */
-/* to this column node from the column buffer and type. */
-/***********************************************************************/
-void XMLCOL::WriteColumn(PGLOBAL g)
- {
- char *p, buf[16];
- int done = 0;
- int i, n, k = 0;
- PXNODE TopNode = NULL;
-//PXATTR AttNode = NULL;
-
- if (trace)
- htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
- Name, Tdbp->GetTdb_No(), ColUse, Status);
-
- /*********************************************************************/
- /* Check whether this node must be written. */
- /*********************************************************************/
- if (Value != To_Val)
- Value->SetValue_pval(To_Val, false); // Convert the updated value
-
- if (Tdbp->Skipnull && Value->IsZero())
- return;
-
- /*********************************************************************/
- /* If a check pass was done while updating, all node contruction */
- /* has been already one. */
- /*********************************************************************/
- if (Status && Tdbp->Checked) {
- assert (ColNode != NULL);
- assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
- goto fin;
- } // endif Checked
-
- /*********************************************************************/
- /* On Insert, a Row node must be created for each row; */
- /* For columns having an Xpath, the Clist must be updated. */
- /*********************************************************************/
- if (Tdbp->CheckRow(g, Nod || Tdbp->Colname))
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
-
- /*********************************************************************/
- /* Find the column and value nodes to update or insert. */
- /*********************************************************************/
- if (Tdbp->Clist) {
- n = Tdbp->Clist->GetLength();
- ColNode = NULL;
- } else {
- n = 1;
- ColNode = Tdbp->RowNode->Clone(g, ColNode);
- } // endif Clist
-
- ValNode = NULL;
-
- for (i = 0; i < n; i++) {
- if (Tdbp->Clist)
- ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
-
- /*******************************************************************/
- /* Check whether an Xpath was provided to go to the column node. */
- /*******************************************************************/
- for (k = 0; k < Nod; k++)
- if ((ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp)))
- TopNode = ColNode;
- else
- break;
-
- if (ColNode)
- if (Type)
- ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
- else
- AttNode = ColNode->GetAttribute(g, Xname, Vxap);
-
- if (TopNode || ValNode || AttNode)
- break; // We found the good column
- else if (Tdbp->Clist)
- ColNode = NULL;
-
- } // endfor i
-
- /*********************************************************************/
- /* Create missing nodes. */
- /*********************************************************************/
- if (ColNode == NULL) {
- if (TopNode == NULL)
- if (Tdbp->Clist) {
- Tdbp->RowNode->AddText(g, "\n\t\t");
- ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
- done = 2;
- TopNode = ColNode;
- } else
- TopNode = Tdbp->RowNode;
-
- for (; k < Nod && TopNode; k++) {
- if (!done) {
- TopNode->AddText(g, "\n\t\t");
- done = 1;
- } // endif done
-
- ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
- TopNode = ColNode;
- } // endfor k
-
- if (ColNode == NULL) {
- strcpy(g->Message, MSG(COL_ALLOC_ERR));
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif ColNode
-
- } // endif ColNode
-
- if (Type == 1) {
- if (ValNode == NULL) {
- if (done < 2)
- ColNode->AddText(g, "\n\t\t");
-
- ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
- } // endif ValNode
-
- } else // (Type == 0)
- if (AttNode == NULL)
- AttNode = ColNode->AddProperty(g, Xname, Vxap);
-
- if (ValNode == NULL && AttNode == NULL) {
- strcpy(g->Message, MSG(VAL_ALLOC_ERR));
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif ValNode
-
- /*********************************************************************/
- /* Get the string representation of Value according to column type. */
- /*********************************************************************/
- p = Value->GetCharString(buf);
-
- if (strlen(p) > (unsigned)Long) {
- sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } else
- strcpy(Valbuf, p);
-
- /*********************************************************************/
- /* Updating must be done only when not in checking pass. */
- /*********************************************************************/
- fin:
- if (Status) {
- if (Type) {
- ValNode->SetContent(g, Valbuf, Long);
- } else
- AttNode->SetText(g, Valbuf, Long);
-
- } // endif Status
-
- } // end of WriteColumn
-
-// ------------------------ XMULCOL functions ---------------------------
-
-/***********************************************************************/
-/* ReadColumn: what this routine does is to access the column node */
-/* from the corresponding table, extract from it the node text and */
-/* convert it to the column type. */
-/***********************************************************************/
-void XMULCOL::ReadColumn(PGLOBAL g)
- {
- char *p;
- int i, n, len;
-
- if (Nx != Tdbp->Irow) // New row
- Nl = Tdbp->RowNode->SelectNodes(g, Xname, Nl);
- else if (Sx == Tdbp->Nsub)
- return; // Same row
-
- n = Nl->GetLength();
- *(p = Valbuf) = '\0';
- len = Long;
-
- for (i = Tdbp->Nsub; i < n; i++) {
- ValNode = Nl->GetItem(g, i, Vxnp);
-
- if (ValNode->GetType() != XML_ELEMENT_NODE &&
- ValNode->GetType() != XML_ATTRIBUTE_NODE) {
- sprintf(g->Message, MSG(BAD_VALNODE), Name, ValNode->GetType());
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif type
-
- // Get the Xname value from the XML file
- ValNode->GetText(p, len);
-
- if (!Tdbp->Xpand) {
- // Concatenate all values
- if (n - i > 1)
- strncat(Valbuf, ", ", Long + 1);
-
- len -= strlen(p);
- p += strlen(p);
- } else
- break;
-
- } // endfor i
-
-// } // endif Nx
-
- Value->SetValue_psz(Valbuf);
- Nx = Tdbp->Irow;
- Sx = Tdbp->Nsub;
- Tdbp->NextSame = (Tdbp->Xpand && Nl->GetLength() - Sx > 1);
- } // 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 XMULCOL::WriteColumn(PGLOBAL g)
- {
- char *p, buf[16];
- int done = 0;
- int i, n, len, k = 0;
- PXNODE TopNode = NULL;
-//PXATTR AttNode = NULL;
-
- if (trace)
- htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
- Name, Tdbp->GetTdb_No(), ColUse, Status);
-
- /*********************************************************************/
- /* Check whether this node must be written. */
- /*********************************************************************/
- if (Value != To_Val)
- Value->SetValue_pval(To_Val, false); // Convert the updated value
-
- if (Tdbp->Skipnull && Value->IsZero())
- return;
-
- /*********************************************************************/
- /* If a check pass was done while updating, all node contruction */
- /* has been already one. */
- /*********************************************************************/
- if (Status && Tdbp->Checked) {
- assert (ColNode);
- assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
- goto fin;
- } // endif Checked
-
- /*********************************************************************/
- /* On Insert, a Row node must be created for each row; */
- /* For columns having an Xpath, the Clist must be updated. */
- /*********************************************************************/
- if (Tdbp->CheckRow(g, Nod))
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
-
- /*********************************************************************/
- /* Find the column and value nodes to update or insert. */
- /*********************************************************************/
- if (Tdbp->Clist) {
- n = Tdbp->Clist->GetLength();
- ColNode = NULL;
- } else {
- n = 1;
- ColNode = Tdbp->RowNode->Clone(g, ColNode);
- } // endif Clist
-
- ValNode = NULL;
-
- for (i = 0; i < n; i++) {
- if (Tdbp->Clist)
- ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
-
- /*******************************************************************/
- /* Check whether an Xpath was provided to go to the column node. */
- /*******************************************************************/
- for (k = 0; k < Nod; k++) {
- if (k == Inod) {
- // This is the multiple node
- Nlx = ColNode->SelectNodes(g, Nodes[k], Nlx);
- ColNode = Nlx->GetItem(g, Tdbp->Nsub, Cxnp);
- } else
- ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp);
-
- if (ColNode == NULL)
- break;
-
- TopNode = ColNode;
- } // endfor k
-
- if (ColNode)
- if (Inod == Nod) {
- /***************************************************************/
- /* The node value can be multiple. */
- /***************************************************************/
- assert (Type);
-
- // Get the value Node from the XML list
- Nlx = ColNode->SelectNodes(g, Xname, Nlx);
- len = Nlx->GetLength();
-
- if (len > 1 && !Tdbp->Xpand) {
- sprintf(g->Message, MSG(BAD_VAL_UPDATE), Name);
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } else
- ValNode = Nlx->GetItem(g, Tdbp->Nsub, Vxnp);
-
- } else // Inod != Nod
- if (Type)
- ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
- else
- AttNode = ColNode->GetAttribute(g, Xname, Vxap);
-
- if (TopNode || ValNode || AttNode)
- break; // We found the good column
- else if (Tdbp->Clist)
- ColNode = NULL;
-
- } // endfor i
-
- /*********************************************************************/
- /* Create missing nodes. */
- /*********************************************************************/
- if (ColNode == NULL) {
- if (TopNode == NULL)
- if (Tdbp->Clist) {
- Tdbp->RowNode->AddText(g, "\n\t\t");
- ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
- done = 2;
- TopNode = ColNode;
- } else
- TopNode = Tdbp->RowNode;
-
- for (; k < Nod && TopNode; k++) {
- if (!done) {
- TopNode->AddText(g, "\n\t\t");
- done = 1;
- } // endif done
-
- ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
- TopNode = ColNode;
- } // endfor k
-
- if (ColNode == NULL) {
- strcpy(g->Message, MSG(COL_ALLOC_ERR));
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif ColNode
-
- } // endif ColNode
-
- if (Type == 1) {
- if (ValNode == NULL) {
- if (done < 2)
- ColNode->AddText(g, "\n\t\t");
-
- ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
- } // endif ValNode
-
- } else // (Type == 0)
- if (AttNode == NULL)
- AttNode = ColNode->AddProperty(g, Xname, Vxap);
-
- if (ValNode == NULL && AttNode == NULL) {
- strcpy(g->Message, MSG(VAL_ALLOC_ERR));
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif ValNode
-
- /*********************************************************************/
- /* Get the string representation of Value according to column type. */
- /*********************************************************************/
- p = Value->GetCharString(buf);
-
- if (strlen(p) > (unsigned)Long) {
- sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } else
- strcpy(Valbuf, p);
-
- /*********************************************************************/
- /* Updating must be done only when not in checking pass. */
- /*********************************************************************/
- fin:
- if (Status) {
- if (Type) {
- ValNode->SetContent(g, Valbuf, Long);
- } else
- AttNode->SetText(g, Valbuf, Long);
-
- } // endif Status
-
- } // end of WriteColumn
-
-/* ------------------------ XPOSCOL functions ------------------------ */
-
-/***********************************************************************/
-/* ReadColumn: what this routine does is to access the column node */
-/* from the corresponding table, extract from it the node text and */
-/* convert it to the column type. */
-/***********************************************************************/
-void XPOSCOL::ReadColumn(PGLOBAL g)
- {
- if (Nx == Tdbp->Irow)
- return; // Same row than the last read
-
- if (Tdbp->Clist == NULL) {
- strcpy(g->Message, MSG(MIS_TAG_LIST));
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif Clist
-
- *Valbuf = '\0';
-
- if ((ValNode = Tdbp->Clist->GetItem(g, Rank, Vxnp)))
- // Get the column value from the XML file
- ValNode->GetText(Valbuf, Long);
-
- Value->SetValue_psz(Valbuf);
- Nx = Tdbp->Irow;
- } // 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 XPOSCOL::WriteColumn(PGLOBAL g)
- {
- char *p, buf[16];
- int i, k, n;
-
- if (trace)
- htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
- Name, Tdbp->GetTdb_No(), ColUse, Status);
-
- /*********************************************************************/
- /* Check whether this node must be written. */
- /*********************************************************************/
- if (Value != To_Val)
- Value->SetValue_pval(To_Val, false); // Convert the updated value
-
- if (Tdbp->Skipnull && Value->IsZero())
- return;
-
- /*********************************************************************/
- /* If a check pass was done while updating, all node contruction */
- /* has been already one. */
- /*********************************************************************/
- if (Status && Tdbp->Checked) {
- assert (ValNode);
- goto fin;
- } // endif Checked
-
- /*********************************************************************/
- /* On Insert, a Row node must be created for each row; */
- /* For all columns the Clist must be updated. */
- /*********************************************************************/
- if (Tdbp->CheckRow(g, true))
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
-
- /*********************************************************************/
- /* Find the column and value nodes to update or insert. */
- /*********************************************************************/
- if (Tdbp->Clist == NULL) {
- strcpy(g->Message, MSG(MIS_TAG_LIST));
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } // endif Clist
-
- n = Tdbp->Clist->GetLength();
- k = Rank;
-
- if (!(ValNode = Tdbp->Clist->GetItem(g, k, Vxnp))) {
- /*******************************************************************/
- /* Create missing column nodes. */
- /*******************************************************************/
- Tdbp->RowNode->AddText(g, "\n\t\t");
-
- for (i = n; i <= k; i++)
- ValNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname, Vxnp);
-
- assert (ValNode);
- } // endif ValNode
-
- /*********************************************************************/
- /* Get the string representation of Value according to column type. */
- /*********************************************************************/
- p = Value->GetCharString(buf);
-
- if (strlen(p) > (unsigned)Long) {
- sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
- longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
- } else
- strcpy(Valbuf, p);
-
- /*********************************************************************/
- /* Updating must be done only when not in checking pass. */
- /*********************************************************************/
- fin:
- if (Status)
- ValNode->SetContent(g, Valbuf, Long);
-
- } // end of WriteColumn
-
-/* ------------------------ End of Tabxml ---------------------------- */
+/************* Tabxml C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABXML */
+/* ------------- */
+/* Version 2.6 */
+/* */
+/* Author Olivier BERTRAND 2007 - 2013 */
+/* */
+/* This program are the XML tables classes using MS-DOM or libxml2. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include required compiler header files. */
+/***********************************************************************/
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#if defined(WIN32)
+#include <io.h>
+#include <winsock2.h>
+//#include <windows.h>
+#include <comdef.h>
+#else // !WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+//#include <ctype.h>
+#include "osutil.h"
+#define _O_RDONLY O_RDONLY
+#endif // !WIN32
+#include "my_global.h"
+
+#define INCLUDE_TDBXML
+#define NODE_TYPE_LIST
+
+/***********************************************************************/
+/* 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 "xtable.h"
+#include "colblk.h"
+#include "xindex.h"
+#include "plgxml.h"
+#include "tabxml.h"
+
+extern "C" {
+extern char version[];
+extern int trace;
+} // "C"
+
+#if defined(WIN32) && defined(DOMDOC_SUPPORT)
+#define XMLSUP "MS-DOM"
+#else // !WIN32
+#define XMLSUP "libxml2"
+#endif // !WIN32
+
+bool PushWarning(PGLOBAL g, PTDBASE tdbp);
+
+/* -------------- Implementation of the XMLDEF class ---------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+XMLDEF::XMLDEF(void)
+ {
+ Pseudo = 3;
+ Fn = NULL;
+ Encoding = NULL;
+ Tabname = NULL;
+ Rowname = NULL;
+ Colname = NULL;
+ Mulnode = NULL;
+ XmlDB = NULL;
+ Nslist = NULL;
+ DefNs = NULL;
+ Attrib = NULL;
+ Hdattr = NULL;
+ Limit = 0;
+ Xpand = false;
+ Usedom = false;
+ Skipnull = false;
+ } // end of XMLDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ char *defrow, *defcol, buf[10];
+//void *memp = Cat->GetDescp();
+//PSZ dbfile = Cat->GetDescFile();
+
+ Fn = Cat->GetStringCatInfo(g, Name, "Filename", "?");
+ Encoding = Cat->GetStringCatInfo(g, Name, "Encoding", "UTF-8");
+
+ if (*Fn == '?') {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return true;
+ } // endif fn
+
+ if ((signed)Cat->GetIntCatInfo(Name, "Flag", -1) != -1) {
+ strcpy(g->Message, MSG(DEPREC_FLAG));
+ return true;
+ } // endif flag
+
+ defrow = defcol = "";
+ Cat->GetCharCatInfo(Name, "Coltype", "", buf, sizeof(buf));
+
+ switch (toupper(*buf)) {
+ case 'A': // Attribute
+ case '@':
+ case '0':
+ Coltype = 0;
+ break;
+ case '\0': // Default
+ case 'T': // Tag
+ case 'N': // Node
+ case '1':
+ Coltype = 1;
+ break;
+ case 'C': // Column
+ case 'P': // Position
+ case 'H': // HTML
+ case '2':
+ Coltype = 2;
+ defrow = "TR";
+ defcol = "TD";
+ break;
+ default:
+ sprintf(g->Message, MSG(INV_COL_TYPE), buf);
+ return true;
+ } // endswitch typname
+
+ Tabname = Cat->GetStringCatInfo(g, Name, "Name", Name); // Deprecated
+ Tabname = Cat->GetStringCatInfo(g, Name, "Table_name", Tabname);
+ Rowname = Cat->GetStringCatInfo(g, Name, "Rownode", defrow);
+ Colname = Cat->GetStringCatInfo(g, Name, "Colnode", defcol);
+ Mulnode = Cat->GetStringCatInfo(g, Name, "Mulnode", "");
+ XmlDB = Cat->GetStringCatInfo(g, Name, "XmlDB", "");
+ Nslist = Cat->GetStringCatInfo(g, Name, "Nslist", "");
+ DefNs = Cat->GetStringCatInfo(g, Name, "DefNs", "");
+ Limit = Cat->GetIntCatInfo(Name, "Limit", 2);
+ Xpand = (Cat->GetIntCatInfo(Name, "Expand", 0) != 0);
+ Skipnull = (Cat->GetIntCatInfo(Name, "Skipnull", 0) != 0);
+ Header = Cat->GetIntCatInfo(Name, "Header", 0);
+ Cat->GetCharCatInfo(Name, "Xmlsup", "*", buf, sizeof(buf));
+
+ if (*buf == '*') // Try the old (deprecated) option
+ Cat->GetCharCatInfo(Name, "Method", "*", buf, sizeof(buf));
+
+ if (*buf == '*') // Is there a default for the database?
+ Cat->GetCharCatInfo("Database", "Defxml", XMLSUP,
+ buf, sizeof(buf));
+
+ // Note that if no support is specified, the default is MS-DOM
+ Usedom = (toupper(*buf) == 'M' || toupper(*buf) == 'D');
+
+ // Get eventual table node attribute
+ Attrib = Cat->GetStringCatInfo(g, Name, "Attribute", "");
+ Hdattr = Cat->GetStringCatInfo(g, Name, "HeadAttr", "");
+
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB XMLDEF::GetTable(PGLOBAL g, MODE m)
+ {
+ return new(g) TDBXML(this);
+ } // end of GetTable
+
+/***********************************************************************/
+/* DeleteTableFile: Delete XML table files using platform API. */
+/***********************************************************************/
+bool XMLDEF::DeleteTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool rc;
+
+ // Delete the XML table file if not protected
+ if (!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
+
+/* ------------------------- TDBXML Class ---------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBXML constuctor. */
+/***********************************************************************/
+TDBXML::TDBXML(PXMLDEF tdp) : TDBASE(tdp)
+ {
+ Docp = NULL;
+ Root = NULL;
+ Curp = NULL;
+ DBnode = NULL;
+ TabNode = NULL;
+ RowNode = NULL;
+ ColNode = NULL;
+ Nlist = NULL;
+ Clist = NULL;
+ To_Xb = NULL;
+ Colp = NULL;
+ Xfile = tdp->Fn;
+ Enc = tdp->Encoding;
+ Tabname = tdp->Tabname;
+ Rowname = (*tdp->Rowname) ? tdp->Rowname : NULL;
+ Colname = (*tdp->Colname) ? tdp->Colname : NULL;
+ Mulnode = (*tdp->Mulnode) ? tdp->Mulnode : NULL;
+ XmlDB = (*tdp->XmlDB) ? tdp->XmlDB : NULL;
+ Nslist = (*tdp->Nslist) ? tdp->Nslist : NULL;
+ DefNs = (*tdp->DefNs) ? tdp->DefNs : NULL;
+ Attrib = (*tdp->Attrib) ? tdp->Attrib : NULL;
+ Hdattr = (*tdp->Hdattr) ? tdp->Hdattr : NULL;
+ Coltype = tdp->Coltype;
+ Limit = tdp->Limit;
+ Xpand = tdp->Xpand;
+ Skipnull = tdp->Skipnull;
+ Changed = false;
+ Checked = false;
+ NextSame = false;
+ NewRow = false;
+ Hasnod = false;
+ Write = false;
+ Bufdone = false;
+ Nodedone = false;
+ Void = false;
+ Usedom = tdp->Usedom;
+ Header = tdp->Header;
+ Nrow = -1;
+ Irow = Header - 1;
+ Nsub = 0;
+ N = 0;
+ } // end of TDBXML constructor
+
+TDBXML::TDBXML(PTDBXML tdbp) : TDBASE(tdbp)
+ {
+ Docp = tdbp->Docp;
+ Root = tdbp->Root;
+ Curp = tdbp->Curp;
+ DBnode = tdbp->DBnode;
+ TabNode = tdbp->TabNode;
+ RowNode = tdbp->RowNode;
+ ColNode = tdbp->ColNode;
+ Nlist = tdbp->Nlist;
+ Clist = tdbp->Clist;
+ To_Xb = tdbp->To_Xb;
+ Colp = tdbp->Colp;
+ Xfile = tdbp->Xfile;
+ Enc = tdbp->Enc;
+ Tabname = tdbp->Tabname;
+ Rowname = tdbp->Rowname;
+ Colname = tdbp->Colname;
+ Mulnode = tdbp->Mulnode;
+ XmlDB = tdbp->XmlDB;
+ Nslist = tdbp->Nslist;
+ DefNs = tdbp->DefNs;
+ Attrib = tdbp->Attrib;
+ Hdattr = tdbp->Hdattr;
+ Coltype = tdbp->Coltype;
+ Limit = tdbp->Limit;
+ Xpand = tdbp->Xpand;
+ Skipnull = tdbp->Skipnull;
+ Changed = tdbp->Changed;
+ Checked = tdbp->Checked;
+ NextSame = tdbp->NextSame;
+ NewRow = tdbp->NewRow;
+ Hasnod = tdbp->Hasnod;
+ Write = tdbp->Write;
+ Void = tdbp->Void;
+ Usedom = tdbp->Usedom;
+ Header = tdbp->Header;
+ Nrow = tdbp->Nrow;
+ Irow = tdbp->Irow;
+ Nsub = tdbp->Nsub;
+ N = tdbp->N;
+ } // end of TDBXML copy constructor
+
+// Used for update
+PTDB TDBXML::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PXMLCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBXML(this);
+
+ for (cp1 = (PXMLCOL)Columns; cp1; cp1 = (PXMLCOL)cp1->GetNext()) {
+ cp2 = new(g) XMLCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Allocate XML column description block. */
+/***********************************************************************/
+PCOL TDBXML::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ if (trace)
+ htrc("TDBXML: MakeCol %s n=%d\n", (cdp) ? cdp->GetName() : "<null>", n);
+
+ return new(g) XMLCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBXML::InsertSpecialColumn(PGLOBAL g, PCOL colp)
+ {
+ if (!colp->IsSpecial())
+ return NULL;
+
+//if (Xpand && ((SPCBLK*)colp)->GetRnm())
+// colp->SetKey(0); // Rownum is no more a key
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+ } // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* LoadTableFile: Load and parse an XML file. */
+/***********************************************************************/
+int TDBXML::LoadTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int rc = RC_OK, type = (Usedom) ? TYPE_FB_XML : TYPE_FB_XML2;
+ PFBLOCK fp = NULL;
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ /*********************************************************************/
+ /* We used the file name relative to recorded datapath. */
+ /*********************************************************************/
+ PlugSetPath(filename, Xfile, GetPath());
+
+ if (trace)
+ htrc("TDBXML: loading %s\n", filename);
+
+ /*********************************************************************/
+ /* Firstly we check whether this file have been already loaded. */
+ /*********************************************************************/
+ if (Mode == MODE_READ)
+ for (fp = dup->Openlist; fp; fp = fp->Next)
+ if (fp->Type == type && fp->Length && fp->Count)
+ if (!stricmp(fp->Fname, filename))
+ break;
+
+ if (fp) {
+ /*******************************************************************/
+ /* File already loaded. Just increment use count and get pointer. */
+ /*******************************************************************/
+ fp->Count++;
+ Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc, fp)
+ : GetLibxmlDoc(g, Nslist, DefNs, Enc, fp);
+ } else {
+ /*******************************************************************/
+ /* Parse the XML file. */
+ /*******************************************************************/
+ if (!(Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc)
+ : GetLibxmlDoc(g, Nslist, DefNs, Enc)))
+ return RC_FX;
+
+ // Initialize the implementation
+ if (Docp->Initialize(g)) {
+ sprintf(g->Message, MSG(INIT_FAILED), (Usedom) ? "DOM" : "libxml2");
+ return RC_FX;
+ } // endif init
+
+ if (trace)
+ htrc("TDBXML: parsing %s rc=%d\n", filename, rc);
+
+ // Parse the XML file
+ if (Docp->ParseFile(filename)) {
+ // Does the file exist?
+ int h= global_open(g, MSGID_NONE, filename, _O_RDONLY);
+
+ rc = (h == -1 && errno == ENOENT) ? RC_NF : RC_INFO;
+ if (h != -1) close(h);
+ return rc;
+ } // endif Docp
+
+ /*******************************************************************/
+ /* Link a Xblock. This make possible to reuse already opened docs */
+ /* and also to automatically close them in case of error g->jump. */
+ /*******************************************************************/
+ fp = Docp->LinkXblock(g, Mode, rc, filename);
+ } // endif xp
+
+ To_Xb = fp; // Useful when closing
+ return rc;
+ } // end of LoadTableFile
+
+/***********************************************************************/
+/* Initialize the processing of the XML file. */
+/* Note: this function can be called several times, eventally before */
+/* the columns are known (from TBL for instance) */
+/***********************************************************************/
+bool TDBXML::Initialize(PGLOBAL g)
+ {
+ char tabpath[64];
+ int rc;
+ PXMLCOL colp;
+
+ if (Void)
+ return false;
+
+ if (Columns && !Bufdone) {
+ // Allocate the buffers that will contain node values
+ for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
+ if (!colp->IsSpecial()) // Not a pseudo column
+ if (colp->AllocBuf(g, Mode == MODE_INSERT))
+ return true;
+
+ Bufdone = true;
+ } // endif Bufdone
+
+#if !defined(UNIX)
+ if (!Root) try {
+#else
+ if (!Root) {
+#endif
+ // Load or re-use the table file
+ rc = LoadTableFile(g);
+
+ if (rc == RC_OK) {
+ // Get root node
+ if (!(Root = Docp->GetRoot(g))) {
+ // This should never happen as load should have failed
+ strcpy(g->Message, MSG(EMPTY_DOC));
+ goto error;
+ } // endif Root
+
+ // If tabname is not an Xpath,
+ // construct one that will find it anywhere
+ if (!strchr(Tabname, '/'))
+ strcat(strcpy(tabpath, "//"), Tabname);
+ else
+ strcpy(tabpath, Tabname);
+
+ // Evaluate table xpath
+ if ((TabNode = Root->SelectSingleNode(g, tabpath))) {
+ if (TabNode->GetType() != XML_ELEMENT_NODE) {
+ sprintf(g->Message, MSG(BAD_NODE_TYPE), TabNode->GetType());
+ goto error;
+ } // endif Type
+
+ } else if (Mode == MODE_INSERT && XmlDB) {
+ // We are adding a new table to a multi-table file
+
+ // If XmlDB is not an Xpath,
+ // construct one that will find it anywhere
+ if (!strchr(XmlDB, '/'))
+ strcat(strcpy(tabpath, "//"), XmlDB);
+ else
+ strcpy(tabpath, XmlDB);
+
+ if (!(DBnode = Root->SelectSingleNode(g, tabpath))) {
+ // DB node does not exist yet; we cannot create it
+ // because we don't know where it should be placed
+ sprintf(g->Message, MSG(MISSING_NODE), XmlDB, Xfile);
+ goto error;
+ } // endif DBnode
+
+ if (!(TabNode = DBnode->AddChildNode(g, Tabname))) {
+ sprintf(g->Message, MSG(FAIL_ADD_NODE), Tabname);
+ goto error;
+ } // endif TabNode
+
+ DBnode->AddText(g, "\n");
+ } else
+ TabNode = Root; // Try this ?
+
+ } else if (rc == RC_NF) {
+ // The XML file does not exist
+ if (Mode == MODE_INSERT) {
+ // New Document
+ char buf[64];
+
+ // Create the XML node
+ if (Docp->NewDoc(g, "1.0")) {
+ strcpy(g->Message, MSG(NEW_DOC_FAILED));
+ goto error;
+ } // endif NewDoc
+
+ // Add a PlugDB comment node
+ sprintf(buf, MSG(CREATED_PLUGDB), version);
+ Docp->AddComment(g, buf);
+
+ if (XmlDB) {
+ // This is a multi-table file
+ DBnode = Root = Docp->NewRoot(g, XmlDB);
+ DBnode->AddText(g, "\n");
+ TabNode = DBnode->AddChildNode(g, Tabname);
+ DBnode->AddText(g, "\n");
+ } else
+ TabNode = Root = Docp->NewRoot(g, Tabname);
+
+ if (TabNode == NULL || Root == NULL) {
+ strcpy(g->Message, MSG(XML_INIT_ERROR));
+ goto error;
+ } else if (SetTabNode(g))
+ goto error;
+
+ } else {
+ sprintf(g->Message, MSG(FILE_UNFOUND), Xfile);
+
+ if (Mode == MODE_READ) {
+ PushWarning(g, this);
+ Void = true;
+ } // endif Mode
+
+ goto error;
+ } // endif Mode
+
+ } else if (rc == RC_INFO) {
+ // Loading failed
+ sprintf(g->Message, MSG(LOADING_FAILED), Xfile);
+ goto error;
+ } else // (rc == RC_FX)
+ goto error;
+
+ // Get row node list
+ if (Rowname)
+ Nlist = TabNode->SelectNodes(g, Rowname);
+ else
+ Nlist = TabNode->GetChildElements(g);
+
+#if defined(WIN32)
+ } catch(_com_error e) {
+ // We come here if a DOM command threw an error
+ char buf[128];
+
+ rc = WideCharToMultiByte(CP_ACP, 0, e.Description(), -1,
+ buf, sizeof(buf), NULL, NULL);
+
+ if (rc)
+ sprintf(g->Message, "%s: %s", MSG(COM_ERROR), buf);
+ else
+ sprintf(g->Message, "%s hr=%p", MSG(COM_ERROR), e.Error());
+
+ goto error;
+#endif // WIN32
+#if !defined(UNIX)
+ } catch(...) {
+ // Other errors
+ strcpy(g->Message, MSG(XMLTAB_INIT_ERR));
+ goto error;
+#endif
+ } // end of try-catches
+
+ if (Root && Columns && !Nodedone) {
+ // Allocate class nodes to avoid dynamic allocation
+ for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
+ if (!colp->IsSpecial()) // Not a pseudo column
+ colp->AllocNodes(g, Docp);
+
+ Nodedone = true;
+ } // endif Nodedone
+
+ if (Nrow < 0)
+ Nrow = (Nlist) ? Nlist->GetLength() : 0;
+
+ // Init is Ok
+ return false;
+
+error:
+ if (Docp)
+ Docp->CloseDoc(g, To_Xb);
+
+ return !Void;
+} // end of Initialize
+
+/***********************************************************************/
+/* Set TabNode attributes or header. */
+/***********************************************************************/
+bool TDBXML::SetTabNode(PGLOBAL g)
+ {
+ assert(Mode == MODE_INSERT);
+
+ if (Attrib)
+ SetNodeAttr(g, Attrib, TabNode);
+
+ if (Header) {
+ PCOLDEF cdp;
+ PXNODE rn, cn;
+
+ if (Rowname) {
+ TabNode->AddText(g, "\n\t");
+ rn = TabNode->AddChildNode(g, Rowname, NULL);
+ } else {
+ strcpy(g->Message, MSG(NO_ROW_NODE));
+ return true;
+ } // endif Rowname
+
+ if (Hdattr)
+ SetNodeAttr(g, Hdattr, rn);
+
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
+ rn->AddText(g, "\n\t\t");
+ cn = rn->AddChildNode(g, "TH", NULL);
+ cn->SetContent(g, (char *)cdp->GetName(),
+ strlen(cdp->GetName()) + 1);
+ } // endfor cdp
+
+ rn->AddText(g, "\n\t");
+ } // endif ColType
+
+ return false;
+ } // end of SetTabNode
+
+/***********************************************************************/
+/* Set attributes of a table or header node. */
+/***********************************************************************/
+void TDBXML::SetNodeAttr(PGLOBAL g, char *attr, PXNODE node)
+ {
+ char *p, *pa, *pn = attr;
+ PXATTR an;
+
+ do {
+ if ((p = strchr(pn, '='))) {
+ pa = pn;
+ *p++ = 0;
+
+ if ((pn = strchr(p, ';')))
+ *pn++ = 0;
+
+ an = node->AddProperty(g, pa, NULL);
+ an->SetText(g, p, strlen(p) + 1);
+ } else
+ break;
+
+ } while (pn);
+
+ } // end of SetNodeAttr
+
+/***********************************************************************/
+/* XML 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 TDBXML::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return (Xpand || Coltype == 2) ? 0 : 1;
+
+ if (Nrow < 0)
+ if (Initialize(g))
+ return -1;
+
+ return (Void) ? 0 : Nrow - Header;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* XML GetMaxSize: returns the number of tables in the database. */
+/***********************************************************************/
+int TDBXML::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0)
+ MaxSize = Cardinality(g) * ((Xpand) ? Limit : 1);
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* Return the position in the table. */
+/***********************************************************************/
+int TDBXML::GetRecpos(void)
+ {
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ Rpos = htonl(Irow);
+ Spos[0] = (BYTE)Nsub;
+ return Rpos;
+ } // end of GetRecpos
+
+/***********************************************************************/
+/* RowNumber: return the ordinal number of the current row. */
+/***********************************************************************/
+int TDBXML::RowNumber(PGLOBAL g, bool b)
+ {
+ if (To_Kindex && (Xpand || Coltype == 2) && !b) {
+ /*******************************************************************/
+ /* Don't know how to retrieve RowID for expanded XML tables. */
+ /*******************************************************************/
+ sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
+ GetAmName(g, GetAmType()));
+ return 0; // Means error
+ } else
+ return (b || !(Xpand || Coltype == 2)) ? Irow - Header + 1 : N;
+
+ } // end of RowNumber
+
+/***********************************************************************/
+/* XML Access Method opening routine. */
+/***********************************************************************/
+bool TDBXML::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. */
+ /*******************************************************************/
+ if (!To_Kindex) {
+ Irow = Header - 1;
+ Nsub = 0;
+ } else
+ /*****************************************************************/
+ /* Table is to be accessed through a sorted index table. */
+ /*****************************************************************/
+ To_Kindex->Reset();
+
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* OpenDB: initialize the XML file processing. */
+ /*********************************************************************/
+ Write = (Mode == MODE_INSERT || Mode == MODE_UPDATE);
+ Skipnull = (Skipnull && Mode == MODE_INSERT);
+
+ if (Initialize(g))
+ return true;
+
+ NewRow = (Mode == MODE_INSERT);
+ Nsub = 0;
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for XML access method. */
+/***********************************************************************/
+int TDBXML::ReadDB(PGLOBAL g)
+ {
+ bool same;
+
+ if (Void)
+ return RC_EF;
+
+ /*********************************************************************/
+ /* Now start the pseudo reading process. */
+ /*********************************************************************/
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ 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
+ same = true;
+ return RC_OK;
+ default:
+ Rpos = recpos;
+ Nsub = Spos[0];
+ Spos[0] = 0;
+
+ if (Irow != (signed)ntohl(Rpos)) {
+ Irow = ntohl(Rpos);
+ same = false;
+ } else
+ same = true;
+
+ } // endswitch recpos
+
+ } else {
+ if (trace)
+ htrc("TDBXML ReadDB: Irow=%d Nrow=%d\n", Irow, Nrow);
+
+ // This is to force the table to be expanded when constructing
+ // an index for which the expand column is not specified.
+ if (Colp && Irow >= Header) {
+ Colp->Eval(g);
+ Colp->Reset();
+ } // endif Colp
+
+ if (!NextSame) {
+ if (++Irow == Nrow)
+ return RC_EF;
+
+ same = false;
+ Nsub = 0;
+ } else {
+ // Not sure the multiple column read will be called
+ NextSame = false;
+ same = true;
+ Nsub++;
+ } // endif NextSame
+
+ N++; // RowID
+ } // endif To_Kindex
+
+ if (!same) {
+ if (trace > 1)
+ htrc("TDBXML ReadDB: Irow=%d RowNode=%p\n", Irow, RowNode);
+
+ // Get the new row node
+ if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
+ sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
+ return RC_FX;
+ } // endif RowNode
+
+ if (Colname && Coltype == 2)
+ Clist = RowNode->SelectNodes(g, Colname, Clist);
+
+ } // endif same
+
+ return RC_OK;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* CheckRow: called On Insert and Update. Must create the Row node */
+/* if it does not exist (Insert) and update the Clist if called by */
+/* a column having an Xpath because it can use an existing node that */
+/* was added while inserting or Updating this row. */
+/***********************************************************************/
+bool TDBXML::CheckRow(PGLOBAL g, bool b)
+ {
+ if (NewRow && Mode == MODE_INSERT)
+ if (Rowname) {
+ TabNode->AddText(g, "\n\t");
+ RowNode = TabNode->AddChildNode(g, Rowname, RowNode);
+ } else {
+ strcpy(g->Message, MSG(NO_ROW_NODE));
+ return true;
+ } // endif Rowname
+
+ if (Colname && (NewRow || b))
+ Clist = RowNode->SelectNodes(g, Colname, Clist);
+
+ return NewRow = false;
+ } // end of CheckRow
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for XDB access methods. */
+/***********************************************************************/
+int TDBXML::WriteDB(PGLOBAL g)
+ {
+ if (Mode == MODE_INSERT) {
+ if (Hasnod)
+ RowNode->AddText(g, "\n\t");
+
+ NewRow = true;
+ } // endif Mode
+
+ // Something was changed in the document
+ Changed = true;
+ return RC_OK;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for XDB access methods. */
+/***********************************************************************/
+int TDBXML::DeleteDB(PGLOBAL g, int irc)
+ {
+ if (irc == RC_FX) {
+ // Delete all rows
+ for (Irow = 0; Irow < Nrow; Irow++)
+ if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
+ sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
+ return RC_FX;
+ } else
+ TabNode->DeleteChild(g, RowNode);
+
+ Changed = true;
+ } else if (irc != RC_EF) {
+ TabNode->DeleteChild(g, RowNode);
+ Changed = true;
+ } // endif's irc
+
+ return RC_OK;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for XDB access methods. */
+/***********************************************************************/
+void TDBXML::CloseDB(PGLOBAL g)
+ {
+ if (Docp) {
+ if (Changed) {
+ char filename[_MAX_PATH];
+// PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, Xfile, GetPath());
+
+ if (Mode == MODE_INSERT)
+ TabNode->AddText(g, "\n");
+
+ // Save the modified document
+ int rc = Docp->DumpDoc(g, filename);
+ } // endif Changed
+
+ // Free the document and terminate XML processing
+ Docp->CloseDoc(g, To_Xb);
+ } // endif docp
+
+ } // end of CloseDB
+
+// ------------------------ XMLCOL functions ----------------------------
+
+/***********************************************************************/
+/* XMLCOL public constructor. */
+/***********************************************************************/
+XMLCOL::XMLCOL(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 XML access method information for column.
+ Tdbp = (PTDBXML)tdbp;
+ Nl = NULL;
+ Nlx = NULL;
+ ColNode = NULL;
+ ValNode = NULL;
+ Cxnp = NULL;
+ Vxnp = NULL;
+ Vxap = NULL;
+ AttNode = NULL;
+ Nodes = NULL;
+ Nod = 0;
+ Inod = -1;
+ Mul = false;
+ Checked = false;
+ Xname = cdp->GetFmt();
+ Long = cdp->GetLong();
+ Rank = cdp->GetOffset();
+ Type = Tdbp->Coltype;
+ Nx = -1;
+ Sx = -1;
+ Valbuf = NULL;
+ To_Val = NULL;
+ } // end of XMLCOL constructor
+
+/***********************************************************************/
+/* XMLCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Tdbp = col1->Tdbp;
+ Nl = col1->Nl;
+ Nlx = col1->Nlx;
+ ColNode = col1->ColNode;
+ ValNode = col1->ValNode;
+ Cxnp = col1->Cxnp;
+ Vxnp = col1->Vxnp;
+ Vxap = col1->Vxap;
+ AttNode = col1->AttNode;
+ Nodes = col1->Nodes;
+ Nod = col1->Nod;
+ Inod = col1->Inod;
+ Mul = col1->Mul;
+ Checked = col1->Checked;
+ Xname = col1->Xname;
+ Valbuf = col1->Valbuf;
+ Long = col1->Long;
+ Rank = col1->Rank;
+ Nx = col1->Nx;
+ Sx = col1->Sx;
+ Type = col1->Type;
+ To_Val = col1->To_Val;
+ } // end of XMLCOL copy constructor
+
+/***********************************************************************/
+/* Allocate a buffer of the proper size. */
+/***********************************************************************/
+bool XMLCOL::AllocBuf(PGLOBAL g, bool mode)
+ {
+ if (Valbuf)
+ return false; // Already done
+
+ Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1);
+ Valbuf[Long] = '\0';
+ return ParseXpath(g, mode);
+ } // end of AllocBuf
+
+/***********************************************************************/
+/* Parse the eventual passed Xpath information. */
+/* This information can be specified in the Xpath (or Fieldfmt) */
+/* column option when creating the table. It permits to indicate the */
+/* position of the node corresponding to that column in a Xpath-like */
+/* language (but not a truly compliant one). */
+/***********************************************************************/
+bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
+ {
+ char *p, *p2, *pbuf = NULL;
+ int i, len = strlen(Name);
+
+ len += ((Tdbp->Colname) ? strlen(Tdbp->Colname) : 0);
+ len += ((Xname) ? strlen(Xname) : 0);
+ pbuf = (char*)PlugSubAlloc(g, NULL, len + 3);
+ *pbuf = '\0';
+
+ if (!mode)
+ // Take care of an eventual extra column node a la html
+ if (Tdbp->Colname) {
+ sprintf(pbuf, Tdbp->Colname, Rank + ((Tdbp->Usedom) ? 0 : 1));
+ strcat(pbuf, "/");
+ } // endif Colname
+
+ if (Xname) {
+ if (Type == 2) {
+ sprintf(g->Message, MSG(BAD_COL_XPATH), Name, Tdbp->Name);
+ return true;
+ } else
+ strcat(pbuf, Xname);
+
+ if (trace)
+ htrc("XMLCOL: pbuf=%s\n", pbuf);
+
+ // For Update or Insert the Xpath must be analyzed
+ if (mode) {
+ for (i = 0, p = pbuf; (p = strchr(p, '/')); i++, p++)
+ Nod++; // One path node found
+
+ if (Nod)
+ Nodes = (char**)PlugSubAlloc(g, NULL, Nod * sizeof(char*));
+
+ } // endif mode
+
+ // Analyze the Xpath for this column
+ for (i = 0, p = pbuf; (p2 = strchr(p, '/')); i++, p = p2 + 1) {
+ if (Tdbp->Mulnode && !strncmp(p, Tdbp->Mulnode, p2 - p))
+ if (!Tdbp->Xpand && mode) {
+ strcpy(g->Message, MSG(CONCAT_SUBNODE));
+ return true;
+ } else
+ Inod = i; // Index of multiple node
+
+ if (mode) {
+ // For Update or Insert the Xpath must be explicit
+ if (strchr("@/.*", *p)) {
+ sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
+ return true;
+ } else
+ Nodes[i] = p;
+
+ *p2 = '\0';
+ } // endif mode
+
+ } // endfor i, p
+
+ if (*p == '/' || *p == '.') {
+ sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
+ return true;
+ } else if (*p == '@') {
+ p++; // Remove the @ if mode
+ Type = 0; // Column is an attribute
+ } else
+ Type = 1; // Column is a node
+
+ if (!*p)
+ strcpy(p, Name); // Xname is column name
+
+ if (Type && Tdbp->Mulnode && !strcmp(p, Tdbp->Mulnode))
+ Inod = Nod; // Index of multiple node
+
+ if (mode) // Prepare Xname
+ pbuf = p;
+
+ } else if (Type == 2) {
+ // HTML like table, columns are retrieved by position
+ new(this) XPOSCOL(Value); // Change the class of this column
+ Tdbp->Hasnod = true;
+ return false;
+ } else if (Type == 0 && !mode) {
+ strcat(strcat(pbuf, "@"), Name);
+ } else { // Type == 1
+ if (Tdbp->Mulnode && !strcmp(Name, Tdbp->Mulnode))
+ Inod = 0; // Nod
+
+ strcat(pbuf, Name);
+ } // endif,s
+
+ if (Inod >= 0) {
+ Tdbp->Colp = this; // To force expand
+ new(this) XMULCOL(Value); // Change the class of this column
+ } // endif Inod
+
+ if (Type || Nod)
+ Tdbp->Hasnod = true;
+
+ if (trace)
+ htrc("XMLCOL: Xname=%s\n", pbuf);
+
+ // Save the calculated Xpath
+ Xname = pbuf;
+ return false;
+ } // end of ParseXpath
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool XMLCOL::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();
+ Tdbp = (PTDBXML)To_Tdb; // Specific of XMLCOL
+
+ // Allocate the XML buffer
+ if (AllocBuf(g, true)) // In Write mode
+ return true;
+
+ } // endif GetOrig
+
+ // Set the Column
+ Status = (ok) ? BUF_EMPTY : BUF_NO;
+ return false;
+ } // end of SetBuffer
+
+/***********************************************************************/
+/* Alloc the nodes that will be used during the whole process. */
+/***********************************************************************/
+void XMLCOL::AllocNodes(PGLOBAL g, PXDOC dp)
+{
+ Cxnp = dp->NewPnode(g);
+ Vxnp = dp->NewPnode(g);
+ Vxap = dp->NewPattr(g);
+} // end of AllocNodes
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the column node */
+/* from the corresponding table, extract from it the node text and */
+/* convert it to the column type. */
+/***********************************************************************/
+void XMLCOL::ReadColumn(PGLOBAL g)
+ {
+ if (Nx == Tdbp->Irow)
+ return; // Same row than the last read
+
+ ValNode = Tdbp->RowNode->SelectSingleNode(g, Xname, Vxnp);
+
+ if (ValNode) {
+ if (ValNode->GetType() != XML_ELEMENT_NODE &&
+ ValNode->GetType() != XML_ATTRIBUTE_NODE) {
+ sprintf(g->Message, MSG(BAD_VALNODE), Name, ValNode->GetType());
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif type
+
+ // Get the Xname value from the XML file
+ ValNode->GetText(Valbuf, Long);
+ } else
+ *Valbuf = '\0';
+
+ Value->SetValue_psz(Valbuf);
+ Nx = Tdbp->Irow;
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last row of */
+/* the corresponding table, and rewrite the content corresponding */
+/* to this column node from the column buffer and type. */
+/***********************************************************************/
+void XMLCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, buf[16];
+ int done = 0;
+ int i, n, k = 0;
+ PXNODE TopNode = NULL;
+//PXATTR AttNode = NULL;
+
+ if (trace)
+ htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, Tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ if (Tdbp->Skipnull && Value->IsZero())
+ return;
+
+ /*********************************************************************/
+ /* If a check pass was done while updating, all node contruction */
+ /* has been already one. */
+ /*********************************************************************/
+ if (Status && Tdbp->Checked) {
+ assert (ColNode != NULL);
+ assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
+ goto fin;
+ } // endif Checked
+
+ /*********************************************************************/
+ /* On Insert, a Row node must be created for each row; */
+ /* For columns having an Xpath, the Clist must be updated. */
+ /*********************************************************************/
+ if (Tdbp->CheckRow(g, Nod || Tdbp->Colname))
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+
+ /*********************************************************************/
+ /* Find the column and value nodes to update or insert. */
+ /*********************************************************************/
+ if (Tdbp->Clist) {
+ n = Tdbp->Clist->GetLength();
+ ColNode = NULL;
+ } else {
+ n = 1;
+ ColNode = Tdbp->RowNode->Clone(g, ColNode);
+ } // endif Clist
+
+ ValNode = NULL;
+
+ for (i = 0; i < n; i++) {
+ if (Tdbp->Clist)
+ ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
+
+ /*******************************************************************/
+ /* Check whether an Xpath was provided to go to the column node. */
+ /*******************************************************************/
+ for (k = 0; k < Nod; k++)
+ if ((ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp)))
+ TopNode = ColNode;
+ else
+ break;
+
+ if (ColNode)
+ if (Type)
+ ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
+ else
+ AttNode = ColNode->GetAttribute(g, Xname, Vxap);
+
+ if (TopNode || ValNode || AttNode)
+ break; // We found the good column
+ else if (Tdbp->Clist)
+ ColNode = NULL;
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Create missing nodes. */
+ /*********************************************************************/
+ if (ColNode == NULL) {
+ if (TopNode == NULL)
+ if (Tdbp->Clist) {
+ Tdbp->RowNode->AddText(g, "\n\t\t");
+ ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
+ done = 2;
+ TopNode = ColNode;
+ } else
+ TopNode = Tdbp->RowNode;
+
+ for (; k < Nod && TopNode; k++) {
+ if (!done) {
+ TopNode->AddText(g, "\n\t\t");
+ done = 1;
+ } // endif done
+
+ ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
+ TopNode = ColNode;
+ } // endfor k
+
+ if (ColNode == NULL) {
+ strcpy(g->Message, MSG(COL_ALLOC_ERR));
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif ColNode
+
+ } // endif ColNode
+
+ if (Type == 1) {
+ if (ValNode == NULL) {
+ if (done < 2)
+ ColNode->AddText(g, "\n\t\t");
+
+ ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
+ } // endif ValNode
+
+ } else // (Type == 0)
+ if (AttNode == NULL)
+ AttNode = ColNode->AddProperty(g, Xname, Vxap);
+
+ if (ValNode == NULL && AttNode == NULL) {
+ strcpy(g->Message, MSG(VAL_ALLOC_ERR));
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif ValNode
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ p = Value->GetCharString(buf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } else
+ strcpy(Valbuf, p);
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ fin:
+ if (Status) {
+ if (Type) {
+ ValNode->SetContent(g, Valbuf, Long);
+ } else
+ AttNode->SetText(g, Valbuf, Long);
+
+ } // endif Status
+
+ } // end of WriteColumn
+
+// ------------------------ XMULCOL functions ---------------------------
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the column node */
+/* from the corresponding table, extract from it the node text and */
+/* convert it to the column type. */
+/***********************************************************************/
+void XMULCOL::ReadColumn(PGLOBAL g)
+ {
+ char *p;
+ int i, n, len;
+
+ if (Nx != Tdbp->Irow) // New row
+ Nl = Tdbp->RowNode->SelectNodes(g, Xname, Nl);
+ else if (Sx == Tdbp->Nsub)
+ return; // Same row
+
+ n = Nl->GetLength();
+ *(p = Valbuf) = '\0';
+ len = Long;
+
+ for (i = Tdbp->Nsub; i < n; i++) {
+ ValNode = Nl->GetItem(g, i, Vxnp);
+
+ if (ValNode->GetType() != XML_ELEMENT_NODE &&
+ ValNode->GetType() != XML_ATTRIBUTE_NODE) {
+ sprintf(g->Message, MSG(BAD_VALNODE), Name, ValNode->GetType());
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif type
+
+ // Get the Xname value from the XML file
+ ValNode->GetText(p, len);
+
+ if (!Tdbp->Xpand) {
+ // Concatenate all values
+ if (n - i > 1)
+ strncat(Valbuf, ", ", Long + 1);
+
+ len -= strlen(p);
+ p += strlen(p);
+ } else
+ break;
+
+ } // endfor i
+
+// } // endif Nx
+
+ Value->SetValue_psz(Valbuf);
+ Nx = Tdbp->Irow;
+ Sx = Tdbp->Nsub;
+ Tdbp->NextSame = (Tdbp->Xpand && Nl->GetLength() - Sx > 1);
+ } // 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 XMULCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, buf[16];
+ int done = 0;
+ int i, n, len, k = 0;
+ PXNODE TopNode = NULL;
+//PXATTR AttNode = NULL;
+
+ if (trace)
+ htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, Tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ if (Tdbp->Skipnull && Value->IsZero())
+ return;
+
+ /*********************************************************************/
+ /* If a check pass was done while updating, all node contruction */
+ /* has been already one. */
+ /*********************************************************************/
+ if (Status && Tdbp->Checked) {
+ assert (ColNode);
+ assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
+ goto fin;
+ } // endif Checked
+
+ /*********************************************************************/
+ /* On Insert, a Row node must be created for each row; */
+ /* For columns having an Xpath, the Clist must be updated. */
+ /*********************************************************************/
+ if (Tdbp->CheckRow(g, Nod))
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+
+ /*********************************************************************/
+ /* Find the column and value nodes to update or insert. */
+ /*********************************************************************/
+ if (Tdbp->Clist) {
+ n = Tdbp->Clist->GetLength();
+ ColNode = NULL;
+ } else {
+ n = 1;
+ ColNode = Tdbp->RowNode->Clone(g, ColNode);
+ } // endif Clist
+
+ ValNode = NULL;
+
+ for (i = 0; i < n; i++) {
+ if (Tdbp->Clist)
+ ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
+
+ /*******************************************************************/
+ /* Check whether an Xpath was provided to go to the column node. */
+ /*******************************************************************/
+ for (k = 0; k < Nod; k++) {
+ if (k == Inod) {
+ // This is the multiple node
+ Nlx = ColNode->SelectNodes(g, Nodes[k], Nlx);
+ ColNode = Nlx->GetItem(g, Tdbp->Nsub, Cxnp);
+ } else
+ ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp);
+
+ if (ColNode == NULL)
+ break;
+
+ TopNode = ColNode;
+ } // endfor k
+
+ if (ColNode)
+ if (Inod == Nod) {
+ /***************************************************************/
+ /* The node value can be multiple. */
+ /***************************************************************/
+ assert (Type);
+
+ // Get the value Node from the XML list
+ Nlx = ColNode->SelectNodes(g, Xname, Nlx);
+ len = Nlx->GetLength();
+
+ if (len > 1 && !Tdbp->Xpand) {
+ sprintf(g->Message, MSG(BAD_VAL_UPDATE), Name);
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } else
+ ValNode = Nlx->GetItem(g, Tdbp->Nsub, Vxnp);
+
+ } else // Inod != Nod
+ if (Type)
+ ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
+ else
+ AttNode = ColNode->GetAttribute(g, Xname, Vxap);
+
+ if (TopNode || ValNode || AttNode)
+ break; // We found the good column
+ else if (Tdbp->Clist)
+ ColNode = NULL;
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Create missing nodes. */
+ /*********************************************************************/
+ if (ColNode == NULL) {
+ if (TopNode == NULL)
+ if (Tdbp->Clist) {
+ Tdbp->RowNode->AddText(g, "\n\t\t");
+ ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
+ done = 2;
+ TopNode = ColNode;
+ } else
+ TopNode = Tdbp->RowNode;
+
+ for (; k < Nod && TopNode; k++) {
+ if (!done) {
+ TopNode->AddText(g, "\n\t\t");
+ done = 1;
+ } // endif done
+
+ ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
+ TopNode = ColNode;
+ } // endfor k
+
+ if (ColNode == NULL) {
+ strcpy(g->Message, MSG(COL_ALLOC_ERR));
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif ColNode
+
+ } // endif ColNode
+
+ if (Type == 1) {
+ if (ValNode == NULL) {
+ if (done < 2)
+ ColNode->AddText(g, "\n\t\t");
+
+ ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
+ } // endif ValNode
+
+ } else // (Type == 0)
+ if (AttNode == NULL)
+ AttNode = ColNode->AddProperty(g, Xname, Vxap);
+
+ if (ValNode == NULL && AttNode == NULL) {
+ strcpy(g->Message, MSG(VAL_ALLOC_ERR));
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif ValNode
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ p = Value->GetCharString(buf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } else
+ strcpy(Valbuf, p);
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ fin:
+ if (Status) {
+ if (Type) {
+ ValNode->SetContent(g, Valbuf, Long);
+ } else
+ AttNode->SetText(g, Valbuf, Long);
+
+ } // endif Status
+
+ } // end of WriteColumn
+
+/* ------------------------ XPOSCOL functions ------------------------ */
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the column node */
+/* from the corresponding table, extract from it the node text and */
+/* convert it to the column type. */
+/***********************************************************************/
+void XPOSCOL::ReadColumn(PGLOBAL g)
+ {
+ if (Nx == Tdbp->Irow)
+ return; // Same row than the last read
+
+ if (Tdbp->Clist == NULL) {
+ strcpy(g->Message, MSG(MIS_TAG_LIST));
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif Clist
+
+ *Valbuf = '\0';
+
+ if ((ValNode = Tdbp->Clist->GetItem(g, Rank, Vxnp)))
+ // Get the column value from the XML file
+ ValNode->GetText(Valbuf, Long);
+
+ Value->SetValue_psz(Valbuf);
+ Nx = Tdbp->Irow;
+ } // 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 XPOSCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, buf[16];
+ int i, k, n;
+
+ if (trace)
+ htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, Tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ if (Tdbp->Skipnull && Value->IsZero())
+ return;
+
+ /*********************************************************************/
+ /* If a check pass was done while updating, all node contruction */
+ /* has been already one. */
+ /*********************************************************************/
+ if (Status && Tdbp->Checked) {
+ assert (ValNode);
+ goto fin;
+ } // endif Checked
+
+ /*********************************************************************/
+ /* On Insert, a Row node must be created for each row; */
+ /* For all columns the Clist must be updated. */
+ /*********************************************************************/
+ if (Tdbp->CheckRow(g, true))
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+
+ /*********************************************************************/
+ /* Find the column and value nodes to update or insert. */
+ /*********************************************************************/
+ if (Tdbp->Clist == NULL) {
+ strcpy(g->Message, MSG(MIS_TAG_LIST));
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } // endif Clist
+
+ n = Tdbp->Clist->GetLength();
+ k = Rank;
+
+ if (!(ValNode = Tdbp->Clist->GetItem(g, k, Vxnp))) {
+ /*******************************************************************/
+ /* Create missing column nodes. */
+ /*******************************************************************/
+ Tdbp->RowNode->AddText(g, "\n\t\t");
+
+ for (i = n; i <= k; i++)
+ ValNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname, Vxnp);
+
+ assert (ValNode);
+ } // endif ValNode
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ p = Value->GetCharString(buf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ longjmp(g->jumper[g->jump_level], TYPE_AM_XML);
+ } else
+ strcpy(Valbuf, p);
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ fin:
+ if (Status)
+ ValNode->SetContent(g, Valbuf, Long);
+
+ } // end of WriteColumn
+
+/* ------------------------ End of Tabxml ---------------------------- */
diff --git a/storage/connect/tabxml.h b/storage/connect/tabxml.h
index fa66b385fa1..b23306d0fb9 100644
--- a/storage/connect/tabxml.h
+++ b/storage/connect/tabxml.h
@@ -1,246 +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
+
+/*************** 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
diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc
index e1a8d6d6c8b..8c14fa2f45e 100644
--- a/storage/connect/user_connect.cc
+++ b/storage/connect/user_connect.cc
@@ -1,154 +1,154 @@
-/* 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;
- tb1= 0;
-} // 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
-
+/* 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;
+ tb1= 0;
+} // 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
+
diff --git a/storage/connect/user_connect.h b/storage/connect/user_connect.h
index 621835b103f..1cd3d937730 100644
--- a/storage/connect/user_connect.h
+++ b/storage/connect/user_connect.h
@@ -1,80 +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;
- ulonglong tb1;
-}; // end of user_connect class definition
-
+/* 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;
+ ulonglong tb1;
+}; // end of user_connect class definition
+
diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp
index 55141ff36c0..2ae564f2e62 100644
--- a/storage/connect/valblk.cpp
+++ b/storage/connect/valblk.cpp
@@ -1,1413 +1,1413 @@
-/************ Valblk C++ Functions Source Code File (.CPP) *************/
-/* Name: VALBLK.CPP Version 1.5 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
-/* */
-/* This file contains the VALBLK and derived classes functions. */
-/* Second family is VALBLK, representing simple suballocated arrays */
-/* of values treated sequentially by FIX, BIN and VCT tables and */
-/* columns, as well for min/max blocks as for VCT column blocks. */
-/* Q&A: why not using only one family ? Simple values are arrays that */
-/* have only one element and arrays could have functions for all kind */
-/* of processing. The answer is a-because historically it was simpler */
-/* to do that way, b-because of performance on single values, and c- */
-/* to avoid too complicated classes and unuseful duplication of many */
-/* functions used on one family only. The drawback is that for new */
-/* types of objects, we shall have more classes to update. */
-/* Currently the only implemented types are STRING, int and DOUBLE. */
-/* Shortly we should add at least int VARCHAR and DATE. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant MariaDB header file. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-//#include <windows.h>
-#else
-#include "osutil.h"
-#include "string.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. */
-/* valblk.h is header containing VALBLK derived classes declares. */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "valblk.h"
-
-/***********************************************************************/
-/* Check macro's. */
-/***********************************************************************/
-#if defined(_DEBUG) || defined(DEBTRACE)
-#define CheckIndex(N) ChkIndx(N);
-void VALBLK::ChkIndx(int n) {
- if (n >= Nval) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(BAD_VALBLK_INDX));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif N
- } // end of ChkIndx
-#define CheckParms(V,N) ChkPrm(V,N);
-void VALBLK::ChkPrm(PVAL v, int n) {
- ChkIndx(n);
- if (Check && Type != v->GetType()) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(VALTYPE_NOMATCH));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Check
- } // end of ChkPrm
-#define CheckBlanks assert(!Blanks);
-#define CheckType(V) ChkTyp(V);
-void VALBLK::ChkTyp(PVAL v) {
- if (Type != v->GetType()) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(VALTYPE_NOMATCH));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Type
- } // end of ChkTyp
-void VALBLK::ChkTyp(PVBLK vb) {
- if (Type != vb->GetType()) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(VALTYPE_NOMATCH));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Type
- } // end of ChkTyp
-#else
-#define CheckIndex(N)
-#define CheckParms(V,N)
-#define CheckBlanks
-#define CheckType(V)
-#endif
-
-/***********************************************************************/
-/* AllocValBlock: allocate a VALBLK according to type. */
-/***********************************************************************/
-PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
- int prec, bool check, bool blank)
- {
- PVBLK blkp;
-
-#ifdef DEBTRACE
- htrc("AVB: mp=%p type=%d nval=%d len=%d check=%u blank=%u\n",
- mp, type, nval, len, check, blank);
-#endif
-
- switch (type) {
- case TYPE_STRING:
- if (len)
- blkp = new(g) CHRBLK(mp, nval, len, prec, blank);
- else
- blkp = new(g) STRBLK(g, mp, nval);
-
- break;
- case TYPE_SHORT:
- blkp = new(g) SHRBLK(mp, nval);
- break;
- case TYPE_INT:
- blkp = new(g) LNGBLK(mp, nval);
- break;
- case TYPE_DATE: // ?????
- blkp = new(g) DATBLK(mp, nval);
- break;
- case TYPE_BIGINT:
- blkp = new(g) BIGBLK(mp, nval);
- break;
- case TYPE_FLOAT:
- blkp = new(g) DBLBLK(mp, nval, prec);
- break;
- default:
- sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type);
- return NULL;
- } // endswitch Type
-
- blkp->Init(g, check);
- return blkp;
- } // end of AllocValBlock
-
-/* -------------------------- Class VALBLK --------------------------- */
-
-/***********************************************************************/
-/* Raise error for numeric types. */
-/***********************************************************************/
-PSZ VALBLK::GetCharValue(int n)
- {
- PGLOBAL& g = Global;
-
- assert(g);
- sprintf(g->Message, MSG(NO_CHAR_FROM), Type);
- longjmp(g->jumper[g->jump_level], Type);
- return NULL;
- } // end of GetCharValue
-
-/***********************************************************************/
-/* Set format so formatted dates can be converted on input. */
-/***********************************************************************/
-bool VALBLK::SetFormat(PGLOBAL g, PSZ fmt, int len, int year)
- {
- sprintf(g->Message, MSG(NO_DATE_FMT), Type);
- return true;
- } // end of SetFormat
-
-/***********************************************************************/
-/* Set the index of the location of value and return true if found. */
-/* To be used on ascending sorted arrays only. */
-/* Currently used by some BLKFIL classes only. */
-/***********************************************************************/
-bool VALBLK::Locate(PVAL vp, int& i)
- {
- CheckType(vp)
-
- int n = 1;
-
- for (i = 0; i < Nval; i++)
- if ((n = CompVal(vp, i)) <= 0)
- break;
-
- return (!n);
- } // end of Locate
-
-
-/* -------------------------- Class CHRBLK --------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-CHRBLK::CHRBLK(void *mp, int nval, int len, int prec, bool blank)
- : VALBLK(mp, TYPE_STRING, nval), Chrp((char*&)Blkp)
- {
- Valp = NULL;
- Blanks = blank;
- Ci = (prec != 0);
- Long = len;
- } // end of CHRBLK constructor
-
-/***********************************************************************/
-/* Initialization routine. */
-/***********************************************************************/
-void CHRBLK::Init(PGLOBAL g, bool check)
- {
- Valp = (char*)PlugSubAlloc(g, NULL, Long + 1);
- Valp[Long] = '\0';
-
- if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * Long);
-
- Check = check;
- Global = g;
- } // end of Init
-
-/***********************************************************************/
-/* Reset nth element to a null string. */
-/***********************************************************************/
-void CHRBLK::Reset(int n)
- {
- if (Blanks)
- memset(Chrp + n * Long, ' ', Long);
- else
- *(Chrp + n * Long) = '\0';
-
- } // end of Reset
-
-/***********************************************************************/
-/* Return the zero ending value of the nth element. */
-/***********************************************************************/
-char *CHRBLK::GetCharValue(int n)
- {
- return (char *)GetValPtrEx(n);
- } // end of GetCharValue
-
-/***********************************************************************/
-/* Return the value of the nth element converted to short. */
-/***********************************************************************/
-short CHRBLK::GetShortValue(int n)
- {
- return (short)atoi((char *)GetValPtrEx(n));
- } // end of GetIntValue
-
-/***********************************************************************/
-/* Return the value of the nth element converted to int. */
-/***********************************************************************/
-int CHRBLK::GetIntValue(int n)
- {
- return atol((char *)GetValPtrEx(n));
- } // end of GetIntValue
-
-/***********************************************************************/
-/* Return the value of the nth element converted to big int. */
-/***********************************************************************/
-longlong CHRBLK::GetBigintValue(int n)
- {
- return atoll((char *)GetValPtrEx(n));
- } // end of GetIntValue
-
-/***********************************************************************/
-/* Return the value of the nth element converted to double. */
-/***********************************************************************/
-double CHRBLK::GetFloatValue(int n)
- {
- return atof((char *)GetValPtrEx(n));
- } // end of GetFloatValue
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void CHRBLK::SetValue(PVAL valp, int n)
- {
- CheckParms(valp, n)
-
- SetValue((PSZ)valp->GetCharValue(), n);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void CHRBLK::SetValue(PSZ sp, int n)
- {
- size_t len = (sp) ? strlen(sp) : 0;
- char *p = Chrp + n * Long;
-
-#if defined(_DEBUG) || defined(DEBTRACE)
- if (Check && (signed)len > Long) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(SET_STR_TRUNC));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Check
-#endif
-
- if (sp)
- strncpy(p, sp, Long);
- else
- *p = '\0';
-
- if (Blanks)
- // Suppress eventual ending zero and right fill with blanks
- for (register int i = len; i < Long; i++)
- p[i] = ' ';
-
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block from a value in another block. */
-/***********************************************************************/
-void CHRBLK::SetValue(PVBLK pv, int n1, int n2)
- {
-#if defined(_DEBUG) || defined(DEBTRACE)
- if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(BLKTYPLEN_MISM));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Type
-#endif
-
- memcpy(Chrp + n1 * Long, ((CHRBLK*)pv)->Chrp + n2 * Long, Long);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set many values in a block from values in another block. */
-/***********************************************************************/
-void CHRBLK::SetValues(PVBLK pv, int k, int n)
- {
-#if defined(_DEBUG) || defined(DEBTRACE)
- if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(BLKTYPLEN_MISM));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Type
-#endif
- char *p = ((CHRBLK*)pv)->Chrp;
-
- if (!k)
- memcpy(Chrp, p, Long * n);
- else
- memcpy(Chrp + k * Long, p + k * Long, Long * (n - k));
-
- } // end of SetValues
-
-/***********************************************************************/
-/* Set one value in a block if val is less than the current value. */
-/***********************************************************************/
-void CHRBLK::SetMin(PVAL valp, int n)
- {
- CheckParms(valp, n)
- CheckBlanks
- char *vp = valp->GetCharValue();
- char *bp = Chrp + n * Long;
-
- if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) < 0)
- memcpy(bp, vp, Long);
-
- } // end of SetMin
-
-/***********************************************************************/
-/* Set one value in a block if val is greater than the current value. */
-/***********************************************************************/
-void CHRBLK::SetMax(PVAL valp, int n)
- {
- CheckParms(valp, n)
- CheckBlanks
- char *vp = valp->GetCharValue();
- char *bp = Chrp + n * Long;
-
- if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) > 0)
- memcpy(bp, vp, Long);
-
- } // end of SetMax
-
-/***********************************************************************/
-/* Move one value from i to j. */
-/***********************************************************************/
-void CHRBLK::Move(int i, int j)
- {
- memcpy(Chrp + j * Long, Chrp + i * Long, Long);
- } // end of Move
-
-/***********************************************************************/
-/* Compare a Value object with the nth value of the block. */
-/***********************************************************************/
-int CHRBLK::CompVal(PVAL vp, int n)
- {
- CheckParms(vp, n)
- char *xvp = vp->GetCharValue(); // Get Value zero ended string
- bool ci = Ci || vp->IsCi(); // true if is case insensitive
-
- GetValPtrEx(n); // Get a zero ended string in Valp
- return (ci) ? stricmp(xvp, Valp) : strcmp(xvp, Valp);
- } // end of CompVal
-
-/***********************************************************************/
-/* Compare two values of the block. */
-/***********************************************************************/
-int CHRBLK::CompVal(int i1, int i2)
- {
- return (Ci) ? strnicmp(Chrp + i1 * Long, Chrp + i2 * Long, Long)
- : strncmp(Chrp + i1 * Long, Chrp + i2 * Long, Long);
- } // end of CompVal
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *CHRBLK::GetValPtr(int n)
- {
- CheckIndex(n)
- return Chrp + n * Long;
- } // end of GetValPtr
-
-/***********************************************************************/
-/* Get a pointer on a zero ended string equal to nth value. */
-/***********************************************************************/
-void *CHRBLK::GetValPtrEx(int n)
- {
- CheckIndex(n)
- memcpy(Valp, Chrp + n * Long, Long);
-
- if (Blanks) {
- // The (fast) way this is done works only for blocks such
- // as Min and Max where strings are stored with the ending 0
- // except for those whose length is equal to Len.
- // For VCT blocks we must remove rightmost blanks.
- char *p = Valp + Long;
-
- for (p--; *p == ' ' && p >= Valp; p--) ;
-
- *(++p) = '\0';
- } // endif Blanks
-
- return Valp;
- } // end of GetValPtrEx
-
-/***********************************************************************/
-/* Returns index of matching value in block or -1. */
-/***********************************************************************/
-int CHRBLK::Find(PVAL vp)
- {
- CheckType(vp)
- int i;
- bool ci = Ci || vp->IsCi();
- PSZ s = vp->GetCharValue();
-
- for (i = 0; i < Nval; i++) {
- GetValPtrEx(i); // Get a zero ended string in Valp
-
- if (!((ci) ? strnicmp(s, Valp, Long) : strncmp(s, Valp, Long)))
- break;
-
- } // endfor i
-
- return (i < Nval) ? i : (-1);
- } // end of GetValPtr
-
-/***********************************************************************/
-/* Returns the length of the longest string in the block. */
-/***********************************************************************/
-int CHRBLK::GetMaxLength(void)
- {
- int i, n;
-
- for (i = n = 0; i < Nval; i++) {
- GetValPtrEx(i);
- n = max(n, (signed)strlen(Valp));
- } // endfor i
-
- return n;
- } // end of GetMaxLength
-
-
-/* -------------------------- Class STRBLK --------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-STRBLK::STRBLK(PGLOBAL g, void *mp, int nval)
- : VALBLK(mp, TYPE_STRING, nval), Strp((PSZ*&)Blkp)
- {
- Global = g;
- } // end of STRBLK constructor
-
-/***********************************************************************/
-/* Initialization routine. */
-/***********************************************************************/
-void STRBLK::Init(PGLOBAL g, bool check)
- {
- if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(PSZ));
-
- Check = check;
- Global = g;
- } // end of Init
-
-/***********************************************************************/
-/* Set one value in a block from a value in another block. */
-/***********************************************************************/
-void STRBLK::SetValue(PVBLK pv, int n1, int n2)
- {
- CheckType(pv)
-
- Strp[n1] = ((STRBLK*)pv)->Strp[n2];
- } // end of SetValue
-
-/***********************************************************************/
-/* Set many values in a block from values in another block. */
-/***********************************************************************/
-void STRBLK::SetValues(PVBLK pv, int k, int n)
- {
- CheckType(pv)
- PSZ *sp = ((STRBLK*)pv)->Strp;
-
- for (register int i = k; i < n; i++)
- Strp[i] = sp[i];
-
- } // end of SetValues
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void STRBLK::SetValue(PVAL valp, int n)
- {
- CheckParms(valp, n)
- SetValue((PSZ)valp->GetCharValue(), n);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void STRBLK::SetValue(PSZ p, int n)
- {
- Strp[n] = (PSZ)PlugSubAlloc(Global, NULL, strlen(p) + 1);
- strcpy(Strp[n], p);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block if val is less than the current value. */
-/***********************************************************************/
-void STRBLK::SetMin(PVAL valp, int n)
- {
- CheckParms(valp, n)
- char *vp = valp->GetCharValue();
- char *bp = Strp[n];
-
- if (strcmp(vp, bp) < 0)
- SetValue(valp, n);
-
- } // end of SetMin
-
-/***********************************************************************/
-/* Set one value in a block if val is greater than the current value. */
-/***********************************************************************/
-void STRBLK::SetMax(PVAL valp, int n)
- {
- CheckParms(valp, n)
- char *vp = valp->GetCharValue();
- char *bp = Strp[n];
-
- if (strcmp(vp, bp) > 0)
- SetValue(valp, n);
-
- } // end of SetMax
-
-/***********************************************************************/
-/* Move one value from i to j. */
-/***********************************************************************/
-void STRBLK::Move(int i, int j)
- {
- Strp[j] = Strp[i];
- } // end of Move
-
-/***********************************************************************/
-/* Compare a Value object with the nth value of the block. */
-/***********************************************************************/
-int STRBLK::CompVal(PVAL vp, int n)
- {
- CheckParms(vp, n)
- return strcmp(vp->GetCharValue(), Strp[n]);
- } // end of CompVal
-
-/***********************************************************************/
-/* Compare two values of the block. */
-/***********************************************************************/
-int STRBLK::CompVal(int i1, int i2)
- {
- return (strcmp(Strp[i1], Strp[i2]));
- } // end of CompVal
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *STRBLK::GetValPtr(int n)
- {
- CheckIndex(n)
- return Strp + n;
- } // end of GetValPtr
-
-/***********************************************************************/
-/* Get a pointer on a zero ended string equal to nth value. */
-/***********************************************************************/
-void *STRBLK::GetValPtrEx(int n)
- {
- CheckIndex(n)
- return Strp[n];
- } // end of GetValPtrEx
-
-/***********************************************************************/
-/* Returns index of matching value in block or -1. */
-/***********************************************************************/
-int STRBLK::Find(PVAL vp)
- {
- CheckType(vp)
- int i;
- PSZ s = vp->GetCharValue();
-
- for (i = 0; i < Nval; i++)
- if (!strcmp(s, Strp[i]))
- break;
-
- return (i < Nval) ? i : (-1);
- } // end of Find
-
-/***********************************************************************/
-/* Returns the length of the longest string in the block. */
-/***********************************************************************/
-int STRBLK::GetMaxLength(void)
- {
- int i, n;
-
- for (i = n = 0; i < Nval; i++)
- n = max(n, (signed)strlen(Strp[i]));
-
- return n;
- } // end of GetMaxLength
-
-
-/* -------------------------- Class SHRBLK --------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-SHRBLK::SHRBLK(void *mp, int nval)
- : VALBLK(mp, TYPE_SHORT, nval), Shrp((short*&)Blkp)
- {
- } // end of SHRBLK constructor
-
-/***********************************************************************/
-/* Initialization routine. */
-/***********************************************************************/
-void SHRBLK::Init(PGLOBAL g, bool check)
- {
- if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(short));
-
- Check = check;
- Global = g;
- } // end of Init
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void SHRBLK::SetValue(PVAL valp, int n)
- {
- CheckParms(valp, n)
- Shrp[n] = valp->GetShortValue();
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void SHRBLK::SetValue(PSZ p, int n)
- {
-#if defined(_DEBUG) || defined(DEBTRACE)
- if (Check) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(BAD_SET_STRING));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Check
-#endif
-
- Shrp[n] = (short)atoi(p);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block if val is less than the current value. */
-/***********************************************************************/
-void SHRBLK::SetMin(PVAL valp, int n)
- {
- CheckParms(valp, n)
- short sval = valp->GetShortValue();
- short& smin = Shrp[n];
-
- if (sval < smin)
- smin = sval;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* Set one value in a block if val is greater than the current value. */
-/***********************************************************************/
-void SHRBLK::SetMax(PVAL valp, int n)
- {
- CheckParms(valp, n)
- short sval = valp->GetShortValue();
- short& smin = Shrp[n];
-
- if (sval > smin)
- smin = sval;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* Set one value in a block from a value in another block. */
-/***********************************************************************/
-void SHRBLK::SetValue(PVBLK pv, int n1, int n2)
- {
- CheckType(pv)
-
- Shrp[n1] = ((SHRBLK*)pv)->Shrp[n2];
- } // end of SetValue
-
-/***********************************************************************/
-/* Set many values in a block from values in another block. */
-/***********************************************************************/
-void SHRBLK::SetValues(PVBLK pv, int k, int n)
- {
- CheckType(pv)
- short *sp = ((SHRBLK*)pv)->Shrp;
-
- for (register int i = k; i < n; i++)
- Shrp[i] = sp[i];
-
- } // end of SetValues
-
-/***********************************************************************/
-/* This function is used by class RESCOL when calculating COUNT. */
-/***********************************************************************/
-void SHRBLK::AddMinus1(PVBLK pv, int n1, int n2)
- {
- assert(Type == pv->GetType());
- Shrp[n1] += (((SHRBLK*)pv)->Shrp[n2] - 1);
- } // end of AddMinus1
-
-/***********************************************************************/
-/* Move one value from i to j. */
-/***********************************************************************/
-void SHRBLK::Move(int i, int j)
- {
- Shrp[j] = Shrp[i];
- } // end of Move
-
-/***********************************************************************/
-/* Compare a Value object with the nth value of the block. */
-/***********************************************************************/
-int SHRBLK::CompVal(PVAL vp, int n)
- {
- CheckParms(vp, n)
- short msv = Shrp[n];
- short vsv = vp->GetShortValue();
-
- return (vsv > msv) ? 1 : (vsv < msv) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Compare two values of the block. */
-/***********************************************************************/
-int SHRBLK::CompVal(int i1, int i2)
- {
- short sv1 = Shrp[i1];
- short sv2 = Shrp[i2];
-
- return (sv1 > sv2) ? 1 : (sv1 < sv2) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *SHRBLK::GetValPtr(int n)
- {
- CheckIndex(n)
- return Shrp + n;
- } // end of GetValPtr
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *SHRBLK::GetValPtrEx(int n)
- {
- CheckIndex(n)
- return Shrp + n;
- } // end of GetValPtrEx
-
-/***********************************************************************/
-/* Returns index of matching value in block or -1. */
-/***********************************************************************/
-int SHRBLK::Find(PVAL vp)
- {
- CheckType(vp)
- int i;
- short n = vp->GetShortValue();
-
- for (i = 0; i < Nval; i++)
- if (n == Shrp[i])
- break;
-
- return (i < Nval) ? i : (-1);
- } // end of Find
-
-/***********************************************************************/
-/* Returns the length of the longest string in the block. */
-/***********************************************************************/
-int SHRBLK::GetMaxLength(void)
- {
- char buf[12];
- int i, n;
-
- for (i = n = 0; i < Nval; i++) {
- sprintf(buf, "%hd", Shrp[i]);
-
- n = max(n, (signed)strlen(buf));
- } // endfor i
-
- return n;
- } // end of GetMaxLength
-
-
-/* -------------------------- Class LNGBLK --------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-LNGBLK::LNGBLK(void *mp, int nval)
- : VALBLK(mp, TYPE_INT, nval), Lngp((int*&)Blkp)
- {
- } // end of LNGBLK constructor
-
-/***********************************************************************/
-/* Initialization routine. */
-/***********************************************************************/
-void LNGBLK::Init(PGLOBAL g, bool check)
- {
- if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(int));
-
- Check = check;
- Global = g;
- } // end of Init
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void LNGBLK::SetValue(PVAL valp, int n)
- {
- CheckParms(valp, n)
- Lngp[n] = valp->GetIntValue();
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void LNGBLK::SetValue(PSZ p, int n)
- {
-#if defined(_DEBUG) || defined(DEBTRACE)
- if (Check) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(BAD_SET_STRING));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Check
-#endif
-
- Lngp[n] = atol(p);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block if val is less than the current value. */
-/***********************************************************************/
-void LNGBLK::SetMin(PVAL valp, int n)
- {
- CheckParms(valp, n)
- int lval = valp->GetIntValue();
- int& lmin = Lngp[n];
-
- if (lval < lmin)
- lmin = lval;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* Set one value in a block if val is greater than the current value. */
-/***********************************************************************/
-void LNGBLK::SetMax(PVAL valp, int n)
- {
- CheckParms(valp, n)
- int lval = valp->GetIntValue();
- int& lmax = Lngp[n];
-
- if (lval > lmax)
- lmax = lval;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* Set one value in a block from a value in another block. */
-/***********************************************************************/
-void LNGBLK::SetValue(PVBLK pv, int n1, int n2)
- {
- CheckType(pv)
-
- Lngp[n1] = ((LNGBLK*)pv)->Lngp[n2];
- } // end of SetValue
-
-/***********************************************************************/
-/* Set many values in a block from values in another block. */
-/***********************************************************************/
-void LNGBLK::SetValues(PVBLK pv, int k, int n)
- {
- CheckType(pv)
- int *lp = ((LNGBLK*)pv)->Lngp;
-
- for (register int i = k; i < n; i++)
- Lngp[i] = lp[i];
-
- } // end of SetValues
-
-/***********************************************************************/
-/* This function is used by class RESCOL when calculating COUNT. */
-/***********************************************************************/
-void LNGBLK::AddMinus1(PVBLK pv, int n1, int n2)
- {
- assert(Type == pv->GetType());
- Lngp[n1] += (((LNGBLK*)pv)->Lngp[n2] - 1);
- } // end of AddMinus1
-
-/***********************************************************************/
-/* Move one value from i to j. */
-/***********************************************************************/
-void LNGBLK::Move(int i, int j)
- {
- Lngp[j] = Lngp[i];
- } // end of Move
-
-/***********************************************************************/
-/* Compare a Value object with the nth value of the block. */
-/***********************************************************************/
-int LNGBLK::CompVal(PVAL vp, int n)
- {
- CheckParms(vp, n)
- register int mlv = Lngp[n];
- register int vlv = vp->GetIntValue();
-
- return (vlv > mlv) ? 1 : (vlv < mlv) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Compare two values of the block. */
-/***********************************************************************/
-int LNGBLK::CompVal(int i1, int i2)
- {
- register int lv1 = Lngp[i1];
- register int lv2 = Lngp[i2];
-
- return (lv1 > lv2) ? 1 : (lv1 < lv2) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *LNGBLK::GetValPtr(int n)
- {
- CheckIndex(n)
- return Lngp + n;
- } // end of GetValPtr
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *LNGBLK::GetValPtrEx(int n)
- {
- CheckIndex(n)
- return Lngp + n;
- } // end of GetValPtrEx
-
-/***********************************************************************/
-/* Returns index of matching value in block or -1. */
-/***********************************************************************/
-int LNGBLK::Find(PVAL vp)
- {
- CheckType(vp)
- int i;
- int n = vp->GetIntValue();
-
- for (i = 0; i < Nval; i++)
- if (n == Lngp[i])
- break;
-
- return (i < Nval) ? i : (-1);
- } // end of Find
-
-/***********************************************************************/
-/* Returns the length of the longest string in the block. */
-/***********************************************************************/
-int LNGBLK::GetMaxLength(void)
- {
- char buf[12];
- int i, n;
-
- for (i = n = 0; i < Nval; i++) {
- sprintf(buf, "%d", Lngp[i]);
-
- n = max(n, (signed)strlen(buf));
- } // endfor i
-
- return n;
- } // end of GetMaxLength
-
-
-/* -------------------------- Class DATBLK --------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-DATBLK::DATBLK(void *mp, int nval) : LNGBLK(mp, nval)
- {
- Type = TYPE_DATE;
- Dvalp = NULL;
- } // end of DATBLK constructor
-
-/***********************************************************************/
-/* Set format so formatted dates can be converted on input. */
-/***********************************************************************/
-bool DATBLK::SetFormat(PGLOBAL g, PSZ fmt, int len, int year)
- {
- if (!(Dvalp = AllocateValue(g, TYPE_DATE, len, year, fmt)))
- return true;
-
- return false;
- } // end of SetFormat
-
-/***********************************************************************/
-/* Set one value in a block from a char string. */
-/***********************************************************************/
-void DATBLK::SetValue(PSZ p, int n)
- {
- if (Dvalp) {
- // Decode the string according to format
- Dvalp->SetValue_psz(p);
- Lngp[n] = Dvalp->GetIntValue();
- } else
- LNGBLK::SetValue(p, n);
-
- } // end of SetValue
-
-
-/* -------------------------- Class BIGBLK --------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-BIGBLK::BIGBLK(void *mp, int nval)
- : VALBLK(mp, TYPE_BIGINT, nval), Lngp((longlong*&)Blkp)
- {
- } // end of BIGBLK constructor
-
-/***********************************************************************/
-/* Initialization routine. */
-/***********************************************************************/
-void BIGBLK::Init(PGLOBAL g, bool check)
- {
- if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(longlong));
-
- Check = check;
- Global = g;
- } // end of Init
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void BIGBLK::SetValue(PVAL valp, int n)
- {
- CheckParms(valp, n)
- Lngp[n] = valp->GetBigintValue();
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void BIGBLK::SetValue(PSZ p, int n)
- {
-#if defined(_DEBUG) || defined(DEBTRACE)
- if (Check) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(BAD_SET_STRING));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Check
-#endif
-
- Lngp[n] = atoll(p);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block if val is less than the current value. */
-/***********************************************************************/
-void BIGBLK::SetMin(PVAL valp, int n)
- {
- CheckParms(valp, n)
- longlong lval = valp->GetIntValue();
- longlong& lmin = Lngp[n];
-
- if (lval < lmin)
- lmin = lval;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* Set one value in a block if val is greater than the current value. */
-/***********************************************************************/
-void BIGBLK::SetMax(PVAL valp, int n)
- {
- CheckParms(valp, n)
- longlong lval = valp->GetIntValue();
- longlong& lmax = Lngp[n];
-
- if (lval > lmax)
- lmax = lval;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* Set one value in a block from a value in another block. */
-/***********************************************************************/
-void BIGBLK::SetValue(PVBLK pv, int n1, int n2)
- {
- CheckType(pv)
-
- Lngp[n1] = ((BIGBLK*)pv)->Lngp[n2];
- } // end of SetValue
-
-/***********************************************************************/
-/* Set many values in a block from values in another block. */
-/***********************************************************************/
-void BIGBLK::SetValues(PVBLK pv, int k, int n)
- {
- CheckType(pv)
- longlong *lp = ((BIGBLK*)pv)->Lngp;
-
- for (register int i = k; i < n; i++)
- Lngp[i] = lp[i];
-
- } // end of SetValues
-
-/***********************************************************************/
-/* This function is used by class RESCOL when calculating COUNT. */
-/***********************************************************************/
-void BIGBLK::AddMinus1(PVBLK pv, int n1, int n2)
- {
- assert(Type == pv->GetType());
- Lngp[n1] += (((BIGBLK*)pv)->Lngp[n2] - 1);
- } // end of AddMinus1
-
-/***********************************************************************/
-/* Move one value from i to j. */
-/***********************************************************************/
-void BIGBLK::Move(int i, int j)
- {
- Lngp[j] = Lngp[i];
- } // end of Move
-
-/***********************************************************************/
-/* Compare a Value object with the nth value of the block. */
-/***********************************************************************/
-int BIGBLK::CompVal(PVAL vp, int n)
- {
- CheckParms(vp, n)
- longlong mlv = Lngp[n];
- longlong vlv = vp->GetBigintValue();
-
- return (vlv > mlv) ? 1 : (vlv < mlv) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Compare two values of the block. */
-/***********************************************************************/
-int BIGBLK::CompVal(int i1, int i2)
- {
- longlong lv1 = Lngp[i1];
- longlong lv2 = Lngp[i2];
-
- return (lv1 > lv2) ? 1 : (lv1 < lv2) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *BIGBLK::GetValPtr(int n)
- {
- CheckIndex(n)
- return Lngp + n;
- } // end of GetValPtr
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *BIGBLK::GetValPtrEx(int n)
- {
- CheckIndex(n)
- return Lngp + n;
- } // end of GetValPtrEx
-
-/***********************************************************************/
-/* Returns index of matching value in block or -1. */
-/***********************************************************************/
-int BIGBLK::Find(PVAL vp)
- {
- CheckType(vp)
- int i;
- longlong n = vp->GetBigintValue();
-
- for (i = 0; i < Nval; i++)
- if (n == Lngp[i])
- break;
-
- return (i < Nval) ? i : (-1);
- } // end of Find
-
-/***********************************************************************/
-/* Returns the length of the longest string in the block. */
-/***********************************************************************/
-int BIGBLK::GetMaxLength(void)
- {
- char buf[24];
- int i, n;
-
- for (i = n = 0; i < Nval; i++) {
- sprintf(buf, "%lld", Lngp[i]);
-
- n = max(n, (signed)strlen(buf));
- } // endfor i
-
- return n;
- } // end of GetMaxLength
-
-
-/* -------------------------- Class DBLBLK --------------------------- */
-
-/***********************************************************************/
-/* Constructor. */
-/***********************************************************************/
-DBLBLK::DBLBLK(void *mp, int nval, int prec)
- : VALBLK(mp, TYPE_FLOAT, nval), Dblp((double*&)Blkp)
- {
- Prec = prec;
- } // end of DBLBLK constructor
-
-/***********************************************************************/
-/* Initialization routine. */
-/***********************************************************************/
-void DBLBLK::Init(PGLOBAL g, bool check)
- {
- if (!Blkp)
- Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(double));
-
- Check = check;
- Global = g;
- } // end of Init
-
-/***********************************************************************/
-/* Set one value in a block from a value in another block. */
-/***********************************************************************/
-void DBLBLK::SetValue(PVBLK pv, int n1, int n2)
- {
- CheckType(pv)
-
- Dblp[n1] = ((DBLBLK*)pv)->Dblp[n2];
- } // end of SetValue
-
-/***********************************************************************/
-/* Set many values in a block from values in another block. */
-/***********************************************************************/
-void DBLBLK::SetValues(PVBLK pv, int k, int n)
- {
- CheckType(pv)
- double *dp = ((DBLBLK*)pv)->Dblp;
-
- for (register int i = k; i < n; i++)
- Dblp[i] = dp[i];
-
- } // end of SetValues
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void DBLBLK::SetValue(PVAL valp, int n)
- {
- CheckParms(valp, n)
- Dblp[n] = valp->GetFloatValue();
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block. */
-/***********************************************************************/
-void DBLBLK::SetValue(PSZ p, int n)
- {
-#if defined(_DEBUG) || defined(DEBTRACE)
- if (Check) {
- PGLOBAL& g = Global;
- strcpy(g->Message, MSG(BAD_SET_STRING));
- longjmp(g->jumper[g->jump_level], Type);
- } // endif Check
-#endif
-
- Dblp[n] = atof(p);
- } // end of SetValue
-
-/***********************************************************************/
-/* Set one value in a block if val is less than the current value. */
-/***********************************************************************/
-void DBLBLK::SetMin(PVAL valp, int n)
- {
- CheckParms(valp, n)
- double fval = valp->GetFloatValue();
- double& fmin = Dblp[n];
-
- if (fval < fmin)
- fmin = fval;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* Set one value in a block if val is greater than the current value. */
-/***********************************************************************/
-void DBLBLK::SetMax(PVAL valp, int n)
- {
- CheckParms(valp, n)
- double fval = valp->GetFloatValue();
- double& fmax = Dblp[n];
-
- if (fval > fmax)
- fmax = fval;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* Move one value from i to j. */
-/***********************************************************************/
-void DBLBLK::Move(int i, int j)
- {
- Dblp[j] = Dblp[i];
- } // end of Move
-
-/***********************************************************************/
-/* Compare a Value object with the nth value of the block. */
-/***********************************************************************/
-int DBLBLK::CompVal(PVAL vp, int n)
- {
- CheckParms(vp, n)
- double mfv = Dblp[n];
- double vfv = vp->GetFloatValue();
-
- return (vfv > mfv) ? 1 : (vfv < mfv) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Compare two values of the block. */
-/***********************************************************************/
-int DBLBLK::CompVal(int i1, int i2)
- {
- register double dv1 = Dblp[i1];
- register double dv2 = Dblp[i2];
-
- return (dv1 > dv2) ? 1 : (dv1 < dv2) ? (-1) : 0;
- } // end of CompVal
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *DBLBLK::GetValPtr(int n)
- {
- CheckIndex(n)
- return Dblp + n;
- } // end of GetValPtr
-
-/***********************************************************************/
-/* Get a pointer on the nth value of the block. */
-/***********************************************************************/
-void *DBLBLK::GetValPtrEx(int n)
- {
- CheckIndex(n)
- return Dblp + n;
- } // end of GetValPtrEx
-
-/***********************************************************************/
-/* Returns index of matching value in block or -1. */
-/***********************************************************************/
-int DBLBLK::Find(PVAL vp)
- {
- CheckType(vp)
- int i;
- double d = vp->GetFloatValue();
-
- for (i = 0; i < Nval; i++)
- if (d == Dblp[i])
- break;
-
- return (i < Nval) ? i : (-1);
- } // end of Find
-
-/***********************************************************************/
-/* Returns the length of the longest string in the block. */
-/***********************************************************************/
-int DBLBLK::GetMaxLength(void)
- {
- char buf[32];
- int i, n;
-
- for (i = n = 0; i < Nval; i++) {
- sprintf(buf, "%lf", Dblp[i]);
-
- n = max(n, (signed)strlen(buf));
- } // endfor i
-
- return n;
- } // end of GetMaxLength
-
-/* ------------------------- End of Valblk --------------------------- */
-
+/************ Valblk C++ Functions Source Code File (.CPP) *************/
+/* Name: VALBLK.CPP Version 1.5 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
+/* */
+/* This file contains the VALBLK and derived classes functions. */
+/* Second family is VALBLK, representing simple suballocated arrays */
+/* of values treated sequentially by FIX, BIN and VCT tables and */
+/* columns, as well for min/max blocks as for VCT column blocks. */
+/* Q&A: why not using only one family ? Simple values are arrays that */
+/* have only one element and arrays could have functions for all kind */
+/* of processing. The answer is a-because historically it was simpler */
+/* to do that way, b-because of performance on single values, and c- */
+/* to avoid too complicated classes and unuseful duplication of many */
+/* functions used on one family only. The drawback is that for new */
+/* types of objects, we shall have more classes to update. */
+/* Currently the only implemented types are STRING, int and DOUBLE. */
+/* Shortly we should add at least int VARCHAR and DATE. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(WIN32)
+//#include <windows.h>
+#else
+#include "osutil.h"
+#include "string.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. */
+/* valblk.h is header containing VALBLK derived classes declares. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "valblk.h"
+
+/***********************************************************************/
+/* Check macro's. */
+/***********************************************************************/
+#if defined(_DEBUG) || defined(DEBTRACE)
+#define CheckIndex(N) ChkIndx(N);
+void VALBLK::ChkIndx(int n) {
+ if (n >= Nval) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BAD_VALBLK_INDX));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif N
+ } // end of ChkIndx
+#define CheckParms(V,N) ChkPrm(V,N);
+void VALBLK::ChkPrm(PVAL v, int n) {
+ ChkIndx(n);
+ if (Check && Type != v->GetType()) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(VALTYPE_NOMATCH));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Check
+ } // end of ChkPrm
+#define CheckBlanks assert(!Blanks);
+#define CheckType(V) ChkTyp(V);
+void VALBLK::ChkTyp(PVAL v) {
+ if (Type != v->GetType()) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(VALTYPE_NOMATCH));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Type
+ } // end of ChkTyp
+void VALBLK::ChkTyp(PVBLK vb) {
+ if (Type != vb->GetType()) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(VALTYPE_NOMATCH));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Type
+ } // end of ChkTyp
+#else
+#define CheckIndex(N)
+#define CheckParms(V,N)
+#define CheckBlanks
+#define CheckType(V)
+#endif
+
+/***********************************************************************/
+/* AllocValBlock: allocate a VALBLK according to type. */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
+ int prec, bool check, bool blank)
+ {
+ PVBLK blkp;
+
+#ifdef DEBTRACE
+ htrc("AVB: mp=%p type=%d nval=%d len=%d check=%u blank=%u\n",
+ mp, type, nval, len, check, blank);
+#endif
+
+ switch (type) {
+ case TYPE_STRING:
+ if (len)
+ blkp = new(g) CHRBLK(mp, nval, len, prec, blank);
+ else
+ blkp = new(g) STRBLK(g, mp, nval);
+
+ break;
+ case TYPE_SHORT:
+ blkp = new(g) SHRBLK(mp, nval);
+ break;
+ case TYPE_INT:
+ blkp = new(g) LNGBLK(mp, nval);
+ break;
+ case TYPE_DATE: // ?????
+ blkp = new(g) DATBLK(mp, nval);
+ break;
+ case TYPE_BIGINT:
+ blkp = new(g) BIGBLK(mp, nval);
+ break;
+ case TYPE_FLOAT:
+ blkp = new(g) DBLBLK(mp, nval, prec);
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type);
+ return NULL;
+ } // endswitch Type
+
+ blkp->Init(g, check);
+ return blkp;
+ } // end of AllocValBlock
+
+/* -------------------------- Class VALBLK --------------------------- */
+
+/***********************************************************************/
+/* Raise error for numeric types. */
+/***********************************************************************/
+PSZ VALBLK::GetCharValue(int n)
+ {
+ PGLOBAL& g = Global;
+
+ assert(g);
+ sprintf(g->Message, MSG(NO_CHAR_FROM), Type);
+ longjmp(g->jumper[g->jump_level], Type);
+ return NULL;
+ } // end of GetCharValue
+
+/***********************************************************************/
+/* Set format so formatted dates can be converted on input. */
+/***********************************************************************/
+bool VALBLK::SetFormat(PGLOBAL g, PSZ fmt, int len, int year)
+ {
+ sprintf(g->Message, MSG(NO_DATE_FMT), Type);
+ return true;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* Set the index of the location of value and return true if found. */
+/* To be used on ascending sorted arrays only. */
+/* Currently used by some BLKFIL classes only. */
+/***********************************************************************/
+bool VALBLK::Locate(PVAL vp, int& i)
+ {
+ CheckType(vp)
+
+ int n = 1;
+
+ for (i = 0; i < Nval; i++)
+ if ((n = CompVal(vp, i)) <= 0)
+ break;
+
+ return (!n);
+ } // end of Locate
+
+
+/* -------------------------- Class CHRBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+CHRBLK::CHRBLK(void *mp, int nval, int len, int prec, bool blank)
+ : VALBLK(mp, TYPE_STRING, nval), Chrp((char*&)Blkp)
+ {
+ Valp = NULL;
+ Blanks = blank;
+ Ci = (prec != 0);
+ Long = len;
+ } // end of CHRBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+void CHRBLK::Init(PGLOBAL g, bool check)
+ {
+ Valp = (char*)PlugSubAlloc(g, NULL, Long + 1);
+ Valp[Long] = '\0';
+
+ if (!Blkp)
+ Blkp = PlugSubAlloc(g, NULL, Nval * Long);
+
+ Check = check;
+ Global = g;
+ } // end of Init
+
+/***********************************************************************/
+/* Reset nth element to a null string. */
+/***********************************************************************/
+void CHRBLK::Reset(int n)
+ {
+ if (Blanks)
+ memset(Chrp + n * Long, ' ', Long);
+ else
+ *(Chrp + n * Long) = '\0';
+
+ } // end of Reset
+
+/***********************************************************************/
+/* Return the zero ending value of the nth element. */
+/***********************************************************************/
+char *CHRBLK::GetCharValue(int n)
+ {
+ return (char *)GetValPtrEx(n);
+ } // end of GetCharValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to short. */
+/***********************************************************************/
+short CHRBLK::GetShortValue(int n)
+ {
+ return (short)atoi((char *)GetValPtrEx(n));
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to int. */
+/***********************************************************************/
+int CHRBLK::GetIntValue(int n)
+ {
+ return atol((char *)GetValPtrEx(n));
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to big int. */
+/***********************************************************************/
+longlong CHRBLK::GetBigintValue(int n)
+ {
+ return atoll((char *)GetValPtrEx(n));
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to double. */
+/***********************************************************************/
+double CHRBLK::GetFloatValue(int n)
+ {
+ return atof((char *)GetValPtrEx(n));
+ } // end of GetFloatValue
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void CHRBLK::SetValue(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+
+ SetValue((PSZ)valp->GetCharValue(), n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void CHRBLK::SetValue(PSZ sp, int n)
+ {
+ size_t len = (sp) ? strlen(sp) : 0;
+ char *p = Chrp + n * Long;
+
+#if defined(_DEBUG) || defined(DEBTRACE)
+ if (Check && (signed)len > Long) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(SET_STR_TRUNC));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Check
+#endif
+
+ if (sp)
+ strncpy(p, sp, Long);
+ else
+ *p = '\0';
+
+ if (Blanks)
+ // Suppress eventual ending zero and right fill with blanks
+ for (register int i = len; i < Long; i++)
+ p[i] = ' ';
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void CHRBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+#if defined(_DEBUG) || defined(DEBTRACE)
+ if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BLKTYPLEN_MISM));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Type
+#endif
+
+ memcpy(Chrp + n1 * Long, ((CHRBLK*)pv)->Chrp + n2 * Long, Long);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void CHRBLK::SetValues(PVBLK pv, int k, int n)
+ {
+#if defined(_DEBUG) || defined(DEBTRACE)
+ if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BLKTYPLEN_MISM));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Type
+#endif
+ char *p = ((CHRBLK*)pv)->Chrp;
+
+ if (!k)
+ memcpy(Chrp, p, Long * n);
+ else
+ memcpy(Chrp + k * Long, p + k * Long, Long * (n - k));
+
+ } // end of SetValues
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void CHRBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ CheckBlanks
+ char *vp = valp->GetCharValue();
+ char *bp = Chrp + n * Long;
+
+ if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) < 0)
+ memcpy(bp, vp, Long);
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void CHRBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ CheckBlanks
+ char *vp = valp->GetCharValue();
+ char *bp = Chrp + n * Long;
+
+ if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) > 0)
+ memcpy(bp, vp, Long);
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void CHRBLK::Move(int i, int j)
+ {
+ memcpy(Chrp + j * Long, Chrp + i * Long, Long);
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int CHRBLK::CompVal(PVAL vp, int n)
+ {
+ CheckParms(vp, n)
+ char *xvp = vp->GetCharValue(); // Get Value zero ended string
+ bool ci = Ci || vp->IsCi(); // true if is case insensitive
+
+ GetValPtrEx(n); // Get a zero ended string in Valp
+ return (ci) ? stricmp(xvp, Valp) : strcmp(xvp, Valp);
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int CHRBLK::CompVal(int i1, int i2)
+ {
+ return (Ci) ? strnicmp(Chrp + i1 * Long, Chrp + i2 * Long, Long)
+ : strncmp(Chrp + i1 * Long, Chrp + i2 * Long, Long);
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *CHRBLK::GetValPtr(int n)
+ {
+ CheckIndex(n)
+ return Chrp + n * Long;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on a zero ended string equal to nth value. */
+/***********************************************************************/
+void *CHRBLK::GetValPtrEx(int n)
+ {
+ CheckIndex(n)
+ memcpy(Valp, Chrp + n * Long, Long);
+
+ if (Blanks) {
+ // The (fast) way this is done works only for blocks such
+ // as Min and Max where strings are stored with the ending 0
+ // except for those whose length is equal to Len.
+ // For VCT blocks we must remove rightmost blanks.
+ char *p = Valp + Long;
+
+ for (p--; *p == ' ' && p >= Valp; p--) ;
+
+ *(++p) = '\0';
+ } // endif Blanks
+
+ return Valp;
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int CHRBLK::Find(PVAL vp)
+ {
+ CheckType(vp)
+ int i;
+ bool ci = Ci || vp->IsCi();
+ PSZ s = vp->GetCharValue();
+
+ for (i = 0; i < Nval; i++) {
+ GetValPtrEx(i); // Get a zero ended string in Valp
+
+ if (!((ci) ? strnicmp(s, Valp, Long) : strncmp(s, Valp, Long)))
+ break;
+
+ } // endfor i
+
+ return (i < Nval) ? i : (-1);
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int CHRBLK::GetMaxLength(void)
+ {
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++) {
+ GetValPtrEx(i);
+ n = max(n, (signed)strlen(Valp));
+ } // endfor i
+
+ return n;
+ } // end of GetMaxLength
+
+
+/* -------------------------- Class STRBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+STRBLK::STRBLK(PGLOBAL g, void *mp, int nval)
+ : VALBLK(mp, TYPE_STRING, nval), Strp((PSZ*&)Blkp)
+ {
+ Global = g;
+ } // end of STRBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+void STRBLK::Init(PGLOBAL g, bool check)
+ {
+ if (!Blkp)
+ Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(PSZ));
+
+ Check = check;
+ Global = g;
+ } // end of Init
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void STRBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+ CheckType(pv)
+
+ Strp[n1] = ((STRBLK*)pv)->Strp[n2];
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void STRBLK::SetValues(PVBLK pv, int k, int n)
+ {
+ CheckType(pv)
+ PSZ *sp = ((STRBLK*)pv)->Strp;
+
+ for (register int i = k; i < n; i++)
+ Strp[i] = sp[i];
+
+ } // end of SetValues
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void STRBLK::SetValue(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ SetValue((PSZ)valp->GetCharValue(), n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void STRBLK::SetValue(PSZ p, int n)
+ {
+ Strp[n] = (PSZ)PlugSubAlloc(Global, NULL, strlen(p) + 1);
+ strcpy(Strp[n], p);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void STRBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ char *vp = valp->GetCharValue();
+ char *bp = Strp[n];
+
+ if (strcmp(vp, bp) < 0)
+ SetValue(valp, n);
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void STRBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ char *vp = valp->GetCharValue();
+ char *bp = Strp[n];
+
+ if (strcmp(vp, bp) > 0)
+ SetValue(valp, n);
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void STRBLK::Move(int i, int j)
+ {
+ Strp[j] = Strp[i];
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int STRBLK::CompVal(PVAL vp, int n)
+ {
+ CheckParms(vp, n)
+ return strcmp(vp->GetCharValue(), Strp[n]);
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int STRBLK::CompVal(int i1, int i2)
+ {
+ return (strcmp(Strp[i1], Strp[i2]));
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *STRBLK::GetValPtr(int n)
+ {
+ CheckIndex(n)
+ return Strp + n;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on a zero ended string equal to nth value. */
+/***********************************************************************/
+void *STRBLK::GetValPtrEx(int n)
+ {
+ CheckIndex(n)
+ return Strp[n];
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int STRBLK::Find(PVAL vp)
+ {
+ CheckType(vp)
+ int i;
+ PSZ s = vp->GetCharValue();
+
+ for (i = 0; i < Nval; i++)
+ if (!strcmp(s, Strp[i]))
+ break;
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int STRBLK::GetMaxLength(void)
+ {
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++)
+ n = max(n, (signed)strlen(Strp[i]));
+
+ return n;
+ } // end of GetMaxLength
+
+
+/* -------------------------- Class SHRBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+SHRBLK::SHRBLK(void *mp, int nval)
+ : VALBLK(mp, TYPE_SHORT, nval), Shrp((short*&)Blkp)
+ {
+ } // end of SHRBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+void SHRBLK::Init(PGLOBAL g, bool check)
+ {
+ if (!Blkp)
+ Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(short));
+
+ Check = check;
+ Global = g;
+ } // end of Init
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void SHRBLK::SetValue(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ Shrp[n] = valp->GetShortValue();
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void SHRBLK::SetValue(PSZ p, int n)
+ {
+#if defined(_DEBUG) || defined(DEBTRACE)
+ if (Check) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BAD_SET_STRING));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Check
+#endif
+
+ Shrp[n] = (short)atoi(p);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void SHRBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ short sval = valp->GetShortValue();
+ short& smin = Shrp[n];
+
+ if (sval < smin)
+ smin = sval;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void SHRBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ short sval = valp->GetShortValue();
+ short& smin = Shrp[n];
+
+ if (sval > smin)
+ smin = sval;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void SHRBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+ CheckType(pv)
+
+ Shrp[n1] = ((SHRBLK*)pv)->Shrp[n2];
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void SHRBLK::SetValues(PVBLK pv, int k, int n)
+ {
+ CheckType(pv)
+ short *sp = ((SHRBLK*)pv)->Shrp;
+
+ for (register int i = k; i < n; i++)
+ Shrp[i] = sp[i];
+
+ } // end of SetValues
+
+/***********************************************************************/
+/* This function is used by class RESCOL when calculating COUNT. */
+/***********************************************************************/
+void SHRBLK::AddMinus1(PVBLK pv, int n1, int n2)
+ {
+ assert(Type == pv->GetType());
+ Shrp[n1] += (((SHRBLK*)pv)->Shrp[n2] - 1);
+ } // end of AddMinus1
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void SHRBLK::Move(int i, int j)
+ {
+ Shrp[j] = Shrp[i];
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int SHRBLK::CompVal(PVAL vp, int n)
+ {
+ CheckParms(vp, n)
+ short msv = Shrp[n];
+ short vsv = vp->GetShortValue();
+
+ return (vsv > msv) ? 1 : (vsv < msv) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int SHRBLK::CompVal(int i1, int i2)
+ {
+ short sv1 = Shrp[i1];
+ short sv2 = Shrp[i2];
+
+ return (sv1 > sv2) ? 1 : (sv1 < sv2) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *SHRBLK::GetValPtr(int n)
+ {
+ CheckIndex(n)
+ return Shrp + n;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *SHRBLK::GetValPtrEx(int n)
+ {
+ CheckIndex(n)
+ return Shrp + n;
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int SHRBLK::Find(PVAL vp)
+ {
+ CheckType(vp)
+ int i;
+ short n = vp->GetShortValue();
+
+ for (i = 0; i < Nval; i++)
+ if (n == Shrp[i])
+ break;
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int SHRBLK::GetMaxLength(void)
+ {
+ char buf[12];
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++) {
+ sprintf(buf, "%hd", Shrp[i]);
+
+ n = max(n, (signed)strlen(buf));
+ } // endfor i
+
+ return n;
+ } // end of GetMaxLength
+
+
+/* -------------------------- Class LNGBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+LNGBLK::LNGBLK(void *mp, int nval)
+ : VALBLK(mp, TYPE_INT, nval), Lngp((int*&)Blkp)
+ {
+ } // end of LNGBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+void LNGBLK::Init(PGLOBAL g, bool check)
+ {
+ if (!Blkp)
+ Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(int));
+
+ Check = check;
+ Global = g;
+ } // end of Init
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void LNGBLK::SetValue(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ Lngp[n] = valp->GetIntValue();
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void LNGBLK::SetValue(PSZ p, int n)
+ {
+#if defined(_DEBUG) || defined(DEBTRACE)
+ if (Check) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BAD_SET_STRING));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Check
+#endif
+
+ Lngp[n] = atol(p);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void LNGBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ int lval = valp->GetIntValue();
+ int& lmin = Lngp[n];
+
+ if (lval < lmin)
+ lmin = lval;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void LNGBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ int lval = valp->GetIntValue();
+ int& lmax = Lngp[n];
+
+ if (lval > lmax)
+ lmax = lval;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void LNGBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+ CheckType(pv)
+
+ Lngp[n1] = ((LNGBLK*)pv)->Lngp[n2];
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void LNGBLK::SetValues(PVBLK pv, int k, int n)
+ {
+ CheckType(pv)
+ int *lp = ((LNGBLK*)pv)->Lngp;
+
+ for (register int i = k; i < n; i++)
+ Lngp[i] = lp[i];
+
+ } // end of SetValues
+
+/***********************************************************************/
+/* This function is used by class RESCOL when calculating COUNT. */
+/***********************************************************************/
+void LNGBLK::AddMinus1(PVBLK pv, int n1, int n2)
+ {
+ assert(Type == pv->GetType());
+ Lngp[n1] += (((LNGBLK*)pv)->Lngp[n2] - 1);
+ } // end of AddMinus1
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void LNGBLK::Move(int i, int j)
+ {
+ Lngp[j] = Lngp[i];
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int LNGBLK::CompVal(PVAL vp, int n)
+ {
+ CheckParms(vp, n)
+ register int mlv = Lngp[n];
+ register int vlv = vp->GetIntValue();
+
+ return (vlv > mlv) ? 1 : (vlv < mlv) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int LNGBLK::CompVal(int i1, int i2)
+ {
+ register int lv1 = Lngp[i1];
+ register int lv2 = Lngp[i2];
+
+ return (lv1 > lv2) ? 1 : (lv1 < lv2) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *LNGBLK::GetValPtr(int n)
+ {
+ CheckIndex(n)
+ return Lngp + n;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *LNGBLK::GetValPtrEx(int n)
+ {
+ CheckIndex(n)
+ return Lngp + n;
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int LNGBLK::Find(PVAL vp)
+ {
+ CheckType(vp)
+ int i;
+ int n = vp->GetIntValue();
+
+ for (i = 0; i < Nval; i++)
+ if (n == Lngp[i])
+ break;
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int LNGBLK::GetMaxLength(void)
+ {
+ char buf[12];
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++) {
+ sprintf(buf, "%d", Lngp[i]);
+
+ n = max(n, (signed)strlen(buf));
+ } // endfor i
+
+ return n;
+ } // end of GetMaxLength
+
+
+/* -------------------------- Class DATBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+DATBLK::DATBLK(void *mp, int nval) : LNGBLK(mp, nval)
+ {
+ Type = TYPE_DATE;
+ Dvalp = NULL;
+ } // end of DATBLK constructor
+
+/***********************************************************************/
+/* Set format so formatted dates can be converted on input. */
+/***********************************************************************/
+bool DATBLK::SetFormat(PGLOBAL g, PSZ fmt, int len, int year)
+ {
+ if (!(Dvalp = AllocateValue(g, TYPE_DATE, len, year, fmt)))
+ return true;
+
+ return false;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* Set one value in a block from a char string. */
+/***********************************************************************/
+void DATBLK::SetValue(PSZ p, int n)
+ {
+ if (Dvalp) {
+ // Decode the string according to format
+ Dvalp->SetValue_psz(p);
+ Lngp[n] = Dvalp->GetIntValue();
+ } else
+ LNGBLK::SetValue(p, n);
+
+ } // end of SetValue
+
+
+/* -------------------------- Class BIGBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+BIGBLK::BIGBLK(void *mp, int nval)
+ : VALBLK(mp, TYPE_BIGINT, nval), Lngp((longlong*&)Blkp)
+ {
+ } // end of BIGBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+void BIGBLK::Init(PGLOBAL g, bool check)
+ {
+ if (!Blkp)
+ Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(longlong));
+
+ Check = check;
+ Global = g;
+ } // end of Init
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void BIGBLK::SetValue(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ Lngp[n] = valp->GetBigintValue();
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void BIGBLK::SetValue(PSZ p, int n)
+ {
+#if defined(_DEBUG) || defined(DEBTRACE)
+ if (Check) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BAD_SET_STRING));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Check
+#endif
+
+ Lngp[n] = atoll(p);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void BIGBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ longlong lval = valp->GetIntValue();
+ longlong& lmin = Lngp[n];
+
+ if (lval < lmin)
+ lmin = lval;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void BIGBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ longlong lval = valp->GetIntValue();
+ longlong& lmax = Lngp[n];
+
+ if (lval > lmax)
+ lmax = lval;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void BIGBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+ CheckType(pv)
+
+ Lngp[n1] = ((BIGBLK*)pv)->Lngp[n2];
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void BIGBLK::SetValues(PVBLK pv, int k, int n)
+ {
+ CheckType(pv)
+ longlong *lp = ((BIGBLK*)pv)->Lngp;
+
+ for (register int i = k; i < n; i++)
+ Lngp[i] = lp[i];
+
+ } // end of SetValues
+
+/***********************************************************************/
+/* This function is used by class RESCOL when calculating COUNT. */
+/***********************************************************************/
+void BIGBLK::AddMinus1(PVBLK pv, int n1, int n2)
+ {
+ assert(Type == pv->GetType());
+ Lngp[n1] += (((BIGBLK*)pv)->Lngp[n2] - 1);
+ } // end of AddMinus1
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void BIGBLK::Move(int i, int j)
+ {
+ Lngp[j] = Lngp[i];
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int BIGBLK::CompVal(PVAL vp, int n)
+ {
+ CheckParms(vp, n)
+ longlong mlv = Lngp[n];
+ longlong vlv = vp->GetBigintValue();
+
+ return (vlv > mlv) ? 1 : (vlv < mlv) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int BIGBLK::CompVal(int i1, int i2)
+ {
+ longlong lv1 = Lngp[i1];
+ longlong lv2 = Lngp[i2];
+
+ return (lv1 > lv2) ? 1 : (lv1 < lv2) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *BIGBLK::GetValPtr(int n)
+ {
+ CheckIndex(n)
+ return Lngp + n;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *BIGBLK::GetValPtrEx(int n)
+ {
+ CheckIndex(n)
+ return Lngp + n;
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int BIGBLK::Find(PVAL vp)
+ {
+ CheckType(vp)
+ int i;
+ longlong n = vp->GetBigintValue();
+
+ for (i = 0; i < Nval; i++)
+ if (n == Lngp[i])
+ break;
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int BIGBLK::GetMaxLength(void)
+ {
+ char buf[24];
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++) {
+ sprintf(buf, "%lld", Lngp[i]);
+
+ n = max(n, (signed)strlen(buf));
+ } // endfor i
+
+ return n;
+ } // end of GetMaxLength
+
+
+/* -------------------------- Class DBLBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+DBLBLK::DBLBLK(void *mp, int nval, int prec)
+ : VALBLK(mp, TYPE_FLOAT, nval), Dblp((double*&)Blkp)
+ {
+ Prec = prec;
+ } // end of DBLBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+void DBLBLK::Init(PGLOBAL g, bool check)
+ {
+ if (!Blkp)
+ Blkp = PlugSubAlloc(g, NULL, Nval * sizeof(double));
+
+ Check = check;
+ Global = g;
+ } // end of Init
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void DBLBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+ CheckType(pv)
+
+ Dblp[n1] = ((DBLBLK*)pv)->Dblp[n2];
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void DBLBLK::SetValues(PVBLK pv, int k, int n)
+ {
+ CheckType(pv)
+ double *dp = ((DBLBLK*)pv)->Dblp;
+
+ for (register int i = k; i < n; i++)
+ Dblp[i] = dp[i];
+
+ } // end of SetValues
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void DBLBLK::SetValue(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ Dblp[n] = valp->GetFloatValue();
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void DBLBLK::SetValue(PSZ p, int n)
+ {
+#if defined(_DEBUG) || defined(DEBTRACE)
+ if (Check) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BAD_SET_STRING));
+ longjmp(g->jumper[g->jump_level], Type);
+ } // endif Check
+#endif
+
+ Dblp[n] = atof(p);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void DBLBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ double fval = valp->GetFloatValue();
+ double& fmin = Dblp[n];
+
+ if (fval < fmin)
+ fmin = fval;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void DBLBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ double fval = valp->GetFloatValue();
+ double& fmax = Dblp[n];
+
+ if (fval > fmax)
+ fmax = fval;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void DBLBLK::Move(int i, int j)
+ {
+ Dblp[j] = Dblp[i];
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int DBLBLK::CompVal(PVAL vp, int n)
+ {
+ CheckParms(vp, n)
+ double mfv = Dblp[n];
+ double vfv = vp->GetFloatValue();
+
+ return (vfv > mfv) ? 1 : (vfv < mfv) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int DBLBLK::CompVal(int i1, int i2)
+ {
+ register double dv1 = Dblp[i1];
+ register double dv2 = Dblp[i2];
+
+ return (dv1 > dv2) ? 1 : (dv1 < dv2) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *DBLBLK::GetValPtr(int n)
+ {
+ CheckIndex(n)
+ return Dblp + n;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *DBLBLK::GetValPtrEx(int n)
+ {
+ CheckIndex(n)
+ return Dblp + n;
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int DBLBLK::Find(PVAL vp)
+ {
+ CheckType(vp)
+ int i;
+ double d = vp->GetFloatValue();
+
+ for (i = 0; i < Nval; i++)
+ if (d == Dblp[i])
+ break;
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int DBLBLK::GetMaxLength(void)
+ {
+ char buf[32];
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++) {
+ sprintf(buf, "%lf", Dblp[i]);
+
+ n = max(n, (signed)strlen(buf));
+ } // endfor i
+
+ return n;
+ } // end of GetMaxLength
+
+/* ------------------------- End of Valblk --------------------------- */
+
diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h
index 4d1260abda2..6c04bfdab65 100644
--- a/storage/connect/valblk.h
+++ b/storage/connect/valblk.h
@@ -1,359 +1,359 @@
-/*************** Valblk H Declares Source Code File (.H) ***************/
-/* Name: VALBLK.H Version 1.7 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
-/* */
-/* 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 longlong GetBigintValue(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(longlong 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 longlong GetBigintValue(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 longlong GetBigintValue(int n) {return atoll(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 longlong GetBigintValue(int n) {return (longlong)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(longlong 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 longlong GetBigintValue(int n) {return (longlong)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(longlong lval, int n) {Lngp[n] = (int)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 BIGBLK: represents a block of big integer values. */
-/***********************************************************************/
-class BIGBLK : public VALBLK {
- public:
- // Constructors
- BIGBLK(void *mp, int size);
-
- // Implementation
- virtual void Init(PGLOBAL g, bool check);
- virtual int GetVlen(void) {return sizeof(longlong);}
-//virtual PSZ GetCharValue(int n);
- virtual short GetShortValue(int n) {return (short)Lngp[n];}
- virtual int GetIntValue(int n) {return (int)Lngp[n];}
- virtual longlong GetBigintValue(int n) {return Lngp[n];}
- virtual double GetFloatValue(int n) {return (double)Lngp[n];}
- virtual void Reset(int n) {Lngp[n] = 0LL;}
-
- // Methods
- virtual void SetValue(PSZ sp, int n);
- virtual void SetValue(short sval, int n) {Lngp[n] = (longlong)sval;}
- virtual void SetValue(int lval, int n) {Lngp[n] = (longlong)lval;}
- virtual void SetValue(longlong 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
- longlong* const &Lngp;
- }; // end of class BIGBLK
-
-/***********************************************************************/
-/* 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 longlong GetBigintValue(int n) {return (longlong)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__
-
+/*************** Valblk H Declares Source Code File (.H) ***************/
+/* Name: VALBLK.H Version 1.7 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
+/* */
+/* 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 longlong GetBigintValue(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(longlong 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 longlong GetBigintValue(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 longlong GetBigintValue(int n) {return atoll(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 longlong GetBigintValue(int n) {return (longlong)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(longlong 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 longlong GetBigintValue(int n) {return (longlong)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(longlong lval, int n) {Lngp[n] = (int)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 BIGBLK: represents a block of big integer values. */
+/***********************************************************************/
+class BIGBLK : public VALBLK {
+ public:
+ // Constructors
+ BIGBLK(void *mp, int size);
+
+ // Implementation
+ virtual void Init(PGLOBAL g, bool check);
+ virtual int GetVlen(void) {return sizeof(longlong);}
+//virtual PSZ GetCharValue(int n);
+ virtual short GetShortValue(int n) {return (short)Lngp[n];}
+ virtual int GetIntValue(int n) {return (int)Lngp[n];}
+ virtual longlong GetBigintValue(int n) {return Lngp[n];}
+ virtual double GetFloatValue(int n) {return (double)Lngp[n];}
+ virtual void Reset(int n) {Lngp[n] = 0LL;}
+
+ // Methods
+ virtual void SetValue(PSZ sp, int n);
+ virtual void SetValue(short sval, int n) {Lngp[n] = (longlong)sval;}
+ virtual void SetValue(int lval, int n) {Lngp[n] = (longlong)lval;}
+ virtual void SetValue(longlong 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
+ longlong* const &Lngp;
+ }; // end of class BIGBLK
+
+/***********************************************************************/
+/* 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 longlong GetBigintValue(int n) {return (longlong)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__
+
diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp
index 38c558c7e68..8a87c860634 100644
--- a/storage/connect/value.cpp
+++ b/storage/connect/value.cpp
@@ -1,4825 +1,4825 @@
-/************* Value C++ Functions Source Code File (.CPP) *************/
-/* Name: VALUE.CPP Version 2.0 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
-/* */
-/* This file contains the VALUE and derived classes family functions. */
-/* These classes contain values of different types. They are used so */
-/* new object types can be defined and added to the processing simply */
-/* (hopefully) adding their specific functions in this file. */
-/* First family is VALUE that represent single typed objects. It is */
-/* used by columns (COLBLK), SELECT and FILTER (derived) objects. */
-/* Second family is VALBLK, representing simple suballocated arrays */
-/* of values treated sequentially by FIX, BIN and VCT tables and */
-/* columns, as well for min/max blocks as for VCT column blocks. */
-/* Q&A: why not using only one family ? Simple values are arrays that */
-/* have only one element and arrays could have functions for all kind */
-/* of processing. The answer is a-because historically it was simpler */
-/* to do that way, b-because of performance on single values, and c- */
-/* to avoid too complicated classes and unuseful duplication of many */
-/* functions used on one family only. The drawback is that for new */
-/* types of objects, we shall have more classes to update. */
-/* Currently the only implemented types are STRING, INT, DOUBLE, DATE */
-/* and LONGLONG. Shortly we should add at least TINY and VARCHAR. */
-/***********************************************************************/
-
-#ifndef __VALUE_H
-#define __VALUE_H
-
-/***********************************************************************/
-/* Include relevant MariaDB header file. */
-/***********************************************************************/
-#include "my_global.h"
-#if defined(WIN32)
-//#include <windows.h>
-#else // !WIN32
-#include <string.h>
-#endif // !WIN32
-
-#include <math.h>
-
-#undef DOMAIN // Was defined in math.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 "preparse.h" // For DATPAR
-//#include "value.h"
-#include "valblk.h"
-#define NO_FUNC // Already defined in ODBConn
-#include "plgcnx.h" // For DB types
-
-/***********************************************************************/
-/* Check macro's. */
-/***********************************************************************/
-#if defined(_DEBUG)
-#define CheckType(V) if (Type != V->GetType()) { \
- PGLOBAL& g = Global; \
- strcpy(g->Message, MSG(VALTYPE_NOMATCH)); \
- longjmp(g->jumper[g->jump_level], Type); }
-#else
-#define CheckType(V)
-#endif
-
-#define FOURYEARS 126230400 // Four years in seconds (1 leap)
-
-/***********************************************************************/
-/* Static variables. */
-/***********************************************************************/
-static char *list =
- " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.*-‘abcdefghijklmnopqrstuv"; //wxyzñ'
-//" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.";
-extern "C" int trace;
-
-/***********************************************************************/
-/* Initialize the DTVAL static member. */
-/***********************************************************************/
-int DTVAL::Shift = 0;
-
-/***********************************************************************/
-/* Routines called externally. */
-/***********************************************************************/
-bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
-#if !defined(WIN32)
-extern "C" {
-PSZ strupr(PSZ s);
-PSZ strlwr(PSZ s);
-}
-#endif // !WIN32
-
-/***********************************************************************/
-/* Returns the bitmap representing the conditions that must not be */
-/* met when returning from TestValue for a given operator. */
-/* Bit one is EQ, bit 2 is LT, and bit 3 is GT. */
-/***********************************************************************/
-BYTE OpBmp(PGLOBAL g, OPVAL opc)
- {
- BYTE bt;
-
- switch (opc) {
- case OP_IN:
- case OP_EQ: bt = 0x06; break;
- case OP_NE: bt = 0x01; break;
- case OP_GT: bt = 0x03; break;
- case OP_GE: bt = 0x02; break;
- case OP_LT: bt = 0x05; break;
- case OP_LE: bt = 0x04; break;
- case OP_EXIST: bt = 0x00; break;
- default:
- sprintf(g->Message, MSG(BAD_FILTER_OP), opc);
- longjmp(g->jumper[g->jump_level], 777);
- } // endswitch opc
-
- return bt;
- } // end of OpBmp
-
-/***********************************************************************/
-/* GetTypeName: returns the PlugDB internal type name. */
-/***********************************************************************/
-PSZ GetTypeName(int type)
- {
- PSZ name = "UNKNOWN";
-
- switch (type) {
- case TYPE_STRING: name = "CHAR"; break;
- case TYPE_SHORT: name = "SMALLINT"; break;
- case TYPE_INT: name = "INTEGER"; break;
- case TYPE_BIGINT: name = "BIGINT"; break;
- case TYPE_DATE: name = "DATE"; break;
- case TYPE_FLOAT: name = "FLOAT"; break;
- } // endswitch type
-
- return name;
- } // end of GetTypeName
-
-/***********************************************************************/
-/* GetTypeSize: returns the PlugDB internal type size. */
-/***********************************************************************/
-int GetTypeSize(int type, int len)
- {
- switch (type) {
- case TYPE_STRING: len = len * sizeof(char); break;
- case TYPE_SHORT: len = sizeof(short); break;
- case TYPE_INT: len = sizeof(int); break;
- case TYPE_BIGINT: len = sizeof(longlong); break;
- case TYPE_DATE: len = sizeof(int); break;
- case TYPE_FLOAT: len = sizeof(double); break;
- break;
- default: len = 0;
- } // endswitch type
-
- return len;
- } // end of GetTypeSize
-
-/***********************************************************************/
-/* GetPLGType: returns the PlugDB type corresponding to a DB type. */
-/***********************************************************************/
-int GetPLGType(int type)
- {
- int tp;
-
- switch (type) {
- case DB_CHAR:
- case DB_STRING: tp = TYPE_STRING; break;
- case DB_SHORT: tp = TYPE_SHORT; break;
- case DB_INT: tp = TYPE_INT; break;
- case DB_DOUBLE: tp = TYPE_FLOAT; break;
- case DB_DATE: tp = TYPE_DATE; break;
- default: tp = TYPE_ERROR;
- } // endswitch type
-
- return tp;
- } // end of GetPLGType
-
-/***********************************************************************/
-/* GetDBType: returns the DB type corresponding to a PlugDB type. */
-/***********************************************************************/
-int GetDBType(int type)
- {
- int tp;
-
- switch (type) {
- case TYPE_STRING: tp = DB_CHAR; break;
- case TYPE_SHORT: tp = DB_SHORT; break;
- case TYPE_INT: tp = DB_INT; break;
- case TYPE_BIGINT:
- case TYPE_FLOAT: tp = DB_DOUBLE; break;
- case TYPE_DATE: tp = DB_DATE; break;
- default: tp = DB_ERROR;
- } // endswitch type
-
- return tp;
- } // end of GetPLGType
-
-/***********************************************************************/
-/* GetFormatType: returns the FORMAT character(s) according to type. */
-/***********************************************************************/
-char *GetFormatType(int type)
- {
- char *c = "X";
-
- switch (type) {
- case TYPE_STRING: c = "C"; break;
- case TYPE_SHORT: c = "S"; break;
- case TYPE_INT: c = "N"; break;
- case TYPE_BIGINT: c = "L"; break;
- case TYPE_FLOAT: c = "F"; break;
- case TYPE_DATE: c = "D"; break;
- } // endswitch type
-
- return c;
- } // end of GetFormatType
-
-/***********************************************************************/
-/* GetFormatType: returns the FORMAT type according to character. */
-/***********************************************************************/
-int GetFormatType(char c)
- {
- int type = TYPE_ERROR;
-
- switch (c) {
- case 'C': type = TYPE_STRING; break;
- case 'S': type = TYPE_SHORT; break;
- case 'N': type = TYPE_INT; break;
- case 'L': type = TYPE_BIGINT; break;
- case 'F': type = TYPE_FLOAT; break;
- case 'D': type = TYPE_DATE; break;
- } // endswitch type
-
- return type;
- } // end of GetFormatType
-
-
-/***********************************************************************/
-/* IsTypeChar: returns true for character type(s). */
-/***********************************************************************/
-bool IsTypeChar(int type)
- {
- switch (type) {
- case TYPE_STRING:
- return true;
- } // endswitch type
-
- return false;
- } // end of IsTypeChar
-
-/***********************************************************************/
-/* IsTypeNum: returns true for numeric types. */
-/***********************************************************************/
-bool IsTypeNum(int type)
- {
- switch (type) {
- case TYPE_INT:
- case TYPE_BIGINT:
- case TYPE_DATE:
- case TYPE_FLOAT:
- case TYPE_SHORT:
- case TYPE_NUM:
- return true;
- } // endswitch type
-
- return false;
- } // end of IsTypeNum
-
-/***********************************************************************/
-/* ConvertType: what this function does is to determine the type to */
-/* which should be converted a value so no precision would be lost. */
-/* This can be a numeric type if num is true or non numeric if false. */
-/* Note: this is an ultra simplified version of this function that */
-/* should become more and more complex as new types are added. */
-/* Not evaluated types (TYPE_VOID or TYPE_UNDEF) return false from */
-/* IsType... functions so match does not prevent correct setting. */
-/***********************************************************************/
-int ConvertType(int target, int type, CONV kind, bool match)
- {
- switch (kind) {
- case CNV_CHAR:
- if (match && (!IsTypeChar(target) || !IsTypeChar(type)))
- return TYPE_ERROR;
-
- return TYPE_STRING;
- case CNV_NUM:
- if (match && (!IsTypeNum(target) || !IsTypeNum(type)))
- return TYPE_ERROR;
-
- return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT
- : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
- : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
- : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
- : TYPE_SHORT;
- default:
- if (target == TYPE_ERROR || target == type)
- return type;
-
- if (match && ((IsTypeChar(target) && !IsTypeChar(type)) ||
- (IsTypeNum(target) && !IsTypeNum(type))))
- return TYPE_ERROR;
-
- return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT
- : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
- : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
- : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
- : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT
- : (target == TYPE_STRING || type == TYPE_STRING) ? TYPE_STRING
- : TYPE_ERROR;
- } // endswitch kind
-
- } // end of ConvertType
-
-/***********************************************************************/
-/* AllocateConstant: allocates a constant Value. */
-/***********************************************************************/
-PVAL AllocateValue(PGLOBAL g, void *value, short type)
- {
- PVAL valp;
-
- if (trace)
- htrc("AllocateConstant: value=%p type=%hd\n", value, type);
-
- switch (type) {
- case TYPE_STRING: valp = new(g) STRING((PSZ)value); break;
- case TYPE_SHORT: valp = new(g) SHVAL(*(short*)value); break;
- case TYPE_INT: valp = new(g) INTVAL(*(int*)value); break;
- case TYPE_BIGINT: valp = new(g) BIGVAL(*(longlong*)value); break;
- case TYPE_FLOAT: valp = new(g) DFVAL(*(double *)value); break;
- default:
- sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
- return NULL;
- } // endswitch Type
-
- valp->SetGlobal(g);
- return valp;
- } // end of AllocateValue
-
-/***********************************************************************/
-/* Allocate a variable Value according to type, length and precision. */
-/***********************************************************************/
-PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
- PSZ dom, PCATLG cat)
- {
- PVAL valp;
-
- switch (type) {
- case TYPE_STRING: valp = new(g) STRING(g, (PSZ)NULL, len, prec);
- break;
- case TYPE_DATE: valp = new(g) DTVAL(g, len, prec, dom); break;
- case TYPE_INT: valp = new(g) INTVAL((int)0); break;
- case TYPE_BIGINT: valp = new(g) BIGVAL((longlong)0); break;
- case TYPE_SHORT: valp = new(g) SHVAL((short)0); break;
- case TYPE_FLOAT: valp = new(g) DFVAL(0.0, prec); break;
- default:
- sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
- return NULL;
- } // endswitch type
-
- valp->SetGlobal(g);
- return valp;
- } // end of AllocateValue
-
-/***********************************************************************/
-/* Allocate a constant Value converted to newtype. */
-/* Can also be used to copy a Value eventually converted. */
-/***********************************************************************/
-PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
- {
- PSZ p, sp;
-
- if (newtype == TYPE_VOID) // Means allocate a value of the same type
- newtype = valp->GetType();
-
- switch (newtype) {
- case TYPE_STRING:
- p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen());
-
- if ((sp = valp->GetCharString(p)) != p)
- strcpy (p, sp);
-
- valp = new(g) STRING(g, p, valp->GetValLen(), valp->GetValPrec());
- break;
- case TYPE_SHORT: valp = new(g) SHVAL(valp->GetShortValue()); break;
- case TYPE_INT: valp = new(g) INTVAL(valp->GetIntValue()); break;
- case TYPE_BIGINT: valp = new(g) BIGVAL(valp->GetBigintValue()); break;
- case TYPE_DATE: valp = new(g) DTVAL(g, valp->GetIntValue()); break;
- case TYPE_FLOAT: valp = new(g) DFVAL(valp->GetFloatValue()); break;
- default:
- sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype);
- return NULL;
- } // endswitch type
-
- valp->SetGlobal(g);
- return valp;
- } // end of AllocateValue
-
-
-/* -------------------------- Class VALUE ---------------------------- */
-
-/***********************************************************************/
-/* ShowTypedValue: send back the value formatted according to parms. */
-/* buf: is a pointer to a buffer large enough for big double values. */
-/* typ: is the type wanted for the value character representation. */
-/* n: is the field length (needed for right justification. */
-/* p: is the precision (for float representations). */
-/* Note: this fonction is currently not used anymore. */
-/***********************************************************************/
-char *VALUE::ShowTypedValue(PGLOBAL g, char *buf, int typ, int n, int p)
- {
- switch (typ) {
- case TYPE_STRING:
- buf = GetCharString(buf);
- break;
- case TYPE_INT:
- case TYPE_DATE:
- buf = GetIntString(buf, n);
- break;
- case TYPE_FLOAT:
- buf = GetFloatString(buf, n, p);
- break;
- case TYPE_SHORT:
- buf = GetShortString(buf, n);
- break;
- case TYPE_BIGINT:
- buf = GetBigintString(buf, n);
- break;
- default:
- // More should be added for additional values.
- if (trace)
- htrc("Invalid col format type %d\n", typ);
-
- sprintf(g->Message, MSG(BAD_COL_FORMAT), typ);
- longjmp(g->jumper[g->jump_level], 31);
- } // endswitch Type
-
- return buf;
- } // end of ShowTypedValue
-
-/***********************************************************************/
-/* Returns a BYTE indicating the comparison between two values. */
-/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */
-/* More than 1 bit can be set only in the case of TYPE_LIST. */
-/***********************************************************************/
-BYTE VALUE::TestValue(PVAL vp)
- {
- int n = CompareValue(vp);
-
- return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01;
- } // end of TestValue
-
-/* -------------------------- Class STRING --------------------------- */
-
-/***********************************************************************/
-/* STRING public constructor from a constant string. */
-/***********************************************************************/
-STRING::STRING(PSZ s) : VALUE(TYPE_STRING)
- {
- Strp = s;
- Len = strlen(s);
- Clen = Len;
- Ci = false;
- } // end of STRING constructor
-
-/***********************************************************************/
-/* STRING public constructor from char. */
-/***********************************************************************/
-STRING::STRING(PGLOBAL g, PSZ s, int n, int c) : VALUE(TYPE_STRING)
- {
- Len = n;
-
- if (!s) {
- Strp = (char *)PlugSubAlloc(g, NULL, Len + 1);
- Strp[Len] = '\0';
- } else
- Strp = s;
-
- Clen = Len;
- Ci = (c != 0);
- } // end of STRING constructor
-
-/***********************************************************************/
-/* STRING public constructor from short. */
-/***********************************************************************/
-STRING::STRING(PGLOBAL g, short i) : VALUE(TYPE_STRING)
- {
- Strp = (char *)PlugSubAlloc(g, NULL, 12);
- Len = sprintf(Strp, "%hd", i);
- Clen = Len;
- Ci = false;
- } // end of STRING constructor
-
-/***********************************************************************/
-/* STRING public constructor from int. */
-/***********************************************************************/
-STRING::STRING(PGLOBAL g, int n) : VALUE(TYPE_STRING)
- {
- Strp = (char *)PlugSubAlloc(g, NULL, 12);
- Len = sprintf(Strp, "%d", n);
- Clen = Len;
- Ci = false;
- } // end of STRING constructor
-
-/***********************************************************************/
-/* STRING public constructor from bigint. */
-/***********************************************************************/
-STRING::STRING(PGLOBAL g, longlong n) : VALUE(TYPE_STRING)
- {
- Strp = (char *)PlugSubAlloc(g, NULL, 12);
- Len = sprintf(Strp, "%lld", n);
- Clen = Len;
- Ci = false;
- } // end of STRING constructor
-
-/***********************************************************************/
-/* STRING public constructor from double. */
-/***********************************************************************/
-STRING::STRING(PGLOBAL g, double f) : VALUE(TYPE_STRING)
- {
- Strp = (char *)PlugSubAlloc(g, NULL, 32);
- Len = sprintf(Strp, "%lf", f);
- Clen = Len;
- Ci = false;
- } // end of STRING constructor
-
-/***********************************************************************/
-/* STRING SetValue: copy the value of another Value object. */
-/***********************************************************************/
-bool STRING::SetValue_pval(PVAL valp, bool chktype)
- {
- if (chktype && (valp->GetType() != Type || valp->GetSize() > Len))
- return true;
-
- char buf[32];
-
- strncpy(Strp, valp->GetCharString(buf), Len);
- return false;
- } // end of SetValue_pval
-
-/***********************************************************************/
-/* STRING SetValue: fill string with chars extracted from a line. */
-/***********************************************************************/
-void STRING::SetValue_char(char *p, int n)
- {
- n = min(n, Len);
- strncpy(Strp, p, n);
-
- for (p = Strp + n - 1; (*p == ' ' || *p == '\0') && p >= Strp; p--) ;
-
- *(++p) = '\0';
-
- if (trace)
- htrc(" Setting string to: '%s'\n", Strp);
-
- } // end of SetValue_char
-
-/***********************************************************************/
-/* STRING SetValue: fill string with another string. */
-/***********************************************************************/
-void STRING::SetValue_psz(PSZ s)
- {
- strncpy(Strp, s, Len);
- } // end of SetValue_psz
-
-/***********************************************************************/
-/* STRING SetValue: fill string with a string extracted from a block. */
-/***********************************************************************/
-void STRING::SetValue_pvblk(PVBLK blk, int n)
- {
- strncpy(Strp, blk->GetCharValue(n), Len);
- } // end of SetValue_pvblk
-
-/***********************************************************************/
-/* STRING SetValue: get the character representation of a short int. */
-/***********************************************************************/
-void STRING::SetValue(short n)
- {
- SetValue((int)n);
- } // end of SetValue
-
-/***********************************************************************/
-/* STRING SetValue: get the character representation of an integer. */
-/***********************************************************************/
-void STRING::SetValue(int n)
- {
- char buf[16];
- PGLOBAL& g = Global;
- int k = sprintf(buf, "%d", n);
-
- if (k > Len) {
- sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
- longjmp(g->jumper[g->jump_level], 138);
- } else
- SetValue_psz(buf);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* STRING SetValue: get the character representation of a big integer.*/
-/***********************************************************************/
-void STRING::SetValue(longlong n)
- {
- char buf[24];
- PGLOBAL& g = Global;
- int k = sprintf(buf, "%lld", n);
-
- if (k > Len) {
- sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
- longjmp(g->jumper[g->jump_level], 138);
- } else
- SetValue_psz(buf);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* STRING SetValue: get the character representation of a double. */
-/***********************************************************************/
-void STRING::SetValue(double f)
- {
- char *p, buf[32];
- PGLOBAL& g = Global;
- int k = sprintf(buf, "%lf", f);
-
- for (p = buf + k - 1; p >= buf; p--)
- if (*p == '0') {
- *p = 0;
- k--;
- } else
- break;
-
- if (k > Len) {
- sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
- longjmp(g->jumper[g->jump_level], 138);
- } else
- SetValue_psz(buf);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* STRING SetBinValue: fill string with chars extracted from a line. */
-/***********************************************************************/
-void STRING::SetBinValue(void *p)
- {
- SetValue_char((char *)p, Len);
- } // end of SetBinValue
-
-/***********************************************************************/
-/* GetBinValue: fill a buffer with the internal binary value. */
-/* This function checks whether the buffer length is enough and */
-/* returns true if not. Actual filling occurs only if go is true. */
-/* Currently used by WriteColumn of binary files. */
-/***********************************************************************/
-bool STRING::GetBinValue(void *buf, int buflen, bool go)
- {
- int len = strlen(Strp);
-
- if (len > buflen)
- return true;
- else if (go) {
- memset(buf, ' ', buflen);
- memcpy(buf, Strp, len);
- } // endif go
-
- return false;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
-/* This is a fast implementation that does not do any checking. */
-/***********************************************************************/
-void STRING::GetBinValue(void *buf, int buflen)
- {
- assert(buflen >= (signed)strlen(Strp));
-
- memset(buf, ' ', buflen);
- memcpy(buf, Strp, buflen);
- } // end of GetBinValue
-
-/***********************************************************************/
-/* STRING ShowValue: get string representation of a char value. */
-/***********************************************************************/
-char *STRING::ShowValue(char *buf, int len)
- {
- return Strp;
- } // end of ShowValue
-
-/***********************************************************************/
-/* STRING GetCharString: get string representation of a char value. */
-/***********************************************************************/
-char *STRING::GetCharString(char *p)
- {
- return Strp;
- } // end of GetCharString
-
-/***********************************************************************/
-/* STRING GetShortString: get short representation of a char value. */
-/***********************************************************************/
-char *STRING::GetShortString(char *p, int n)
- {
- sprintf(p, "%*hd", n, (short)atoi(Strp));
- return p;
- } // end of GetShortString
-
-/***********************************************************************/
-/* STRING GetIntString: get int representation of a char value. */
-/***********************************************************************/
-char *STRING::GetIntString(char *p, int n)
- {
- sprintf(p, "%*d", n, atol(Strp));
- return p;
- } // end of GetIntString
-
-/***********************************************************************/
-/* STRING GetBigintString: get big int representation of a char value.*/
-/***********************************************************************/
-char *STRING::GetBigintString(char *p, int n)
- {
- sprintf(p, "%*lld", n, atoll(Strp));
- return p;
- } // end of GetBigintString
-
-/***********************************************************************/
-/* STRING GetFloatString: get double representation of a char value. */
-/***********************************************************************/
-char *STRING::GetFloatString(char *p, int n, int prec)
- {
- sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, atof(Strp));
- return p;
- } // end of GetFloatString
-
-/***********************************************************************/
-/* STRING compare value with another Value. */
-/***********************************************************************/
-bool STRING::IsEqual(PVAL vp, bool chktype)
- {
- if (this == vp)
- return true;
- else if (chktype && Type != vp->GetType())
- return false;
- else if (Ci || vp->IsCi())
- return !stricmp(Strp, vp->GetCharValue());
- else // (!Ci)
- return !strcmp(Strp, vp->GetCharValue());
-
- } // end of IsEqual
-
-/***********************************************************************/
-/* Compare values and returns 1, 0 or -1 according to comparison. */
-/* This function is used for evaluation of character filters. */
-/***********************************************************************/
-int STRING::CompareValue(PVAL vp)
- {
- int n;
-//assert(vp->GetType() == Type);
-
- if (trace)
- htrc(" Comparing: val='%s','%s'\n", Strp, vp->GetCharValue());
-
- // Process filtering on character strings.
- if (Ci || vp->IsCi())
- n = stricmp(Strp, vp->GetCharValue());
- else
- n = strcmp(Strp, vp->GetCharValue());
-
-#if defined(WIN32)
- if (n == _NLSCMPERROR)
- return n; // Here we should raise an error
-#endif // WIN32
-
- return (n > 0) ? 1 : (n < 0) ? -1 : 0;
- } // end of CompareValue
-
-/***********************************************************************/
-/* Returns a BYTE indicating the comparison between two values. */
-/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */
-/* More than 1 bit are set only in the case of error. */
-/***********************************************************************/
-BYTE STRING::TestValue(PVAL vp)
- {
- // Process filtering on character strings.
- bool ci = (Ci || vp->IsCi());
- int n = (ci) ? stricmp(Strp, vp->GetCharValue())
- : strcmp(Strp, vp->GetCharValue());
-
-#if defined(WIN32)
- if (n == _NLSCMPERROR)
- return 0x07; // Here we could raise an error
-#endif // WIN32
-
- return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01;
- } // end of TestValue
-
-/***********************************************************************/
-/* Compute a function on a string. */
-/***********************************************************************/
-bool STRING::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
- {
- assert(np <= 3);
-
- if (op == OP_SUBST) {
- /*******************************************************************/
- /* SUBSTR: this functions have 1 STRING parameter followed by */
- /* 1 or 2 int parameters. */
- /*******************************************************************/
- char *p, *s, buf[32];
- int i, n, len;
-
- assert(np >= 2);
-
- s = vp[0]->GetCharString(buf);
- i = (int)vp[1]->GetIntValue(); // Starting point
- n = (np > 2) ? (int)vp[2]->GetIntValue(): 0;
- len = strlen(s);
- *Strp = '\0';
-
- if (i > len || i < -len || i == 0 || n < 0)
- p = NULL;
- else if (i > 0)
- p = s + i - 1;
- else
- p = s + len + i;
-
- if (p) {
- /******************************************************************/
- /* This should not happen if the result size has been set */
- /* accurately, and this test could be placed under trace. */
- /******************************************************************/
- if (((n > 0) ? min(n, (signed)strlen(p)) : (signed)strlen(p)) > Len) {
- strcpy(g->Message, MSG(SUB_RES_TOO_LNG));
- return true;
- } // endif
-
- /******************************************************************/
- /* Do the actual Substr operation. */
- /******************************************************************/
- if (n > 0)
- strncat(Strp, p, n);
- else
- strcpy(Strp, p);
-
- } // endif p
-
- if (trace)
- htrc("SUBSTR result=%s val=%s,%d,%d", Strp, s, i, n);
-
- } else if (op == OP_LTRIM || op == OP_RTRIM) {
- /*******************************************************************/
- /* Trimming functions have one STRING parameter followed by one */
- /* CHAR parameter (one chararacter). */
- /*******************************************************************/
- char *p, buf[32], c = ' ';
- PSZ strg;
- int len;
-
- assert(np > 0);
-
- strg = vp[0]->GetCharString(buf);
- len = strlen(strg);
- strg = strcpy(Strp, strg);
-
- if (len > 0) {
- if (np > 1) {
- // Character value may have been entered as an integer
- if (vp[1]->GetType() == TYPE_INT)
- c = (char)vp[1]->GetIntValue();
- else if (IsTypeChar(vp[1]->GetType()))
- c = *vp[1]->GetCharValue();
- else {
- strcpy(g->Message, MSG(BAD_TRIM_ARGTYP));
- return true;
- } // endelse
-
- } // endif 2 args
-
- if (op == OP_LTRIM) {
- for (p = strg; *p == c; p++) ;
-
- if (p != strg)
- do {
- *(strg++) = *p;
- } while (*(p++)); /* enddo */
-
- } else // OP_RTRIM:
- for (p = strg + len - 1; *p == c && p >= strg; p--)
- *p = '\0';
-
- } // endif len
-
- } else if (op == OP_LPAD || op == OP_RPAD ||
- op == OP_LJUST || op == OP_RJUST || op == OP_CJUST) {
- /*******************************************************************/
- /* Pad and justify functions have 3 arguments char, NUM and C. */
- /*******************************************************************/
- PSZ strg;
- int i, n1, n2, len;
- int n = 0;
- char buf[32], c = ' ';
-
- assert(np > 0);
-
- strg = vp[0]->GetCharString(buf);
- len = strlen(strg);
- strg = strcpy(Strp, strg);
-
- if (np > 1) {
- n = vp[1]->GetIntValue();
-
- if (n > Len) {
- sprintf(g->Message, MSG(OP_RES_TOO_LONG), op);
- return true;
- } // endif
-
- if (np > 2) {
- // Character value may have been entered as an integer
- if (vp[2]->GetType() == TYPE_INT)
- c = (char)vp[2]->GetIntValue();
- else if (IsTypeChar(vp[2]->GetType()))
- c = *vp[2]->GetCharValue();
- else {
- strcpy(g->Message, MSG(BAD_PAD_ARGTYP));
- return true;
- } // endelse
-
- } // endif 3 args
-
- } // endif 2 args
-
- if (n == 0)
- n = Len;
-
- if ((n = (n - (int)len)) > 0) {
- switch (op) {
- case OP_RPAD:
- case OP_LJUST:
- n1 = 0;
- n2 = (int)n;
- break;
- case OP_LPAD:
- case OP_RJUST:
- n1 = (int)n;
- n2 = 0;
- break;
- case OP_CJUST:
- n1 = (int)n / 2;
- n2 = (int)n - n1;
- break;
- default:
- sprintf(g->Message, MSG(INVALID_OPER), op, "Compute");
- return true;
- } // endswitch op
-
- if (n1 > 0) {
- for (i = len; i >= 0; i--)
- *(strg + i + n1) = *(strg + i);
-
- for (i = 0; i < n1; i++)
- *(strg + i) = c;
-
- len += n1;
- } // endif n1
-
- if (n2 > 0) {
- for (i = len; i < len + n2; i++)
- *(strg + i) = c;
-
- *(strg + len + n2) = '\0';
- } // endif n2
-
- } // endif n
-
- if (trace)
- htrc(" function result=%s\n", strg);
-
- } else if (op == OP_SNDX) {
- /*******************************************************************/
- /* SOUNDEX function: one string argument. */
- /* In addition to Knuth standard algorithm, we accept and ignore */
- /* all non alpha characters. */
- /*******************************************************************/
- static int t[27] =
- {0,1,2,3,0,1,2,0,0,2,2,4,5,5,0,1,2,6,2,3,0,1,0,2,0,2,0};
- // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [
- char *p, s[65];
- int i, n;
- bool b = false;
-
- assert(np == 1);
-
- p = vp[0]->GetCharValue();
-
- for (i = 0; i < 64; p++)
- if (isalpha(*p)) {
- s[i++] = toupper(*p);
- b = true;
- } else if (!*p)
- break;
- else
- s[i++] = 'Z' + 1;
-
- if (b) {
- s[i] = '\0';
- Strp[0] = *s;
- } else {
- strcpy(Strp, " "); // Null string
- return false;
- } // endif i
-
- for (i = 1, p = s + 1; *p && i < 4; p++)
- if ((n = t[*p - 'A'])) {
- Strp[i] = '0' + n;
-
- if (!b || Strp[i] != Strp[i - 1]) {
- b = true;
- i++;
- } // endif dup
-
- } else
- b = false;
-
- for (; i < 4; i++)
- Strp[i] = '0';
-
-// Strp[4] = '\0';
- } else {
- /*******************************************************************/
- /* All other functions have STRING parameter(s). */
- /*******************************************************************/
- char *p[3], val[3][32];
- int i;
-
- for (i = 0; i < np; i++)
- p[i] = vp[i]->GetCharString(val[i]);
-
- switch (op) {
- case OP_LOWER:
- assert(np == 1);
- strlwr(strcpy(Strp, p[0]));
- break;
- case OP_UPPER:
- assert(np == 1);
- strupr(strcpy(Strp, p[0]));
- break;
- case OP_CNC:
- assert(np == 2);
- strncat(strncpy(Strp, p[0], Len), p[1], Len);
- break;
- case OP_MIN:
- assert(np == 2);
- strcpy(Strp, (strcmp(p[0], p[1]) < 0) ? p[0] : p[1]);
- break;
- case OP_MAX:
- assert(np == 2);
- strcpy(Strp, (strcmp(p[0], p[1]) > 0) ? p[0] : p[1]);
- break;
- case OP_REPL:
- {char *pp;
- int i, len;
-
- if (np == 2) {
- p[2] = "";
- np = 3;
- } else
- assert(np == 3);
-
- if ((len = strlen(p[1]))) {
- *Strp = '\0';
-
- do {
- if ((pp = strstr(p[0], p[1]))) {
- i = strlen(Strp) + (pp - p[0]) + strlen(p[2]);
-
- if (i > Len) {
- if (trace)
- htrc(" error len=%d R_Length=%d\n", i, Len);
-
- sprintf(g->Message, MSG(OP_RES_TOO_LONG), op);
- return true;
- } // endif
-
- strncat(Strp, p[0], pp - p[0]);
- strcat(Strp, p[2]);
- p[0] = pp + len;
- } else
- strcat(Strp, p[0]);
-
- } while (pp); // enddo
-
- } else
- strcpy(Strp, p[0]);
-
- }break;
- case OP_TRANSL:
- {unsigned char *p0, *p1, *p2, cp[256];
- unsigned int k, n = strlen(p[1]);
-
- assert(np == 3 && n == strlen(p[2]));
-
- p0 = (unsigned char *)p[0];
- p1 = (unsigned char *)p[1];
- p2 = (unsigned char *)p[2];
-
- for (k = 0; k < 256; k++)
- cp[k] = k;
-
- for (k = 0; k < n; k++)
- cp[p1[k]] = p2[k];
-
- for (k = 0; k < strlen(p[0]); k++)
- Strp[k] = cp[p0[k]];
-
- Strp[k] = 0;
- }break;
- case OP_FDISK:
- case OP_FPATH:
- case OP_FNAME:
- case OP_FTYPE:
-// if (!ExtractFromPath(g, Strp, p[0], op))
-// return true;
-
-// break;
- default:
- sprintf(g->Message, MSG(BAD_EXP_OPER), op);
- return true;
- } // endswitch op
-
- if (trace) {
- htrc("Compute result=%s val=%s", Strp, p[0]);
-
- for (i = 1; i < np; i++)
- htrc(",%s", p[i]);
-
- htrc(" op=%d\n", op);
- } // endif trace
-
- } // endif op
-
- return false;
- } // end of Compute
-
-/***********************************************************************/
-/* GetTime: extract the time from a string of format hh:mm:ss */
-/***********************************************************************/
-int STRING::GetTime(PGLOBAL g, PVAL *vp, int np)
- {
- int hh, mm, ss;
-
- hh = mm = ss = 0;
- sscanf(Strp, " %d : %d : %d", &hh, &mm, &ss);
- return ((hh * 3600) + (mm * 60) + ss);
- } // end of GetTime
-
-/***********************************************************************/
-/* FormatValue: This function set vp (a STRING value) to the string */
-/* constructed from its own value formated using the fmt format. */
-/* This function assumes that the format matches the value type. */
-/***********************************************************************/
-bool STRING::FormatValue(PVAL vp, char *fmt)
- {
- char *buf = (char*)vp->GetTo_Val(); // Should be big enough
- int n = sprintf(buf, fmt, Strp);
-
- return (n > vp->GetValLen());
- } // end of FormatValue
-
-/***********************************************************************/
-/* SetMin: used by the aggregate function MIN. */
-/***********************************************************************/
-void STRING::SetMin(PVAL vp)
- {
- char *val = vp->GetCharValue();
-
- assert(strlen(val) <= (unsigned)Len);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
- strcpy(Strp, val);
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void STRING::SetMin(PVBLK vbp, int i)
- {
- char *val = vbp->GetCharValue(i);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
- strcpy(Strp, val);
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void STRING::SetMin(PVBLK vbp, int j, int k)
- {
- char *val;
-
- for (register int i = j; i < k; i++) {
- val = vbp->GetCharValue(i);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
- strcpy(Strp, val);
-
- } // endfor i
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void STRING::SetMin(PVBLK vbp, int *x, int j, int k)
- {
- char *val;
-
- for (register int i = j; i < k; i++) {
- val = vbp->GetCharValue(x[i]);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
- strcpy(Strp, val);
-
- } // endfor i
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMax: used by the aggregate function MAX. */
-/***********************************************************************/
-void STRING::SetMax(PVAL vp)
- {
- char *val = vp->GetCharValue();
-
- assert(strlen(val) <= (unsigned)Len);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
- strcpy(Strp, val);
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void STRING::SetMax(PVBLK vbp, int i)
- {
- char *val = vbp->GetCharValue(i);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
- strcpy(Strp, val);
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void STRING::SetMax(PVBLK vbp, int j, int k)
- {
- char *val;
-
- for (register int i = j; i < k; i++) {
- val = vbp->GetCharValue(i);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
- strcpy(Strp, val);
-
- } // endfor i
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void STRING::SetMax(PVBLK vbp, int *x, int j, int k)
- {
- char *val;
-
- for (register int i = j; i < k; i++) {
- val = vbp->GetCharValue(x[i]);
-
- if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
- strcpy(Strp, val);
-
- } // endfor i
-
- } // end of SetMax
-
-/***********************************************************************/
-/* STRING SetFormat function (used to set SELECT output format). */
-/***********************************************************************/
-bool STRING::SetConstFormat(PGLOBAL g, FORMAT& fmt)
- {
- fmt.Type[0] = 'C';
- fmt.Length = Len;
- fmt.Prec = 0;
- return false;
- } // end of SetConstFormat
-
-/***********************************************************************/
-/* Make file output of a STRING object. */
-/***********************************************************************/
-void STRING::Print(PGLOBAL g, FILE *f, uint n)
- {
- char m[64];
-
- memset(m, ' ', n); /* Make margin string */
- m[n] = '\0';
-
- fprintf(f, "%s%s\n", m, Strp);
- } // end of Print
-
-/***********************************************************************/
-/* Make string output of a STRING object. */
-/***********************************************************************/
-void STRING::Print(PGLOBAL g, char *ps, uint z)
- {
- sprintf(ps, "'%.*s'", z-3, Strp);
- } // end of Print
-
-/* -------------------------- Class SHVAL ---------------------------- */
-
-/***********************************************************************/
-/* SHVAL public constructor from char. */
-/***********************************************************************/
-SHVAL::SHVAL(PSZ s) : VALUE(TYPE_SHORT)
- {
- Sval = atoi(s);
- Clen = sizeof(short);
- } // end of SHVAL constructor
-
-/***********************************************************************/
-/* SHVAL public constructor from short. */
-/***********************************************************************/
-SHVAL::SHVAL(short i) : VALUE(TYPE_SHORT)
- {
- Sval = i;
- Clen = sizeof(short);
- } // end of SHVAL constructor
-
-/***********************************************************************/
-/* SHVAL public constructor from int. */
-/***********************************************************************/
-SHVAL::SHVAL(int n) : VALUE(TYPE_SHORT)
- {
- Sval = (short)n;
- Clen = sizeof(short);
- } // end of SHVAL constructor
-
-/***********************************************************************/
-/* SHVAL public constructor from big int. */
-/***********************************************************************/
-SHVAL::SHVAL(longlong n) : VALUE(TYPE_SHORT)
- {
- Sval = (short)n;
- Clen = sizeof(short);
- } // end of SHVAL constructor
-
-/***********************************************************************/
-/* SHVAL public constructor from double. */
-/***********************************************************************/
-SHVAL::SHVAL(double f) : VALUE(TYPE_SHORT)
- {
- Sval = (short)f;
- Clen = sizeof(short);
- } // end of SHVAL constructor
-
-/***********************************************************************/
-/* SHVAL GetValLen: returns the print length of the short object. */
-/***********************************************************************/
-int SHVAL::GetValLen(void)
- {
- char c[16];
-
- return sprintf(c, "%hd", Sval);
- } // end of GetValLen
-
-/***********************************************************************/
-/* SHVAL SetValue: copy the value of another Value object. */
-/* This function allows conversion if chktype is false. */
-/***********************************************************************/
-bool SHVAL::SetValue_pval(PVAL valp, bool chktype)
- {
- if (chktype && Type != valp->GetType())
- return true;
-
- Sval = valp->GetShortValue();
- return false;
- } // end of SetValue
-
-/***********************************************************************/
-/* SHVAL SetValue: convert chars extracted from a line to short value */
-/***********************************************************************/
-void SHVAL::SetValue_char(char *p, int n)
- {
- char *p2;
- bool minus;
-
-// if (trace) wrong because p can be not null terminated
-// htrc("SHVAL_char: p='%s' n=%d\n", p, n);
-
- for (p2 = p + n; p < p2 && *p == ' '; p++) ;
-
- for (Sval = 0, minus = false; p < p2; p++)
- switch (*p) {
- case '-':
- minus = true;
- case '+':
- break;
- case '0': Sval = Sval * 10; break;
- case '1': Sval = Sval * 10 + 1; break;
- case '2': Sval = Sval * 10 + 2; break;
- case '3': Sval = Sval * 10 + 3; break;
- case '4': Sval = Sval * 10 + 4; break;
- case '5': Sval = Sval * 10 + 5; break;
- case '6': Sval = Sval * 10 + 6; break;
- case '7': Sval = Sval * 10 + 7; break;
- case '8': Sval = Sval * 10 + 8; break;
- case '9': Sval = Sval * 10 + 9; break;
- default:
- p = p2;
- } // endswitch *p
-
- if (minus && Sval)
- Sval = - Sval;
-
- if (trace)
- htrc(" setting short to: %hd\n", Sval);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* SHVAL SetValue: fill a short value from a string. */
-/***********************************************************************/
-void SHVAL::SetValue_psz(PSZ s)
- {
- Sval = atoi(s);
- } // end of SetValue
-
-/***********************************************************************/
-/* SHVAL SetValue: set value with a short extracted from a block. */
-/***********************************************************************/
-void SHVAL::SetValue_pvblk(PVBLK blk, int n)
- {
- Sval = blk->GetShortValue(n);
- } // end of SetValue
-
-/***********************************************************************/
-/* SHVAL SetBinValue: with bytes extracted from a line. */
-/***********************************************************************/
-void SHVAL::SetBinValue(void *p)
- {
- Sval = *(short *)p;
- } // end of SetBinValue
-
-/***********************************************************************/
-/* GetBinValue: fill a buffer with the internal binary value. */
-/* This function checks whether the buffer length is enough and */
-/* returns true if not. Actual filling occurs only if go is true. */
-/* Currently used by WriteColumn of binary files. */
-/***********************************************************************/
-bool SHVAL::GetBinValue(void *buf, int buflen, bool go)
- {
- // Test on length was removed here until a variable in column give the
- // real field length. For BIN files the field length logically cannot
- // be different from the variable length because no conversion is done.
- // Therefore this test is useless anyway.
-//#if defined(_DEBUG)
-// if (sizeof(short) > buflen)
-// return true;
-//#endif
-
- if (go)
- *(short *)buf = Sval;
-
- return false;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
-/* This is a fast implementation that does not do any checking. */
-/***********************************************************************/
-void SHVAL::GetBinValue(void *buf, int buflen)
- {
- assert(buflen == sizeof(short));
-
- *(short *)buf = Sval;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* SHVAL ShowValue: get string representation of a short value. */
-/***********************************************************************/
-char *SHVAL::ShowValue(char *buf, int len)
- {
- sprintf(buf, "%*hd", len, Sval);
- return buf;
- } // end of ShowValue
-
-/***********************************************************************/
-/* SHVAL GetCharString: get string representation of a short value. */
-/***********************************************************************/
-char *SHVAL::GetCharString(char *p)
- {
- sprintf(p, "%hd", Sval);
- return p;
- } // end of GetCharString
-
-/***********************************************************************/
-/* SHVAL GetShortString: get short representation of a short value. */
-/***********************************************************************/
-char *SHVAL::GetShortString(char *p, int n)
- {
- sprintf(p, "%*hd", n, Sval);
- return p;
- } // end of GetShortString
-
-/***********************************************************************/
-/* SHVAL GetIntString: get int representation of a short value. */
-/***********************************************************************/
-char *SHVAL::GetIntString(char *p, int n)
- {
- sprintf(p, "%*d", n, (int)Sval);
- return p;
- } // end of GetIntString
-
-/***********************************************************************/
-/* SHVAL GetBigintString: get big int representation of a short value.*/
-/***********************************************************************/
-char *SHVAL::GetBigintString(char *p, int n)
- {
- sprintf(p, "%*lld", n, (longlong)Sval);
- return p;
- } // end of GetBigintString
-
-/***********************************************************************/
-/* SHVAL GetFloatString: get double representation of a short value. */
-/***********************************************************************/
-char *SHVAL::GetFloatString(char *p, int n, int prec)
- {
- sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Sval);
- return p;
- } // end of GetFloatString
-
-/***********************************************************************/
-/* SHVAL compare value with another Value. */
-/***********************************************************************/
-bool SHVAL::IsEqual(PVAL vp, bool chktype)
- {
- if (this == vp)
- return true;
- else if (chktype && Type != vp->GetType())
- return false;
- else
- return (Sval == vp->GetShortValue());
-
- } // end of IsEqual
-
-/***********************************************************************/
-/* Compare values and returns 1, 0 or -1 according to comparison. */
-/* This function is used for evaluation of short integer filters. */
-/***********************************************************************/
-int SHVAL::CompareValue(PVAL vp)
- {
-//assert(vp->GetType() == Type);
-
- // Process filtering on short integers.
- short n = vp->GetShortValue();
-
- if (trace > 1)
- htrc(" Comparing: val=%hd,%hd\n", Sval, n);
-
- return (Sval > n) ? 1 : (Sval < n) ? (-1) : 0;
- } // end of CompareValue
-
-/***********************************************************************/
-/* SafeAdd: adds a value and test whether overflow/underflow occured. */
-/***********************************************************************/
-short SHVAL::SafeAdd(short n1, short n2)
- {
- PGLOBAL& g = Global;
- short n = n1 + n2;
-
- if ((n2 > 0) && (n < n1)) {
- // Overflow
- strcpy(g->Message, MSG(FIX_OVFLW_ADD));
- longjmp(g->jumper[g->jump_level], 138);
- } else if ((n2 < 0) && (n > n1)) {
- // Underflow
- strcpy(g->Message, MSG(FIX_UNFLW_ADD));
- longjmp(g->jumper[g->jump_level], 138);
- } // endif's n2
-
- return n;
- } // end of SafeAdd
-
-/***********************************************************************/
-/* SafeMult: multiply values and test whether overflow occured. */
-/***********************************************************************/
-short SHVAL::SafeMult(short n1, short n2)
- {
- PGLOBAL& g = Global;
- double n = (double)n1 * (double)n2;
-
- if (n > 32767.0) {
- // Overflow
- strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
- longjmp(g->jumper[g->jump_level], 138);
- } else if (n < -32768.0) {
- // Underflow
- strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
- longjmp(g->jumper[g->jump_level], 138);
- } // endif's n2
-
- return (short)n;
- } // end of SafeMult
-
-/***********************************************************************/
-/* Compute a function on a int integers. */
-/***********************************************************************/
-bool SHVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
- {
- if (op == OP_LEN) {
- assert(np == 1);
- char buf[32];
- char *p = vp[0]->GetCharString(buf);
-
- Sval = strlen(p);
-
- if (trace)
- htrc("Compute result=%hd val=%s op=%d\n", Sval, p, op);
-
- } else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
- char *p, *tp = g->Message;
- char *p1, val1[32];
- char *p2, val2[32];
- bool b = (vp[0]->IsCi() || vp[1]->IsCi());
-
- assert(np == 2);
-
- p1 = vp[0]->GetCharString(val1);
- p2 = vp[1]->GetCharString(val2);
-
- if (op != OP_LIKE) {
- if (!strcmp(p2, "\\t"))
- p2 = "\t";
-
- if (b) { // Case insensitive
- if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
- !(tp = new char[strlen(p1) + strlen(p2) + 2])) {
- strcpy(g->Message, MSG(NEW_RETURN_NULL));
- return true;
- } // endif p
-
- // Make a lower case copy of p1 and p2
- p1 = strlwr(strcpy(tp, p1));
- p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
- } // endif Ci
-
- if (op == OP_CNTIN) {
- size_t t2 = strlen(p2);
-
- for (Sval = 0; (p = strstr(p1, p2)); Sval++, p1 = p + t2) ;
-
- } else // OP_INSTR
- Sval = (p = strstr(p1, p2)) ? 1 + (short)(p - p1) : 0;
-
- if (tp != g->Message) // If working space was obtained
- delete [] tp; // by the use of new, delete it.
-
- } else // OP_LIKE
- Sval = (PlugEvalLike(g, p1, p2, b)) ? 1 : 0;
-
-
- if (trace)
- htrc("Compute result=%hd val=%s,%s op=%d\n", Sval, p1, p2, op);
-
- } else {
- short val[2];
-
- assert(np <= 2);
-
- for (int i = 0; i < np; i++)
- val[i] = vp[i]->GetShortValue();
-
- switch (op) {
- case OP_ABS:
- assert(np == 1);
- Sval = abs(*val);
- break;
- case OP_SIGN:
- assert(np == 1);
- Sval = (*val < 0) ? (-1) : 1;
- break;
- case OP_CEIL:
- case OP_FLOOR:
- assert(np == 1);
- Sval = *val;
- break;
- case OP_ADD:
- assert(np == 2);
- Sval = SafeAdd(val[0], val[1]);
- break;
- case OP_SUB:
- assert(np == 2);
- Sval = SafeAdd(val[0], -val[1]);
- break;
- case OP_MULT:
- assert(np == 2);
- Sval = SafeMult(val[0], val[1]);
- break;
- case OP_MIN:
- assert(np == 2);
- Sval = min(val[0], val[1]);
- break;
- case OP_MAX:
- assert(np == 2);
- Sval = max(val[0], val[1]);
- break;
- case OP_DIV:
- assert(np == 2);
-
- if (!val[1]) {
- strcpy(g->Message, MSG(ZERO_DIVIDE));
- return true;
- } // endif
-
- Sval = val[0] / val[1];
- break;
- case OP_MOD:
- assert(np == 2);
-
- if (!val[1]) {
- strcpy(g->Message, MSG(ZERO_DIVIDE));
- return true;
- } // endif
-
- Sval = val[0] % val[1];
- break;
- case OP_BITAND:
- assert(np == 2);
- Sval = val[0] & val[1];
- break;
- case OP_BITOR:
- assert(np == 2);
- Sval = val[0] | val[1];
- break;
- case OP_BITXOR:
- assert(np == 2);
- Sval = val[0] ^ val[1];
- break;
- case OP_BITNOT:
- assert(np == 1);
- Sval = ~val[0];
- break;
- case OP_DELTA:
-// assert(np == 1);
- Sval = val[0] - Sval;
- break;
- default:
- sprintf(g->Message, MSG(BAD_EXP_OPER), op);
- return true;
- } // endswitch op
-
- if (trace) {
- if (np = 1)
- htrc(" result=%hd val=%hd op=%d\n", Sval, val[0], op);
- else
- htrc(" result=%hd val=%hd,%hd op=%d\n",
- Sval, val[0], val[1], op);
- } // endif trace
-
- } // endif op
-
- return false;
- } // end of Compute
-
-/***********************************************************************/
-/* Divide: used by aggregate functions when calculating average. */
-/***********************************************************************/
-void SHVAL::Divide(int cnt)
- {
- Sval /= (short)cnt;
- } // end of Divide
-
-/***********************************************************************/
-/* StdVar: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void SHVAL::StdVar(PVAL vp, int cnt, bool b)
- {
- short lv2 = vp->GetShortValue(), scnt = (short)cnt;
-
- Sval = (scnt == 1) ? 0
- : (SafeAdd(lv2, -(SafeMult(Sval, Sval) / scnt)) / (scnt - 1));
-
- if (b) // Builtin == FNC_STDDEV
- Sval = (short)sqrt((double)Sval);
-
- } // end of StdVar
-
-/***********************************************************************/
-/* Times: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void SHVAL::Times(PVAL vp)
- {
- Sval = SafeMult(Sval, vp->GetShortValue());
- } // end of Times
-
-/***********************************************************************/
-/* Add: used by aggregate functions for Sum and other functions. */
-/***********************************************************************/
-void SHVAL::Add(PVAL vp)
- {
- Sval = SafeAdd(Sval, vp->GetShortValue());
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void SHVAL::Add(PVBLK vbp, int i)
- {
- Sval = SafeAdd(Sval, vbp->GetShortValue(i));
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void SHVAL::Add(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- short *lp = (short *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Sval = SafeAdd(Sval, lp[i]);
-
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void SHVAL::Add(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- short *lp = (short *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Sval = SafeAdd(Sval, lp[x[i]]);
-
- } // end of Add
-
-/***********************************************************************/
-/* AddSquare: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void SHVAL::AddSquare(PVAL vp)
- {
- short val = vp->GetShortValue();
-
- Sval = SafeAdd(Sval, SafeMult(val, val));
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by QUERY for functions Stddev and Variance. */
-/***********************************************************************/
-void SHVAL::AddSquare(PVBLK vbp, int i)
- {
- short val = vbp->GetShortValue(i);
-
- Sval = SafeAdd(Sval, SafeMult(val, val));
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by QUERY for functions Stddev and Variance. */
-/***********************************************************************/
-void SHVAL::AddSquare(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- short *lp = (short *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Sval = SafeAdd(Sval, SafeMult(lp[i], lp[i]));
-
- } // end of AddSquare
-
-/***********************************************************************/
-/* FormatValue: This function set vp (a STRING value) to the string */
-/* constructed from its own value formated using the fmt format. */
-/* This function assumes that the format matches the value type. */
-/***********************************************************************/
-bool SHVAL::FormatValue(PVAL vp, char *fmt)
- {
- char *buf = (char*)vp->GetTo_Val(); // Should be big enough
- int n = sprintf(buf, fmt, Sval);
-
- return (n > vp->GetValLen());
- } // end of FormatValue
-
-/***********************************************************************/
-/* SetMin: used by the aggregate function MIN. */
-/***********************************************************************/
-void SHVAL::SetMin(PVAL vp)
- {
- short val = vp->GetShortValue();
-
- if (val < Sval)
- Sval = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void SHVAL::SetMin(PVBLK vbp, int i)
- {
- short val = vbp->GetShortValue(i);
-
- if (val < Sval)
- Sval = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void SHVAL::SetMin(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- short *lp = (short *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (lp[i] < Sval)
- Sval = lp[i];
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void SHVAL::SetMin(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- short val;
- short *lp = (short *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = lp[x[i]];
-
- if (val < Sval)
- Sval = val;
-
- } // endfor i
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMax: used by the aggregate function MAX. */
-/***********************************************************************/
-void SHVAL::SetMax(PVAL vp)
- {
- short val = vp->GetShortValue();
-
- if (val > Sval)
- Sval = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void SHVAL::SetMax(PVBLK vbp, int i)
- {
- short val = vbp->GetShortValue(i);
-
- if (val > Sval)
- Sval = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void SHVAL::SetMax(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- short *lp = (short *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (lp[i] > Sval)
- Sval = lp[i];
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void SHVAL::SetMax(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- short val;
- short *lp = (short *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = lp[x[i]];
-
- if (val > Sval)
- Sval = val;
-
- } // endfor i
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SHVAL SetFormat function (used to set SELECT output format). */
-/***********************************************************************/
-bool SHVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
- {
- char c[16];
-
- fmt.Type[0] = 'S';
- fmt.Length = sprintf(c, "%hd", Sval);
- fmt.Prec = 0;
- return false;
- } // end of SetConstFormat
-
-/***********************************************************************/
-/* Make file output of a short object. */
-/***********************************************************************/
-void SHVAL::Print(PGLOBAL g, FILE *f, uint n)
- {
- char m[64];
-
- memset(m, ' ', n); /* Make margin string */
- m[n] = '\0';
-
- fprintf(f, "%s%hd\n", m, Sval);
- } /* end of Print */
-
-/***********************************************************************/
-/* Make string output of a short object. */
-/***********************************************************************/
-void SHVAL::Print(PGLOBAL g, char *ps, uint z)
- {
- sprintf(ps, "%hd", Sval);
- } /* end of Print */
-
-/* -------------------------- Class INTVAL ---------------------------- */
-
-/***********************************************************************/
-/* INTVAL public constructor from char. */
-/***********************************************************************/
-INTVAL::INTVAL(PSZ s) : VALUE(TYPE_INT)
- {
- Ival = atol(s);
- Clen = sizeof(int);
- } // end of INTVAL constructor
-
-/***********************************************************************/
-/* INTVAL public constructor from short. */
-/***********************************************************************/
-INTVAL::INTVAL(short n) : VALUE(TYPE_INT)
- {
- Ival = (int)n;
- Clen = sizeof(int);
- } // end of INTVAL constructor
-
-/***********************************************************************/
-/* INTVAL public constructor from int. */
-/***********************************************************************/
-INTVAL::INTVAL(int n) : VALUE(TYPE_INT)
- {
- Ival = n;
- Clen = sizeof(int);
- } // end of INTVAL constructor
-
-/***********************************************************************/
-/* INTVAL public constructor from big int. */
-/***********************************************************************/
-INTVAL::INTVAL(longlong n) : VALUE(TYPE_INT)
- {
- Ival = (int)n;
- Clen = sizeof(int);
- } // end of INTVAL constructor
-
-/***********************************************************************/
-/* INTVAL public constructor from double. */
-/***********************************************************************/
-INTVAL::INTVAL(double f) : VALUE(TYPE_INT)
- {
- Ival = (int)f;
- Clen = sizeof(int);
- } // end of INTVAL constructor
-
-/***********************************************************************/
-/* INTVAL GetValLen: returns the print length of the int object. */
-/***********************************************************************/
-int INTVAL::GetValLen(void)
- {
- char c[16];
-
- return sprintf(c, "%d", Ival);
- } // end of GetValLen
-
-/***********************************************************************/
-/* INTVAL SetValue: copy the value of another Value object. */
-/* This function allows conversion if chktype is false. */
-/***********************************************************************/
-bool INTVAL::SetValue_pval(PVAL valp, bool chktype)
- {
- if (chktype && Type != valp->GetType())
- return true;
-
- Ival = valp->GetIntValue();
- return false;
- } // end of SetValue
-
-/***********************************************************************/
-/* INTVAL SetValue: convert chars extracted from a line to int value. */
-/***********************************************************************/
-void INTVAL::SetValue_char(char *p, int n)
- {
- char *p2;
- bool minus;
-
- for (p2 = p + n; p < p2 && *p == ' '; p++) ;
-
- for (Ival = 0, minus = false; p < p2; p++)
- switch (*p) {
- case '-':
- minus = true;
- case '+':
- break;
- case '0': Ival = Ival * 10; break;
- case '1': Ival = Ival * 10 + 1; break;
- case '2': Ival = Ival * 10 + 2; break;
- case '3': Ival = Ival * 10 + 3; break;
- case '4': Ival = Ival * 10 + 4; break;
- case '5': Ival = Ival * 10 + 5; break;
- case '6': Ival = Ival * 10 + 6; break;
- case '7': Ival = Ival * 10 + 7; break;
- case '8': Ival = Ival * 10 + 8; break;
- case '9': Ival = Ival * 10 + 9; break;
- default:
- p = p2;
- } // endswitch *p
-
- if (minus && Ival)
- Ival = - Ival;
-
- if (trace)
- htrc(" setting int to: %d\n", Ival);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* INTVAL SetValue: fill a int value from a string. */
-/***********************************************************************/
-void INTVAL::SetValue_psz(PSZ s)
- {
- Ival = atol(s);
- } // end of SetValue
-
-/***********************************************************************/
-/* INTVAL SetValue: set value with a int extracted from a block. */
-/***********************************************************************/
-void INTVAL::SetValue_pvblk(PVBLK blk, int n)
- {
- Ival = blk->GetIntValue(n);
- } // end of SetValue
-
-/***********************************************************************/
-/* INTVAL SetBinValue: with bytes extracted from a line. */
-/***********************************************************************/
-void INTVAL::SetBinValue(void *p)
- {
- Ival = *(int *)p;
- } // end of SetBinValue
-
-/***********************************************************************/
-/* GetBinValue: fill a buffer with the internal binary value. */
-/* This function checks whether the buffer length is enough and */
-/* returns true if not. Actual filling occurs only if go is true. */
-/* Currently used by WriteColumn of binary files. */
-/***********************************************************************/
-bool INTVAL::GetBinValue(void *buf, int buflen, bool go)
- {
- // Test on length was removed here until a variable in column give the
- // real field length. For BIN files the field length logically cannot
- // be different from the variable length because no conversion is done.
- // Therefore this test is useless anyway.
-//#if defined(_DEBUG)
-// if (sizeof(int) > buflen)
-// return true;
-//#endif
-
- if (go)
- *(int *)buf = Ival;
-
- return false;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
-/* This is a fast implementation that does not do any checking. */
-/***********************************************************************/
-void INTVAL::GetBinValue(void *buf, int buflen)
- {
- assert(buflen == sizeof(int));
-
- *(int *)buf = Ival;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* INTVAL ShowValue: get string representation of a int value. */
-/***********************************************************************/
-char *INTVAL::ShowValue(char *buf, int len)
- {
- sprintf(buf, "%*d", len, Ival);
- return buf;
- } // end of ShowValue
-
-/***********************************************************************/
-/* INTVAL GetCharString: get string representation of a int value. */
-/***********************************************************************/
-char *INTVAL::GetCharString(char *p)
- {
- sprintf(p, "%d", Ival);
- return p;
- } // end of GetCharString
-
-/***********************************************************************/
-/* INTVAL GetShortString: get short representation of a int value. */
-/***********************************************************************/
-char *INTVAL::GetShortString(char *p, int n)
- {
- sprintf(p, "%*hd", n, (short)Ival);
- return p;
- } // end of GetShortString
-
-/***********************************************************************/
-/* INTVAL GetIntString: get int representation of a int value. */
-/***********************************************************************/
-char *INTVAL::GetIntString(char *p, int n)
- {
- sprintf(p, "%*d", n, Ival);
- return p;
- } // end of GetIntString
-
-/***********************************************************************/
-/* INTVAL GetBigintString: get big int representation of a int value. */
-/***********************************************************************/
-char *INTVAL::GetBigintString(char *p, int n)
- {
- sprintf(p, "%*lld", n, (longlong)Ival);
- return p;
- } // end of GetBigintString
-
-/***********************************************************************/
-/* INTVAL GetFloatString: get double representation of a int value. */
-/***********************************************************************/
-char *INTVAL::GetFloatString(char *p, int n, int prec)
- {
- sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Ival);
- return p;
- } // end of GetFloatString
-
-/***********************************************************************/
-/* INTVAL compare value with another Value. */
-/***********************************************************************/
-bool INTVAL::IsEqual(PVAL vp, bool chktype)
- {
- if (this == vp)
- return true;
- else if (chktype && Type != vp->GetType())
- return false;
- else
- return (Ival == vp->GetIntValue());
-
- } // end of IsEqual
-
-/***********************************************************************/
-/* Compare values and returns 1, 0 or -1 according to comparison. */
-/* This function is used for evaluation of int integer filters. */
-/***********************************************************************/
-int INTVAL::CompareValue(PVAL vp)
- {
-//assert(vp->GetType() == Type);
-
- // Process filtering on int integers.
- int n = vp->GetIntValue();
-
- if (trace > 1)
- htrc(" Comparing: val=%d,%d\n", Ival, n);
-
- return (Ival > n) ? 1 : (Ival < n) ? (-1) : 0;
- } // end of CompareValue
-
-/***********************************************************************/
-/* SafeAdd: adds a value and test whether overflow/underflow occured. */
-/***********************************************************************/
-int INTVAL::SafeAdd(int n1, int n2)
- {
- PGLOBAL& g = Global;
- int n = n1 + n2;
-
- if ((n2 > 0) && (n < n1)) {
- // Overflow
- strcpy(g->Message, MSG(FIX_OVFLW_ADD));
- longjmp(g->jumper[g->jump_level], 138);
- } else if ((n2 < 0) && (n > n1)) {
- // Underflow
- strcpy(g->Message, MSG(FIX_UNFLW_ADD));
- longjmp(g->jumper[g->jump_level], 138);
- } // endif's n2
-
- return n;
- } // end of SafeAdd
-
-/***********************************************************************/
-/* SafeMult: multiply values and test whether overflow occured. */
-/***********************************************************************/
-int INTVAL::SafeMult(int n1, int n2)
- {
- PGLOBAL& g = Global;
- double n = (double)n1 * (double)n2;
-
- if (n > 2147483647.0) {
- // Overflow
- strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
- longjmp(g->jumper[g->jump_level], 138);
- } else if (n < -2147483648.0) {
- // Underflow
- strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
- longjmp(g->jumper[g->jump_level], 138);
- } // endif's n2
-
- return (int)n;
- } // end of SafeMult
-
-/***********************************************************************/
-/* Compute a function on a int integers. */
-/***********************************************************************/
-bool INTVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
- {
- if (op == OP_LEN) {
- assert(np == 1);
- char buf[32];
- char *p = vp[0]->GetCharString(buf);
-
- Ival = strlen(p);
-
- if (trace)
- htrc("Compute result=%d val=%s op=%d\n", Ival, p, op);
-
- } else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
- char *p, *tp = g->Message;
- char *p1, val1[32];
- char *p2, val2[32];
- bool b = (vp[0]->IsCi() || vp[1]->IsCi());
-
- assert(np == 2);
-
- p1 = vp[0]->GetCharString(val1);
- p2 = vp[1]->GetCharString(val2);
-
- if (op != OP_LIKE) {
- if (!strcmp(p2, "\\t"))
- p2 = "\t";
-
- if (b) { // Case insensitive
- if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
- !(tp = new char[strlen(p1) + strlen(p2) + 2])) {
- strcpy(g->Message, MSG(NEW_RETURN_NULL));
- return true;
- } // endif p
-
- // Make a lower case copy of p1 and p2
- p1 = strlwr(strcpy(tp, p1));
- p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
- } // endif b
-
- if (op == OP_CNTIN) {
- size_t t2 = strlen(p2);
-
- for (Ival = 0; (p = strstr(p1, p2)); Ival++, p1 = p + t2) ;
-
- } else // OP_INSTR
- Ival = (p = strstr(p1, p2)) ? 1 + (int)(p - p1) : 0;
-
- if (tp != g->Message) // If working space was obtained
- delete [] tp; // by the use of new, delete it.
-
- } else // OP_LIKE
- Ival = (PlugEvalLike(g, p1, p2, b)) ? 1 : 0;
-
- if (trace)
- htrc("Compute result=%d val=%s,%s op=%d\n", Ival, p1, p2, op);
-
- } else if (op == OP_MDAY || op == OP_MONTH || op == OP_YEAR ||
- op == OP_WDAY || op == OP_QUART || op == OP_YDAY) {
- assert(np == 1 && vp[0]->GetType() == TYPE_DATE);
-
- if (((DTVAL*)vp[0])->GetTmMember(op, Ival)) {
- sprintf(g->Message, MSG(COMPUTE_ERROR), op);
- return true;
- } // endif
-
- } else if (op == OP_NWEEK) {
- // Week number of the year for the internal date value
- assert((np == 1 || np == 2) && vp[0]->GetType() == TYPE_DATE);
-
- // Start of the week SUN=0, MON=1, etc.
- Ival = (np == 2) ? vp[1]->GetIntValue() : 1;
-
- // This function sets Ival to nweek
- if (((DTVAL*)vp[0])->WeekNum(g, Ival))
- return true;
-
- } else if (op == OP_DBTWN || op == OP_MBTWN || op == OP_YBTWN) {
- assert(np == 2 && vp[0]->GetType() == TYPE_DATE
- && vp[1]->GetType() == TYPE_DATE);
-
- if (((DTVAL*)vp[0])->DateDiff((DTVAL*)vp[1], op, Ival)) {
- sprintf(g->Message, MSG(COMPUTE_ERROR), op);
- return true;
- } // endif
-
- } else if (op == OP_TIME) {
- Ival = vp[0]->GetTime(g, (np == 1) ? NULL : vp + 1, np - 1);
- } else {
- int val[2];
-
- assert(np <= 2);
-
- for (int i = 0; i < np; i++)
- val[i] = vp[i]->GetIntValue();
-
- switch (op) {
- case OP_ABS:
- assert(np == 1);
- Ival = labs(*val);
- break;
- case OP_SIGN:
- assert(np == 1);
- Ival = (*val < 0) ? (-1) : 1;
- break;
- case OP_CEIL:
- case OP_FLOOR:
- assert(np == 1);
- Ival = *val;
- break;
- case OP_ADD:
- assert(np == 2);
- Ival = SafeAdd(val[0], val[1]);
- break;
- case OP_SUB:
- assert(np == 2);
- Ival = SafeAdd(val[0], -val[1]);
- break;
- case OP_MULT:
- assert(np == 2);
- Ival = SafeMult(val[0], val[1]);
- break;
- case OP_MIN:
- assert(np == 2);
- Ival = min(val[0], val[1]);
- break;
- case OP_MAX:
- assert(np == 2);
- Ival = max(val[0], val[1]);
- break;
- case OP_DIV:
- assert(np == 2);
-
- if (!val[1]) {
- strcpy(g->Message, MSG(ZERO_DIVIDE));
- return true;
- } // endif
-
- Ival = val[0] / val[1];
- break;
- case OP_MOD:
- assert(np == 2);
-
- if (!val[1]) {
- strcpy(g->Message, MSG(ZERO_DIVIDE));
- return true;
- } // endif
-
- Ival = val[0] % val[1];
- break;
- case OP_BITAND:
- assert(np == 2);
- Ival = val[0] & val[1];
- break;
- case OP_BITOR:
- assert(np == 2);
- Ival = val[0] | val[1];
- break;
- case OP_BITXOR:
- assert(np == 2);
- Ival = val[0] ^ val[1];
- break;
- case OP_BITNOT:
- assert(np == 1);
- Ival = ~val[0];
- break;
- case OP_DELTA:
-// assert(np == 1);
- Ival = val[0] - Ival;
- break;
- default:
- sprintf(g->Message, MSG(BAD_EXP_OPER), op);
- return true;
- } // endswitch op
-
- if (trace) {
- if (np = 1)
- htrc(" result=%d val=%d op=%d\n", Ival, val[0], op);
- else
- htrc(" result=%d val=%d,%d op=%d\n",
- Ival, val[0], val[1], op);
- } // endif trace
-
- } // endif op
-
- return false;
- } // end of Compute
-
-/***********************************************************************/
-/* GetTime: convert HR/MIN/SEC in a number of seconds. */
-/***********************************************************************/
-int INTVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
- {
- int sec = Ival;
-
- for (int i = 0; i < 2; i++) {
- sec *= 60;
-
- if (np > i)
- sec += vp[i]->GetIntValue();
-
- } // endfor i
-
- return sec;
- } // end of GetTime
-
-/***********************************************************************/
-/* Divide: used by aggregate functions when calculating average. */
-/***********************************************************************/
-void INTVAL::Divide(int cnt)
- {
- Ival /= cnt;
- } // end of Divide
-
-/***********************************************************************/
-/* StdVar: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void INTVAL::StdVar(PVAL vp, int cnt, bool b)
- {
- int lv2 = vp->GetIntValue();
-
- Ival = (cnt == 1) ? 0
- : (SafeAdd(lv2, -(SafeMult(Ival, Ival) / cnt)) / (cnt - 1));
-
- if (b) // Builtin == FNC_STDDEV
- Ival = (int)sqrt((double)Ival);
-
- } // end of StdVar
-
-/***********************************************************************/
-/* Times: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void INTVAL::Times(PVAL vp)
- {
- Ival = SafeMult(Ival, vp->GetIntValue());
- } // end of Times
-
-/***********************************************************************/
-/* Add: used by aggregate functions for Sum and other functions. */
-/***********************************************************************/
-void INTVAL::Add(PVAL vp)
- {
- Ival = SafeAdd(Ival, vp->GetIntValue());
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void INTVAL::Add(PVBLK vbp, int i)
- {
- Ival = SafeAdd(Ival, vbp->GetIntValue(i));
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void INTVAL::Add(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- int *lp = (int *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Ival = SafeAdd(Ival, lp[i]);
-
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void INTVAL::Add(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- int *lp = (int *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Ival = SafeAdd(Ival, lp[x[i]]);
-
- } // end of Add
-
-/***********************************************************************/
-/* AddSquare: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void INTVAL::AddSquare(PVAL vp)
- {
- int val = vp->GetIntValue();
-
- Ival = SafeAdd(Ival, SafeMult(val, val));
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by QUERY for functions Stddev and Variance. */
-/***********************************************************************/
-void INTVAL::AddSquare(PVBLK vbp, int i)
- {
- int val = vbp->GetIntValue(i);
-
- Ival = SafeAdd(Ival, SafeMult(val, val));
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by QUERY for functions Stddev and Variance. */
-/***********************************************************************/
-void INTVAL::AddSquare(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- int *lp = (int *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Ival = SafeAdd(Ival, SafeMult(lp[i], lp[i]));
-
- } // end of AddSquare
-
-/***********************************************************************/
-/* FormatValue: This function set vp (a STRING value) to the string */
-/* constructed from its own value formated using the fmt format. */
-/* This function assumes that the format matches the value type. */
-/***********************************************************************/
-bool INTVAL::FormatValue(PVAL vp, char *fmt)
- {
- char *buf = (char*)vp->GetTo_Val(); // Should be big enough
- int n = sprintf(buf, fmt, Ival);
-
- return (n > vp->GetValLen());
- } // end of FormatValue
-
-/***********************************************************************/
-/* SetMin: used by the aggregate function MIN. */
-/***********************************************************************/
-void INTVAL::SetMin(PVAL vp)
- {
- int val = vp->GetIntValue();
-
- if (val < Ival)
- Ival = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void INTVAL::SetMin(PVBLK vbp, int i)
- {
- int val = vbp->GetIntValue(i);
-
- if (val < Ival)
- Ival = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void INTVAL::SetMin(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- int *lp = (int *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (lp[i] < Ival)
- Ival = lp[i];
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void INTVAL::SetMin(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- register int val;
- int *lp = (int *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = lp[x[i]];
-
- if (val < Ival)
- Ival = val;
-
- } // endfor i
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMax: used by the aggregate function MAX. */
-/***********************************************************************/
-void INTVAL::SetMax(PVAL vp)
- {
- int val = vp->GetIntValue();
-
- if (val > Ival)
- Ival = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void INTVAL::SetMax(PVBLK vbp, int i)
- {
- int val = vbp->GetIntValue(i);
-
- if (val > Ival)
- Ival = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void INTVAL::SetMax(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- int *lp = (int *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (lp[i] > Ival)
- Ival = lp[i];
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void INTVAL::SetMax(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- register int val;
- int *lp = (int *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = lp[x[i]];
-
- if (val > Ival)
- Ival = val;
-
- } // endfor i
-
- } // end of SetMax
-
-/***********************************************************************/
-/* INTVAL SetFormat function (used to set SELECT output format). */
-/***********************************************************************/
-bool INTVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
- {
- char c[16];
-
- fmt.Type[0] = 'N';
- fmt.Length = sprintf(c, "%d", Ival);
- fmt.Prec = 0;
- return false;
- } // end of SetConstFormat
-
-/***********************************************************************/
-/* Make file output of a int object. */
-/***********************************************************************/
-void INTVAL::Print(PGLOBAL g, FILE *f, uint n)
- {
- char m[64];
-
- memset(m, ' ', n); /* Make margin string */
- m[n] = '\0';
-
- fprintf(f, "%s%d\n", m, Ival);
- } /* end of Print */
-
-/***********************************************************************/
-/* Make string output of a int object. */
-/***********************************************************************/
-void INTVAL::Print(PGLOBAL g, char *ps, uint z)
- {
- sprintf(ps, "%d", Ival);
- } /* end of Print */
-
-/* -------------------------- Class DTVAL ---------------------------- */
-
-/***********************************************************************/
-/* DTVAL public constructor for new void values. */
-/***********************************************************************/
-DTVAL::DTVAL(PGLOBAL g, int n, int prec, PSZ fmt) : INTVAL((int)0)
- {
- if (!fmt) {
- Pdtp = NULL;
- Sdate = NULL;
- DefYear = 0;
- Len = n;
- } else
- SetFormat(g, fmt, n, prec);
-
- Type = TYPE_DATE;
- } // end of DTVAL constructor
-
-/***********************************************************************/
-/* DTVAL public constructor from char. */
-/***********************************************************************/
-DTVAL::DTVAL(PGLOBAL g, PSZ s, int n) : INTVAL((s) ? s : (char *)"0")
- {
- Pdtp = NULL;
- Len = n;
- Type = TYPE_DATE;
- Sdate = NULL;
- DefYear = 0;
- } // end of DTVAL constructor
-
-/***********************************************************************/
-/* DTVAL public constructor from short. */
-/***********************************************************************/
-DTVAL::DTVAL(PGLOBAL g, short n) : INTVAL((int)n)
- {
- Pdtp = NULL;
- Len = 19;
- Type = TYPE_DATE;
- Sdate = NULL;
- DefYear = 0;
- } // end of DTVAL constructor
-
-/***********************************************************************/
-/* DTVAL public constructor from int. */
-/***********************************************************************/
-DTVAL::DTVAL(PGLOBAL g, int n) : INTVAL(n)
- {
- Pdtp = NULL;
- Len = 19;
- Type = TYPE_DATE;
- Sdate = NULL;
- DefYear = 0;
- } // end of DTVAL constructor
-
-/***********************************************************************/
-/* DTVAL public constructor from double. */
-/***********************************************************************/
-DTVAL::DTVAL(PGLOBAL g, double f) : INTVAL(f)
- {
- Pdtp = NULL;
- Len = 19;
- Type = TYPE_DATE;
- Sdate = NULL;
- DefYear = 0;
- } // end of DTVAL constructor
-
-/***********************************************************************/
-/* Set format so formatted dates can be converted on input/output. */
-/***********************************************************************/
-bool DTVAL::SetFormat(PGLOBAL g, PSZ fmt, int len, int year)
- {
- Pdtp = MakeDateFormat(g, fmt, true, true, (year > 9999) ? 1 : 0);
- Sdate = (char*)PlugSubAlloc(g, NULL, len + 1);
- DefYear = (int)((year > 9999) ? (year - 10000) : year);
- Len = len;
- return false;
- } // end of SetFormat
-
-/***********************************************************************/
-/* Set format from the format of another date value. */
-/***********************************************************************/
-bool DTVAL::SetFormat(PGLOBAL g, PVAL valp)
- {
- DTVAL *vp;
-
- if (valp->GetType() != TYPE_DATE) {
- sprintf(g->Message, MSG(NO_FORMAT_TYPE), valp->GetType());
- return true;
- } else
- vp = (DTVAL*)valp;
-
- Len = vp->Len;
- Pdtp = vp->Pdtp;
- Sdate = (char*)PlugSubAlloc(g, NULL, Len + 1);
- DefYear = vp->DefYear;
- return false;
- } // end of SetFormat
-
-/***********************************************************************/
-/* We need TimeShift because the mktime C function does a correction */
-/* for local time zone that we want to override for DB operations. */
-/***********************************************************************/
-void DTVAL::SetTimeShift(void)
- {
- struct tm dtm = {0,0,0,2,0,70,0,0,0};
-
- Shift = (int)mktime(&dtm) - 86400;
-
- if (trace)
- htrc("DTVAL Shift=%d\n", Shift);
-
- } // end of SetTimeShift
-
-/***********************************************************************/
-/* GetGmTime: returns a pointer to a static tm structure obtained */
-/* though the gmtime C function. The purpose of this function is to */
-/* extend the range of valid dates by accepting negative time values. */
-/***********************************************************************/
-struct tm *DTVAL::GetGmTime(void)
- {
- struct tm *datm;
- time_t t = (time_t)Ival;
-
- if (Ival < 0) {
- int n;
-
- for (n = 0; t < 0; n += 4)
- t += FOURYEARS;
-
- datm = gmtime(&t);
-
- if (datm)
- datm->tm_year -= n;
-
- } else
- datm = gmtime((const time_t *)&t);
-
- return datm;
- } // end of GetGmTime
-
-/***********************************************************************/
-/* MakeTime: calculates a date value from a tm structures using the */
-/* mktime C function. The purpose of this function is to extend the */
-/* range of valid dates by accepting to set negative time values. */
-/***********************************************************************/
-bool DTVAL::MakeTime(struct tm *ptm)
- {
- int n, y = ptm->tm_year;
- time_t t = mktime(ptm);
-
- if (trace)
- htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n",
- ptm->tm_year, ptm->tm_mon, ptm->tm_mday,
- ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
-
- if (t == -1) {
- if (y < 1 || y > 71)
- return true;
-
- for (n = 0; t == -1 && n < 20; n++) {
- ptm->tm_year += 4;
- t = mktime(ptm);
- } // endfor t
-
- if (t == -1)
- return true;
-
- if ((t -= (n * FOURYEARS + Shift)) > 2000000000)
- return true;
-
- Ival = (int)t;
- } else
- Ival = (int)t - Shift;
-
- if (trace)
- htrc("MakeTime Ival=%d\n", Ival);
-
- return false;
- } // end of MakeTime
-
-/***********************************************************************/
-/* Make a time_t datetime from its components (YY, MM, DD, hh, mm, ss) */
-/***********************************************************************/
-bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval)
- {
- int i, m;
- int n;
- bool rc = false;
- struct tm datm = {0,0,0,1,0,70,0,0,0};
-
- if (trace)
- htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n",
- val[0], val[1], val[2], val[3], val[4], val[5], nval);
-
- for (i = 0; i < nval; i++) {
- n = val[i];
-
-// if (trace > 1)
-// htrc("i=%d n=%d\n", i, n);
-
- switch (i) {
- case 0:
- if (n >= 1900)
- n -= 1900;
-
- datm.tm_year = n;
-
-// if (trace > 1)
-// htrc("n=%d tm_year=%d\n", n, datm.tm_year);
-
- break;
- case 1:
- // If mktime handles apparently correctly large or negative
- // day values, it is not the same for months. Therefore we
- // do the ajustment here, thus mktime has not to do it.
- if (n > 0) {
- m = (n - 1) % 12;
- n = (n - 1) / 12;
- } else {
- m = 11 + n % 12;
- n = n / 12 - 1;
- } // endfi n
-
- datm.tm_mon = m;
- datm.tm_year += n;
-
-// if (trace > 1)
-// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
-
- break;
- case 2:
- // For days, big or negative values may also cause problems
- m = n % 1461;
- n = 4 * (n / 1461);
-
- if (m < 0) {
- m += 1461;
- n -= 4;
- } // endif m
-
- datm.tm_mday = m;
- datm.tm_year += n;
-
-// if (trace > 1)
-// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
-
- break;
- case 3: datm.tm_hour = n; break;
- case 4: datm.tm_min = n; break;
- case 5: datm.tm_sec = n; break;
- } // endswitch i
-
- } // endfor i
-
- if (trace)
- htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n",
- datm.tm_year, datm.tm_mon, datm.tm_mday,
- datm.tm_hour, datm.tm_min, datm.tm_sec);
-
- // Pass g to have an error return or NULL to set invalid dates to 0
- if (MakeTime(&datm))
- if (g) {
- strcpy(g->Message, MSG(BAD_DATETIME));
- rc = true;
- } else
- Ival = 0;
-
- return rc;
- } // end of MakeDate
-
-/***********************************************************************/
-/* DTVAL SetValue: copy the value of another Value object. */
-/* This function allows conversion if chktype is false. */
-/***********************************************************************/
-bool DTVAL::SetValue_pval(PVAL valp, bool chktype)
- {
- if (chktype && Type != valp->GetType())
- return true;
-
- if (Pdtp && !valp->IsTypeNum()) {
- int ndv;
- int dval[6];
-
- ndv = ExtractDate(valp->GetCharValue(), Pdtp, DefYear, dval);
- MakeDate(NULL, dval, ndv);
- } else
- Ival = valp->GetIntValue();
-
- return false;
- } // end of SetValue
-
-/***********************************************************************/
-/* SetValue: convert chars extracted from a line to date value. */
-/***********************************************************************/
-void DTVAL::SetValue_char(char *p, int n)
- {
- if (Pdtp) {
- char *p2;
- int ndv;
- int dval[6];
-
- // Trim trailing blanks
- for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--) ;
-
- n = min(p2 - p + 1, Len);
- memcpy(Sdate, p, n);
- Sdate[n] = '\0';
-
- ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
- MakeDate(NULL, dval, ndv);
-
- if (trace)
- htrc(" setting date: '%s' -> %d\n", Sdate, Ival);
-
- } else
- INTVAL::SetValue_char(p, n);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* SetValue: convert a char string to date value. */
-/***********************************************************************/
-void DTVAL::SetValue_psz(PSZ p)
- {
- if (Pdtp) {
- int ndv;
- int dval[6];
-
- strncpy(Sdate, p, Len);
- Sdate[Len] = '\0';
-
- ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
- MakeDate(NULL, dval, ndv);
-
- if (trace)
- htrc(" setting date: '%s' -> %d\n", Sdate, Ival);
-
- } else
- INTVAL::SetValue_psz(p);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* DTVAL SetValue: set value with a value extracted from a block. */
-/***********************************************************************/
-void DTVAL::SetValue_pvblk(PVBLK blk, int n)
- {
- if (Pdtp && !::IsTypeNum(blk->GetType())) {
- int ndv;
- int dval[6];
-
- ndv = ExtractDate(blk->GetCharValue(n), Pdtp, DefYear, dval);
- MakeDate(NULL, dval, ndv);
- } else
- Ival = blk->GetIntValue(n);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* DTVAL GetCharString: get string representation of a date value. */
-/***********************************************************************/
-char *DTVAL::GetCharString(char *p)
- {
- if (Pdtp) {
- size_t n = 0;
- struct tm *ptm = GetGmTime();
-
- if (ptm)
- n = strftime(Sdate, Len + 1, Pdtp->OutFmt, ptm);
-
- if (!n) {
- *Sdate = '\0';
- strncat(Sdate, "Error", Len + 1);
- } // endif n
-
- return Sdate;
- } else
- sprintf(p, "%d", Ival);
-
- return p;
- } // end of GetCharString
-
-/***********************************************************************/
-/* DTVAL ShowValue: get string representation of a date value. */
-/***********************************************************************/
-char *DTVAL::ShowValue(char *buf, int len)
- {
- if (Pdtp) {
- char *p;
- size_t m, n = 0;
- struct tm *ptm = GetGmTime();
-
- if (Len < len) {
- p = buf;
- m = len;
- } else {
- p = Sdate;
- m = Len + 1;
- } // endif Len
-
- if (ptm)
- n = strftime(p, m, Pdtp->OutFmt, ptm);
-
- if (!n) {
- *p = '\0';
- strncat(p, "Error", m);
- } // endif n
-
- return p;
- } else
- return INTVAL::ShowValue(buf, len);
-
- } // end of ShowValue
-
-/***********************************************************************/
-/* Compute a function on a date time stamp. */
-/***********************************************************************/
-bool DTVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
- {
- bool rc = false;
-
- if (op == OP_DATE) {
- int val[6];
- int nval = min(np, 6);
-
- for (int i = 0; i < nval; i++)
- val[i] = vp[i]->GetIntValue();
-
- rc = MakeDate(g, val, nval);
- } else if (op == OP_ADDAY || op == OP_ADDMTH ||
- op == OP_ADDYR || op == OP_NXTDAY) {
- struct tm *ptm;
- int n = (op != OP_NXTDAY) ? (int)vp[1]->GetIntValue() : 1;
-
- INTVAL::SetValue_pval(vp[0], true);
- Ival -= Shift;
- ptm = GetGmTime();
-
- switch (op) {
- case OP_ADDAY:
- case OP_NXTDAY:
- ptm->tm_mday += n;
- break;
- case OP_ADDMTH:
- ptm->tm_mon += n;
- break;
- case OP_ADDYR:
- ptm->tm_year += n;
- break;
- default:
- sprintf(g->Message, MSG(BAD_DATE_OPER), op);
- return true;
- } // endswitch op
-
- if (MakeTime(ptm)) {
- strcpy(g->Message, MSG(BAD_DATETIME));
- rc = true;
- } // endif MakeTime
-
- } else if (op == OP_SYSDT) {
- Ival = (int)time(NULL) - Shift;
- } else if (op == OP_CURDT) {
- Ival = (((int)time(NULL) - Shift) / 86400) * 86400;
- } else
- rc = INTVAL::Compute(g, vp, np, op);
-
- return rc;
- } // end of Compute
-
-/***********************************************************************/
-/* GetTime: extract the time info from a date stamp. */
-/***********************************************************************/
-int DTVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
- {
- return (Ival % 86400);
- } // end of GetTime
-
-/***********************************************************************/
-/* Returns a member of the struct tm representation of the date. */
-/***********************************************************************/
-bool DTVAL::GetTmMember(OPVAL op, int& mval)
- {
- bool rc = false;
- struct tm *ptm = GetGmTime();
-
- switch (op) {
- case OP_MDAY: mval = ptm->tm_mday; break;
- case OP_MONTH: mval = ptm->tm_mon + 1; break;
- case OP_YEAR: mval = ptm->tm_year + 1900; break;
- case OP_WDAY: mval = ptm->tm_wday + 1; break;
- case OP_YDAY: mval = ptm->tm_yday + 1; break;
- case OP_QUART: mval = ptm->tm_mon / 3 + 1; break;
- default:
- rc = true;
- } // endswitch op
-
- return rc;
- } // end of GetTmMember
-
-/***********************************************************************/
-/* Calculates the week number of the year for the internal date value.*/
-/* The International Standard ISO 8601 has decreed that Monday shall */
-/* be the first day of the week. A week that lies partly in one year */
-/* and partly in another is assigned a number in the year in which */
-/* most of its days lie. That means that week number 1 of any year is */
-/* the week that contains the January 4th. */
-/***********************************************************************/
-bool DTVAL::WeekNum(PGLOBAL g, int& nval)
- {
- // w is the start of the week SUN=0, MON=1, etc.
- int m, n, w = nval % 7;
- struct tm *ptm = GetGmTime();
-
- // Which day is January 4th of this year?
- m = (367 + ptm->tm_wday - ptm->tm_yday) % 7;
-
- // When does the first week begins?
- n = 3 - (7 + m - w) % 7;
-
- // Now calculate the week number
- if (!(nval = (7 + ptm->tm_yday - n) / 7))
- nval = 52;
-
- // Everything should be Ok
- return false;
- } // end of WeekNum
-
-/***********************************************************************/
-/* This covers days, months and years between two dates. */
-/***********************************************************************/
-bool DTVAL::DateDiff(DTVAL *dtp, OPVAL op, int& tdif)
- {
- bool rc = false;
- int lv1, lv2, t1, t2;
- int s = CompareValue(dtp);
- struct tm dat1, dat2, *ptm = dtp->GetGmTime();
-
- if (!ptm)
- return true;
-
- if (s == 0) {
- // Dates are equal
- tdif = 0;
- return rc;
- } else if (s > 0) {
- // This Date is greater than dtp->Date
- dat1 = *ptm;
- lv1 = dtp->GetIntValue();
- lv2 = Ival;
-
- if ((ptm = GetGmTime()))
- dat2 = *ptm;
-
- } else {
- // This Date is less than dtp->Date
- dat2 = *ptm;
- lv2 = dtp->GetIntValue();
- lv1 = Ival;
-
- if ((ptm = GetGmTime()))
- dat1 = *ptm;
-
- } // endif's s
-
- if (!ptm)
- return true;
-
- // Both dates are valid and dat2 is greater than dat1
- t1 = lv1 % 86400; if (t1 < 0) t1 += 86400;
- t2 = lv2 % 86400; if (t2 < 0) t2 += 86400;
-
- if (t1 > t2) {
- lv1 += 86400;
- dat1.tm_mday++;
- } // endif
-
- if (dat1.tm_mday > dat2.tm_mday)
- dat1.tm_mon++;
-
- switch (op) {
- case OP_DBTWN:
- tdif = (lv2 / 86400) - (lv1 / 86400);
- break;
- case OP_MBTWN:
- tdif = (dat2.tm_year - dat1.tm_year) * 12
- + (dat2.tm_mon - dat1.tm_mon);
- break;
- case OP_YBTWN:
- if (dat1.tm_mon > dat2.tm_mon)
- dat1.tm_year++;
-
- tdif = dat2.tm_year - dat1.tm_year;
- break;
- default:
- rc = true;
- } // endswitch op
-
- if (!rc && s < 0)
- tdif = -tdif;
-
- return rc;
- } // end of DateDiff
-
-/***********************************************************************/
-/* FormatValue: This function set vp (a STRING value) to the string */
-/* constructed from its own value formated using the fmt format. */
-/* This function assumes that the format matches the value type. */
-/***********************************************************************/
-bool DTVAL::FormatValue(PVAL vp, char *fmt)
- {
- char *buf = (char*)vp->GetTo_Val(); // Should be big enough
- struct tm *ptm = GetGmTime();
-
- if (trace)
- htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen());
-
- if (ptm) {
- size_t n = strftime(buf, vp->GetValLen(), fmt, ptm);
-
- if (trace)
- htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???");
-
- return (n == 0);
- } else
- return true;
-
- } // end of FormatValue
-
-/* -------------------------- Class BIGVAL ---------------------------- */
-
-/***********************************************************************/
-/* BIGVAL public constructor from char. */
-/***********************************************************************/
-BIGVAL::BIGVAL(PSZ s) : VALUE(TYPE_BIGINT)
- {
- Lval = atoll(s);
- Clen = sizeof(longlong);
- } // end of BIGVAL constructor
-
-/***********************************************************************/
-/* BIGVAL public constructor from short. */
-/***********************************************************************/
-BIGVAL::BIGVAL(short n) : VALUE(TYPE_BIGINT)
- {
- Lval = (longlong)n;
- Clen = sizeof(longlong);
- } // end of BIGVAL constructor
-
-/***********************************************************************/
-/* BIGVAL public constructor from int. */
-/***********************************************************************/
-BIGVAL::BIGVAL(int n) : VALUE(TYPE_BIGINT)
- {
- Lval = (longlong)n;
- Clen = sizeof(longlong);
- } // end of BIGVAL constructor
-
-/***********************************************************************/
-/* BIGVAL public constructor from big int. */
-/***********************************************************************/
-BIGVAL::BIGVAL(longlong n) : VALUE(TYPE_BIGINT)
- {
- Lval = n;
- Clen = sizeof(longlong);
- } // end of BIGVAL constructor
-
-/***********************************************************************/
-/* BIGVAL public constructor from double. */
-/***********************************************************************/
-BIGVAL::BIGVAL(double f) : VALUE(TYPE_BIGINT)
- {
- Lval = (longlong)f;
- Clen = sizeof(longlong);
- } // end of BIGVAL constructor
-
-/***********************************************************************/
-/* BIGVAL GetValLen: returns the print length of the int object. */
-/***********************************************************************/
-int BIGVAL::GetValLen(void)
- {
- char c[24];
-
- return sprintf(c, "%lld", Lval);
- } // end of GetValLen
-
-/***********************************************************************/
-/* BIGVAL SetValue: copy the value of another Value object. */
-/* This function allows conversion if chktype is false. */
-/***********************************************************************/
-bool BIGVAL::SetValue_pval(PVAL valp, bool chktype)
- {
- if (chktype && Type != valp->GetType())
- return true;
-
- Lval = valp->GetBigintValue();
- return false;
- } // end of SetValue
-
-/***********************************************************************/
-/* BIGVAL SetValue: convert chars extracted from a line to a big int. */
-/***********************************************************************/
-void BIGVAL::SetValue_char(char *p, int n)
- {
- char *p2;
- bool minus;
-
- for (p2 = p + n; p < p2 && *p == ' '; p++) ;
-
- for (Lval = 0LL, minus = false; p < p2; p++)
- switch (*p) {
- case '-':
- minus = true;
- case '+':
- break;
- case '0': Lval = Lval * 10LL; break;
- case '1': Lval = Lval * 10LL + 1LL; break;
- case '2': Lval = Lval * 10LL + 2LL; break;
- case '3': Lval = Lval * 10LL + 3LL; break;
- case '4': Lval = Lval * 10LL + 4LL; break;
- case '5': Lval = Lval * 10LL + 5LL; break;
- case '6': Lval = Lval * 10LL + 6LL; break;
- case '7': Lval = Lval * 10LL + 7LL; break;
- case '8': Lval = Lval * 10LL + 8LL; break;
- case '9': Lval = Lval * 10LL + 9LL; break;
- default:
- p = p2;
- } // endswitch *p
-
- if (minus && Lval)
- Lval = - Lval;
-
- if (trace)
- htrc(" setting big int to: %lld\n", Lval);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* BIGVAL SetValue: fill a big int value from a string. */
-/***********************************************************************/
-void BIGVAL::SetValue_psz(PSZ s)
- {
- Lval = atoll(s);
- } // end of SetValue
-
-/***********************************************************************/
-/* BIGVAL SetValue: set value with a int extracted from a block. */
-/***********************************************************************/
-void BIGVAL::SetValue_pvblk(PVBLK blk, int n)
- {
- Lval = blk->GetBigintValue(n);
- } // end of SetValue
-
-/***********************************************************************/
-/* BIGVAL SetBinValue: with bytes extracted from a line. */
-/***********************************************************************/
-void BIGVAL::SetBinValue(void *p)
- {
- Lval = *(longlong *)p;
- } // end of SetBinValue
-
-/***********************************************************************/
-/* GetBinValue: fill a buffer with the internal binary value. */
-/* This function checks whether the buffer length is enough and */
-/* returns true if not. Actual filling occurs only if go is true. */
-/* Currently used by WriteColumn of binary files. */
-/***********************************************************************/
-bool BIGVAL::GetBinValue(void *buf, int buflen, bool go)
- {
- // Test on length was removed here until a variable in column give the
- // real field length. For BIN files the field length logically cannot
- // be different from the variable length because no conversion is done.
- // Therefore this test is useless anyway.
-//#if defined(_DEBUG)
-// if (sizeof(int) > buflen)
-// return true;
-//#endif
-
- if (go)
- *(longlong *)buf = Lval;
-
- return false;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
-/* This is a fast implementation that does not do any checking. */
-/***********************************************************************/
-void BIGVAL::GetBinValue(void *buf, int buflen)
- {
- assert(buflen == sizeof(longlong));
-
- *(longlong *)buf = Lval;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* BIGVAL ShowValue: get string representation of a big int value. */
-/***********************************************************************/
-char *BIGVAL::ShowValue(char *buf, int len)
- {
- sprintf(buf, "%*lld", len, Lval);
- return buf;
- } // end of ShowValue
-
-/***********************************************************************/
-/* BIGVAL GetCharString: get string representation of a big int value.*/
-/***********************************************************************/
-char *BIGVAL::GetCharString(char *p)
- {
- sprintf(p, "%lld", Lval);
- return p;
- } // end of GetCharString
-
-/***********************************************************************/
-/* BIGVAL GetShortString: get short representation of a int value. */
-/***********************************************************************/
-char *BIGVAL::GetShortString(char *p, int n)
- {
- sprintf(p, "%*hd", n, (short)Lval);
- return p;
- } // end of GetShortString
-
-/***********************************************************************/
-/* BIGVAL GetIntString: get int representation of a int value. */
-/***********************************************************************/
-char *BIGVAL::GetIntString(char *p, int n)
- {
- sprintf(p, "%*d", n, (int)Lval);
- return p;
- } // end of GetIntString
-
-/***********************************************************************/
-/* BIGVAL GetBigintString: get big int representation of a int value. */
-/***********************************************************************/
-char *BIGVAL::GetBigintString(char *p, int n)
- {
- sprintf(p, "%*lld", n, Lval);
- return p;
- } // end of GetBigintString
-
-/***********************************************************************/
-/* BIGVAL GetFloatString: get double representation of a int value. */
-/***********************************************************************/
-char *BIGVAL::GetFloatString(char *p, int n, int prec)
- {
- sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Lval);
- return p;
- } // end of GetFloatString
-
-/***********************************************************************/
-/* BIGVAL compare value with another Value. */
-/***********************************************************************/
-bool BIGVAL::IsEqual(PVAL vp, bool chktype)
- {
- if (this == vp)
- return true;
- else if (chktype && Type != vp->GetType())
- return false;
- else
- return (Lval == vp->GetBigintValue());
-
- } // end of IsEqual
-
-/***********************************************************************/
-/* Compare values and returns 1, 0 or -1 according to comparison. */
-/* This function is used for evaluation of big int integer filters. */
-/***********************************************************************/
-int BIGVAL::CompareValue(PVAL vp)
- {
-//assert(vp->GetType() == Type);
-
- // Process filtering on big int integers.
- longlong n = vp->GetBigintValue();
-
- if (trace > 1)
- htrc(" Comparing: val=%lld,%lld\n", Lval, n);
-
- return (Lval > n) ? 1 : (Lval < n) ? (-1) : 0;
- } // end of CompareValue
-
-/***********************************************************************/
-/* SafeAdd: adds a value and test whether overflow/underflow occured. */
-/***********************************************************************/
-longlong BIGVAL::SafeAdd(longlong n1, longlong n2)
- {
- PGLOBAL& g = Global;
- longlong n = n1 + n2;
-
- if ((n2 > 0LL) && (n < n1)) {
- // Overflow
- strcpy(g->Message, MSG(FIX_OVFLW_ADD));
- longjmp(g->jumper[g->jump_level], 138);
- } else if ((n2 < 0LL) && (n > n1)) {
- // Underflow
- strcpy(g->Message, MSG(FIX_UNFLW_ADD));
- longjmp(g->jumper[g->jump_level], 138);
- } // endif's n2
-
- return n;
- } // end of SafeAdd
-
-/***********************************************************************/
-/* SafeMult: multiply values and test whether overflow occured. */
-/***********************************************************************/
-longlong BIGVAL::SafeMult(longlong n1, longlong n2)
- {
- PGLOBAL& g = Global;
- double n = (double)n1 * (double)n2;
-
- if (n > LLONG_MAX) {
- // Overflow
- strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
- longjmp(g->jumper[g->jump_level], 138);
- } else if (n < LLONG_MIN) {
- // Underflow
- strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
- longjmp(g->jumper[g->jump_level], 138);
- } // endif's n2
-
- return n1 * n2;
- } // end of SafeMult
-
-/***********************************************************************/
-/* Compute a function on a int integers. */
-/***********************************************************************/
-bool BIGVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
- {
- if (op == OP_LEN) {
- assert(np == 1);
- char buf[32];
- char *p = vp[0]->GetCharString(buf);
-
- Lval = strlen(p);
-
- if (trace)
- htrc("Compute result=%lld val=%s op=%d\n", Lval, p, op);
-
- } else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
- char *p, *tp = g->Message;
- char *p1, val1[32];
- char *p2, val2[32];
- bool b = (vp[0]->IsCi() || vp[1]->IsCi());
-
- assert(np == 2);
-
- p1 = vp[0]->GetCharString(val1);
- p2 = vp[1]->GetCharString(val2);
-
- if (op != OP_LIKE) {
- if (!strcmp(p2, "\\t"))
- p2 = "\t";
-
- if (b) { // Case insensitive
- if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
- !(tp = new char[strlen(p1) + strlen(p2) + 2])) {
- strcpy(g->Message, MSG(NEW_RETURN_NULL));
- return true;
- } // endif p
-
- // Make a lower case copy of p1 and p2
- p1 = strlwr(strcpy(tp, p1));
- p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
- } // endif b
-
- if (op == OP_CNTIN) {
- size_t t2 = strlen(p2);
-
- for (Lval = 0LL; (p = strstr(p1, p2)); Lval++, p1 = p + t2) ;
-
- } else // OP_INSTR
- Lval = (p = strstr(p1, p2)) ? 1LL + (longlong)(p - p1) : 0LL;
-
- if (tp != g->Message) // If working space was obtained
- delete [] tp; // by the use of new, delete it.
-
- } else // OP_LIKE
- Lval = (PlugEvalLike(g, p1, p2, b)) ? 1LL : 0LL;
-
- if (trace)
- htrc("Compute result=%lld val=%s,%s op=%d\n", Lval, p1, p2, op);
-
- } else {
- longlong val[2];
-
- assert(np <= 2);
-
- for (int i = 0; i < np; i++)
- val[i] = vp[i]->GetBigintValue();
-
- switch (op) {
- case OP_ABS:
- assert(np == 1);
- Lval = (*val >= 0LL) ? *val : -*val;
- break;
- case OP_SIGN:
- assert(np == 1);
- Lval = (*val < 0LL) ? (-1) : 1;
- break;
- case OP_CEIL:
- case OP_FLOOR:
- assert(np == 1);
- Lval = *val;
- break;
- case OP_ADD:
- assert(np == 2);
- Lval = SafeAdd(val[0], val[1]);
- break;
- case OP_SUB:
- assert(np == 2);
- Lval = SafeAdd(val[0], -val[1]);
- break;
- case OP_MULT:
- assert(np == 2);
- Lval = SafeMult(val[0], val[1]);
- break;
- case OP_MIN:
- assert(np == 2);
- Lval = min(val[0], val[1]);
- break;
- case OP_MAX:
- assert(np == 2);
- Lval = max(val[0], val[1]);
- break;
- case OP_DIV:
- assert(np == 2);
-
- if (!val[1]) {
- strcpy(g->Message, MSG(ZERO_DIVIDE));
- return true;
- } // endif
-
- Lval = val[0] / val[1];
- break;
- case OP_MOD:
- assert(np == 2);
-
- if (!val[1]) {
- strcpy(g->Message, MSG(ZERO_DIVIDE));
- return true;
- } // endif
-
- Lval = val[0] % val[1];
- break;
- case OP_BITAND:
- assert(np == 2);
- Lval = val[0] & val[1];
- break;
- case OP_BITOR:
- assert(np == 2);
- Lval = val[0] | val[1];
- break;
- case OP_BITXOR:
- assert(np == 2);
- Lval = val[0] ^ val[1];
- break;
- case OP_BITNOT:
- assert(np == 1);
- Lval = ~val[0];
- break;
- case OP_DELTA:
-// assert(np == 1);
- Lval = val[0] - Lval;
- break;
- default:
- sprintf(g->Message, MSG(BAD_EXP_OPER), op);
- return true;
- } // endswitch op
-
- if (trace)
- if (np = 1)
- htrc(" result=%lld val=%lld op=%d\n", Lval, val[0], op);
- else
- htrc(" result=%lld val=%lld,%lld op=%d\n",
- Lval, val[0], val[1], op);
-
- } // endif op
-
- return false;
- } // end of Compute
-
-/***********************************************************************/
-/* Divide: used by aggregate functions when calculating average. */
-/***********************************************************************/
-void BIGVAL::Divide(int cnt)
- {
- Lval /= cnt;
- } // end of Divide
-
-/***********************************************************************/
-/* StdVar: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void BIGVAL::StdVar(PVAL vp, int cnt, bool b)
- {
- longlong lv2 = vp->GetBigintValue();
-
- Lval = (cnt == 1) ? 0
- : (SafeAdd(lv2, -(SafeMult(Lval, Lval) / cnt)) / (cnt - 1));
-
- if (b) // Builtin == FNC_STDDEV
- Lval = (longlong)sqrt((double)Lval);
-
- } // end of StdVar
-
-/***********************************************************************/
-/* Times: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void BIGVAL::Times(PVAL vp)
- {
- Lval = SafeMult(Lval, vp->GetBigintValue());
- } // end of Times
-
-/***********************************************************************/
-/* Add: used by aggregate functions for Sum and other functions. */
-/***********************************************************************/
-void BIGVAL::Add(PVAL vp)
- {
- Lval = SafeAdd(Lval, vp->GetBigintValue());
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void BIGVAL::Add(PVBLK vbp, int i)
- {
- Lval = SafeAdd(Lval, vbp->GetBigintValue(i));
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void BIGVAL::Add(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- longlong *lp = (longlong *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Lval = SafeAdd(Lval, lp[i]);
-
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by QUERY for function Sum and other functions. */
-/***********************************************************************/
-void BIGVAL::Add(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- longlong *lp = (longlong *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Lval = SafeAdd(Lval, lp[x[i]]);
-
- } // end of Add
-
-/***********************************************************************/
-/* AddSquare: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void BIGVAL::AddSquare(PVAL vp)
- {
- longlong val = vp->GetBigintValue();
-
- Lval = SafeAdd(Lval, SafeMult(val, val));
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by QUERY for functions Stddev and Variance. */
-/***********************************************************************/
-void BIGVAL::AddSquare(PVBLK vbp, int i)
- {
- longlong val = vbp->GetBigintValue(i);
-
- Lval = SafeAdd(Lval, SafeMult(val, val));
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by QUERY for functions Stddev and Variance. */
-/***********************************************************************/
-void BIGVAL::AddSquare(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- longlong *lp = (longlong *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Lval = SafeAdd(Lval, SafeMult(lp[i], lp[i]));
-
- } // end of AddSquare
-
-/***********************************************************************/
-/* FormatValue: This function set vp (a STRING value) to the string */
-/* constructed from its own value formated using the fmt format. */
-/* This function assumes that the format matches the value type. */
-/***********************************************************************/
-bool BIGVAL::FormatValue(PVAL vp, char *fmt)
- {
- char *buf = (char*)vp->GetTo_Val(); // Should be big enough
- int n = sprintf(buf, fmt, Lval);
-
- return (n > vp->GetValLen());
- } // end of FormatValue
-
-/***********************************************************************/
-/* SetMin: used by the aggregate function MIN. */
-/***********************************************************************/
-void BIGVAL::SetMin(PVAL vp)
- {
- longlong val = vp->GetBigintValue();
-
- if (val < Lval)
- Lval = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void BIGVAL::SetMin(PVBLK vbp, int i)
- {
- longlong val = vbp->GetBigintValue(i);
-
- if (val < Lval)
- Lval = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void BIGVAL::SetMin(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- longlong *lp = (longlong *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (lp[i] < Lval)
- Lval = lp[i];
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void BIGVAL::SetMin(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- longlong val;
- longlong *lp = (longlong *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = lp[x[i]];
-
- if (val < Lval)
- Lval = val;
-
- } // endfor i
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMax: used by the aggregate function MAX. */
-/***********************************************************************/
-void BIGVAL::SetMax(PVAL vp)
- {
- longlong val = vp->GetBigintValue();
-
- if (val > Lval)
- Lval = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void BIGVAL::SetMax(PVBLK vbp, int i)
- {
- longlong val = vbp->GetBigintValue(i);
-
- if (val > Lval)
- Lval = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void BIGVAL::SetMax(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- longlong *lp = (longlong *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (lp[i] > Lval)
- Lval = lp[i];
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void BIGVAL::SetMax(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- longlong val;
- longlong *lp = (longlong *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = lp[x[i]];
-
- if (val > Lval)
- Lval = val;
-
- } // endfor i
-
- } // end of SetMax
-
-/***********************************************************************/
-/* BIGVAL SetFormat function (used to set SELECT output format). */
-/***********************************************************************/
-bool BIGVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
- {
- char c[16];
-
- fmt.Type[0] = 'L';
- fmt.Length = sprintf(c, "%lld", Lval);
- fmt.Prec = 0;
- return false;
- } // end of SetConstFormat
-
-/***********************************************************************/
-/* Make file output of a big int object. */
-/***********************************************************************/
-void BIGVAL::Print(PGLOBAL g, FILE *f, uint n)
- {
- char m[64];
-
- memset(m, ' ', n); /* Make margin string */
- m[n] = '\0';
-
- fprintf(f, "%s%lld\n", m, Lval);
- } /* end of Print */
-
-/***********************************************************************/
-/* Make string output of a int object. */
-/***********************************************************************/
-void BIGVAL::Print(PGLOBAL g, char *ps, uint z)
- {
- sprintf(ps, "%lld", Lval);
- } /* end of Print */
-
-/* -------------------------- Class DFVAL ---------------------------- */
-
-/***********************************************************************/
-/* DFVAL public constructor from char. */
-/***********************************************************************/
-DFVAL::DFVAL(PSZ s, int prec) : VALUE(TYPE_FLOAT)
- {
- Fval = atof(s);
- Prec = prec;
- Clen = sizeof(double);
- } // end of DFVAL constructor
-
-/***********************************************************************/
-/* DFVAL public constructor from short. */
-/***********************************************************************/
-DFVAL::DFVAL(short n, int prec) : VALUE(TYPE_FLOAT)
- {
- Fval = (double)n;
- Prec = prec;
- Clen = sizeof(double);
- } // end of DFVAL constructor
-
-/***********************************************************************/
-/* DFVAL public constructor from int. */
-/***********************************************************************/
-DFVAL::DFVAL(int n, int prec) : VALUE(TYPE_FLOAT)
- {
- Fval = (double)n;
- Prec = prec;
- Clen = sizeof(double);
- } // end of DFVAL constructor
-
-/***********************************************************************/
-/* DFVAL public constructor from big int. */
-/***********************************************************************/
-DFVAL::DFVAL(longlong n, int prec) : VALUE(TYPE_FLOAT)
- {
- Fval = (double)n;
- Prec = prec;
- Clen = sizeof(double);
- } // end of DFVAL constructor
-
-/***********************************************************************/
-/* DFVAL public constructor from double. */
-/***********************************************************************/
-DFVAL::DFVAL(double f, int prec) : VALUE(TYPE_FLOAT)
- {
- Fval = f;
- Prec = prec;
- Clen = sizeof(double);
- } // end of DFVAL constructor
-
-/***********************************************************************/
-/* DFVAL GetValLen: returns the print length of the double object. */
-/***********************************************************************/
-int DFVAL::GetValLen(void)
- {
- char c[32];
-
- return sprintf(c, "%.*lf", Prec, Fval);
- } // end of GetValLen
-
-/***********************************************************************/
-/* DFVAL SetValue: copy the value of another Value object. */
-/* This function allows conversion if chktype is false. */
-/***********************************************************************/
-bool DFVAL::SetValue_pval(PVAL valp, bool chktype)
- {
- if (chktype && Type != valp->GetType())
- return true;
-
- Fval = valp->GetFloatValue();
- return false;
- } // end of SetValue
-
-/***********************************************************************/
-/* SetValue: convert chars extracted from a line to double value. */
-/***********************************************************************/
-void DFVAL::SetValue_char(char *p, int n)
- {
- char *p2, buf[32];
-
- for (p2 = p + n; p < p2 && *p == ' '; p++) ;
-
- n = min(p2 - p, 31);
- memcpy(buf, p, n);
- buf[n] = '\0';
- Fval = atof(buf);
-
- if (trace)
- htrc(" setting double: '%s' -> %lf\n", buf, Fval);
-
- } // end of SetValue
-
-/***********************************************************************/
-/* DFVAL SetValue: fill a double float value from a string. */
-/***********************************************************************/
-void DFVAL::SetValue_psz(PSZ s)
- {
- Fval = atof(s);
- } // end of SetValue
-
-/***********************************************************************/
-/* DFVAL SetValue: set value with a double extracted from a block. */
-/***********************************************************************/
-void DFVAL::SetValue_pvblk(PVBLK blk, int n)
- {
- Fval = blk->GetFloatValue(n);
- } // end of SetValue
-
-/***********************************************************************/
-/* SetBinValue: with bytes extracted from a line. */
-/***********************************************************************/
-void DFVAL::SetBinValue(void *p)
- {
- Fval = *(double *)p;
- } // end of SetBinValue
-
-/***********************************************************************/
-/* GetBinValue: fill a buffer with the internal binary value. */
-/* This function checks whether the buffer length is enough and */
-/* returns true if not. Actual filling occurs only if go is true. */
-/* Currently used by WriteColumn of binary files. */
-/***********************************************************************/
-bool DFVAL::GetBinValue(void *buf, int buflen, bool go)
- {
- // Test on length was removed here until a variable in column give the
- // real field length. For BIN files the field length logically cannot
- // be different from the variable length because no conversion is done.
- // Therefore this test is useless anyway.
-//#if defined(_DEBUG)
-// if (sizeof(double) > buflen)
-// return true;
-//#endif
-
- if (go)
- *(double *)buf = Fval;
-
- return false;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
-/* This is a fast implementation that does not do any checking. */
-/* Note: type is not needed here and just kept for compatibility. */
-/***********************************************************************/
-void DFVAL::GetBinValue(void *buf, int buflen)
- {
- assert(buflen == sizeof(double));
-
- *(double *)buf = Fval;
- } // end of GetBinValue
-
-/***********************************************************************/
-/* DFVAL ShowValue: get string representation of a double value. */
-/***********************************************************************/
-char *DFVAL::ShowValue(char *buf, int len)
- {
- // TODO: use snprintf to avoid possible overflow
- sprintf(buf, "%*.*lf", len, Prec, Fval);
- return buf;
- } // end of ShowValue
-
-/***********************************************************************/
-/* DFVAL GetCharString: get string representation of a double value. */
-/***********************************************************************/
-char *DFVAL::GetCharString(char *p)
- {
- sprintf(p, "%.*lf", Prec, Fval);
- return p;
- } // end of GetCharString
-
-/***********************************************************************/
-/* DFVAL GetShortString: get short representation of a double value. */
-/***********************************************************************/
-char *DFVAL::GetShortString(char *p, int n)
- {
- sprintf(p, "%*hd", n, (short)Fval);
- return p;
- } // end of GetShortString
-
-/***********************************************************************/
-/* DFVAL GetIntString: get int representation of a double value. */
-/***********************************************************************/
-char *DFVAL::GetIntString(char *p, int n)
- {
- sprintf(p, "%*ld", n, (int)Fval);
- return p;
- } // end of GetIntString
-
-/***********************************************************************/
-/* DFVAL GetBigintString: get big int representation of a double val. */
-/***********************************************************************/
-char *DFVAL::GetBigintString(char *p, int n)
- {
- sprintf(p, "%*lld", n, (longlong)Fval);
- return p;
- } // end of GetBigintString
-
-/***********************************************************************/
-/* DFVAL GetFloatString: get double representation of a double value. */
-/***********************************************************************/
-char *DFVAL::GetFloatString(char *p, int n, int prec)
- {
- sprintf(p, "%*.*lf", n, (prec < 0) ? Prec : prec, Fval);
- return p;
- } // end of GetFloatString
-
-/***********************************************************************/
-/* DFVAL compare value with another Value. */
-/***********************************************************************/
-bool DFVAL::IsEqual(PVAL vp, bool chktype)
- {
- if (this == vp)
- return true;
- else if (chktype && Type != vp->GetType())
- return false;
- else
- return (Fval == vp->GetFloatValue());
-
- } // end of IsEqual
-
-/***********************************************************************/
-/* Compare values and returns 1, 0 or -1 according to comparison. */
-/* This function is used for evaluation of double float filters. */
-/***********************************************************************/
-int DFVAL::CompareValue(PVAL vp)
- {
-//assert(vp->GetType() == Type);
-
- // Process filtering on int integers.
- double d = vp->GetFloatValue();
-
- if (trace)
- htrc(" Comparing: val=%.2f,%.2f\n", Fval, d);
-
- return (Fval > d) ? 1 : (Fval < d) ? (-1) : 0;
- } // end of CompareValue
-
-/***********************************************************************/
-/* Compute a function on double floats. */
-/***********************************************************************/
-bool DFVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
- {
- double val[2];
-
- assert(np <= 2);
-
- for (int i = 0; i < np; i++)
- val[i] = vp[i]->GetFloatValue();
-
- switch (op) {
- case OP_ABS:
- assert(np == 1);
- Fval = fabs(*val);
- break;
- case OP_CEIL:
- assert(np == 1);
- Fval = ceil(*val);
- break;
- case OP_FLOOR:
- assert(np == 1);
- Fval = floor(*val);
- break;
- case OP_SIGN:
- assert(np == 1);
- Fval = (*val < 0.0) ? (-1.0) : 1.0;
- break;
- case OP_ADD:
- assert(np == 2);
- Fval = val[0] + val[1];
- break;
- case OP_SUB:
- assert(np == 2);
- Fval = val[0] - val[1];
- break;
- case OP_MULT:
- assert(np == 2);
- Fval = val[0] * val[1];
- break;
- case OP_MIN:
- assert(np == 2);
- Fval = min(val[0], val[1]);
- break;
- case OP_MAX:
- assert(np == 2);
- Fval = max(val[0], val[1]);
- break;
- case OP_DIV:
- assert(np == 2);
- if (!val[1]) {
- strcpy(g->Message, MSG(ZERO_DIVIDE));
- return true;
- } // endif
-
- Fval = val[0] / val[1];
- break;
- case OP_MOD:
- assert(np == 2);
- Fval = fmod(val[0], val[1]);
- break;
- case OP_SQRT:
- assert(np == 1);
- Fval = sqrt(*val);
- break;
- case OP_LN:
- assert(np == 1);
- Fval = log(*val);
- break;
- case OP_EXP:
- assert(np == 1);
- Fval = exp(*val);
- break;
- case OP_COS:
- assert(np == 1);
- Fval = cos(*val);
- break;
- case OP_SIN:
- assert(np == 1);
- Fval = sin(*val);
- break;
- case OP_TAN:
- assert(np == 1);
- Fval = tan(*val);
- break;
- case OP_COSH:
- assert(np == 1);
- Fval = cosh(*val);
- break;
- case OP_SINH:
- assert(np == 1);
- Fval = sinh(*val);
- break;
- case OP_TANH:
- assert(np == 1);
- Fval = tanh(*val);
- break;
- case OP_LOG:
- assert(np > 0);
-
- if (np > 1 && val[1] != 10.0) {
- strcpy(g->Message, MSG(ONLY_LOG10_IMPL));
- return true;
- } // endif Numarg
-
- Fval = log10(val[0]);
- break;
- case OP_POWER:
- assert(np == 2);
- Fval = pow(val[0], val[1]);
- break;
- case OP_ROUND:
- assert(np > 0);
-
- if (np > 1) {
- double dx, dy = val[1];
-
- modf(dy, &dx); // Get integral part of arg
- dx = pow(10.0, dx);
- modf(val[0] * dx + 0.5, &dy);
- Fval = dy / dx;
- } else
- modf(val[0] + 0.5, &Fval);
-
- break;
- case OP_DELTA:
-// assert(np == 1);
- Fval = val[0] - Fval;
- break;
- default:
- sprintf(g->Message, MSG(BAD_EXP_OPER), op);
- return true;
- } // endswitch op
-
- if (trace) {
- if (np == 1)
- htrc("Compute result=%lf val=%lf op=%d\n", Fval, val[0], op);
- else
- htrc("Compute result=%lf val=%lf,%lf op=%d\n",
- Fval, val[0], val[1], op);
- } // endif trace
-
- return false;
- } // end of Compute
-
-/***********************************************************************/
-/* GetTime: convert HR/MIN/SEC in a number of seconds. */
-/***********************************************************************/
-int DFVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
- {
- double sec = Fval;
-
- for (int i = 0; i < 2; i++) {
- sec *= 60.0;
-
- if (np > i)
- sec += vp[i]->GetFloatValue();
-
- } // endfor i
-
- return (int)sec;
- } // end of GetTime
-
-/***********************************************************************/
-/* Divide: used by aggregate functions when calculating average. */
-/***********************************************************************/
-void DFVAL::Divide(int cnt)
- {
- Fval /= (double)cnt;
- } // end of Divide
-
-/***********************************************************************/
-/* StdVar: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void DFVAL::StdVar(PVAL vp, int cnt, bool b)
- {
- double fv2 = vp->GetFloatValue();
- double cnd = (double)cnt;
-
- Fval = (cnt == 1) ? 0.0 : ((fv2 - (Fval * Fval) / cnd) / (cnd - 1.0));
-
- if (b) // Builtin == FNC_STDDEV
- Fval = sqrt(Fval);
-
- } // end of StdVar
-
-/***********************************************************************/
-/* Times: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void DFVAL::Times(PVAL vp)
- {
- Fval *= vp->GetFloatValue();
- } // end of Times
-
-/***********************************************************************/
-/* Add: used by aggregate functions for Sum and other functions. */
-/***********************************************************************/
-void DFVAL::Add(PVAL vp)
- {
- Fval += vp->GetFloatValue();
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by aggregate functions for Sum and other functions. */
-/***********************************************************************/
-void DFVAL::Add(PVBLK vbp, int i)
- {
- Fval += vbp->GetFloatValue(i);
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by aggregate functions for Sum and other functions. */
-/***********************************************************************/
-void DFVAL::Add(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- double *dp = (double *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Fval += dp[i];
-
- } // end of Add
-
-/***********************************************************************/
-/* Add: used by aggregate functions for Sum and other functions. */
-/***********************************************************************/
-void DFVAL::Add(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- double *dp = (double *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Fval += dp[x[i]];
-
- } // end of Add
-
-/***********************************************************************/
-/* AddSquare: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void DFVAL::AddSquare(PVAL vp)
- {
- double val = vp->GetFloatValue();
-
- Fval += (val * val);
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void DFVAL::AddSquare(PVBLK vbp, int i)
- {
- double val = vbp->GetFloatValue(i);
-
- Fval += (val * val);
- } // end of AddSquare
-
-/***********************************************************************/
-/* AddSquare: used by aggregate functions for Stddev and Variance. */
-/***********************************************************************/
-void DFVAL::AddSquare(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- double *dp = (double *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- Fval += (dp[i] * dp[i]);
-
- } // end of AddSquare
-
-/***********************************************************************/
-/* FormatValue: This function set vp (a STRING value) to the string */
-/* constructed from its own value formated using the fmt format. */
-/* This function assumes that the format matches the value type. */
-/***********************************************************************/
-bool DFVAL::FormatValue(PVAL vp, char *fmt)
- {
- char *buf = (char*)vp->GetTo_Val(); // Should be big enough
- int n = sprintf(buf, fmt, Fval);
-
- return (n > vp->GetValLen());
- } // end of FormatValue
-
-/***********************************************************************/
-/* SetMin: used by the aggregate function MIN. */
-/***********************************************************************/
-void DFVAL::SetMin(PVAL vp)
- {
- double val = vp->GetFloatValue();
-
- if (val < Fval)
- Fval = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void DFVAL::SetMin(PVBLK vbp, int i)
- {
- double val = vbp->GetFloatValue(i);
-
- if (val < Fval)
- Fval = val;
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMin: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void DFVAL::SetMin(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- double *dp = (double *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (dp[i] < Fval)
- Fval = dp[i];
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void DFVAL::SetMin(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- register double val;
- double *dp = (double *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = dp[x[i]];
-
- if (val < Fval)
- Fval = val;
-
- } // endfor i
-
- } // end of SetMin
-
-/***********************************************************************/
-/* SetMax: used by the aggregate function MAX. */
-/***********************************************************************/
-void DFVAL::SetMax(PVAL vp)
- {
- double val = vp->GetFloatValue();
-
- if (val > Fval)
- Fval = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MAX. */
-/***********************************************************************/
-void DFVAL::SetMax(PVBLK vbp, int i)
- {
- double val = vbp->GetFloatValue(i);
-
- if (val > Fval)
- Fval = val;
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void DFVAL::SetMax(PVBLK vbp, int j, int k)
- {
- CheckType(vbp)
- double *dp = (double *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++)
- if (dp[i] > Fval)
- Fval = dp[i];
-
- } // end of SetMax
-
-/***********************************************************************/
-/* SetMax: used by QUERY for the aggregate function MIN. */
-/***********************************************************************/
-void DFVAL::SetMax(PVBLK vbp, int *x, int j, int k)
- {
- CheckType(vbp)
- register double val;
- double *dp = (double *)vbp->GetValPointer();
-
- for (register int i = j; i < k; i++) {
- val = dp[x[i]];
-
- if (val > Fval)
- Fval = val;
-
- } // endfor i
-
- } // end of SetMax
-
-/***********************************************************************/
-/* DFVAL SetFormat function (used to set SELECT output format). */
-/***********************************************************************/
-bool DFVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
- {
- char c[32];
-
- fmt.Type[0] = 'F';
- fmt.Length = sprintf(c, "%.*lf", Prec, Fval);
- fmt.Prec = Prec;
- return false;
- } // end of SetConstFormat
-
-/***********************************************************************/
-/* Make file output of a double object. */
-/***********************************************************************/
-void DFVAL::Print(PGLOBAL g, FILE *f, uint n)
- {
- char m[64];
-
- memset(m, ' ', n); /* Make margin string */
- m[n] = '\0';
-
- fprintf(f, "%s%.*lf\n", m, Prec, Fval);
- } /* end of Print */
-
-/***********************************************************************/
-/* Make string output of a double object. */
-/***********************************************************************/
-void DFVAL::Print(PGLOBAL g, char *ps, uint z)
- {
- sprintf(ps, "%.*lf", Prec, Fval);
- } /* end of Print */
-
-#endif // __VALUE_H
-
-/* -------------------------- End of Value --------------------------- */
+/************* Value C++ Functions Source Code File (.CPP) *************/
+/* Name: VALUE.CPP Version 2.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
+/* */
+/* This file contains the VALUE and derived classes family functions. */
+/* These classes contain values of different types. They are used so */
+/* new object types can be defined and added to the processing simply */
+/* (hopefully) adding their specific functions in this file. */
+/* First family is VALUE that represent single typed objects. It is */
+/* used by columns (COLBLK), SELECT and FILTER (derived) objects. */
+/* Second family is VALBLK, representing simple suballocated arrays */
+/* of values treated sequentially by FIX, BIN and VCT tables and */
+/* columns, as well for min/max blocks as for VCT column blocks. */
+/* Q&A: why not using only one family ? Simple values are arrays that */
+/* have only one element and arrays could have functions for all kind */
+/* of processing. The answer is a-because historically it was simpler */
+/* to do that way, b-because of performance on single values, and c- */
+/* to avoid too complicated classes and unuseful duplication of many */
+/* functions used on one family only. The drawback is that for new */
+/* types of objects, we shall have more classes to update. */
+/* Currently the only implemented types are STRING, INT, DOUBLE, DATE */
+/* and LONGLONG. Shortly we should add at least TINY and VARCHAR. */
+/***********************************************************************/
+
+#ifndef __VALUE_H
+#define __VALUE_H
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(WIN32)
+//#include <windows.h>
+#else // !WIN32
+#include <string.h>
+#endif // !WIN32
+
+#include <math.h>
+
+#undef DOMAIN // Was defined in math.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 "preparse.h" // For DATPAR
+//#include "value.h"
+#include "valblk.h"
+#define NO_FUNC // Already defined in ODBConn
+#include "plgcnx.h" // For DB types
+
+/***********************************************************************/
+/* Check macro's. */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define CheckType(V) if (Type != V->GetType()) { \
+ PGLOBAL& g = Global; \
+ strcpy(g->Message, MSG(VALTYPE_NOMATCH)); \
+ longjmp(g->jumper[g->jump_level], Type); }
+#else
+#define CheckType(V)
+#endif
+
+#define FOURYEARS 126230400 // Four years in seconds (1 leap)
+
+/***********************************************************************/
+/* Static variables. */
+/***********************************************************************/
+static char *list =
+ " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.*-‘abcdefghijklmnopqrstuv"; //wxyzñ'
+//" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.";
+extern "C" int trace;
+
+/***********************************************************************/
+/* Initialize the DTVAL static member. */
+/***********************************************************************/
+int DTVAL::Shift = 0;
+
+/***********************************************************************/
+/* Routines called externally. */
+/***********************************************************************/
+bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
+#if !defined(WIN32)
+extern "C" {
+PSZ strupr(PSZ s);
+PSZ strlwr(PSZ s);
+}
+#endif // !WIN32
+
+/***********************************************************************/
+/* Returns the bitmap representing the conditions that must not be */
+/* met when returning from TestValue for a given operator. */
+/* Bit one is EQ, bit 2 is LT, and bit 3 is GT. */
+/***********************************************************************/
+BYTE OpBmp(PGLOBAL g, OPVAL opc)
+ {
+ BYTE bt;
+
+ switch (opc) {
+ case OP_IN:
+ case OP_EQ: bt = 0x06; break;
+ case OP_NE: bt = 0x01; break;
+ case OP_GT: bt = 0x03; break;
+ case OP_GE: bt = 0x02; break;
+ case OP_LT: bt = 0x05; break;
+ case OP_LE: bt = 0x04; break;
+ case OP_EXIST: bt = 0x00; break;
+ default:
+ sprintf(g->Message, MSG(BAD_FILTER_OP), opc);
+ longjmp(g->jumper[g->jump_level], 777);
+ } // endswitch opc
+
+ return bt;
+ } // end of OpBmp
+
+/***********************************************************************/
+/* GetTypeName: returns the PlugDB internal type name. */
+/***********************************************************************/
+PSZ GetTypeName(int type)
+ {
+ PSZ name = "UNKNOWN";
+
+ switch (type) {
+ case TYPE_STRING: name = "CHAR"; break;
+ case TYPE_SHORT: name = "SMALLINT"; break;
+ case TYPE_INT: name = "INTEGER"; break;
+ case TYPE_BIGINT: name = "BIGINT"; break;
+ case TYPE_DATE: name = "DATE"; break;
+ case TYPE_FLOAT: name = "FLOAT"; break;
+ } // endswitch type
+
+ return name;
+ } // end of GetTypeName
+
+/***********************************************************************/
+/* GetTypeSize: returns the PlugDB internal type size. */
+/***********************************************************************/
+int GetTypeSize(int type, int len)
+ {
+ switch (type) {
+ case TYPE_STRING: len = len * sizeof(char); break;
+ case TYPE_SHORT: len = sizeof(short); break;
+ case TYPE_INT: len = sizeof(int); break;
+ case TYPE_BIGINT: len = sizeof(longlong); break;
+ case TYPE_DATE: len = sizeof(int); break;
+ case TYPE_FLOAT: len = sizeof(double); break;
+ break;
+ default: len = 0;
+ } // endswitch type
+
+ return len;
+ } // end of GetTypeSize
+
+/***********************************************************************/
+/* GetPLGType: returns the PlugDB type corresponding to a DB type. */
+/***********************************************************************/
+int GetPLGType(int type)
+ {
+ int tp;
+
+ switch (type) {
+ case DB_CHAR:
+ case DB_STRING: tp = TYPE_STRING; break;
+ case DB_SHORT: tp = TYPE_SHORT; break;
+ case DB_INT: tp = TYPE_INT; break;
+ case DB_DOUBLE: tp = TYPE_FLOAT; break;
+ case DB_DATE: tp = TYPE_DATE; break;
+ default: tp = TYPE_ERROR;
+ } // endswitch type
+
+ return tp;
+ } // end of GetPLGType
+
+/***********************************************************************/
+/* GetDBType: returns the DB type corresponding to a PlugDB type. */
+/***********************************************************************/
+int GetDBType(int type)
+ {
+ int tp;
+
+ switch (type) {
+ case TYPE_STRING: tp = DB_CHAR; break;
+ case TYPE_SHORT: tp = DB_SHORT; break;
+ case TYPE_INT: tp = DB_INT; break;
+ case TYPE_BIGINT:
+ case TYPE_FLOAT: tp = DB_DOUBLE; break;
+ case TYPE_DATE: tp = DB_DATE; break;
+ default: tp = DB_ERROR;
+ } // endswitch type
+
+ return tp;
+ } // end of GetPLGType
+
+/***********************************************************************/
+/* GetFormatType: returns the FORMAT character(s) according to type. */
+/***********************************************************************/
+char *GetFormatType(int type)
+ {
+ char *c = "X";
+
+ switch (type) {
+ case TYPE_STRING: c = "C"; break;
+ case TYPE_SHORT: c = "S"; break;
+ case TYPE_INT: c = "N"; break;
+ case TYPE_BIGINT: c = "L"; break;
+ case TYPE_FLOAT: c = "F"; break;
+ case TYPE_DATE: c = "D"; break;
+ } // endswitch type
+
+ return c;
+ } // end of GetFormatType
+
+/***********************************************************************/
+/* GetFormatType: returns the FORMAT type according to character. */
+/***********************************************************************/
+int GetFormatType(char c)
+ {
+ int type = TYPE_ERROR;
+
+ switch (c) {
+ case 'C': type = TYPE_STRING; break;
+ case 'S': type = TYPE_SHORT; break;
+ case 'N': type = TYPE_INT; break;
+ case 'L': type = TYPE_BIGINT; break;
+ case 'F': type = TYPE_FLOAT; break;
+ case 'D': type = TYPE_DATE; break;
+ } // endswitch type
+
+ return type;
+ } // end of GetFormatType
+
+
+/***********************************************************************/
+/* IsTypeChar: returns true for character type(s). */
+/***********************************************************************/
+bool IsTypeChar(int type)
+ {
+ switch (type) {
+ case TYPE_STRING:
+ return true;
+ } // endswitch type
+
+ return false;
+ } // end of IsTypeChar
+
+/***********************************************************************/
+/* IsTypeNum: returns true for numeric types. */
+/***********************************************************************/
+bool IsTypeNum(int type)
+ {
+ switch (type) {
+ case TYPE_INT:
+ case TYPE_BIGINT:
+ case TYPE_DATE:
+ case TYPE_FLOAT:
+ case TYPE_SHORT:
+ case TYPE_NUM:
+ return true;
+ } // endswitch type
+
+ return false;
+ } // end of IsTypeNum
+
+/***********************************************************************/
+/* ConvertType: what this function does is to determine the type to */
+/* which should be converted a value so no precision would be lost. */
+/* This can be a numeric type if num is true or non numeric if false. */
+/* Note: this is an ultra simplified version of this function that */
+/* should become more and more complex as new types are added. */
+/* Not evaluated types (TYPE_VOID or TYPE_UNDEF) return false from */
+/* IsType... functions so match does not prevent correct setting. */
+/***********************************************************************/
+int ConvertType(int target, int type, CONV kind, bool match)
+ {
+ switch (kind) {
+ case CNV_CHAR:
+ if (match && (!IsTypeChar(target) || !IsTypeChar(type)))
+ return TYPE_ERROR;
+
+ return TYPE_STRING;
+ case CNV_NUM:
+ if (match && (!IsTypeNum(target) || !IsTypeNum(type)))
+ return TYPE_ERROR;
+
+ return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT
+ : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
+ : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
+ : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
+ : TYPE_SHORT;
+ default:
+ if (target == TYPE_ERROR || target == type)
+ return type;
+
+ if (match && ((IsTypeChar(target) && !IsTypeChar(type)) ||
+ (IsTypeNum(target) && !IsTypeNum(type))))
+ return TYPE_ERROR;
+
+ return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT
+ : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
+ : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
+ : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
+ : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT
+ : (target == TYPE_STRING || type == TYPE_STRING) ? TYPE_STRING
+ : TYPE_ERROR;
+ } // endswitch kind
+
+ } // end of ConvertType
+
+/***********************************************************************/
+/* AllocateConstant: allocates a constant Value. */
+/***********************************************************************/
+PVAL AllocateValue(PGLOBAL g, void *value, short type)
+ {
+ PVAL valp;
+
+ if (trace)
+ htrc("AllocateConstant: value=%p type=%hd\n", value, type);
+
+ switch (type) {
+ case TYPE_STRING: valp = new(g) STRING((PSZ)value); break;
+ case TYPE_SHORT: valp = new(g) SHVAL(*(short*)value); break;
+ case TYPE_INT: valp = new(g) INTVAL(*(int*)value); break;
+ case TYPE_BIGINT: valp = new(g) BIGVAL(*(longlong*)value); break;
+ case TYPE_FLOAT: valp = new(g) DFVAL(*(double *)value); break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
+ return NULL;
+ } // endswitch Type
+
+ valp->SetGlobal(g);
+ return valp;
+ } // end of AllocateValue
+
+/***********************************************************************/
+/* Allocate a variable Value according to type, length and precision. */
+/***********************************************************************/
+PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
+ PSZ dom, PCATLG cat)
+ {
+ PVAL valp;
+
+ switch (type) {
+ case TYPE_STRING: valp = new(g) STRING(g, (PSZ)NULL, len, prec);
+ break;
+ case TYPE_DATE: valp = new(g) DTVAL(g, len, prec, dom); break;
+ case TYPE_INT: valp = new(g) INTVAL((int)0); break;
+ case TYPE_BIGINT: valp = new(g) BIGVAL((longlong)0); break;
+ case TYPE_SHORT: valp = new(g) SHVAL((short)0); break;
+ case TYPE_FLOAT: valp = new(g) DFVAL(0.0, prec); break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
+ return NULL;
+ } // endswitch type
+
+ valp->SetGlobal(g);
+ return valp;
+ } // end of AllocateValue
+
+/***********************************************************************/
+/* Allocate a constant Value converted to newtype. */
+/* Can also be used to copy a Value eventually converted. */
+/***********************************************************************/
+PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
+ {
+ PSZ p, sp;
+
+ if (newtype == TYPE_VOID) // Means allocate a value of the same type
+ newtype = valp->GetType();
+
+ switch (newtype) {
+ case TYPE_STRING:
+ p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen());
+
+ if ((sp = valp->GetCharString(p)) != p)
+ strcpy (p, sp);
+
+ valp = new(g) STRING(g, p, valp->GetValLen(), valp->GetValPrec());
+ break;
+ case TYPE_SHORT: valp = new(g) SHVAL(valp->GetShortValue()); break;
+ case TYPE_INT: valp = new(g) INTVAL(valp->GetIntValue()); break;
+ case TYPE_BIGINT: valp = new(g) BIGVAL(valp->GetBigintValue()); break;
+ case TYPE_DATE: valp = new(g) DTVAL(g, valp->GetIntValue()); break;
+ case TYPE_FLOAT: valp = new(g) DFVAL(valp->GetFloatValue()); break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype);
+ return NULL;
+ } // endswitch type
+
+ valp->SetGlobal(g);
+ return valp;
+ } // end of AllocateValue
+
+
+/* -------------------------- Class VALUE ---------------------------- */
+
+/***********************************************************************/
+/* ShowTypedValue: send back the value formatted according to parms. */
+/* buf: is a pointer to a buffer large enough for big double values. */
+/* typ: is the type wanted for the value character representation. */
+/* n: is the field length (needed for right justification. */
+/* p: is the precision (for float representations). */
+/* Note: this fonction is currently not used anymore. */
+/***********************************************************************/
+char *VALUE::ShowTypedValue(PGLOBAL g, char *buf, int typ, int n, int p)
+ {
+ switch (typ) {
+ case TYPE_STRING:
+ buf = GetCharString(buf);
+ break;
+ case TYPE_INT:
+ case TYPE_DATE:
+ buf = GetIntString(buf, n);
+ break;
+ case TYPE_FLOAT:
+ buf = GetFloatString(buf, n, p);
+ break;
+ case TYPE_SHORT:
+ buf = GetShortString(buf, n);
+ break;
+ case TYPE_BIGINT:
+ buf = GetBigintString(buf, n);
+ break;
+ default:
+ // More should be added for additional values.
+ if (trace)
+ htrc("Invalid col format type %d\n", typ);
+
+ sprintf(g->Message, MSG(BAD_COL_FORMAT), typ);
+ longjmp(g->jumper[g->jump_level], 31);
+ } // endswitch Type
+
+ return buf;
+ } // end of ShowTypedValue
+
+/***********************************************************************/
+/* Returns a BYTE indicating the comparison between two values. */
+/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */
+/* More than 1 bit can be set only in the case of TYPE_LIST. */
+/***********************************************************************/
+BYTE VALUE::TestValue(PVAL vp)
+ {
+ int n = CompareValue(vp);
+
+ return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01;
+ } // end of TestValue
+
+/* -------------------------- Class STRING --------------------------- */
+
+/***********************************************************************/
+/* STRING public constructor from a constant string. */
+/***********************************************************************/
+STRING::STRING(PSZ s) : VALUE(TYPE_STRING)
+ {
+ Strp = s;
+ Len = strlen(s);
+ Clen = Len;
+ Ci = false;
+ } // end of STRING constructor
+
+/***********************************************************************/
+/* STRING public constructor from char. */
+/***********************************************************************/
+STRING::STRING(PGLOBAL g, PSZ s, int n, int c) : VALUE(TYPE_STRING)
+ {
+ Len = n;
+
+ if (!s) {
+ Strp = (char *)PlugSubAlloc(g, NULL, Len + 1);
+ Strp[Len] = '\0';
+ } else
+ Strp = s;
+
+ Clen = Len;
+ Ci = (c != 0);
+ } // end of STRING constructor
+
+/***********************************************************************/
+/* STRING public constructor from short. */
+/***********************************************************************/
+STRING::STRING(PGLOBAL g, short i) : VALUE(TYPE_STRING)
+ {
+ Strp = (char *)PlugSubAlloc(g, NULL, 12);
+ Len = sprintf(Strp, "%hd", i);
+ Clen = Len;
+ Ci = false;
+ } // end of STRING constructor
+
+/***********************************************************************/
+/* STRING public constructor from int. */
+/***********************************************************************/
+STRING::STRING(PGLOBAL g, int n) : VALUE(TYPE_STRING)
+ {
+ Strp = (char *)PlugSubAlloc(g, NULL, 12);
+ Len = sprintf(Strp, "%d", n);
+ Clen = Len;
+ Ci = false;
+ } // end of STRING constructor
+
+/***********************************************************************/
+/* STRING public constructor from bigint. */
+/***********************************************************************/
+STRING::STRING(PGLOBAL g, longlong n) : VALUE(TYPE_STRING)
+ {
+ Strp = (char *)PlugSubAlloc(g, NULL, 12);
+ Len = sprintf(Strp, "%lld", n);
+ Clen = Len;
+ Ci = false;
+ } // end of STRING constructor
+
+/***********************************************************************/
+/* STRING public constructor from double. */
+/***********************************************************************/
+STRING::STRING(PGLOBAL g, double f) : VALUE(TYPE_STRING)
+ {
+ Strp = (char *)PlugSubAlloc(g, NULL, 32);
+ Len = sprintf(Strp, "%lf", f);
+ Clen = Len;
+ Ci = false;
+ } // end of STRING constructor
+
+/***********************************************************************/
+/* STRING SetValue: copy the value of another Value object. */
+/***********************************************************************/
+bool STRING::SetValue_pval(PVAL valp, bool chktype)
+ {
+ if (chktype && (valp->GetType() != Type || valp->GetSize() > Len))
+ return true;
+
+ char buf[32];
+
+ strncpy(Strp, valp->GetCharString(buf), Len);
+ return false;
+ } // end of SetValue_pval
+
+/***********************************************************************/
+/* STRING SetValue: fill string with chars extracted from a line. */
+/***********************************************************************/
+void STRING::SetValue_char(char *p, int n)
+ {
+ n = min(n, Len);
+ strncpy(Strp, p, n);
+
+ for (p = Strp + n - 1; (*p == ' ' || *p == '\0') && p >= Strp; p--) ;
+
+ *(++p) = '\0';
+
+ if (trace)
+ htrc(" Setting string to: '%s'\n", Strp);
+
+ } // end of SetValue_char
+
+/***********************************************************************/
+/* STRING SetValue: fill string with another string. */
+/***********************************************************************/
+void STRING::SetValue_psz(PSZ s)
+ {
+ strncpy(Strp, s, Len);
+ } // end of SetValue_psz
+
+/***********************************************************************/
+/* STRING SetValue: fill string with a string extracted from a block. */
+/***********************************************************************/
+void STRING::SetValue_pvblk(PVBLK blk, int n)
+ {
+ strncpy(Strp, blk->GetCharValue(n), Len);
+ } // end of SetValue_pvblk
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a short int. */
+/***********************************************************************/
+void STRING::SetValue(short n)
+ {
+ SetValue((int)n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of an integer. */
+/***********************************************************************/
+void STRING::SetValue(int n)
+ {
+ char buf[16];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%d", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ longjmp(g->jumper[g->jump_level], 138);
+ } else
+ SetValue_psz(buf);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a big integer.*/
+/***********************************************************************/
+void STRING::SetValue(longlong n)
+ {
+ char buf[24];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%lld", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ longjmp(g->jumper[g->jump_level], 138);
+ } else
+ SetValue_psz(buf);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a double. */
+/***********************************************************************/
+void STRING::SetValue(double f)
+ {
+ char *p, buf[32];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%lf", f);
+
+ for (p = buf + k - 1; p >= buf; p--)
+ if (*p == '0') {
+ *p = 0;
+ k--;
+ } else
+ break;
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ longjmp(g->jumper[g->jump_level], 138);
+ } else
+ SetValue_psz(buf);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* STRING SetBinValue: fill string with chars extracted from a line. */
+/***********************************************************************/
+void STRING::SetBinValue(void *p)
+ {
+ SetValue_char((char *)p, Len);
+ } // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool STRING::GetBinValue(void *buf, int buflen, bool go)
+ {
+ int len = strlen(Strp);
+
+ if (len > buflen)
+ return true;
+ else if (go) {
+ memset(buf, ' ', buflen);
+ memcpy(buf, Strp, len);
+ } // endif go
+
+ return false;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
+/* This is a fast implementation that does not do any checking. */
+/***********************************************************************/
+void STRING::GetBinValue(void *buf, int buflen)
+ {
+ assert(buflen >= (signed)strlen(Strp));
+
+ memset(buf, ' ', buflen);
+ memcpy(buf, Strp, buflen);
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* STRING ShowValue: get string representation of a char value. */
+/***********************************************************************/
+char *STRING::ShowValue(char *buf, int len)
+ {
+ return Strp;
+ } // end of ShowValue
+
+/***********************************************************************/
+/* STRING GetCharString: get string representation of a char value. */
+/***********************************************************************/
+char *STRING::GetCharString(char *p)
+ {
+ return Strp;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* STRING GetShortString: get short representation of a char value. */
+/***********************************************************************/
+char *STRING::GetShortString(char *p, int n)
+ {
+ sprintf(p, "%*hd", n, (short)atoi(Strp));
+ return p;
+ } // end of GetShortString
+
+/***********************************************************************/
+/* STRING GetIntString: get int representation of a char value. */
+/***********************************************************************/
+char *STRING::GetIntString(char *p, int n)
+ {
+ sprintf(p, "%*d", n, atol(Strp));
+ return p;
+ } // end of GetIntString
+
+/***********************************************************************/
+/* STRING GetBigintString: get big int representation of a char value.*/
+/***********************************************************************/
+char *STRING::GetBigintString(char *p, int n)
+ {
+ sprintf(p, "%*lld", n, atoll(Strp));
+ return p;
+ } // end of GetBigintString
+
+/***********************************************************************/
+/* STRING GetFloatString: get double representation of a char value. */
+/***********************************************************************/
+char *STRING::GetFloatString(char *p, int n, int prec)
+ {
+ sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, atof(Strp));
+ return p;
+ } // end of GetFloatString
+
+/***********************************************************************/
+/* STRING compare value with another Value. */
+/***********************************************************************/
+bool STRING::IsEqual(PVAL vp, bool chktype)
+ {
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else if (Ci || vp->IsCi())
+ return !stricmp(Strp, vp->GetCharValue());
+ else // (!Ci)
+ return !strcmp(Strp, vp->GetCharValue());
+
+ } // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of character filters. */
+/***********************************************************************/
+int STRING::CompareValue(PVAL vp)
+ {
+ int n;
+//assert(vp->GetType() == Type);
+
+ if (trace)
+ htrc(" Comparing: val='%s','%s'\n", Strp, vp->GetCharValue());
+
+ // Process filtering on character strings.
+ if (Ci || vp->IsCi())
+ n = stricmp(Strp, vp->GetCharValue());
+ else
+ n = strcmp(Strp, vp->GetCharValue());
+
+#if defined(WIN32)
+ if (n == _NLSCMPERROR)
+ return n; // Here we should raise an error
+#endif // WIN32
+
+ return (n > 0) ? 1 : (n < 0) ? -1 : 0;
+ } // end of CompareValue
+
+/***********************************************************************/
+/* Returns a BYTE indicating the comparison between two values. */
+/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */
+/* More than 1 bit are set only in the case of error. */
+/***********************************************************************/
+BYTE STRING::TestValue(PVAL vp)
+ {
+ // Process filtering on character strings.
+ bool ci = (Ci || vp->IsCi());
+ int n = (ci) ? stricmp(Strp, vp->GetCharValue())
+ : strcmp(Strp, vp->GetCharValue());
+
+#if defined(WIN32)
+ if (n == _NLSCMPERROR)
+ return 0x07; // Here we could raise an error
+#endif // WIN32
+
+ return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01;
+ } // end of TestValue
+
+/***********************************************************************/
+/* Compute a function on a string. */
+/***********************************************************************/
+bool STRING::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+ {
+ assert(np <= 3);
+
+ if (op == OP_SUBST) {
+ /*******************************************************************/
+ /* SUBSTR: this functions have 1 STRING parameter followed by */
+ /* 1 or 2 int parameters. */
+ /*******************************************************************/
+ char *p, *s, buf[32];
+ int i, n, len;
+
+ assert(np >= 2);
+
+ s = vp[0]->GetCharString(buf);
+ i = (int)vp[1]->GetIntValue(); // Starting point
+ n = (np > 2) ? (int)vp[2]->GetIntValue(): 0;
+ len = strlen(s);
+ *Strp = '\0';
+
+ if (i > len || i < -len || i == 0 || n < 0)
+ p = NULL;
+ else if (i > 0)
+ p = s + i - 1;
+ else
+ p = s + len + i;
+
+ if (p) {
+ /******************************************************************/
+ /* This should not happen if the result size has been set */
+ /* accurately, and this test could be placed under trace. */
+ /******************************************************************/
+ if (((n > 0) ? min(n, (signed)strlen(p)) : (signed)strlen(p)) > Len) {
+ strcpy(g->Message, MSG(SUB_RES_TOO_LNG));
+ return true;
+ } // endif
+
+ /******************************************************************/
+ /* Do the actual Substr operation. */
+ /******************************************************************/
+ if (n > 0)
+ strncat(Strp, p, n);
+ else
+ strcpy(Strp, p);
+
+ } // endif p
+
+ if (trace)
+ htrc("SUBSTR result=%s val=%s,%d,%d", Strp, s, i, n);
+
+ } else if (op == OP_LTRIM || op == OP_RTRIM) {
+ /*******************************************************************/
+ /* Trimming functions have one STRING parameter followed by one */
+ /* CHAR parameter (one chararacter). */
+ /*******************************************************************/
+ char *p, buf[32], c = ' ';
+ PSZ strg;
+ int len;
+
+ assert(np > 0);
+
+ strg = vp[0]->GetCharString(buf);
+ len = strlen(strg);
+ strg = strcpy(Strp, strg);
+
+ if (len > 0) {
+ if (np > 1) {
+ // Character value may have been entered as an integer
+ if (vp[1]->GetType() == TYPE_INT)
+ c = (char)vp[1]->GetIntValue();
+ else if (IsTypeChar(vp[1]->GetType()))
+ c = *vp[1]->GetCharValue();
+ else {
+ strcpy(g->Message, MSG(BAD_TRIM_ARGTYP));
+ return true;
+ } // endelse
+
+ } // endif 2 args
+
+ if (op == OP_LTRIM) {
+ for (p = strg; *p == c; p++) ;
+
+ if (p != strg)
+ do {
+ *(strg++) = *p;
+ } while (*(p++)); /* enddo */
+
+ } else // OP_RTRIM:
+ for (p = strg + len - 1; *p == c && p >= strg; p--)
+ *p = '\0';
+
+ } // endif len
+
+ } else if (op == OP_LPAD || op == OP_RPAD ||
+ op == OP_LJUST || op == OP_RJUST || op == OP_CJUST) {
+ /*******************************************************************/
+ /* Pad and justify functions have 3 arguments char, NUM and C. */
+ /*******************************************************************/
+ PSZ strg;
+ int i, n1, n2, len;
+ int n = 0;
+ char buf[32], c = ' ';
+
+ assert(np > 0);
+
+ strg = vp[0]->GetCharString(buf);
+ len = strlen(strg);
+ strg = strcpy(Strp, strg);
+
+ if (np > 1) {
+ n = vp[1]->GetIntValue();
+
+ if (n > Len) {
+ sprintf(g->Message, MSG(OP_RES_TOO_LONG), op);
+ return true;
+ } // endif
+
+ if (np > 2) {
+ // Character value may have been entered as an integer
+ if (vp[2]->GetType() == TYPE_INT)
+ c = (char)vp[2]->GetIntValue();
+ else if (IsTypeChar(vp[2]->GetType()))
+ c = *vp[2]->GetCharValue();
+ else {
+ strcpy(g->Message, MSG(BAD_PAD_ARGTYP));
+ return true;
+ } // endelse
+
+ } // endif 3 args
+
+ } // endif 2 args
+
+ if (n == 0)
+ n = Len;
+
+ if ((n = (n - (int)len)) > 0) {
+ switch (op) {
+ case OP_RPAD:
+ case OP_LJUST:
+ n1 = 0;
+ n2 = (int)n;
+ break;
+ case OP_LPAD:
+ case OP_RJUST:
+ n1 = (int)n;
+ n2 = 0;
+ break;
+ case OP_CJUST:
+ n1 = (int)n / 2;
+ n2 = (int)n - n1;
+ break;
+ default:
+ sprintf(g->Message, MSG(INVALID_OPER), op, "Compute");
+ return true;
+ } // endswitch op
+
+ if (n1 > 0) {
+ for (i = len; i >= 0; i--)
+ *(strg + i + n1) = *(strg + i);
+
+ for (i = 0; i < n1; i++)
+ *(strg + i) = c;
+
+ len += n1;
+ } // endif n1
+
+ if (n2 > 0) {
+ for (i = len; i < len + n2; i++)
+ *(strg + i) = c;
+
+ *(strg + len + n2) = '\0';
+ } // endif n2
+
+ } // endif n
+
+ if (trace)
+ htrc(" function result=%s\n", strg);
+
+ } else if (op == OP_SNDX) {
+ /*******************************************************************/
+ /* SOUNDEX function: one string argument. */
+ /* In addition to Knuth standard algorithm, we accept and ignore */
+ /* all non alpha characters. */
+ /*******************************************************************/
+ static int t[27] =
+ {0,1,2,3,0,1,2,0,0,2,2,4,5,5,0,1,2,6,2,3,0,1,0,2,0,2,0};
+ // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [
+ char *p, s[65];
+ int i, n;
+ bool b = false;
+
+ assert(np == 1);
+
+ p = vp[0]->GetCharValue();
+
+ for (i = 0; i < 64; p++)
+ if (isalpha(*p)) {
+ s[i++] = toupper(*p);
+ b = true;
+ } else if (!*p)
+ break;
+ else
+ s[i++] = 'Z' + 1;
+
+ if (b) {
+ s[i] = '\0';
+ Strp[0] = *s;
+ } else {
+ strcpy(Strp, " "); // Null string
+ return false;
+ } // endif i
+
+ for (i = 1, p = s + 1; *p && i < 4; p++)
+ if ((n = t[*p - 'A'])) {
+ Strp[i] = '0' + n;
+
+ if (!b || Strp[i] != Strp[i - 1]) {
+ b = true;
+ i++;
+ } // endif dup
+
+ } else
+ b = false;
+
+ for (; i < 4; i++)
+ Strp[i] = '0';
+
+// Strp[4] = '\0';
+ } else {
+ /*******************************************************************/
+ /* All other functions have STRING parameter(s). */
+ /*******************************************************************/
+ char *p[3], val[3][32];
+ int i;
+
+ for (i = 0; i < np; i++)
+ p[i] = vp[i]->GetCharString(val[i]);
+
+ switch (op) {
+ case OP_LOWER:
+ assert(np == 1);
+ strlwr(strcpy(Strp, p[0]));
+ break;
+ case OP_UPPER:
+ assert(np == 1);
+ strupr(strcpy(Strp, p[0]));
+ break;
+ case OP_CNC:
+ assert(np == 2);
+ strncat(strncpy(Strp, p[0], Len), p[1], Len);
+ break;
+ case OP_MIN:
+ assert(np == 2);
+ strcpy(Strp, (strcmp(p[0], p[1]) < 0) ? p[0] : p[1]);
+ break;
+ case OP_MAX:
+ assert(np == 2);
+ strcpy(Strp, (strcmp(p[0], p[1]) > 0) ? p[0] : p[1]);
+ break;
+ case OP_REPL:
+ {char *pp;
+ int i, len;
+
+ if (np == 2) {
+ p[2] = "";
+ np = 3;
+ } else
+ assert(np == 3);
+
+ if ((len = strlen(p[1]))) {
+ *Strp = '\0';
+
+ do {
+ if ((pp = strstr(p[0], p[1]))) {
+ i = strlen(Strp) + (pp - p[0]) + strlen(p[2]);
+
+ if (i > Len) {
+ if (trace)
+ htrc(" error len=%d R_Length=%d\n", i, Len);
+
+ sprintf(g->Message, MSG(OP_RES_TOO_LONG), op);
+ return true;
+ } // endif
+
+ strncat(Strp, p[0], pp - p[0]);
+ strcat(Strp, p[2]);
+ p[0] = pp + len;
+ } else
+ strcat(Strp, p[0]);
+
+ } while (pp); // enddo
+
+ } else
+ strcpy(Strp, p[0]);
+
+ }break;
+ case OP_TRANSL:
+ {unsigned char *p0, *p1, *p2, cp[256];
+ unsigned int k, n = strlen(p[1]);
+
+ assert(np == 3 && n == strlen(p[2]));
+
+ p0 = (unsigned char *)p[0];
+ p1 = (unsigned char *)p[1];
+ p2 = (unsigned char *)p[2];
+
+ for (k = 0; k < 256; k++)
+ cp[k] = k;
+
+ for (k = 0; k < n; k++)
+ cp[p1[k]] = p2[k];
+
+ for (k = 0; k < strlen(p[0]); k++)
+ Strp[k] = cp[p0[k]];
+
+ Strp[k] = 0;
+ }break;
+ case OP_FDISK:
+ case OP_FPATH:
+ case OP_FNAME:
+ case OP_FTYPE:
+// if (!ExtractFromPath(g, Strp, p[0], op))
+// return true;
+
+// break;
+ default:
+ sprintf(g->Message, MSG(BAD_EXP_OPER), op);
+ return true;
+ } // endswitch op
+
+ if (trace) {
+ htrc("Compute result=%s val=%s", Strp, p[0]);
+
+ for (i = 1; i < np; i++)
+ htrc(",%s", p[i]);
+
+ htrc(" op=%d\n", op);
+ } // endif trace
+
+ } // endif op
+
+ return false;
+ } // end of Compute
+
+/***********************************************************************/
+/* GetTime: extract the time from a string of format hh:mm:ss */
+/***********************************************************************/
+int STRING::GetTime(PGLOBAL g, PVAL *vp, int np)
+ {
+ int hh, mm, ss;
+
+ hh = mm = ss = 0;
+ sscanf(Strp, " %d : %d : %d", &hh, &mm, &ss);
+ return ((hh * 3600) + (mm * 60) + ss);
+ } // end of GetTime
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool STRING::FormatValue(PVAL vp, char *fmt)
+ {
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Strp);
+
+ return (n > vp->GetValLen());
+ } // end of FormatValue
+
+/***********************************************************************/
+/* SetMin: used by the aggregate function MIN. */
+/***********************************************************************/
+void STRING::SetMin(PVAL vp)
+ {
+ char *val = vp->GetCharValue();
+
+ assert(strlen(val) <= (unsigned)Len);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
+ strcpy(Strp, val);
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void STRING::SetMin(PVBLK vbp, int i)
+ {
+ char *val = vbp->GetCharValue(i);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
+ strcpy(Strp, val);
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void STRING::SetMin(PVBLK vbp, int j, int k)
+ {
+ char *val;
+
+ for (register int i = j; i < k; i++) {
+ val = vbp->GetCharValue(i);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
+ strcpy(Strp, val);
+
+ } // endfor i
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void STRING::SetMin(PVBLK vbp, int *x, int j, int k)
+ {
+ char *val;
+
+ for (register int i = j; i < k; i++) {
+ val = vbp->GetCharValue(x[i]);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
+ strcpy(Strp, val);
+
+ } // endfor i
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMax: used by the aggregate function MAX. */
+/***********************************************************************/
+void STRING::SetMax(PVAL vp)
+ {
+ char *val = vp->GetCharValue();
+
+ assert(strlen(val) <= (unsigned)Len);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
+ strcpy(Strp, val);
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void STRING::SetMax(PVBLK vbp, int i)
+ {
+ char *val = vbp->GetCharValue(i);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
+ strcpy(Strp, val);
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void STRING::SetMax(PVBLK vbp, int j, int k)
+ {
+ char *val;
+
+ for (register int i = j; i < k; i++) {
+ val = vbp->GetCharValue(i);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
+ strcpy(Strp, val);
+
+ } // endfor i
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void STRING::SetMax(PVBLK vbp, int *x, int j, int k)
+ {
+ char *val;
+
+ for (register int i = j; i < k; i++) {
+ val = vbp->GetCharValue(x[i]);
+
+ if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
+ strcpy(Strp, val);
+
+ } // endfor i
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* STRING SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool STRING::SetConstFormat(PGLOBAL g, FORMAT& fmt)
+ {
+ fmt.Type[0] = 'C';
+ fmt.Length = Len;
+ fmt.Prec = 0;
+ return false;
+ } // end of SetConstFormat
+
+/***********************************************************************/
+/* Make file output of a STRING object. */
+/***********************************************************************/
+void STRING::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+
+ fprintf(f, "%s%s\n", m, Strp);
+ } // end of Print
+
+/***********************************************************************/
+/* Make string output of a STRING object. */
+/***********************************************************************/
+void STRING::Print(PGLOBAL g, char *ps, uint z)
+ {
+ sprintf(ps, "'%.*s'", z-3, Strp);
+ } // end of Print
+
+/* -------------------------- Class SHVAL ---------------------------- */
+
+/***********************************************************************/
+/* SHVAL public constructor from char. */
+/***********************************************************************/
+SHVAL::SHVAL(PSZ s) : VALUE(TYPE_SHORT)
+ {
+ Sval = atoi(s);
+ Clen = sizeof(short);
+ } // end of SHVAL constructor
+
+/***********************************************************************/
+/* SHVAL public constructor from short. */
+/***********************************************************************/
+SHVAL::SHVAL(short i) : VALUE(TYPE_SHORT)
+ {
+ Sval = i;
+ Clen = sizeof(short);
+ } // end of SHVAL constructor
+
+/***********************************************************************/
+/* SHVAL public constructor from int. */
+/***********************************************************************/
+SHVAL::SHVAL(int n) : VALUE(TYPE_SHORT)
+ {
+ Sval = (short)n;
+ Clen = sizeof(short);
+ } // end of SHVAL constructor
+
+/***********************************************************************/
+/* SHVAL public constructor from big int. */
+/***********************************************************************/
+SHVAL::SHVAL(longlong n) : VALUE(TYPE_SHORT)
+ {
+ Sval = (short)n;
+ Clen = sizeof(short);
+ } // end of SHVAL constructor
+
+/***********************************************************************/
+/* SHVAL public constructor from double. */
+/***********************************************************************/
+SHVAL::SHVAL(double f) : VALUE(TYPE_SHORT)
+ {
+ Sval = (short)f;
+ Clen = sizeof(short);
+ } // end of SHVAL constructor
+
+/***********************************************************************/
+/* SHVAL GetValLen: returns the print length of the short object. */
+/***********************************************************************/
+int SHVAL::GetValLen(void)
+ {
+ char c[16];
+
+ return sprintf(c, "%hd", Sval);
+ } // end of GetValLen
+
+/***********************************************************************/
+/* SHVAL SetValue: copy the value of another Value object. */
+/* This function allows conversion if chktype is false. */
+/***********************************************************************/
+bool SHVAL::SetValue_pval(PVAL valp, bool chktype)
+ {
+ if (chktype && Type != valp->GetType())
+ return true;
+
+ Sval = valp->GetShortValue();
+ return false;
+ } // end of SetValue
+
+/***********************************************************************/
+/* SHVAL SetValue: convert chars extracted from a line to short value */
+/***********************************************************************/
+void SHVAL::SetValue_char(char *p, int n)
+ {
+ char *p2;
+ bool minus;
+
+// if (trace) wrong because p can be not null terminated
+// htrc("SHVAL_char: p='%s' n=%d\n", p, n);
+
+ for (p2 = p + n; p < p2 && *p == ' '; p++) ;
+
+ for (Sval = 0, minus = false; p < p2; p++)
+ switch (*p) {
+ case '-':
+ minus = true;
+ case '+':
+ break;
+ case '0': Sval = Sval * 10; break;
+ case '1': Sval = Sval * 10 + 1; break;
+ case '2': Sval = Sval * 10 + 2; break;
+ case '3': Sval = Sval * 10 + 3; break;
+ case '4': Sval = Sval * 10 + 4; break;
+ case '5': Sval = Sval * 10 + 5; break;
+ case '6': Sval = Sval * 10 + 6; break;
+ case '7': Sval = Sval * 10 + 7; break;
+ case '8': Sval = Sval * 10 + 8; break;
+ case '9': Sval = Sval * 10 + 9; break;
+ default:
+ p = p2;
+ } // endswitch *p
+
+ if (minus && Sval)
+ Sval = - Sval;
+
+ if (trace)
+ htrc(" setting short to: %hd\n", Sval);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* SHVAL SetValue: fill a short value from a string. */
+/***********************************************************************/
+void SHVAL::SetValue_psz(PSZ s)
+ {
+ Sval = atoi(s);
+ } // end of SetValue
+
+/***********************************************************************/
+/* SHVAL SetValue: set value with a short extracted from a block. */
+/***********************************************************************/
+void SHVAL::SetValue_pvblk(PVBLK blk, int n)
+ {
+ Sval = blk->GetShortValue(n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* SHVAL SetBinValue: with bytes extracted from a line. */
+/***********************************************************************/
+void SHVAL::SetBinValue(void *p)
+ {
+ Sval = *(short *)p;
+ } // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool SHVAL::GetBinValue(void *buf, int buflen, bool go)
+ {
+ // Test on length was removed here until a variable in column give the
+ // real field length. For BIN files the field length logically cannot
+ // be different from the variable length because no conversion is done.
+ // Therefore this test is useless anyway.
+//#if defined(_DEBUG)
+// if (sizeof(short) > buflen)
+// return true;
+//#endif
+
+ if (go)
+ *(short *)buf = Sval;
+
+ return false;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
+/* This is a fast implementation that does not do any checking. */
+/***********************************************************************/
+void SHVAL::GetBinValue(void *buf, int buflen)
+ {
+ assert(buflen == sizeof(short));
+
+ *(short *)buf = Sval;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* SHVAL ShowValue: get string representation of a short value. */
+/***********************************************************************/
+char *SHVAL::ShowValue(char *buf, int len)
+ {
+ sprintf(buf, "%*hd", len, Sval);
+ return buf;
+ } // end of ShowValue
+
+/***********************************************************************/
+/* SHVAL GetCharString: get string representation of a short value. */
+/***********************************************************************/
+char *SHVAL::GetCharString(char *p)
+ {
+ sprintf(p, "%hd", Sval);
+ return p;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* SHVAL GetShortString: get short representation of a short value. */
+/***********************************************************************/
+char *SHVAL::GetShortString(char *p, int n)
+ {
+ sprintf(p, "%*hd", n, Sval);
+ return p;
+ } // end of GetShortString
+
+/***********************************************************************/
+/* SHVAL GetIntString: get int representation of a short value. */
+/***********************************************************************/
+char *SHVAL::GetIntString(char *p, int n)
+ {
+ sprintf(p, "%*d", n, (int)Sval);
+ return p;
+ } // end of GetIntString
+
+/***********************************************************************/
+/* SHVAL GetBigintString: get big int representation of a short value.*/
+/***********************************************************************/
+char *SHVAL::GetBigintString(char *p, int n)
+ {
+ sprintf(p, "%*lld", n, (longlong)Sval);
+ return p;
+ } // end of GetBigintString
+
+/***********************************************************************/
+/* SHVAL GetFloatString: get double representation of a short value. */
+/***********************************************************************/
+char *SHVAL::GetFloatString(char *p, int n, int prec)
+ {
+ sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Sval);
+ return p;
+ } // end of GetFloatString
+
+/***********************************************************************/
+/* SHVAL compare value with another Value. */
+/***********************************************************************/
+bool SHVAL::IsEqual(PVAL vp, bool chktype)
+ {
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else
+ return (Sval == vp->GetShortValue());
+
+ } // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of short integer filters. */
+/***********************************************************************/
+int SHVAL::CompareValue(PVAL vp)
+ {
+//assert(vp->GetType() == Type);
+
+ // Process filtering on short integers.
+ short n = vp->GetShortValue();
+
+ if (trace > 1)
+ htrc(" Comparing: val=%hd,%hd\n", Sval, n);
+
+ return (Sval > n) ? 1 : (Sval < n) ? (-1) : 0;
+ } // end of CompareValue
+
+/***********************************************************************/
+/* SafeAdd: adds a value and test whether overflow/underflow occured. */
+/***********************************************************************/
+short SHVAL::SafeAdd(short n1, short n2)
+ {
+ PGLOBAL& g = Global;
+ short n = n1 + n2;
+
+ if ((n2 > 0) && (n < n1)) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_ADD));
+ longjmp(g->jumper[g->jump_level], 138);
+ } else if ((n2 < 0) && (n > n1)) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_ADD));
+ longjmp(g->jumper[g->jump_level], 138);
+ } // endif's n2
+
+ return n;
+ } // end of SafeAdd
+
+/***********************************************************************/
+/* SafeMult: multiply values and test whether overflow occured. */
+/***********************************************************************/
+short SHVAL::SafeMult(short n1, short n2)
+ {
+ PGLOBAL& g = Global;
+ double n = (double)n1 * (double)n2;
+
+ if (n > 32767.0) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
+ longjmp(g->jumper[g->jump_level], 138);
+ } else if (n < -32768.0) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
+ longjmp(g->jumper[g->jump_level], 138);
+ } // endif's n2
+
+ return (short)n;
+ } // end of SafeMult
+
+/***********************************************************************/
+/* Compute a function on a int integers. */
+/***********************************************************************/
+bool SHVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+ {
+ if (op == OP_LEN) {
+ assert(np == 1);
+ char buf[32];
+ char *p = vp[0]->GetCharString(buf);
+
+ Sval = strlen(p);
+
+ if (trace)
+ htrc("Compute result=%hd val=%s op=%d\n", Sval, p, op);
+
+ } else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
+ char *p, *tp = g->Message;
+ char *p1, val1[32];
+ char *p2, val2[32];
+ bool b = (vp[0]->IsCi() || vp[1]->IsCi());
+
+ assert(np == 2);
+
+ p1 = vp[0]->GetCharString(val1);
+ p2 = vp[1]->GetCharString(val2);
+
+ if (op != OP_LIKE) {
+ if (!strcmp(p2, "\\t"))
+ p2 = "\t";
+
+ if (b) { // Case insensitive
+ if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
+ !(tp = new char[strlen(p1) + strlen(p2) + 2])) {
+ strcpy(g->Message, MSG(NEW_RETURN_NULL));
+ return true;
+ } // endif p
+
+ // Make a lower case copy of p1 and p2
+ p1 = strlwr(strcpy(tp, p1));
+ p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
+ } // endif Ci
+
+ if (op == OP_CNTIN) {
+ size_t t2 = strlen(p2);
+
+ for (Sval = 0; (p = strstr(p1, p2)); Sval++, p1 = p + t2) ;
+
+ } else // OP_INSTR
+ Sval = (p = strstr(p1, p2)) ? 1 + (short)(p - p1) : 0;
+
+ if (tp != g->Message) // If working space was obtained
+ delete [] tp; // by the use of new, delete it.
+
+ } else // OP_LIKE
+ Sval = (PlugEvalLike(g, p1, p2, b)) ? 1 : 0;
+
+
+ if (trace)
+ htrc("Compute result=%hd val=%s,%s op=%d\n", Sval, p1, p2, op);
+
+ } else {
+ short val[2];
+
+ assert(np <= 2);
+
+ for (int i = 0; i < np; i++)
+ val[i] = vp[i]->GetShortValue();
+
+ switch (op) {
+ case OP_ABS:
+ assert(np == 1);
+ Sval = abs(*val);
+ break;
+ case OP_SIGN:
+ assert(np == 1);
+ Sval = (*val < 0) ? (-1) : 1;
+ break;
+ case OP_CEIL:
+ case OP_FLOOR:
+ assert(np == 1);
+ Sval = *val;
+ break;
+ case OP_ADD:
+ assert(np == 2);
+ Sval = SafeAdd(val[0], val[1]);
+ break;
+ case OP_SUB:
+ assert(np == 2);
+ Sval = SafeAdd(val[0], -val[1]);
+ break;
+ case OP_MULT:
+ assert(np == 2);
+ Sval = SafeMult(val[0], val[1]);
+ break;
+ case OP_MIN:
+ assert(np == 2);
+ Sval = min(val[0], val[1]);
+ break;
+ case OP_MAX:
+ assert(np == 2);
+ Sval = max(val[0], val[1]);
+ break;
+ case OP_DIV:
+ assert(np == 2);
+
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Sval = val[0] / val[1];
+ break;
+ case OP_MOD:
+ assert(np == 2);
+
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Sval = val[0] % val[1];
+ break;
+ case OP_BITAND:
+ assert(np == 2);
+ Sval = val[0] & val[1];
+ break;
+ case OP_BITOR:
+ assert(np == 2);
+ Sval = val[0] | val[1];
+ break;
+ case OP_BITXOR:
+ assert(np == 2);
+ Sval = val[0] ^ val[1];
+ break;
+ case OP_BITNOT:
+ assert(np == 1);
+ Sval = ~val[0];
+ break;
+ case OP_DELTA:
+// assert(np == 1);
+ Sval = val[0] - Sval;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_EXP_OPER), op);
+ return true;
+ } // endswitch op
+
+ if (trace) {
+ if (np = 1)
+ htrc(" result=%hd val=%hd op=%d\n", Sval, val[0], op);
+ else
+ htrc(" result=%hd val=%hd,%hd op=%d\n",
+ Sval, val[0], val[1], op);
+ } // endif trace
+
+ } // endif op
+
+ return false;
+ } // end of Compute
+
+/***********************************************************************/
+/* Divide: used by aggregate functions when calculating average. */
+/***********************************************************************/
+void SHVAL::Divide(int cnt)
+ {
+ Sval /= (short)cnt;
+ } // end of Divide
+
+/***********************************************************************/
+/* StdVar: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void SHVAL::StdVar(PVAL vp, int cnt, bool b)
+ {
+ short lv2 = vp->GetShortValue(), scnt = (short)cnt;
+
+ Sval = (scnt == 1) ? 0
+ : (SafeAdd(lv2, -(SafeMult(Sval, Sval) / scnt)) / (scnt - 1));
+
+ if (b) // Builtin == FNC_STDDEV
+ Sval = (short)sqrt((double)Sval);
+
+ } // end of StdVar
+
+/***********************************************************************/
+/* Times: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void SHVAL::Times(PVAL vp)
+ {
+ Sval = SafeMult(Sval, vp->GetShortValue());
+ } // end of Times
+
+/***********************************************************************/
+/* Add: used by aggregate functions for Sum and other functions. */
+/***********************************************************************/
+void SHVAL::Add(PVAL vp)
+ {
+ Sval = SafeAdd(Sval, vp->GetShortValue());
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void SHVAL::Add(PVBLK vbp, int i)
+ {
+ Sval = SafeAdd(Sval, vbp->GetShortValue(i));
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void SHVAL::Add(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ short *lp = (short *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Sval = SafeAdd(Sval, lp[i]);
+
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void SHVAL::Add(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ short *lp = (short *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Sval = SafeAdd(Sval, lp[x[i]]);
+
+ } // end of Add
+
+/***********************************************************************/
+/* AddSquare: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void SHVAL::AddSquare(PVAL vp)
+ {
+ short val = vp->GetShortValue();
+
+ Sval = SafeAdd(Sval, SafeMult(val, val));
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by QUERY for functions Stddev and Variance. */
+/***********************************************************************/
+void SHVAL::AddSquare(PVBLK vbp, int i)
+ {
+ short val = vbp->GetShortValue(i);
+
+ Sval = SafeAdd(Sval, SafeMult(val, val));
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by QUERY for functions Stddev and Variance. */
+/***********************************************************************/
+void SHVAL::AddSquare(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ short *lp = (short *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Sval = SafeAdd(Sval, SafeMult(lp[i], lp[i]));
+
+ } // end of AddSquare
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool SHVAL::FormatValue(PVAL vp, char *fmt)
+ {
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Sval);
+
+ return (n > vp->GetValLen());
+ } // end of FormatValue
+
+/***********************************************************************/
+/* SetMin: used by the aggregate function MIN. */
+/***********************************************************************/
+void SHVAL::SetMin(PVAL vp)
+ {
+ short val = vp->GetShortValue();
+
+ if (val < Sval)
+ Sval = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void SHVAL::SetMin(PVBLK vbp, int i)
+ {
+ short val = vbp->GetShortValue(i);
+
+ if (val < Sval)
+ Sval = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void SHVAL::SetMin(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ short *lp = (short *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (lp[i] < Sval)
+ Sval = lp[i];
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void SHVAL::SetMin(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ short val;
+ short *lp = (short *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = lp[x[i]];
+
+ if (val < Sval)
+ Sval = val;
+
+ } // endfor i
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMax: used by the aggregate function MAX. */
+/***********************************************************************/
+void SHVAL::SetMax(PVAL vp)
+ {
+ short val = vp->GetShortValue();
+
+ if (val > Sval)
+ Sval = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void SHVAL::SetMax(PVBLK vbp, int i)
+ {
+ short val = vbp->GetShortValue(i);
+
+ if (val > Sval)
+ Sval = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void SHVAL::SetMax(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ short *lp = (short *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (lp[i] > Sval)
+ Sval = lp[i];
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void SHVAL::SetMax(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ short val;
+ short *lp = (short *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = lp[x[i]];
+
+ if (val > Sval)
+ Sval = val;
+
+ } // endfor i
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SHVAL SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool SHVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
+ {
+ char c[16];
+
+ fmt.Type[0] = 'S';
+ fmt.Length = sprintf(c, "%hd", Sval);
+ fmt.Prec = 0;
+ return false;
+ } // end of SetConstFormat
+
+/***********************************************************************/
+/* Make file output of a short object. */
+/***********************************************************************/
+void SHVAL::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+
+ fprintf(f, "%s%hd\n", m, Sval);
+ } /* end of Print */
+
+/***********************************************************************/
+/* Make string output of a short object. */
+/***********************************************************************/
+void SHVAL::Print(PGLOBAL g, char *ps, uint z)
+ {
+ sprintf(ps, "%hd", Sval);
+ } /* end of Print */
+
+/* -------------------------- Class INTVAL ---------------------------- */
+
+/***********************************************************************/
+/* INTVAL public constructor from char. */
+/***********************************************************************/
+INTVAL::INTVAL(PSZ s) : VALUE(TYPE_INT)
+ {
+ Ival = atol(s);
+ Clen = sizeof(int);
+ } // end of INTVAL constructor
+
+/***********************************************************************/
+/* INTVAL public constructor from short. */
+/***********************************************************************/
+INTVAL::INTVAL(short n) : VALUE(TYPE_INT)
+ {
+ Ival = (int)n;
+ Clen = sizeof(int);
+ } // end of INTVAL constructor
+
+/***********************************************************************/
+/* INTVAL public constructor from int. */
+/***********************************************************************/
+INTVAL::INTVAL(int n) : VALUE(TYPE_INT)
+ {
+ Ival = n;
+ Clen = sizeof(int);
+ } // end of INTVAL constructor
+
+/***********************************************************************/
+/* INTVAL public constructor from big int. */
+/***********************************************************************/
+INTVAL::INTVAL(longlong n) : VALUE(TYPE_INT)
+ {
+ Ival = (int)n;
+ Clen = sizeof(int);
+ } // end of INTVAL constructor
+
+/***********************************************************************/
+/* INTVAL public constructor from double. */
+/***********************************************************************/
+INTVAL::INTVAL(double f) : VALUE(TYPE_INT)
+ {
+ Ival = (int)f;
+ Clen = sizeof(int);
+ } // end of INTVAL constructor
+
+/***********************************************************************/
+/* INTVAL GetValLen: returns the print length of the int object. */
+/***********************************************************************/
+int INTVAL::GetValLen(void)
+ {
+ char c[16];
+
+ return sprintf(c, "%d", Ival);
+ } // end of GetValLen
+
+/***********************************************************************/
+/* INTVAL SetValue: copy the value of another Value object. */
+/* This function allows conversion if chktype is false. */
+/***********************************************************************/
+bool INTVAL::SetValue_pval(PVAL valp, bool chktype)
+ {
+ if (chktype && Type != valp->GetType())
+ return true;
+
+ Ival = valp->GetIntValue();
+ return false;
+ } // end of SetValue
+
+/***********************************************************************/
+/* INTVAL SetValue: convert chars extracted from a line to int value. */
+/***********************************************************************/
+void INTVAL::SetValue_char(char *p, int n)
+ {
+ char *p2;
+ bool minus;
+
+ for (p2 = p + n; p < p2 && *p == ' '; p++) ;
+
+ for (Ival = 0, minus = false; p < p2; p++)
+ switch (*p) {
+ case '-':
+ minus = true;
+ case '+':
+ break;
+ case '0': Ival = Ival * 10; break;
+ case '1': Ival = Ival * 10 + 1; break;
+ case '2': Ival = Ival * 10 + 2; break;
+ case '3': Ival = Ival * 10 + 3; break;
+ case '4': Ival = Ival * 10 + 4; break;
+ case '5': Ival = Ival * 10 + 5; break;
+ case '6': Ival = Ival * 10 + 6; break;
+ case '7': Ival = Ival * 10 + 7; break;
+ case '8': Ival = Ival * 10 + 8; break;
+ case '9': Ival = Ival * 10 + 9; break;
+ default:
+ p = p2;
+ } // endswitch *p
+
+ if (minus && Ival)
+ Ival = - Ival;
+
+ if (trace)
+ htrc(" setting int to: %d\n", Ival);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* INTVAL SetValue: fill a int value from a string. */
+/***********************************************************************/
+void INTVAL::SetValue_psz(PSZ s)
+ {
+ Ival = atol(s);
+ } // end of SetValue
+
+/***********************************************************************/
+/* INTVAL SetValue: set value with a int extracted from a block. */
+/***********************************************************************/
+void INTVAL::SetValue_pvblk(PVBLK blk, int n)
+ {
+ Ival = blk->GetIntValue(n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* INTVAL SetBinValue: with bytes extracted from a line. */
+/***********************************************************************/
+void INTVAL::SetBinValue(void *p)
+ {
+ Ival = *(int *)p;
+ } // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool INTVAL::GetBinValue(void *buf, int buflen, bool go)
+ {
+ // Test on length was removed here until a variable in column give the
+ // real field length. For BIN files the field length logically cannot
+ // be different from the variable length because no conversion is done.
+ // Therefore this test is useless anyway.
+//#if defined(_DEBUG)
+// if (sizeof(int) > buflen)
+// return true;
+//#endif
+
+ if (go)
+ *(int *)buf = Ival;
+
+ return false;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
+/* This is a fast implementation that does not do any checking. */
+/***********************************************************************/
+void INTVAL::GetBinValue(void *buf, int buflen)
+ {
+ assert(buflen == sizeof(int));
+
+ *(int *)buf = Ival;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* INTVAL ShowValue: get string representation of a int value. */
+/***********************************************************************/
+char *INTVAL::ShowValue(char *buf, int len)
+ {
+ sprintf(buf, "%*d", len, Ival);
+ return buf;
+ } // end of ShowValue
+
+/***********************************************************************/
+/* INTVAL GetCharString: get string representation of a int value. */
+/***********************************************************************/
+char *INTVAL::GetCharString(char *p)
+ {
+ sprintf(p, "%d", Ival);
+ return p;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* INTVAL GetShortString: get short representation of a int value. */
+/***********************************************************************/
+char *INTVAL::GetShortString(char *p, int n)
+ {
+ sprintf(p, "%*hd", n, (short)Ival);
+ return p;
+ } // end of GetShortString
+
+/***********************************************************************/
+/* INTVAL GetIntString: get int representation of a int value. */
+/***********************************************************************/
+char *INTVAL::GetIntString(char *p, int n)
+ {
+ sprintf(p, "%*d", n, Ival);
+ return p;
+ } // end of GetIntString
+
+/***********************************************************************/
+/* INTVAL GetBigintString: get big int representation of a int value. */
+/***********************************************************************/
+char *INTVAL::GetBigintString(char *p, int n)
+ {
+ sprintf(p, "%*lld", n, (longlong)Ival);
+ return p;
+ } // end of GetBigintString
+
+/***********************************************************************/
+/* INTVAL GetFloatString: get double representation of a int value. */
+/***********************************************************************/
+char *INTVAL::GetFloatString(char *p, int n, int prec)
+ {
+ sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Ival);
+ return p;
+ } // end of GetFloatString
+
+/***********************************************************************/
+/* INTVAL compare value with another Value. */
+/***********************************************************************/
+bool INTVAL::IsEqual(PVAL vp, bool chktype)
+ {
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else
+ return (Ival == vp->GetIntValue());
+
+ } // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of int integer filters. */
+/***********************************************************************/
+int INTVAL::CompareValue(PVAL vp)
+ {
+//assert(vp->GetType() == Type);
+
+ // Process filtering on int integers.
+ int n = vp->GetIntValue();
+
+ if (trace > 1)
+ htrc(" Comparing: val=%d,%d\n", Ival, n);
+
+ return (Ival > n) ? 1 : (Ival < n) ? (-1) : 0;
+ } // end of CompareValue
+
+/***********************************************************************/
+/* SafeAdd: adds a value and test whether overflow/underflow occured. */
+/***********************************************************************/
+int INTVAL::SafeAdd(int n1, int n2)
+ {
+ PGLOBAL& g = Global;
+ int n = n1 + n2;
+
+ if ((n2 > 0) && (n < n1)) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_ADD));
+ longjmp(g->jumper[g->jump_level], 138);
+ } else if ((n2 < 0) && (n > n1)) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_ADD));
+ longjmp(g->jumper[g->jump_level], 138);
+ } // endif's n2
+
+ return n;
+ } // end of SafeAdd
+
+/***********************************************************************/
+/* SafeMult: multiply values and test whether overflow occured. */
+/***********************************************************************/
+int INTVAL::SafeMult(int n1, int n2)
+ {
+ PGLOBAL& g = Global;
+ double n = (double)n1 * (double)n2;
+
+ if (n > 2147483647.0) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
+ longjmp(g->jumper[g->jump_level], 138);
+ } else if (n < -2147483648.0) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
+ longjmp(g->jumper[g->jump_level], 138);
+ } // endif's n2
+
+ return (int)n;
+ } // end of SafeMult
+
+/***********************************************************************/
+/* Compute a function on a int integers. */
+/***********************************************************************/
+bool INTVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+ {
+ if (op == OP_LEN) {
+ assert(np == 1);
+ char buf[32];
+ char *p = vp[0]->GetCharString(buf);
+
+ Ival = strlen(p);
+
+ if (trace)
+ htrc("Compute result=%d val=%s op=%d\n", Ival, p, op);
+
+ } else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
+ char *p, *tp = g->Message;
+ char *p1, val1[32];
+ char *p2, val2[32];
+ bool b = (vp[0]->IsCi() || vp[1]->IsCi());
+
+ assert(np == 2);
+
+ p1 = vp[0]->GetCharString(val1);
+ p2 = vp[1]->GetCharString(val2);
+
+ if (op != OP_LIKE) {
+ if (!strcmp(p2, "\\t"))
+ p2 = "\t";
+
+ if (b) { // Case insensitive
+ if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
+ !(tp = new char[strlen(p1) + strlen(p2) + 2])) {
+ strcpy(g->Message, MSG(NEW_RETURN_NULL));
+ return true;
+ } // endif p
+
+ // Make a lower case copy of p1 and p2
+ p1 = strlwr(strcpy(tp, p1));
+ p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
+ } // endif b
+
+ if (op == OP_CNTIN) {
+ size_t t2 = strlen(p2);
+
+ for (Ival = 0; (p = strstr(p1, p2)); Ival++, p1 = p + t2) ;
+
+ } else // OP_INSTR
+ Ival = (p = strstr(p1, p2)) ? 1 + (int)(p - p1) : 0;
+
+ if (tp != g->Message) // If working space was obtained
+ delete [] tp; // by the use of new, delete it.
+
+ } else // OP_LIKE
+ Ival = (PlugEvalLike(g, p1, p2, b)) ? 1 : 0;
+
+ if (trace)
+ htrc("Compute result=%d val=%s,%s op=%d\n", Ival, p1, p2, op);
+
+ } else if (op == OP_MDAY || op == OP_MONTH || op == OP_YEAR ||
+ op == OP_WDAY || op == OP_QUART || op == OP_YDAY) {
+ assert(np == 1 && vp[0]->GetType() == TYPE_DATE);
+
+ if (((DTVAL*)vp[0])->GetTmMember(op, Ival)) {
+ sprintf(g->Message, MSG(COMPUTE_ERROR), op);
+ return true;
+ } // endif
+
+ } else if (op == OP_NWEEK) {
+ // Week number of the year for the internal date value
+ assert((np == 1 || np == 2) && vp[0]->GetType() == TYPE_DATE);
+
+ // Start of the week SUN=0, MON=1, etc.
+ Ival = (np == 2) ? vp[1]->GetIntValue() : 1;
+
+ // This function sets Ival to nweek
+ if (((DTVAL*)vp[0])->WeekNum(g, Ival))
+ return true;
+
+ } else if (op == OP_DBTWN || op == OP_MBTWN || op == OP_YBTWN) {
+ assert(np == 2 && vp[0]->GetType() == TYPE_DATE
+ && vp[1]->GetType() == TYPE_DATE);
+
+ if (((DTVAL*)vp[0])->DateDiff((DTVAL*)vp[1], op, Ival)) {
+ sprintf(g->Message, MSG(COMPUTE_ERROR), op);
+ return true;
+ } // endif
+
+ } else if (op == OP_TIME) {
+ Ival = vp[0]->GetTime(g, (np == 1) ? NULL : vp + 1, np - 1);
+ } else {
+ int val[2];
+
+ assert(np <= 2);
+
+ for (int i = 0; i < np; i++)
+ val[i] = vp[i]->GetIntValue();
+
+ switch (op) {
+ case OP_ABS:
+ assert(np == 1);
+ Ival = labs(*val);
+ break;
+ case OP_SIGN:
+ assert(np == 1);
+ Ival = (*val < 0) ? (-1) : 1;
+ break;
+ case OP_CEIL:
+ case OP_FLOOR:
+ assert(np == 1);
+ Ival = *val;
+ break;
+ case OP_ADD:
+ assert(np == 2);
+ Ival = SafeAdd(val[0], val[1]);
+ break;
+ case OP_SUB:
+ assert(np == 2);
+ Ival = SafeAdd(val[0], -val[1]);
+ break;
+ case OP_MULT:
+ assert(np == 2);
+ Ival = SafeMult(val[0], val[1]);
+ break;
+ case OP_MIN:
+ assert(np == 2);
+ Ival = min(val[0], val[1]);
+ break;
+ case OP_MAX:
+ assert(np == 2);
+ Ival = max(val[0], val[1]);
+ break;
+ case OP_DIV:
+ assert(np == 2);
+
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Ival = val[0] / val[1];
+ break;
+ case OP_MOD:
+ assert(np == 2);
+
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Ival = val[0] % val[1];
+ break;
+ case OP_BITAND:
+ assert(np == 2);
+ Ival = val[0] & val[1];
+ break;
+ case OP_BITOR:
+ assert(np == 2);
+ Ival = val[0] | val[1];
+ break;
+ case OP_BITXOR:
+ assert(np == 2);
+ Ival = val[0] ^ val[1];
+ break;
+ case OP_BITNOT:
+ assert(np == 1);
+ Ival = ~val[0];
+ break;
+ case OP_DELTA:
+// assert(np == 1);
+ Ival = val[0] - Ival;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_EXP_OPER), op);
+ return true;
+ } // endswitch op
+
+ if (trace) {
+ if (np = 1)
+ htrc(" result=%d val=%d op=%d\n", Ival, val[0], op);
+ else
+ htrc(" result=%d val=%d,%d op=%d\n",
+ Ival, val[0], val[1], op);
+ } // endif trace
+
+ } // endif op
+
+ return false;
+ } // end of Compute
+
+/***********************************************************************/
+/* GetTime: convert HR/MIN/SEC in a number of seconds. */
+/***********************************************************************/
+int INTVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
+ {
+ int sec = Ival;
+
+ for (int i = 0; i < 2; i++) {
+ sec *= 60;
+
+ if (np > i)
+ sec += vp[i]->GetIntValue();
+
+ } // endfor i
+
+ return sec;
+ } // end of GetTime
+
+/***********************************************************************/
+/* Divide: used by aggregate functions when calculating average. */
+/***********************************************************************/
+void INTVAL::Divide(int cnt)
+ {
+ Ival /= cnt;
+ } // end of Divide
+
+/***********************************************************************/
+/* StdVar: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void INTVAL::StdVar(PVAL vp, int cnt, bool b)
+ {
+ int lv2 = vp->GetIntValue();
+
+ Ival = (cnt == 1) ? 0
+ : (SafeAdd(lv2, -(SafeMult(Ival, Ival) / cnt)) / (cnt - 1));
+
+ if (b) // Builtin == FNC_STDDEV
+ Ival = (int)sqrt((double)Ival);
+
+ } // end of StdVar
+
+/***********************************************************************/
+/* Times: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void INTVAL::Times(PVAL vp)
+ {
+ Ival = SafeMult(Ival, vp->GetIntValue());
+ } // end of Times
+
+/***********************************************************************/
+/* Add: used by aggregate functions for Sum and other functions. */
+/***********************************************************************/
+void INTVAL::Add(PVAL vp)
+ {
+ Ival = SafeAdd(Ival, vp->GetIntValue());
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void INTVAL::Add(PVBLK vbp, int i)
+ {
+ Ival = SafeAdd(Ival, vbp->GetIntValue(i));
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void INTVAL::Add(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ int *lp = (int *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Ival = SafeAdd(Ival, lp[i]);
+
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void INTVAL::Add(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ int *lp = (int *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Ival = SafeAdd(Ival, lp[x[i]]);
+
+ } // end of Add
+
+/***********************************************************************/
+/* AddSquare: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void INTVAL::AddSquare(PVAL vp)
+ {
+ int val = vp->GetIntValue();
+
+ Ival = SafeAdd(Ival, SafeMult(val, val));
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by QUERY for functions Stddev and Variance. */
+/***********************************************************************/
+void INTVAL::AddSquare(PVBLK vbp, int i)
+ {
+ int val = vbp->GetIntValue(i);
+
+ Ival = SafeAdd(Ival, SafeMult(val, val));
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by QUERY for functions Stddev and Variance. */
+/***********************************************************************/
+void INTVAL::AddSquare(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ int *lp = (int *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Ival = SafeAdd(Ival, SafeMult(lp[i], lp[i]));
+
+ } // end of AddSquare
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool INTVAL::FormatValue(PVAL vp, char *fmt)
+ {
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Ival);
+
+ return (n > vp->GetValLen());
+ } // end of FormatValue
+
+/***********************************************************************/
+/* SetMin: used by the aggregate function MIN. */
+/***********************************************************************/
+void INTVAL::SetMin(PVAL vp)
+ {
+ int val = vp->GetIntValue();
+
+ if (val < Ival)
+ Ival = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void INTVAL::SetMin(PVBLK vbp, int i)
+ {
+ int val = vbp->GetIntValue(i);
+
+ if (val < Ival)
+ Ival = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void INTVAL::SetMin(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ int *lp = (int *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (lp[i] < Ival)
+ Ival = lp[i];
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void INTVAL::SetMin(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ register int val;
+ int *lp = (int *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = lp[x[i]];
+
+ if (val < Ival)
+ Ival = val;
+
+ } // endfor i
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMax: used by the aggregate function MAX. */
+/***********************************************************************/
+void INTVAL::SetMax(PVAL vp)
+ {
+ int val = vp->GetIntValue();
+
+ if (val > Ival)
+ Ival = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void INTVAL::SetMax(PVBLK vbp, int i)
+ {
+ int val = vbp->GetIntValue(i);
+
+ if (val > Ival)
+ Ival = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void INTVAL::SetMax(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ int *lp = (int *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (lp[i] > Ival)
+ Ival = lp[i];
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void INTVAL::SetMax(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ register int val;
+ int *lp = (int *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = lp[x[i]];
+
+ if (val > Ival)
+ Ival = val;
+
+ } // endfor i
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* INTVAL SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool INTVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
+ {
+ char c[16];
+
+ fmt.Type[0] = 'N';
+ fmt.Length = sprintf(c, "%d", Ival);
+ fmt.Prec = 0;
+ return false;
+ } // end of SetConstFormat
+
+/***********************************************************************/
+/* Make file output of a int object. */
+/***********************************************************************/
+void INTVAL::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+
+ fprintf(f, "%s%d\n", m, Ival);
+ } /* end of Print */
+
+/***********************************************************************/
+/* Make string output of a int object. */
+/***********************************************************************/
+void INTVAL::Print(PGLOBAL g, char *ps, uint z)
+ {
+ sprintf(ps, "%d", Ival);
+ } /* end of Print */
+
+/* -------------------------- Class DTVAL ---------------------------- */
+
+/***********************************************************************/
+/* DTVAL public constructor for new void values. */
+/***********************************************************************/
+DTVAL::DTVAL(PGLOBAL g, int n, int prec, PSZ fmt) : INTVAL((int)0)
+ {
+ if (!fmt) {
+ Pdtp = NULL;
+ Sdate = NULL;
+ DefYear = 0;
+ Len = n;
+ } else
+ SetFormat(g, fmt, n, prec);
+
+ Type = TYPE_DATE;
+ } // end of DTVAL constructor
+
+/***********************************************************************/
+/* DTVAL public constructor from char. */
+/***********************************************************************/
+DTVAL::DTVAL(PGLOBAL g, PSZ s, int n) : INTVAL((s) ? s : (char *)"0")
+ {
+ Pdtp = NULL;
+ Len = n;
+ Type = TYPE_DATE;
+ Sdate = NULL;
+ DefYear = 0;
+ } // end of DTVAL constructor
+
+/***********************************************************************/
+/* DTVAL public constructor from short. */
+/***********************************************************************/
+DTVAL::DTVAL(PGLOBAL g, short n) : INTVAL((int)n)
+ {
+ Pdtp = NULL;
+ Len = 19;
+ Type = TYPE_DATE;
+ Sdate = NULL;
+ DefYear = 0;
+ } // end of DTVAL constructor
+
+/***********************************************************************/
+/* DTVAL public constructor from int. */
+/***********************************************************************/
+DTVAL::DTVAL(PGLOBAL g, int n) : INTVAL(n)
+ {
+ Pdtp = NULL;
+ Len = 19;
+ Type = TYPE_DATE;
+ Sdate = NULL;
+ DefYear = 0;
+ } // end of DTVAL constructor
+
+/***********************************************************************/
+/* DTVAL public constructor from double. */
+/***********************************************************************/
+DTVAL::DTVAL(PGLOBAL g, double f) : INTVAL(f)
+ {
+ Pdtp = NULL;
+ Len = 19;
+ Type = TYPE_DATE;
+ Sdate = NULL;
+ DefYear = 0;
+ } // end of DTVAL constructor
+
+/***********************************************************************/
+/* Set format so formatted dates can be converted on input/output. */
+/***********************************************************************/
+bool DTVAL::SetFormat(PGLOBAL g, PSZ fmt, int len, int year)
+ {
+ Pdtp = MakeDateFormat(g, fmt, true, true, (year > 9999) ? 1 : 0);
+ Sdate = (char*)PlugSubAlloc(g, NULL, len + 1);
+ DefYear = (int)((year > 9999) ? (year - 10000) : year);
+ Len = len;
+ return false;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* Set format from the format of another date value. */
+/***********************************************************************/
+bool DTVAL::SetFormat(PGLOBAL g, PVAL valp)
+ {
+ DTVAL *vp;
+
+ if (valp->GetType() != TYPE_DATE) {
+ sprintf(g->Message, MSG(NO_FORMAT_TYPE), valp->GetType());
+ return true;
+ } else
+ vp = (DTVAL*)valp;
+
+ Len = vp->Len;
+ Pdtp = vp->Pdtp;
+ Sdate = (char*)PlugSubAlloc(g, NULL, Len + 1);
+ DefYear = vp->DefYear;
+ return false;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* We need TimeShift because the mktime C function does a correction */
+/* for local time zone that we want to override for DB operations. */
+/***********************************************************************/
+void DTVAL::SetTimeShift(void)
+ {
+ struct tm dtm = {0,0,0,2,0,70,0,0,0};
+
+ Shift = (int)mktime(&dtm) - 86400;
+
+ if (trace)
+ htrc("DTVAL Shift=%d\n", Shift);
+
+ } // end of SetTimeShift
+
+/***********************************************************************/
+/* GetGmTime: returns a pointer to a static tm structure obtained */
+/* though the gmtime C function. The purpose of this function is to */
+/* extend the range of valid dates by accepting negative time values. */
+/***********************************************************************/
+struct tm *DTVAL::GetGmTime(void)
+ {
+ struct tm *datm;
+ time_t t = (time_t)Ival;
+
+ if (Ival < 0) {
+ int n;
+
+ for (n = 0; t < 0; n += 4)
+ t += FOURYEARS;
+
+ datm = gmtime(&t);
+
+ if (datm)
+ datm->tm_year -= n;
+
+ } else
+ datm = gmtime((const time_t *)&t);
+
+ return datm;
+ } // end of GetGmTime
+
+/***********************************************************************/
+/* MakeTime: calculates a date value from a tm structures using the */
+/* mktime C function. The purpose of this function is to extend the */
+/* range of valid dates by accepting to set negative time values. */
+/***********************************************************************/
+bool DTVAL::MakeTime(struct tm *ptm)
+ {
+ int n, y = ptm->tm_year;
+ time_t t = mktime(ptm);
+
+ if (trace)
+ htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n",
+ ptm->tm_year, ptm->tm_mon, ptm->tm_mday,
+ ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
+
+ if (t == -1) {
+ if (y < 1 || y > 71)
+ return true;
+
+ for (n = 0; t == -1 && n < 20; n++) {
+ ptm->tm_year += 4;
+ t = mktime(ptm);
+ } // endfor t
+
+ if (t == -1)
+ return true;
+
+ if ((t -= (n * FOURYEARS + Shift)) > 2000000000)
+ return true;
+
+ Ival = (int)t;
+ } else
+ Ival = (int)t - Shift;
+
+ if (trace)
+ htrc("MakeTime Ival=%d\n", Ival);
+
+ return false;
+ } // end of MakeTime
+
+/***********************************************************************/
+/* Make a time_t datetime from its components (YY, MM, DD, hh, mm, ss) */
+/***********************************************************************/
+bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval)
+ {
+ int i, m;
+ int n;
+ bool rc = false;
+ struct tm datm = {0,0,0,1,0,70,0,0,0};
+
+ if (trace)
+ htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n",
+ val[0], val[1], val[2], val[3], val[4], val[5], nval);
+
+ for (i = 0; i < nval; i++) {
+ n = val[i];
+
+// if (trace > 1)
+// htrc("i=%d n=%d\n", i, n);
+
+ switch (i) {
+ case 0:
+ if (n >= 1900)
+ n -= 1900;
+
+ datm.tm_year = n;
+
+// if (trace > 1)
+// htrc("n=%d tm_year=%d\n", n, datm.tm_year);
+
+ break;
+ case 1:
+ // If mktime handles apparently correctly large or negative
+ // day values, it is not the same for months. Therefore we
+ // do the ajustment here, thus mktime has not to do it.
+ if (n > 0) {
+ m = (n - 1) % 12;
+ n = (n - 1) / 12;
+ } else {
+ m = 11 + n % 12;
+ n = n / 12 - 1;
+ } // endfi n
+
+ datm.tm_mon = m;
+ datm.tm_year += n;
+
+// if (trace > 1)
+// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
+
+ break;
+ case 2:
+ // For days, big or negative values may also cause problems
+ m = n % 1461;
+ n = 4 * (n / 1461);
+
+ if (m < 0) {
+ m += 1461;
+ n -= 4;
+ } // endif m
+
+ datm.tm_mday = m;
+ datm.tm_year += n;
+
+// if (trace > 1)
+// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
+
+ break;
+ case 3: datm.tm_hour = n; break;
+ case 4: datm.tm_min = n; break;
+ case 5: datm.tm_sec = n; break;
+ } // endswitch i
+
+ } // endfor i
+
+ if (trace)
+ htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n",
+ datm.tm_year, datm.tm_mon, datm.tm_mday,
+ datm.tm_hour, datm.tm_min, datm.tm_sec);
+
+ // Pass g to have an error return or NULL to set invalid dates to 0
+ if (MakeTime(&datm))
+ if (g) {
+ strcpy(g->Message, MSG(BAD_DATETIME));
+ rc = true;
+ } else
+ Ival = 0;
+
+ return rc;
+ } // end of MakeDate
+
+/***********************************************************************/
+/* DTVAL SetValue: copy the value of another Value object. */
+/* This function allows conversion if chktype is false. */
+/***********************************************************************/
+bool DTVAL::SetValue_pval(PVAL valp, bool chktype)
+ {
+ if (chktype && Type != valp->GetType())
+ return true;
+
+ if (Pdtp && !valp->IsTypeNum()) {
+ int ndv;
+ int dval[6];
+
+ ndv = ExtractDate(valp->GetCharValue(), Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+ } else
+ Ival = valp->GetIntValue();
+
+ return false;
+ } // end of SetValue
+
+/***********************************************************************/
+/* SetValue: convert chars extracted from a line to date value. */
+/***********************************************************************/
+void DTVAL::SetValue_char(char *p, int n)
+ {
+ if (Pdtp) {
+ char *p2;
+ int ndv;
+ int dval[6];
+
+ // Trim trailing blanks
+ for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--) ;
+
+ n = min(p2 - p + 1, Len);
+ memcpy(Sdate, p, n);
+ Sdate[n] = '\0';
+
+ ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+
+ if (trace)
+ htrc(" setting date: '%s' -> %d\n", Sdate, Ival);
+
+ } else
+ INTVAL::SetValue_char(p, n);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* SetValue: convert a char string to date value. */
+/***********************************************************************/
+void DTVAL::SetValue_psz(PSZ p)
+ {
+ if (Pdtp) {
+ int ndv;
+ int dval[6];
+
+ strncpy(Sdate, p, Len);
+ Sdate[Len] = '\0';
+
+ ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+
+ if (trace)
+ htrc(" setting date: '%s' -> %d\n", Sdate, Ival);
+
+ } else
+ INTVAL::SetValue_psz(p);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* DTVAL SetValue: set value with a value extracted from a block. */
+/***********************************************************************/
+void DTVAL::SetValue_pvblk(PVBLK blk, int n)
+ {
+ if (Pdtp && !::IsTypeNum(blk->GetType())) {
+ int ndv;
+ int dval[6];
+
+ ndv = ExtractDate(blk->GetCharValue(n), Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+ } else
+ Ival = blk->GetIntValue(n);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* DTVAL GetCharString: get string representation of a date value. */
+/***********************************************************************/
+char *DTVAL::GetCharString(char *p)
+ {
+ if (Pdtp) {
+ size_t n = 0;
+ struct tm *ptm = GetGmTime();
+
+ if (ptm)
+ n = strftime(Sdate, Len + 1, Pdtp->OutFmt, ptm);
+
+ if (!n) {
+ *Sdate = '\0';
+ strncat(Sdate, "Error", Len + 1);
+ } // endif n
+
+ return Sdate;
+ } else
+ sprintf(p, "%d", Ival);
+
+ return p;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* DTVAL ShowValue: get string representation of a date value. */
+/***********************************************************************/
+char *DTVAL::ShowValue(char *buf, int len)
+ {
+ if (Pdtp) {
+ char *p;
+ size_t m, n = 0;
+ struct tm *ptm = GetGmTime();
+
+ if (Len < len) {
+ p = buf;
+ m = len;
+ } else {
+ p = Sdate;
+ m = Len + 1;
+ } // endif Len
+
+ if (ptm)
+ n = strftime(p, m, Pdtp->OutFmt, ptm);
+
+ if (!n) {
+ *p = '\0';
+ strncat(p, "Error", m);
+ } // endif n
+
+ return p;
+ } else
+ return INTVAL::ShowValue(buf, len);
+
+ } // end of ShowValue
+
+/***********************************************************************/
+/* Compute a function on a date time stamp. */
+/***********************************************************************/
+bool DTVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+ {
+ bool rc = false;
+
+ if (op == OP_DATE) {
+ int val[6];
+ int nval = min(np, 6);
+
+ for (int i = 0; i < nval; i++)
+ val[i] = vp[i]->GetIntValue();
+
+ rc = MakeDate(g, val, nval);
+ } else if (op == OP_ADDAY || op == OP_ADDMTH ||
+ op == OP_ADDYR || op == OP_NXTDAY) {
+ struct tm *ptm;
+ int n = (op != OP_NXTDAY) ? (int)vp[1]->GetIntValue() : 1;
+
+ INTVAL::SetValue_pval(vp[0], true);
+ Ival -= Shift;
+ ptm = GetGmTime();
+
+ switch (op) {
+ case OP_ADDAY:
+ case OP_NXTDAY:
+ ptm->tm_mday += n;
+ break;
+ case OP_ADDMTH:
+ ptm->tm_mon += n;
+ break;
+ case OP_ADDYR:
+ ptm->tm_year += n;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_DATE_OPER), op);
+ return true;
+ } // endswitch op
+
+ if (MakeTime(ptm)) {
+ strcpy(g->Message, MSG(BAD_DATETIME));
+ rc = true;
+ } // endif MakeTime
+
+ } else if (op == OP_SYSDT) {
+ Ival = (int)time(NULL) - Shift;
+ } else if (op == OP_CURDT) {
+ Ival = (((int)time(NULL) - Shift) / 86400) * 86400;
+ } else
+ rc = INTVAL::Compute(g, vp, np, op);
+
+ return rc;
+ } // end of Compute
+
+/***********************************************************************/
+/* GetTime: extract the time info from a date stamp. */
+/***********************************************************************/
+int DTVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
+ {
+ return (Ival % 86400);
+ } // end of GetTime
+
+/***********************************************************************/
+/* Returns a member of the struct tm representation of the date. */
+/***********************************************************************/
+bool DTVAL::GetTmMember(OPVAL op, int& mval)
+ {
+ bool rc = false;
+ struct tm *ptm = GetGmTime();
+
+ switch (op) {
+ case OP_MDAY: mval = ptm->tm_mday; break;
+ case OP_MONTH: mval = ptm->tm_mon + 1; break;
+ case OP_YEAR: mval = ptm->tm_year + 1900; break;
+ case OP_WDAY: mval = ptm->tm_wday + 1; break;
+ case OP_YDAY: mval = ptm->tm_yday + 1; break;
+ case OP_QUART: mval = ptm->tm_mon / 3 + 1; break;
+ default:
+ rc = true;
+ } // endswitch op
+
+ return rc;
+ } // end of GetTmMember
+
+/***********************************************************************/
+/* Calculates the week number of the year for the internal date value.*/
+/* The International Standard ISO 8601 has decreed that Monday shall */
+/* be the first day of the week. A week that lies partly in one year */
+/* and partly in another is assigned a number in the year in which */
+/* most of its days lie. That means that week number 1 of any year is */
+/* the week that contains the January 4th. */
+/***********************************************************************/
+bool DTVAL::WeekNum(PGLOBAL g, int& nval)
+ {
+ // w is the start of the week SUN=0, MON=1, etc.
+ int m, n, w = nval % 7;
+ struct tm *ptm = GetGmTime();
+
+ // Which day is January 4th of this year?
+ m = (367 + ptm->tm_wday - ptm->tm_yday) % 7;
+
+ // When does the first week begins?
+ n = 3 - (7 + m - w) % 7;
+
+ // Now calculate the week number
+ if (!(nval = (7 + ptm->tm_yday - n) / 7))
+ nval = 52;
+
+ // Everything should be Ok
+ return false;
+ } // end of WeekNum
+
+/***********************************************************************/
+/* This covers days, months and years between two dates. */
+/***********************************************************************/
+bool DTVAL::DateDiff(DTVAL *dtp, OPVAL op, int& tdif)
+ {
+ bool rc = false;
+ int lv1, lv2, t1, t2;
+ int s = CompareValue(dtp);
+ struct tm dat1, dat2, *ptm = dtp->GetGmTime();
+
+ if (!ptm)
+ return true;
+
+ if (s == 0) {
+ // Dates are equal
+ tdif = 0;
+ return rc;
+ } else if (s > 0) {
+ // This Date is greater than dtp->Date
+ dat1 = *ptm;
+ lv1 = dtp->GetIntValue();
+ lv2 = Ival;
+
+ if ((ptm = GetGmTime()))
+ dat2 = *ptm;
+
+ } else {
+ // This Date is less than dtp->Date
+ dat2 = *ptm;
+ lv2 = dtp->GetIntValue();
+ lv1 = Ival;
+
+ if ((ptm = GetGmTime()))
+ dat1 = *ptm;
+
+ } // endif's s
+
+ if (!ptm)
+ return true;
+
+ // Both dates are valid and dat2 is greater than dat1
+ t1 = lv1 % 86400; if (t1 < 0) t1 += 86400;
+ t2 = lv2 % 86400; if (t2 < 0) t2 += 86400;
+
+ if (t1 > t2) {
+ lv1 += 86400;
+ dat1.tm_mday++;
+ } // endif
+
+ if (dat1.tm_mday > dat2.tm_mday)
+ dat1.tm_mon++;
+
+ switch (op) {
+ case OP_DBTWN:
+ tdif = (lv2 / 86400) - (lv1 / 86400);
+ break;
+ case OP_MBTWN:
+ tdif = (dat2.tm_year - dat1.tm_year) * 12
+ + (dat2.tm_mon - dat1.tm_mon);
+ break;
+ case OP_YBTWN:
+ if (dat1.tm_mon > dat2.tm_mon)
+ dat1.tm_year++;
+
+ tdif = dat2.tm_year - dat1.tm_year;
+ break;
+ default:
+ rc = true;
+ } // endswitch op
+
+ if (!rc && s < 0)
+ tdif = -tdif;
+
+ return rc;
+ } // end of DateDiff
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool DTVAL::FormatValue(PVAL vp, char *fmt)
+ {
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ struct tm *ptm = GetGmTime();
+
+ if (trace)
+ htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen());
+
+ if (ptm) {
+ size_t n = strftime(buf, vp->GetValLen(), fmt, ptm);
+
+ if (trace)
+ htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???");
+
+ return (n == 0);
+ } else
+ return true;
+
+ } // end of FormatValue
+
+/* -------------------------- Class BIGVAL ---------------------------- */
+
+/***********************************************************************/
+/* BIGVAL public constructor from char. */
+/***********************************************************************/
+BIGVAL::BIGVAL(PSZ s) : VALUE(TYPE_BIGINT)
+ {
+ Lval = atoll(s);
+ Clen = sizeof(longlong);
+ } // end of BIGVAL constructor
+
+/***********************************************************************/
+/* BIGVAL public constructor from short. */
+/***********************************************************************/
+BIGVAL::BIGVAL(short n) : VALUE(TYPE_BIGINT)
+ {
+ Lval = (longlong)n;
+ Clen = sizeof(longlong);
+ } // end of BIGVAL constructor
+
+/***********************************************************************/
+/* BIGVAL public constructor from int. */
+/***********************************************************************/
+BIGVAL::BIGVAL(int n) : VALUE(TYPE_BIGINT)
+ {
+ Lval = (longlong)n;
+ Clen = sizeof(longlong);
+ } // end of BIGVAL constructor
+
+/***********************************************************************/
+/* BIGVAL public constructor from big int. */
+/***********************************************************************/
+BIGVAL::BIGVAL(longlong n) : VALUE(TYPE_BIGINT)
+ {
+ Lval = n;
+ Clen = sizeof(longlong);
+ } // end of BIGVAL constructor
+
+/***********************************************************************/
+/* BIGVAL public constructor from double. */
+/***********************************************************************/
+BIGVAL::BIGVAL(double f) : VALUE(TYPE_BIGINT)
+ {
+ Lval = (longlong)f;
+ Clen = sizeof(longlong);
+ } // end of BIGVAL constructor
+
+/***********************************************************************/
+/* BIGVAL GetValLen: returns the print length of the int object. */
+/***********************************************************************/
+int BIGVAL::GetValLen(void)
+ {
+ char c[24];
+
+ return sprintf(c, "%lld", Lval);
+ } // end of GetValLen
+
+/***********************************************************************/
+/* BIGVAL SetValue: copy the value of another Value object. */
+/* This function allows conversion if chktype is false. */
+/***********************************************************************/
+bool BIGVAL::SetValue_pval(PVAL valp, bool chktype)
+ {
+ if (chktype && Type != valp->GetType())
+ return true;
+
+ Lval = valp->GetBigintValue();
+ return false;
+ } // end of SetValue
+
+/***********************************************************************/
+/* BIGVAL SetValue: convert chars extracted from a line to a big int. */
+/***********************************************************************/
+void BIGVAL::SetValue_char(char *p, int n)
+ {
+ char *p2;
+ bool minus;
+
+ for (p2 = p + n; p < p2 && *p == ' '; p++) ;
+
+ for (Lval = 0LL, minus = false; p < p2; p++)
+ switch (*p) {
+ case '-':
+ minus = true;
+ case '+':
+ break;
+ case '0': Lval = Lval * 10LL; break;
+ case '1': Lval = Lval * 10LL + 1LL; break;
+ case '2': Lval = Lval * 10LL + 2LL; break;
+ case '3': Lval = Lval * 10LL + 3LL; break;
+ case '4': Lval = Lval * 10LL + 4LL; break;
+ case '5': Lval = Lval * 10LL + 5LL; break;
+ case '6': Lval = Lval * 10LL + 6LL; break;
+ case '7': Lval = Lval * 10LL + 7LL; break;
+ case '8': Lval = Lval * 10LL + 8LL; break;
+ case '9': Lval = Lval * 10LL + 9LL; break;
+ default:
+ p = p2;
+ } // endswitch *p
+
+ if (minus && Lval)
+ Lval = - Lval;
+
+ if (trace)
+ htrc(" setting big int to: %lld\n", Lval);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* BIGVAL SetValue: fill a big int value from a string. */
+/***********************************************************************/
+void BIGVAL::SetValue_psz(PSZ s)
+ {
+ Lval = atoll(s);
+ } // end of SetValue
+
+/***********************************************************************/
+/* BIGVAL SetValue: set value with a int extracted from a block. */
+/***********************************************************************/
+void BIGVAL::SetValue_pvblk(PVBLK blk, int n)
+ {
+ Lval = blk->GetBigintValue(n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* BIGVAL SetBinValue: with bytes extracted from a line. */
+/***********************************************************************/
+void BIGVAL::SetBinValue(void *p)
+ {
+ Lval = *(longlong *)p;
+ } // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool BIGVAL::GetBinValue(void *buf, int buflen, bool go)
+ {
+ // Test on length was removed here until a variable in column give the
+ // real field length. For BIN files the field length logically cannot
+ // be different from the variable length because no conversion is done.
+ // Therefore this test is useless anyway.
+//#if defined(_DEBUG)
+// if (sizeof(int) > buflen)
+// return true;
+//#endif
+
+ if (go)
+ *(longlong *)buf = Lval;
+
+ return false;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
+/* This is a fast implementation that does not do any checking. */
+/***********************************************************************/
+void BIGVAL::GetBinValue(void *buf, int buflen)
+ {
+ assert(buflen == sizeof(longlong));
+
+ *(longlong *)buf = Lval;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* BIGVAL ShowValue: get string representation of a big int value. */
+/***********************************************************************/
+char *BIGVAL::ShowValue(char *buf, int len)
+ {
+ sprintf(buf, "%*lld", len, Lval);
+ return buf;
+ } // end of ShowValue
+
+/***********************************************************************/
+/* BIGVAL GetCharString: get string representation of a big int value.*/
+/***********************************************************************/
+char *BIGVAL::GetCharString(char *p)
+ {
+ sprintf(p, "%lld", Lval);
+ return p;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* BIGVAL GetShortString: get short representation of a int value. */
+/***********************************************************************/
+char *BIGVAL::GetShortString(char *p, int n)
+ {
+ sprintf(p, "%*hd", n, (short)Lval);
+ return p;
+ } // end of GetShortString
+
+/***********************************************************************/
+/* BIGVAL GetIntString: get int representation of a int value. */
+/***********************************************************************/
+char *BIGVAL::GetIntString(char *p, int n)
+ {
+ sprintf(p, "%*d", n, (int)Lval);
+ return p;
+ } // end of GetIntString
+
+/***********************************************************************/
+/* BIGVAL GetBigintString: get big int representation of a int value. */
+/***********************************************************************/
+char *BIGVAL::GetBigintString(char *p, int n)
+ {
+ sprintf(p, "%*lld", n, Lval);
+ return p;
+ } // end of GetBigintString
+
+/***********************************************************************/
+/* BIGVAL GetFloatString: get double representation of a int value. */
+/***********************************************************************/
+char *BIGVAL::GetFloatString(char *p, int n, int prec)
+ {
+ sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Lval);
+ return p;
+ } // end of GetFloatString
+
+/***********************************************************************/
+/* BIGVAL compare value with another Value. */
+/***********************************************************************/
+bool BIGVAL::IsEqual(PVAL vp, bool chktype)
+ {
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else
+ return (Lval == vp->GetBigintValue());
+
+ } // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of big int integer filters. */
+/***********************************************************************/
+int BIGVAL::CompareValue(PVAL vp)
+ {
+//assert(vp->GetType() == Type);
+
+ // Process filtering on big int integers.
+ longlong n = vp->GetBigintValue();
+
+ if (trace > 1)
+ htrc(" Comparing: val=%lld,%lld\n", Lval, n);
+
+ return (Lval > n) ? 1 : (Lval < n) ? (-1) : 0;
+ } // end of CompareValue
+
+/***********************************************************************/
+/* SafeAdd: adds a value and test whether overflow/underflow occured. */
+/***********************************************************************/
+longlong BIGVAL::SafeAdd(longlong n1, longlong n2)
+ {
+ PGLOBAL& g = Global;
+ longlong n = n1 + n2;
+
+ if ((n2 > 0LL) && (n < n1)) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_ADD));
+ longjmp(g->jumper[g->jump_level], 138);
+ } else if ((n2 < 0LL) && (n > n1)) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_ADD));
+ longjmp(g->jumper[g->jump_level], 138);
+ } // endif's n2
+
+ return n;
+ } // end of SafeAdd
+
+/***********************************************************************/
+/* SafeMult: multiply values and test whether overflow occured. */
+/***********************************************************************/
+longlong BIGVAL::SafeMult(longlong n1, longlong n2)
+ {
+ PGLOBAL& g = Global;
+ double n = (double)n1 * (double)n2;
+
+ if (n > LLONG_MAX) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
+ longjmp(g->jumper[g->jump_level], 138);
+ } else if (n < LLONG_MIN) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
+ longjmp(g->jumper[g->jump_level], 138);
+ } // endif's n2
+
+ return n1 * n2;
+ } // end of SafeMult
+
+/***********************************************************************/
+/* Compute a function on a int integers. */
+/***********************************************************************/
+bool BIGVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+ {
+ if (op == OP_LEN) {
+ assert(np == 1);
+ char buf[32];
+ char *p = vp[0]->GetCharString(buf);
+
+ Lval = strlen(p);
+
+ if (trace)
+ htrc("Compute result=%lld val=%s op=%d\n", Lval, p, op);
+
+ } else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
+ char *p, *tp = g->Message;
+ char *p1, val1[32];
+ char *p2, val2[32];
+ bool b = (vp[0]->IsCi() || vp[1]->IsCi());
+
+ assert(np == 2);
+
+ p1 = vp[0]->GetCharString(val1);
+ p2 = vp[1]->GetCharString(val2);
+
+ if (op != OP_LIKE) {
+ if (!strcmp(p2, "\\t"))
+ p2 = "\t";
+
+ if (b) { // Case insensitive
+ if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
+ !(tp = new char[strlen(p1) + strlen(p2) + 2])) {
+ strcpy(g->Message, MSG(NEW_RETURN_NULL));
+ return true;
+ } // endif p
+
+ // Make a lower case copy of p1 and p2
+ p1 = strlwr(strcpy(tp, p1));
+ p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
+ } // endif b
+
+ if (op == OP_CNTIN) {
+ size_t t2 = strlen(p2);
+
+ for (Lval = 0LL; (p = strstr(p1, p2)); Lval++, p1 = p + t2) ;
+
+ } else // OP_INSTR
+ Lval = (p = strstr(p1, p2)) ? 1LL + (longlong)(p - p1) : 0LL;
+
+ if (tp != g->Message) // If working space was obtained
+ delete [] tp; // by the use of new, delete it.
+
+ } else // OP_LIKE
+ Lval = (PlugEvalLike(g, p1, p2, b)) ? 1LL : 0LL;
+
+ if (trace)
+ htrc("Compute result=%lld val=%s,%s op=%d\n", Lval, p1, p2, op);
+
+ } else {
+ longlong val[2];
+
+ assert(np <= 2);
+
+ for (int i = 0; i < np; i++)
+ val[i] = vp[i]->GetBigintValue();
+
+ switch (op) {
+ case OP_ABS:
+ assert(np == 1);
+ Lval = (*val >= 0LL) ? *val : -*val;
+ break;
+ case OP_SIGN:
+ assert(np == 1);
+ Lval = (*val < 0LL) ? (-1) : 1;
+ break;
+ case OP_CEIL:
+ case OP_FLOOR:
+ assert(np == 1);
+ Lval = *val;
+ break;
+ case OP_ADD:
+ assert(np == 2);
+ Lval = SafeAdd(val[0], val[1]);
+ break;
+ case OP_SUB:
+ assert(np == 2);
+ Lval = SafeAdd(val[0], -val[1]);
+ break;
+ case OP_MULT:
+ assert(np == 2);
+ Lval = SafeMult(val[0], val[1]);
+ break;
+ case OP_MIN:
+ assert(np == 2);
+ Lval = min(val[0], val[1]);
+ break;
+ case OP_MAX:
+ assert(np == 2);
+ Lval = max(val[0], val[1]);
+ break;
+ case OP_DIV:
+ assert(np == 2);
+
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Lval = val[0] / val[1];
+ break;
+ case OP_MOD:
+ assert(np == 2);
+
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Lval = val[0] % val[1];
+ break;
+ case OP_BITAND:
+ assert(np == 2);
+ Lval = val[0] & val[1];
+ break;
+ case OP_BITOR:
+ assert(np == 2);
+ Lval = val[0] | val[1];
+ break;
+ case OP_BITXOR:
+ assert(np == 2);
+ Lval = val[0] ^ val[1];
+ break;
+ case OP_BITNOT:
+ assert(np == 1);
+ Lval = ~val[0];
+ break;
+ case OP_DELTA:
+// assert(np == 1);
+ Lval = val[0] - Lval;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_EXP_OPER), op);
+ return true;
+ } // endswitch op
+
+ if (trace)
+ if (np = 1)
+ htrc(" result=%lld val=%lld op=%d\n", Lval, val[0], op);
+ else
+ htrc(" result=%lld val=%lld,%lld op=%d\n",
+ Lval, val[0], val[1], op);
+
+ } // endif op
+
+ return false;
+ } // end of Compute
+
+/***********************************************************************/
+/* Divide: used by aggregate functions when calculating average. */
+/***********************************************************************/
+void BIGVAL::Divide(int cnt)
+ {
+ Lval /= cnt;
+ } // end of Divide
+
+/***********************************************************************/
+/* StdVar: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void BIGVAL::StdVar(PVAL vp, int cnt, bool b)
+ {
+ longlong lv2 = vp->GetBigintValue();
+
+ Lval = (cnt == 1) ? 0
+ : (SafeAdd(lv2, -(SafeMult(Lval, Lval) / cnt)) / (cnt - 1));
+
+ if (b) // Builtin == FNC_STDDEV
+ Lval = (longlong)sqrt((double)Lval);
+
+ } // end of StdVar
+
+/***********************************************************************/
+/* Times: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void BIGVAL::Times(PVAL vp)
+ {
+ Lval = SafeMult(Lval, vp->GetBigintValue());
+ } // end of Times
+
+/***********************************************************************/
+/* Add: used by aggregate functions for Sum and other functions. */
+/***********************************************************************/
+void BIGVAL::Add(PVAL vp)
+ {
+ Lval = SafeAdd(Lval, vp->GetBigintValue());
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void BIGVAL::Add(PVBLK vbp, int i)
+ {
+ Lval = SafeAdd(Lval, vbp->GetBigintValue(i));
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void BIGVAL::Add(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ longlong *lp = (longlong *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Lval = SafeAdd(Lval, lp[i]);
+
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by QUERY for function Sum and other functions. */
+/***********************************************************************/
+void BIGVAL::Add(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ longlong *lp = (longlong *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Lval = SafeAdd(Lval, lp[x[i]]);
+
+ } // end of Add
+
+/***********************************************************************/
+/* AddSquare: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void BIGVAL::AddSquare(PVAL vp)
+ {
+ longlong val = vp->GetBigintValue();
+
+ Lval = SafeAdd(Lval, SafeMult(val, val));
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by QUERY for functions Stddev and Variance. */
+/***********************************************************************/
+void BIGVAL::AddSquare(PVBLK vbp, int i)
+ {
+ longlong val = vbp->GetBigintValue(i);
+
+ Lval = SafeAdd(Lval, SafeMult(val, val));
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by QUERY for functions Stddev and Variance. */
+/***********************************************************************/
+void BIGVAL::AddSquare(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ longlong *lp = (longlong *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Lval = SafeAdd(Lval, SafeMult(lp[i], lp[i]));
+
+ } // end of AddSquare
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool BIGVAL::FormatValue(PVAL vp, char *fmt)
+ {
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Lval);
+
+ return (n > vp->GetValLen());
+ } // end of FormatValue
+
+/***********************************************************************/
+/* SetMin: used by the aggregate function MIN. */
+/***********************************************************************/
+void BIGVAL::SetMin(PVAL vp)
+ {
+ longlong val = vp->GetBigintValue();
+
+ if (val < Lval)
+ Lval = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void BIGVAL::SetMin(PVBLK vbp, int i)
+ {
+ longlong val = vbp->GetBigintValue(i);
+
+ if (val < Lval)
+ Lval = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void BIGVAL::SetMin(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ longlong *lp = (longlong *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (lp[i] < Lval)
+ Lval = lp[i];
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void BIGVAL::SetMin(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ longlong val;
+ longlong *lp = (longlong *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = lp[x[i]];
+
+ if (val < Lval)
+ Lval = val;
+
+ } // endfor i
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMax: used by the aggregate function MAX. */
+/***********************************************************************/
+void BIGVAL::SetMax(PVAL vp)
+ {
+ longlong val = vp->GetBigintValue();
+
+ if (val > Lval)
+ Lval = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void BIGVAL::SetMax(PVBLK vbp, int i)
+ {
+ longlong val = vbp->GetBigintValue(i);
+
+ if (val > Lval)
+ Lval = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void BIGVAL::SetMax(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ longlong *lp = (longlong *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (lp[i] > Lval)
+ Lval = lp[i];
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void BIGVAL::SetMax(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ longlong val;
+ longlong *lp = (longlong *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = lp[x[i]];
+
+ if (val > Lval)
+ Lval = val;
+
+ } // endfor i
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* BIGVAL SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool BIGVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
+ {
+ char c[16];
+
+ fmt.Type[0] = 'L';
+ fmt.Length = sprintf(c, "%lld", Lval);
+ fmt.Prec = 0;
+ return false;
+ } // end of SetConstFormat
+
+/***********************************************************************/
+/* Make file output of a big int object. */
+/***********************************************************************/
+void BIGVAL::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+
+ fprintf(f, "%s%lld\n", m, Lval);
+ } /* end of Print */
+
+/***********************************************************************/
+/* Make string output of a int object. */
+/***********************************************************************/
+void BIGVAL::Print(PGLOBAL g, char *ps, uint z)
+ {
+ sprintf(ps, "%lld", Lval);
+ } /* end of Print */
+
+/* -------------------------- Class DFVAL ---------------------------- */
+
+/***********************************************************************/
+/* DFVAL public constructor from char. */
+/***********************************************************************/
+DFVAL::DFVAL(PSZ s, int prec) : VALUE(TYPE_FLOAT)
+ {
+ Fval = atof(s);
+ Prec = prec;
+ Clen = sizeof(double);
+ } // end of DFVAL constructor
+
+/***********************************************************************/
+/* DFVAL public constructor from short. */
+/***********************************************************************/
+DFVAL::DFVAL(short n, int prec) : VALUE(TYPE_FLOAT)
+ {
+ Fval = (double)n;
+ Prec = prec;
+ Clen = sizeof(double);
+ } // end of DFVAL constructor
+
+/***********************************************************************/
+/* DFVAL public constructor from int. */
+/***********************************************************************/
+DFVAL::DFVAL(int n, int prec) : VALUE(TYPE_FLOAT)
+ {
+ Fval = (double)n;
+ Prec = prec;
+ Clen = sizeof(double);
+ } // end of DFVAL constructor
+
+/***********************************************************************/
+/* DFVAL public constructor from big int. */
+/***********************************************************************/
+DFVAL::DFVAL(longlong n, int prec) : VALUE(TYPE_FLOAT)
+ {
+ Fval = (double)n;
+ Prec = prec;
+ Clen = sizeof(double);
+ } // end of DFVAL constructor
+
+/***********************************************************************/
+/* DFVAL public constructor from double. */
+/***********************************************************************/
+DFVAL::DFVAL(double f, int prec) : VALUE(TYPE_FLOAT)
+ {
+ Fval = f;
+ Prec = prec;
+ Clen = sizeof(double);
+ } // end of DFVAL constructor
+
+/***********************************************************************/
+/* DFVAL GetValLen: returns the print length of the double object. */
+/***********************************************************************/
+int DFVAL::GetValLen(void)
+ {
+ char c[32];
+
+ return sprintf(c, "%.*lf", Prec, Fval);
+ } // end of GetValLen
+
+/***********************************************************************/
+/* DFVAL SetValue: copy the value of another Value object. */
+/* This function allows conversion if chktype is false. */
+/***********************************************************************/
+bool DFVAL::SetValue_pval(PVAL valp, bool chktype)
+ {
+ if (chktype && Type != valp->GetType())
+ return true;
+
+ Fval = valp->GetFloatValue();
+ return false;
+ } // end of SetValue
+
+/***********************************************************************/
+/* SetValue: convert chars extracted from a line to double value. */
+/***********************************************************************/
+void DFVAL::SetValue_char(char *p, int n)
+ {
+ char *p2, buf[32];
+
+ for (p2 = p + n; p < p2 && *p == ' '; p++) ;
+
+ n = min(p2 - p, 31);
+ memcpy(buf, p, n);
+ buf[n] = '\0';
+ Fval = atof(buf);
+
+ if (trace)
+ htrc(" setting double: '%s' -> %lf\n", buf, Fval);
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* DFVAL SetValue: fill a double float value from a string. */
+/***********************************************************************/
+void DFVAL::SetValue_psz(PSZ s)
+ {
+ Fval = atof(s);
+ } // end of SetValue
+
+/***********************************************************************/
+/* DFVAL SetValue: set value with a double extracted from a block. */
+/***********************************************************************/
+void DFVAL::SetValue_pvblk(PVBLK blk, int n)
+ {
+ Fval = blk->GetFloatValue(n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* SetBinValue: with bytes extracted from a line. */
+/***********************************************************************/
+void DFVAL::SetBinValue(void *p)
+ {
+ Fval = *(double *)p;
+ } // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool DFVAL::GetBinValue(void *buf, int buflen, bool go)
+ {
+ // Test on length was removed here until a variable in column give the
+ // real field length. For BIN files the field length logically cannot
+ // be different from the variable length because no conversion is done.
+ // Therefore this test is useless anyway.
+//#if defined(_DEBUG)
+// if (sizeof(double) > buflen)
+// return true;
+//#endif
+
+ if (go)
+ *(double *)buf = Fval;
+
+ return false;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
+/* This is a fast implementation that does not do any checking. */
+/* Note: type is not needed here and just kept for compatibility. */
+/***********************************************************************/
+void DFVAL::GetBinValue(void *buf, int buflen)
+ {
+ assert(buflen == sizeof(double));
+
+ *(double *)buf = Fval;
+ } // end of GetBinValue
+
+/***********************************************************************/
+/* DFVAL ShowValue: get string representation of a double value. */
+/***********************************************************************/
+char *DFVAL::ShowValue(char *buf, int len)
+ {
+ // TODO: use snprintf to avoid possible overflow
+ sprintf(buf, "%*.*lf", len, Prec, Fval);
+ return buf;
+ } // end of ShowValue
+
+/***********************************************************************/
+/* DFVAL GetCharString: get string representation of a double value. */
+/***********************************************************************/
+char *DFVAL::GetCharString(char *p)
+ {
+ sprintf(p, "%.*lf", Prec, Fval);
+ return p;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* DFVAL GetShortString: get short representation of a double value. */
+/***********************************************************************/
+char *DFVAL::GetShortString(char *p, int n)
+ {
+ sprintf(p, "%*hd", n, (short)Fval);
+ return p;
+ } // end of GetShortString
+
+/***********************************************************************/
+/* DFVAL GetIntString: get int representation of a double value. */
+/***********************************************************************/
+char *DFVAL::GetIntString(char *p, int n)
+ {
+ sprintf(p, "%*ld", n, (int)Fval);
+ return p;
+ } // end of GetIntString
+
+/***********************************************************************/
+/* DFVAL GetBigintString: get big int representation of a double val. */
+/***********************************************************************/
+char *DFVAL::GetBigintString(char *p, int n)
+ {
+ sprintf(p, "%*lld", n, (longlong)Fval);
+ return p;
+ } // end of GetBigintString
+
+/***********************************************************************/
+/* DFVAL GetFloatString: get double representation of a double value. */
+/***********************************************************************/
+char *DFVAL::GetFloatString(char *p, int n, int prec)
+ {
+ sprintf(p, "%*.*lf", n, (prec < 0) ? Prec : prec, Fval);
+ return p;
+ } // end of GetFloatString
+
+/***********************************************************************/
+/* DFVAL compare value with another Value. */
+/***********************************************************************/
+bool DFVAL::IsEqual(PVAL vp, bool chktype)
+ {
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else
+ return (Fval == vp->GetFloatValue());
+
+ } // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of double float filters. */
+/***********************************************************************/
+int DFVAL::CompareValue(PVAL vp)
+ {
+//assert(vp->GetType() == Type);
+
+ // Process filtering on int integers.
+ double d = vp->GetFloatValue();
+
+ if (trace)
+ htrc(" Comparing: val=%.2f,%.2f\n", Fval, d);
+
+ return (Fval > d) ? 1 : (Fval < d) ? (-1) : 0;
+ } // end of CompareValue
+
+/***********************************************************************/
+/* Compute a function on double floats. */
+/***********************************************************************/
+bool DFVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+ {
+ double val[2];
+
+ assert(np <= 2);
+
+ for (int i = 0; i < np; i++)
+ val[i] = vp[i]->GetFloatValue();
+
+ switch (op) {
+ case OP_ABS:
+ assert(np == 1);
+ Fval = fabs(*val);
+ break;
+ case OP_CEIL:
+ assert(np == 1);
+ Fval = ceil(*val);
+ break;
+ case OP_FLOOR:
+ assert(np == 1);
+ Fval = floor(*val);
+ break;
+ case OP_SIGN:
+ assert(np == 1);
+ Fval = (*val < 0.0) ? (-1.0) : 1.0;
+ break;
+ case OP_ADD:
+ assert(np == 2);
+ Fval = val[0] + val[1];
+ break;
+ case OP_SUB:
+ assert(np == 2);
+ Fval = val[0] - val[1];
+ break;
+ case OP_MULT:
+ assert(np == 2);
+ Fval = val[0] * val[1];
+ break;
+ case OP_MIN:
+ assert(np == 2);
+ Fval = min(val[0], val[1]);
+ break;
+ case OP_MAX:
+ assert(np == 2);
+ Fval = max(val[0], val[1]);
+ break;
+ case OP_DIV:
+ assert(np == 2);
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Fval = val[0] / val[1];
+ break;
+ case OP_MOD:
+ assert(np == 2);
+ Fval = fmod(val[0], val[1]);
+ break;
+ case OP_SQRT:
+ assert(np == 1);
+ Fval = sqrt(*val);
+ break;
+ case OP_LN:
+ assert(np == 1);
+ Fval = log(*val);
+ break;
+ case OP_EXP:
+ assert(np == 1);
+ Fval = exp(*val);
+ break;
+ case OP_COS:
+ assert(np == 1);
+ Fval = cos(*val);
+ break;
+ case OP_SIN:
+ assert(np == 1);
+ Fval = sin(*val);
+ break;
+ case OP_TAN:
+ assert(np == 1);
+ Fval = tan(*val);
+ break;
+ case OP_COSH:
+ assert(np == 1);
+ Fval = cosh(*val);
+ break;
+ case OP_SINH:
+ assert(np == 1);
+ Fval = sinh(*val);
+ break;
+ case OP_TANH:
+ assert(np == 1);
+ Fval = tanh(*val);
+ break;
+ case OP_LOG:
+ assert(np > 0);
+
+ if (np > 1 && val[1] != 10.0) {
+ strcpy(g->Message, MSG(ONLY_LOG10_IMPL));
+ return true;
+ } // endif Numarg
+
+ Fval = log10(val[0]);
+ break;
+ case OP_POWER:
+ assert(np == 2);
+ Fval = pow(val[0], val[1]);
+ break;
+ case OP_ROUND:
+ assert(np > 0);
+
+ if (np > 1) {
+ double dx, dy = val[1];
+
+ modf(dy, &dx); // Get integral part of arg
+ dx = pow(10.0, dx);
+ modf(val[0] * dx + 0.5, &dy);
+ Fval = dy / dx;
+ } else
+ modf(val[0] + 0.5, &Fval);
+
+ break;
+ case OP_DELTA:
+// assert(np == 1);
+ Fval = val[0] - Fval;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_EXP_OPER), op);
+ return true;
+ } // endswitch op
+
+ if (trace) {
+ if (np == 1)
+ htrc("Compute result=%lf val=%lf op=%d\n", Fval, val[0], op);
+ else
+ htrc("Compute result=%lf val=%lf,%lf op=%d\n",
+ Fval, val[0], val[1], op);
+ } // endif trace
+
+ return false;
+ } // end of Compute
+
+/***********************************************************************/
+/* GetTime: convert HR/MIN/SEC in a number of seconds. */
+/***********************************************************************/
+int DFVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
+ {
+ double sec = Fval;
+
+ for (int i = 0; i < 2; i++) {
+ sec *= 60.0;
+
+ if (np > i)
+ sec += vp[i]->GetFloatValue();
+
+ } // endfor i
+
+ return (int)sec;
+ } // end of GetTime
+
+/***********************************************************************/
+/* Divide: used by aggregate functions when calculating average. */
+/***********************************************************************/
+void DFVAL::Divide(int cnt)
+ {
+ Fval /= (double)cnt;
+ } // end of Divide
+
+/***********************************************************************/
+/* StdVar: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void DFVAL::StdVar(PVAL vp, int cnt, bool b)
+ {
+ double fv2 = vp->GetFloatValue();
+ double cnd = (double)cnt;
+
+ Fval = (cnt == 1) ? 0.0 : ((fv2 - (Fval * Fval) / cnd) / (cnd - 1.0));
+
+ if (b) // Builtin == FNC_STDDEV
+ Fval = sqrt(Fval);
+
+ } // end of StdVar
+
+/***********************************************************************/
+/* Times: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void DFVAL::Times(PVAL vp)
+ {
+ Fval *= vp->GetFloatValue();
+ } // end of Times
+
+/***********************************************************************/
+/* Add: used by aggregate functions for Sum and other functions. */
+/***********************************************************************/
+void DFVAL::Add(PVAL vp)
+ {
+ Fval += vp->GetFloatValue();
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by aggregate functions for Sum and other functions. */
+/***********************************************************************/
+void DFVAL::Add(PVBLK vbp, int i)
+ {
+ Fval += vbp->GetFloatValue(i);
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by aggregate functions for Sum and other functions. */
+/***********************************************************************/
+void DFVAL::Add(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ double *dp = (double *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Fval += dp[i];
+
+ } // end of Add
+
+/***********************************************************************/
+/* Add: used by aggregate functions for Sum and other functions. */
+/***********************************************************************/
+void DFVAL::Add(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ double *dp = (double *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Fval += dp[x[i]];
+
+ } // end of Add
+
+/***********************************************************************/
+/* AddSquare: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void DFVAL::AddSquare(PVAL vp)
+ {
+ double val = vp->GetFloatValue();
+
+ Fval += (val * val);
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void DFVAL::AddSquare(PVBLK vbp, int i)
+ {
+ double val = vbp->GetFloatValue(i);
+
+ Fval += (val * val);
+ } // end of AddSquare
+
+/***********************************************************************/
+/* AddSquare: used by aggregate functions for Stddev and Variance. */
+/***********************************************************************/
+void DFVAL::AddSquare(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ double *dp = (double *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ Fval += (dp[i] * dp[i]);
+
+ } // end of AddSquare
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool DFVAL::FormatValue(PVAL vp, char *fmt)
+ {
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Fval);
+
+ return (n > vp->GetValLen());
+ } // end of FormatValue
+
+/***********************************************************************/
+/* SetMin: used by the aggregate function MIN. */
+/***********************************************************************/
+void DFVAL::SetMin(PVAL vp)
+ {
+ double val = vp->GetFloatValue();
+
+ if (val < Fval)
+ Fval = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void DFVAL::SetMin(PVBLK vbp, int i)
+ {
+ double val = vbp->GetFloatValue(i);
+
+ if (val < Fval)
+ Fval = val;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMin: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void DFVAL::SetMin(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ double *dp = (double *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (dp[i] < Fval)
+ Fval = dp[i];
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void DFVAL::SetMin(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ register double val;
+ double *dp = (double *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = dp[x[i]];
+
+ if (val < Fval)
+ Fval = val;
+
+ } // endfor i
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* SetMax: used by the aggregate function MAX. */
+/***********************************************************************/
+void DFVAL::SetMax(PVAL vp)
+ {
+ double val = vp->GetFloatValue();
+
+ if (val > Fval)
+ Fval = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MAX. */
+/***********************************************************************/
+void DFVAL::SetMax(PVBLK vbp, int i)
+ {
+ double val = vbp->GetFloatValue(i);
+
+ if (val > Fval)
+ Fval = val;
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void DFVAL::SetMax(PVBLK vbp, int j, int k)
+ {
+ CheckType(vbp)
+ double *dp = (double *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++)
+ if (dp[i] > Fval)
+ Fval = dp[i];
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* SetMax: used by QUERY for the aggregate function MIN. */
+/***********************************************************************/
+void DFVAL::SetMax(PVBLK vbp, int *x, int j, int k)
+ {
+ CheckType(vbp)
+ register double val;
+ double *dp = (double *)vbp->GetValPointer();
+
+ for (register int i = j; i < k; i++) {
+ val = dp[x[i]];
+
+ if (val > Fval)
+ Fval = val;
+
+ } // endfor i
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* DFVAL SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool DFVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
+ {
+ char c[32];
+
+ fmt.Type[0] = 'F';
+ fmt.Length = sprintf(c, "%.*lf", Prec, Fval);
+ fmt.Prec = Prec;
+ return false;
+ } // end of SetConstFormat
+
+/***********************************************************************/
+/* Make file output of a double object. */
+/***********************************************************************/
+void DFVAL::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+
+ fprintf(f, "%s%.*lf\n", m, Prec, Fval);
+ } /* end of Print */
+
+/***********************************************************************/
+/* Make string output of a double object. */
+/***********************************************************************/
+void DFVAL::Print(PGLOBAL g, char *ps, uint z)
+ {
+ sprintf(ps, "%.*lf", Prec, Fval);
+ } /* end of Print */
+
+#endif // __VALUE_H
+
+/* -------------------------- End of Value --------------------------- */
diff --git a/storage/connect/value.h b/storage/connect/value.h
index 5e170c40c1b..c0502085be5 100644
--- a/storage/connect/value.h
+++ b/storage/connect/value.h
@@ -1,605 +1,605 @@
-/**************** Value H Declares Source Code File (.H) ***************/
-/* Name: VALUE.H Version 1.7 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
-/* */
-/* 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"
-
-#if defined(WIN32)
-#define strtoll _strtoi64
-#define atoll(S) strtoll(S, NULL, 10)
-#endif // WIN32
-
-/***********************************************************************/
-/* 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);
-PVAL AllocateValue(PGLOBAL, void *, short);
-
-// Exported functions
-DllExport PSZ GetTypeName(int);
-DllExport int GetTypeSize(int, int);
-#ifdef ODBC_SUPPORT
-/* This function is exported for use in EOM table type DLLs */
-DllExport int TranslateSQLType(int stp, int prec, int& len);
-#endif
-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 longlong GetBigintValue(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(longlong 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 *GetBigintString(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, longlong 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 longlong GetBigintValue(void) {return atoll(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(longlong 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 *GetBigintString(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(longlong 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 longlong GetBigintValue(void) {return (longlong)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(longlong 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 *GetBigintString(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(longlong 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 longlong GetBigintValue(void) {return (longlong)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(longlong n) {Ival = (int)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 *GetBigintString(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, longlong 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 BIGVAL: represents bigint integer values. */
-/***********************************************************************/
-class DllExport BIGVAL : public VALUE {
- public:
- // Constructors
- BIGVAL(PSZ s);
- BIGVAL(short i);
- BIGVAL(int n);
- BIGVAL(longlong n);
- BIGVAL(double f);
-
- // Implementation
- virtual bool IsTypeNum(void) {return true;}
- virtual bool IsZero(void) {return Lval == 0LL;}
- virtual void Reset(void) {Lval = 0LL;}
- virtual int GetValLen(void);
- virtual int GetValPrec() {return 0;}
- virtual int GetSize(void) {return sizeof(longlong);}
-//virtual PSZ GetCharValue(void) {}
- virtual short GetShortValue(void) {return (short)Lval;}
- virtual int GetIntValue(void) {return (int)Lval;}
- virtual longlong GetBigintValue(void) {return Lval;}
- virtual double GetFloatValue(void) {return (double)Lval;}
- virtual void *GetTo_Val(void) {return &Lval;}
-
- // 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) {Lval = (b) ? 1LL : 0LL;}
- virtual void SetValue(short i) {Lval = (longlong)i;}
- virtual void SetValue(int n) {Lval = (longlong)n;}
- virtual void SetValue(longlong n) {Lval = n;}
- virtual void SetValue(double f) {Lval = (longlong)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 *GetBigintString(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) {Lval += (longlong)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:
- longlong SafeAdd(longlong n1, longlong n2);
- longlong SafeMult(longlong n1, longlong n2);
- // Default constructor not to be used
- BIGVAL(void) : VALUE(TYPE_ERROR) {}
-
- // Members
- longlong Lval;
- }; // end of class BIGVAL
-
-/***********************************************************************/
-/* 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(longlong 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 longlong GetBigintValue(void) {return (longlong)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(longlong 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 *GetBigintString(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
+/**************** Value H Declares Source Code File (.H) ***************/
+/* Name: VALUE.H Version 1.7 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
+/* */
+/* 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"
+
+#if defined(WIN32)
+#define strtoll _strtoi64
+#define atoll(S) strtoll(S, NULL, 10)
+#endif // WIN32
+
+/***********************************************************************/
+/* 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);
+PVAL AllocateValue(PGLOBAL, void *, short);
+
+// Exported functions
+DllExport PSZ GetTypeName(int);
+DllExport int GetTypeSize(int, int);
+#ifdef ODBC_SUPPORT
+/* This function is exported for use in EOM table type DLLs */
+DllExport int TranslateSQLType(int stp, int prec, int& len);
+#endif
+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 longlong GetBigintValue(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(longlong 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 *GetBigintString(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, longlong 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 longlong GetBigintValue(void) {return atoll(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(longlong 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 *GetBigintString(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(longlong 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 longlong GetBigintValue(void) {return (longlong)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(longlong 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 *GetBigintString(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(longlong 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 longlong GetBigintValue(void) {return (longlong)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(longlong n) {Ival = (int)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 *GetBigintString(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, longlong 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 BIGVAL: represents bigint integer values. */
+/***********************************************************************/
+class DllExport BIGVAL : public VALUE {
+ public:
+ // Constructors
+ BIGVAL(PSZ s);
+ BIGVAL(short i);
+ BIGVAL(int n);
+ BIGVAL(longlong n);
+ BIGVAL(double f);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return true;}
+ virtual bool IsZero(void) {return Lval == 0LL;}
+ virtual void Reset(void) {Lval = 0LL;}
+ virtual int GetValLen(void);
+ virtual int GetValPrec() {return 0;}
+ virtual int GetSize(void) {return sizeof(longlong);}
+//virtual PSZ GetCharValue(void) {}
+ virtual short GetShortValue(void) {return (short)Lval;}
+ virtual int GetIntValue(void) {return (int)Lval;}
+ virtual longlong GetBigintValue(void) {return Lval;}
+ virtual double GetFloatValue(void) {return (double)Lval;}
+ virtual void *GetTo_Val(void) {return &Lval;}
+
+ // 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) {Lval = (b) ? 1LL : 0LL;}
+ virtual void SetValue(short i) {Lval = (longlong)i;}
+ virtual void SetValue(int n) {Lval = (longlong)n;}
+ virtual void SetValue(longlong n) {Lval = n;}
+ virtual void SetValue(double f) {Lval = (longlong)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 *GetBigintString(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) {Lval += (longlong)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:
+ longlong SafeAdd(longlong n1, longlong n2);
+ longlong SafeMult(longlong n1, longlong n2);
+ // Default constructor not to be used
+ BIGVAL(void) : VALUE(TYPE_ERROR) {}
+
+ // Members
+ longlong Lval;
+ }; // end of class BIGVAL
+
+/***********************************************************************/
+/* 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(longlong 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 longlong GetBigintValue(void) {return (longlong)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(longlong 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 *GetBigintString(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
diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp
index e19f7243f72..52595c27df3 100644
--- a/storage/connect/xindex.cpp
+++ b/storage/connect/xindex.cpp
@@ -1,3122 +1,3122 @@
-/***************** Xindex C++ Class Xindex Code (.CPP) *****************/
-/* Name: XINDEX.CPP Version 2.7 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 2004-2012 */
-/* */
-/* This file contains the class XINDEX implementation code. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* 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 <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <unistd.h>
-#else // !UNIX
-#include <io.h>
-#endif // !UNIX
-#include <fcntl.h>
-#endif // !WIN32
-
-/***********************************************************************/
-/* Include required application header files */
-/* global.h is header containing all global Plug declarations. */
-/* plgdbsem.h is header containing the DB applic. declarations. */
-/* kindex.h is header containing the KINDEX class definition. */
-/***********************************************************************/
-#include "global.h"
-#include "plgdbsem.h"
-#include "osutil.h"
-#include "maputil.h"
-//nclude "filter.h"
-#include "tabcol.h"
-#include "xindex.h"
-#include "xobject.h"
-//nclude "scalfnc.h"
-//nclude "array.h"
-#include "filamtxt.h"
-#include "tabdos.h"
-
-/***********************************************************************/
-/* Macro or external routine definition */
-/***********************************************************************/
-#define NZ 7
-#define NW 5
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
-#endif
-
-/***********************************************************************/
-/* DB static external variables. */
-/***********************************************************************/
-extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
-
-/***********************************************************************/
-/* Last two parameters are true to enable type checking, and last one */
-/* to have rows filled by blanks to be compatible with QRY blocks. */
-/***********************************************************************/
-PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
- bool check = true, bool blank = true);
-
-/***********************************************************************/
-/* Check whether we have to create/update permanent indexes. */
-/***********************************************************************/
-int PlgMakeIndex(PGLOBAL g, PSZ name, PIXDEF pxdf, bool add)
- {
- int rc;
- PTABLE tablep;
- PTDBDOS tdbp;
- PCATLG cat = PlgGetCatalog(g, true);
-
- /*********************************************************************/
- /* Open a new table in mode read and with only the keys columns. */
- /*********************************************************************/
- tablep = new(g) XTAB(name);
-
- if (!(tdbp = (PTDBDOS)cat->GetTable(g, tablep)))
- rc = RC_NF;
- else if (!tdbp->GetDef()->Indexable()) {
- sprintf(g->Message, MSG(TABLE_NO_INDEX), name);
- rc = RC_NF;
- } else if ((rc = tdbp->MakeIndex(g, pxdf, add)) == RC_INFO)
- rc = RC_OK; // No index
-
- return rc;
- } // end of PlgMakeIndex
-
-/* -------------------------- Class INDEXDEF ------------------------- */
-
-/***********************************************************************/
-/* INDEXDEF Constructor. */
-/***********************************************************************/
-INDEXDEF::INDEXDEF(char *name, bool uniq, int n)
- {
-//To_Def = NULL;
- Next = NULL;
- ToKeyParts = NULL;
- Name = name;
- Unique = uniq;
- Invalid = false;
- AutoInc = false;
- Nparts = 0;
- ID = n;
- Offset = 0;
- Offhigh = 0;
- Size = 0;
- MaxSame = 1;
- } // end of INDEXDEF constructor
-
-/***********************************************************************/
-/* Set the max same values for each colum after making the index. */
-/***********************************************************************/
-void INDEXDEF::SetMxsame(PXINDEX x)
- {
- PKPDEF kdp;
- PXCOL xcp;
-
- for (kdp = ToKeyParts, xcp = x->To_KeyCol;
- kdp && xcp; kdp = kdp->Next, xcp = xcp->Next)
- kdp->Mxsame = xcp->Mxs;
- } // end of SetMxsame
-
-/* -------------------------- Class KPARTDEF ------------------------- */
-
-/***********************************************************************/
-/* KPARTDEF Constructor. */
-/***********************************************************************/
-KPARTDEF::KPARTDEF(PSZ name, int n)
- {
- Next = NULL;
- Name = name;
- Mxsame = 0;
- Ncol = n;
- Klen = 0;
- } // end of KPARTDEF constructor
-
-/* -------------------------- XXBASE Class --------------------------- */
-
-/***********************************************************************/
-/* XXBASE public constructor. */
-/***********************************************************************/
-XXBASE::XXBASE(PTDBDOS tbxp, bool b) : CSORT(b),
- To_Rec((int*&)Record.Memp)
- {
- Tbxp = tbxp;
- Record = Nmblk;
- Cur_K = -1;
- Old_K = -1;
- Num_K = 0;
- Ndif = 0;
- Bot = Top = Inf = Sup = 0;
- Op = OP_EQ;
- To_KeyCol = NULL;
- Mul = false;
- Val_K = -1;
- Nblk = Sblk = 0;
- Thresh = 7;
- ID = -1;
- Nth = 0;
- } // end of XXBASE constructor
-
-/***********************************************************************/
-/* Make file output of XINDEX contents. */
-/***********************************************************************/
-void XXBASE::Print(PGLOBAL g, FILE *f, uint n)
- {
- char m[64];
-
- memset(m, ' ', n); // Make margin string
- m[n] = '\0';
- fprintf(f, "%sXINDEX: Tbxp=%p Num=%d\n", m, Tbxp, Num_K);
- } // end of Print
-
-/***********************************************************************/
-/* Make string output of XINDEX contents. */
-/***********************************************************************/
-void XXBASE::Print(PGLOBAL g, char *ps, uint z)
- {
- *ps = '\0';
- strncat(ps, "Xindex", z);
- } // end of Print
-
-/* -------------------------- XINDEX Class --------------------------- */
-
-/***********************************************************************/
-/* XINDEX public constructor. */
-/***********************************************************************/
-XINDEX::XINDEX(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp, int k)
- : XXBASE(tdbp, !xdp->IsUnique())
- {
- Xdp = xdp;
- ID = xdp->GetID();
- Tdbp = tdbp;
- X = pxp;
- To_LastCol = NULL;
- To_LastVal = NULL;
- To_Cols = cp;
- To_Vals = xp;
- Mul = !xdp->IsUnique();
- Srtd = false;
- Nk = xdp->GetNparts();
- Nval = (k) ? k : Nk;
- Incr = 0;
- Defoff = xdp->GetOffset();
- Defhigh = xdp->GetOffhigh();
- Size = xdp->GetSize();
- MaxSame = xdp->GetMaxSame();
- } // end of XINDEX constructor
-
-/***********************************************************************/
-/* XINDEX Reset: re-initialize a Xindex block. */
-/***********************************************************************/
-void XINDEX::Reset(void)
- {
- for (PXCOL kp = To_KeyCol; kp; kp = kp->Next)
- kp->Val_K = kp->Ndf;
-
- Cur_K = Num_K;
- Old_K = -1; // Needed to avoid not setting CurBlk for Update
- Op = (Op == OP_FIRST || Op == OP_NEXT) ? OP_FIRST :
- (Op == OP_FSTDIF || Op == OP_NXTDIF) ? OP_FSTDIF : OP_EQ;
- Nth = 0;
- } // end of Reset
-
-/***********************************************************************/
-/* XINDEX Close: terminate index and free all allocated data. */
-/* Do not reset other values that are used at return to make. */
-/***********************************************************************/
-void XINDEX::Close(void)
- {
- // Close file or view of file
- X->Close();
-
- // De-allocate data
- PlgDBfree(Record);
- PlgDBfree(Index);
- PlgDBfree(Offset);
-
- // De-allocate Key data
- for (PXCOL kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->FreeData();
-
- // Column values cannot be retrieved from key anymore
- for (int k = 0; k < Nk; k++)
- To_Cols[k]->SetKcol(NULL);
-
- } // end of Close
-
-/***********************************************************************/
-/* XINDEX compare routine for C Quick/Insertion sort. */
-/***********************************************************************/
-int XINDEX::Qcompare(int *i1, int *i2)
- {
- register int k;
- register PXCOL kcp;
-
- for (kcp = To_KeyCol, k = 0; kcp; kcp = kcp->Next)
- if ((k = kcp->Compare(*i1, *i2)))
- break;
-
-#ifdef DEBTRACE
- num_comp++;
-#endif
-
- return k;
- } // end of Qcompare
-
-/***********************************************************************/
-/* Make: Make and index on key column(s). */
-/***********************************************************************/
-bool XINDEX::Make(PGLOBAL g, PIXDEF sxp)
- {
- /*********************************************************************/
- /* Table can be accessed through an index. */
- /*********************************************************************/
- int k, rc = RC_OK;
- int *bof, i, j, n, ndf, nkey;
- PKPDEF kdfp = Xdp->GetToKeyParts();
- bool brc = true;
- PCOL colp;
- PXCOL kp, prev = NULL, kcp = NULL;
- PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- Defoff = 0;
- Size = 0; // Void index
-
- /*********************************************************************/
- /* Allocate the storage that will contain the keys and the file */
- /* positions corresponding to them. */
- /*********************************************************************/
- if ((n = Tdbp->GetMaxSize(g)) < 0)
- return true;
- else if (!n) {
- Num_K = Ndif = 0;
- MaxSame = 1;
-
- // The if condition was suppressed because this may be an existing
- // index that is now void because all table lines were deleted.
-// if (sxp)
- goto nox; // Truncate eventually existing index file
-// else
-// return false;
-
- } // endif n
-
- // File position must be stored
- Record.Size = n * sizeof(int);
-
- if (!PlgDBalloc(g, NULL, Record)) {
- sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", n);
- goto err; // Error
- } // endif
-
- /*********************************************************************/
- /* Allocate the KXYCOL blocks used to store column values. */
- /*********************************************************************/
- for (k = 0; k < Nk; k++) {
- colp = To_Cols[k];
-
- if (!kdfp) {
- sprintf(g->Message, MSG(INT_COL_ERROR),
- (colp) ? colp->GetName() : "???");
- goto err; // Error
- } // endif kdfp
-
- kcp = new(g) KXYCOL(this);
-
- if (kcp->Init(g, colp, n, true, kdfp->Klen))
- goto err; // Error
-
- if (prev) {
- kcp->Previous = prev;
- prev->Next = kcp;
- } else
- To_KeyCol = kcp;
-
- prev = kcp;
- kdfp = kdfp->Next;
- } // endfor k
-
- To_LastCol = prev;
-
- /*********************************************************************/
- /* Get the starting information for progress. */
- /*********************************************************************/
- dup->Step = (char*)PlugSubAlloc(g, NULL, 128);
- sprintf((char*)dup->Step, MSG(BUILD_INDEX), Xdp->GetName(), Tdbp->Name);
- dup->ProgMax = Tdbp->GetProgMax(g);
- dup->ProgCur = 0;
-
- /*********************************************************************/
- /* Standard init: read the file and construct the index table. */
- /* Note: reading will be sequential as To_Kindex is not set. */
- /*********************************************************************/
- for (i = nkey = 0; i < n && rc != RC_EF; i++) {
-#if defined(THREAD)
- if (!dup->Step) {
- strcpy(g->Message, MSG(QUERY_CANCELLED));
- longjmp(g->jumper[g->jump_level], 99);
- } // endif Step
-#endif // THREAD
-
- /*******************************************************************/
- /* Read a valid record from table file. */
- /*******************************************************************/
- rc = Tdbp->ReadDB(g);
-
- // Update progress information
- dup->ProgCur = Tdbp->GetProgCur();
-
- // Check return code and do whatever must be done according to it
- switch (rc) {
- case RC_OK:
- break;
- case RC_EF:
- goto end_of_file;
- case RC_NF:
- continue;
- default:
- sprintf(g->Message, MSG(RC_READING), rc, Tdbp->Name);
- goto err;
- } // endswitch rc
-
- /*******************************************************************/
- /* Get and Store the file position of the last read record for */
- /* future direct access. */
- /*******************************************************************/
- To_Rec[nkey] = Tdbp->GetRecpos();
-
- /*******************************************************************/
- /* Get the keys and place them in the key blocks. */
- /*******************************************************************/
- for (k = 0, kcp = To_KeyCol;
- k < Nk && kcp;
- k++, kcp = kcp->Next) {
- colp = To_Cols[k];
- colp->Reset();
-
- colp->ReadColumn(g);
-// if (colp->ReadColumn(g))
-// goto err;
-
- kcp->SetValue(colp, nkey);
- } // endfor k
-
- nkey++; // A new valid key was found
- } // endfor i
-
- end_of_file:
-
- // Update progress information
- dup->ProgCur = Tdbp->GetProgMax(g);
-
- /*********************************************************************/
- /* Record the Index size and eventually resize memory allocation. */
- /*********************************************************************/
- if ((Num_K = nkey) < n) {
- PlgDBrealloc(g, NULL, Record, Num_K * sizeof(int));
-
- for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->ReAlloc(g, Num_K);
-
- } // endif Num_K
-
- /*********************************************************************/
- /* Sort the index so we can use an optimized Find algorithm. */
- /* Note: for a unique index we use the non conservative sort */
- /* version because normally all index values are different. */
- /* This was set at CSORT class construction. */
- /* For all indexes, an offset array is made so we can check the */
- /* uniqueness of unique indexes. */
- /*********************************************************************/
- Index.Size = Num_K * sizeof(int);
-
- if (!PlgDBalloc(g, NULL, Index)) {
- sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", Num_K);
- goto err; // Error
- } // endif alloc
-
- Offset.Size = (Num_K + 1) * sizeof(int);
-
- if (!PlgDBalloc(g, NULL, Offset)) {
- sprintf(g->Message, MSG(MEM_ALLOC_ERR), "offset", Num_K + 1);
- goto err; // Error
- } // endif alloc
-
- // Call the sort program, it returns the number of distinct values
- if ((Ndif = Qsort(g, Num_K)) < 0)
- goto err; // Error during sort
-
- // Check whether the unique index is unique indeed
- if (!Mul)
- if (Ndif < Num_K) {
- strcpy(g->Message, MSG(INDEX_NOT_UNIQ));
- goto err;
- } else
- PlgDBfree(Offset); // Not used anymore
-
- // Use the index to physically reorder the xindex
- Srtd = Reorder(g);
-
- if (Ndif < Num_K) {
- // Resize the offset array
- PlgDBrealloc(g, NULL, Offset, (Ndif + 1) * sizeof(int));
-
- // Initial value of MaxSame
- MaxSame = Pof[1] - Pof[0];
-
- // Resize the Key array by only keeping the distinct values
- for (i = 1; i < Ndif; i++) {
- for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->Move(i, Pof[i]);
-
- MaxSame = max(MaxSame, Pof[i + 1] - Pof[i]);
- } // endfor i
-
- for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->ReAlloc(g, Ndif);
-
- } else {
- Mul = false; // Current index is unique
- PlgDBfree(Offset); // Not used anymore
- MaxSame = 1; // Reset it when remaking an index
- } // endif Ndif
-
- /*********************************************************************/
- /* Now do the reduction of the index. Indeed a multi-column index */
- /* can be used for only some of the first columns. For instance if */
- /* an index is defined for column A, B, C PlugDB can use it for */
- /* only the column A or the columns A, B. */
- /* What we do here is to reduce the data so column A will contain */
- /* only the sorted distinct values of A, B will contain data such */
- /* as only distinct values of A,B are stored etc. */
- /* This implies that for each column set an offset array is made */
- /* except if the subset originally contains unique values. */
- /*********************************************************************/
- // Update progress information
- dup->Step = STEP(REDUCE_INDEX);
-
- ndf = Ndif;
- To_LastCol->Mxs = MaxSame;
-
- for (kcp = To_LastCol->Previous; kcp; kcp = kcp->Previous) {
- if (!(bof = kcp->MakeOffset(g, ndf)))
- goto err;
- else
- *bof = 0;
-
- for (n = 0, i = j = 1; i < ndf; i++)
- for (kp = kcp; kp; kp = kp->Previous)
- if (kp->Compare(n, i)) {
- // Values are not equal to last ones
- bof[j++] = n = i;
- break;
- } // endif Compare
-
- if (j < ndf) {
- // Sub-index is multiple
- bof[j] = ndf;
- ndf = j; // New number of distinct values
-
- // Resize the Key array by only keeping the distinct values
- for (kp = kcp; kp; kp = kp->Previous) {
- for (i = 1; i < ndf; i++)
- kp->Move(i, bof[i]);
-
- kp->ReAlloc(g, ndf);
- } // endif kcp
-
- // Resize the offset array
- kcp->MakeOffset(g, ndf);
-
- // Calculate the max same value for this column
- kcp->Mxs = ColMaxSame(kcp);
- } else {
- // Current sub-index is unique
- kcp->MakeOffset(g, 0); // The offset is not used anymore
- kcp->Mxs = 1; // Unique
- } // endif j
-
- } // endfor kcp
-
- /*********************************************************************/
- /* For sorted columns and fixed record size, file position can be */
- /* calculated, so the Record array can be discarted. */
- /* Note: for Num_K = 1 any non null value is Ok. */
- /*********************************************************************/
- if (Srtd && Tdbp->Ftype != RECFM_VAR) {
- Incr = (Num_K > 1) ? To_Rec[1] : Num_K;
- PlgDBfree(Record);
- } // endif Srtd
-
- /*********************************************************************/
- /* Check whether a two-tier find algorithm can be implemented. */
- /* It is currently implemented only for single key indexes. */
- /*********************************************************************/
- if (Nk == 1 && ndf >= 65536) {
- // Implement a two-tier find algorithm
- for (Sblk = 256; (Sblk * Sblk * 4) < ndf; Sblk *= 2) ;
-
- Nblk = (ndf -1) / Sblk + 1;
-
- if (To_KeyCol->MakeBlockArray(g, Nblk, Sblk))
- goto err; // Error
-
- } // endif Num_K
-
- nox:
- /*********************************************************************/
- /* No valid record read yet for secondary file. */
- /*********************************************************************/
- Cur_K = Num_K;
-
- /*********************************************************************/
- /* Save the index so it has not to be recalculated. */
- /*********************************************************************/
- if (!SaveIndex(g, sxp))
- brc = false;
-
- err:
- // We don't need the index anymore
- Close();
- return brc;
- } // end of Make
-
-/***********************************************************************/
-/* Return the max size of the intermediate column. */
-/***********************************************************************/
-int XINDEX::ColMaxSame(PXCOL kp)
- {
- int *kof, i, ck1, ck2, ckn = 1;
- PXCOL kcp;
-
- // Calculate the max same value for this column
- for (i = 0; i < kp->Ndf; i++) {
- ck1 = i;
- ck2 = i + 1;
-
- for (kcp = kp; kcp; kcp = kcp->Next) {
- if (!(kof = (kcp->Next) ? kcp->Kof : Pof))
- break;
-
- ck1 = kof[ck1];
- ck2 = kof[ck2];
- } // endfor kcp
-
- ckn = max(ckn, ck2 - ck1);
- } // endfor i
-
- return ckn;
- } // end of ColMaxSame
-
-/***********************************************************************/
-/* Reorder: use the sort index to reorder the data in storage so */
-/* it will be physically sorted and sort index can be removed. */
-/***********************************************************************/
-bool XINDEX::Reorder(PGLOBAL g)
- {
- register int i, j, k, n;
- bool sorted = true;
- PXCOL kcp;
- PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
-
- if (Num_K > 500000) {
- // Update progress information
- dup->Step = STEP(REORDER_INDEX);
- dup->ProgMax = Num_K;
- dup->ProgCur = 0;
- } else
- dup = NULL;
-
- if (!Pex)
- return Srtd;
-
- for (i = 0; i < Num_K; i++) {
- if (Pex[i] == Num_K) { // Already moved
- continue;
- } else if (Pex[i] == i) { // Already placed
- if (dup)
- dup->ProgCur++;
-
- continue;
- } // endif's Pex
-
- sorted = false;
-
- for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->Save(i);
-
- n = To_Rec[i];
-
- for (j = i;; j = k) {
- k = Pex[j];
- Pex[j] = Num_K; // Mark position as set
-
- if (k == i) {
- for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->Restore(j);
-
- To_Rec[j] = n;
- break; // end of loop
- } else {
- for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->Move(j, k); // Move k to j
-
- To_Rec[j] = To_Rec[k];
- } // endif k
-
- if (dup)
- dup->ProgCur++;
-
- } // endfor j
-
- } // endfor i
-
- // The index is not used anymore
- PlgDBfree(Index);
- return sorted;
- } // end of Reorder
-
-/***********************************************************************/
-/* Save the index values for this table. */
-/* The problem here is to avoid name duplication, because more than */
-/* one data file can have the same name (but different types) and/or */
-/* the same data file can be used with different block sizes. This is */
-/* why we use Ofn that defaults to the file name but can be set to a */
-/* different name if necessary. */
-/***********************************************************************/
-bool XINDEX::SaveIndex(PGLOBAL g, PIXDEF sxp)
- {
- char *ftype;
- char fn[_MAX_PATH];
- int n[NZ], nof = (Mul) ? (Ndif + 1) : 0;
- bool rc = false;
- PXCOL kcp = To_KeyCol;
- PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
- PDBUSER dup = PlgGetUser(g);
-
- dup->Step = STEP(SAVING_INDEX);
- dup->ProgMax = 15 + 16 * Nk;
- dup->ProgCur = 0;
-
- switch (Tdbp->Ftype) {
- case RECFM_VAR: ftype = ".dnx"; break;
- case RECFM_FIX: ftype = ".fnx"; break;
- case RECFM_BIN: ftype = ".bnx"; break;
- case RECFM_VCT: ftype = ".vnx"; break;
- case RECFM_DBF: ftype = ".dbx"; break;
- default:
- sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
- return true;
- } // endswitch Ftype
-
- if (dup->Catalog->GetSepIndex()) {
- // Index is saved in a separate file
-#if !defined(UNIX)
- char drive[_MAX_DRIVE];
-#else
- char *drive = NULL;
-#endif
- char direc[_MAX_DIR];
- char fname[_MAX_FNAME];
-
- _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
- strcat(strcat(fname, "_"), Xdp->GetName());
- _makepath(fn, drive, direc, fname, ftype);
- sxp = NULL;
- } else
- strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
-
- PlugSetPath(fn, fn, Tdbp->GetPath());
-
- if (X->Open(g, fn, (sxp) ? MODE_INSERT : MODE_WRITE)) {
- printf("%s\n", g->Message);
- return true;
- } // endif Open
-
- if (!Ndif)
- goto end; // Void index
-
- // Defoff is the start of the definition in the index file
- X->GetOff(Defoff, Defhigh, sxp);
-
-#if defined(TRACE)
- printf("Defoff=%d Defhigh=%d\n", Defoff, Defhigh);
-#endif // TRACE
-
- /*********************************************************************/
- /* Write the index values on the index file. */
- /*********************************************************************/
- n[0] = ID; // To check validity
- n[1] = Nk; // The number of indexed columns
- n[2] = nof; // The offset array size or 0
- n[3] = Num_K; // The index size
- n[4] = Incr; // Increment of record positions
- n[5] = Nblk; n[6] = Sblk;
-
-#if defined(TRACE)
- printf("Saving index %s\n", Xdp->GetName());
- printf("ID=%d Nk=%d nof=%d Num_K=%d Incr=%d Nblk=%d Sblk=%d\n",
- ID, Nk, nof, Num_K, Incr, Nblk, Sblk);
-#endif // TRACE
-
- Size = X->Write(g, n, NZ, sizeof(int), rc);
- dup->ProgCur = 1;
-
- if (Mul) // Write the offset array
- Size += X->Write(g, Pof, nof, sizeof(int), rc);
-
- dup->ProgCur = 5;
-
- if (!Incr) // Write the record position array(s)
- Size += X->Write(g, To_Rec, Num_K, sizeof(int), rc);
-
- dup->ProgCur = 15;
-
- for (; kcp; kcp = kcp->Next) {
- n[0] = kcp->Ndf; // Number of distinct sub-values
- n[1] = (kcp->Kof) ? kcp->Ndf + 1 : 0; // 0 if unique
- n[2] = (kcp == To_KeyCol) ? Nblk : 0;
- n[3] = kcp->Klen; // To be checked later
- n[4] = kcp->Type; // To be checked later
-
- Size += X->Write(g, n, NW, sizeof(int), rc);
- dup->ProgCur += 1;
-
- if (n[2])
- Size += X->Write(g, kcp->To_Bkeys, Nblk, kcp->Klen, rc);
-
- dup->ProgCur += 5;
-
- Size += X->Write(g, kcp->To_Keys, n[0], kcp->Klen, rc);
- dup->ProgCur += 5;
-
- if (n[1])
- Size += X->Write(g, kcp->Kof, n[1], sizeof(int), rc);
-
- dup->ProgCur += 5;
- } // endfor kcp
-
-#if defined(TRACE)
- printf("Index %s saved, Size=%d\n", Xdp->GetName(), Size);
-#endif // TRACE
-
- end:
- X->Close();
- return rc;
- } // end of SaveIndex
-
-#if !defined(XMAP)
-/***********************************************************************/
-/* Init: Open and Initialize a Key Index. */
-/***********************************************************************/
-bool XINDEX::Init(PGLOBAL g)
- {
- /*********************************************************************/
- /* Table will be accessed through an index table. */
- /* If sorting is required, this will be done later. */
- /*********************************************************************/
- char *ftype;
- char fn[_MAX_PATH];
- int k, n, nv[NZ];
- bool estim = false;
- PCOL colp;
- PXCOL prev = NULL, kcp = NULL;
- PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
-
- /*********************************************************************/
- /* Get the estimated table size. */
- /* Note: for fixed tables we must use cardinality to avoid the call */
- /* to MaxBlkSize that could reduce the cardinality value. */
- /*********************************************************************/
- if (Tdbp->Cardinality(NULL)) {
- // For DBF tables, Cardinality includes bad or soft deleted lines
- // that are not included in the index, and can be larger then the
- // index size.
- estim = (Tdbp->Ftype == RECFM_DBF);
- n = Tdbp->Cardinality(g); // n is exact table size
- } else {
- // Variable table not optimized
- estim = true; // n is an estimate of the size
- n = Tdbp->GetMaxSize(g);
- } // endif Cardinality
-
- if (n <= 0)
- return !(n == 0); // n < 0 error, n = 0 void table
-
- /*********************************************************************/
- /* Get the first key column. */
- /*********************************************************************/
- if (!Nk || !To_Cols || (!To_Vals && Op != OP_FIRST && Op != OP_FSTDIF)) {
- strcpy(g->Message, MSG(NO_KEY_COL));
- return true; // Error
- } else
- colp = To_Cols[0];
-
- switch (Tdbp->Ftype) {
- case RECFM_VAR: ftype = ".dnx"; break;
- case RECFM_FIX: ftype = ".fnx"; break;
- case RECFM_BIN: ftype = ".bnx"; break;
- case RECFM_VCT: ftype = ".vnx"; break;
- case RECFM_DBF: ftype = ".dbx"; break;
- default:
- sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
- return true;
- } // endswitch Ftype
-
- if (defp->SepIndex()) {
- // Index was saved in a separate file
-#if !defined(UNIX)
- char drive[_MAX_DRIVE];
-#else
- char *drive = NULL;
-#endif
- char direc[_MAX_DIR];
- char fname[_MAX_FNAME];
-
- _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
- strcat(strcat(fname, "_"), Xdp->GetName());
- _makepath(fn, drive, direc, fname, ftype);
- } else
- strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
-
- PlugSetPath(fn, fn, Tdbp->GetPath());
-
-#if defined(TRACE)
- printf("Index %s file: %s\n", Xdp->GetName(), fn);
-#endif // TRACE
-
- /*********************************************************************/
- /* Open the index file and check its validity. */
- /*********************************************************************/
- if (X->Open(g, fn, MODE_READ))
- goto err; // No saved values
-
- // Get offset from XDB file
- if (X->Seek(g, Defoff, Defhigh, SEEK_SET))
- goto err;
-
- // Now start the reading process.
- if (X->Read(g, nv, NZ, sizeof(int)))
- goto err;
-
-#if defined(TRACE)
- printf("nv=%d %d %d %d %d %d %d\n",
- nv[0], nv[1], nv[2], nv[3], nv[4], nv[5], nv[6]);
-#endif // TRACE
-
- // The test on ID was suppressed because MariaDB can change an index ID
- // when other indexes are added or deleted
- if (/*nv[0] != ID ||*/ nv[1] != Nk) {
- sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
-#if defined(TRACE)
- printf("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
-#endif // TRACE
- goto err;
- } // endif
-
- if (nv[2]) {
- Mul = true;
- Ndif = nv[2];
-
- // Allocate the storage that will contain the offset array
- Offset.Size = Ndif * sizeof(int);
-
- if (!PlgDBalloc(g, NULL, Offset)) {
- sprintf(g->Message, MSG(MEM_ALLOC_ERR), "offset", Ndif);
- goto err;
- } // endif
-
- if (X->Read(g, Pof, Ndif, sizeof(int)))
- goto err;
-
- Ndif--; // nv[2] is offset size, equal to Ndif + 1
- } else {
- Mul = false;
- Ndif = nv[3];
- } // endif nv[2]
-
- if (nv[3] < n && estim)
- n = nv[3]; // n was just an evaluated max value
-
- if (nv[3] != n) {
- sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
- goto err;
- } // endif
-
- Num_K = nv[3];
- Incr = nv[4];
- Nblk = nv[5];
- Sblk = nv[6];
-
- if (!Incr) {
- /*******************************************************************/
- /* Allocate the storage that will contain the file positions. */
- /*******************************************************************/
- Record.Size = Num_K * sizeof(int);
-
- if (!PlgDBalloc(g, NULL, Record)) {
- sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", Num_K);
- goto err;
- } // endif
-
- if (X->Read(g, To_Rec, Num_K, sizeof(int)))
- goto err;
-
- } else
- Srtd = true; // Sorted positions can be calculated
-
- /*********************************************************************/
- /* Allocate the KXYCOL blocks used to store column values. */
- /*********************************************************************/
- for (k = 0; k < Nk; k++) {
- if (k == Nval)
- To_LastVal = prev;
-
- if (X->Read(g, nv, NW, sizeof(int)))
- goto err;
-
- colp = To_Cols[k];
-
- if (nv[4] != colp->GetResultType() || !colp->GetValue() ||
- (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
- sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
- goto err; // Error
- } // endif GetKey
-
- kcp = new(g) KXYCOL(this);
-
- if (kcp->Init(g, colp, nv[0], true, (int)nv[3]))
- goto err; // Error
-
- /*******************************************************************/
- /* Read the index values from the index file. */
- /*******************************************************************/
- if (k == 0 && Nblk) {
- if (kcp->MakeBlockArray(g, Nblk, 0))
- goto err;
-
- // Read block values
- if (X->Read(g, kcp->To_Bkeys, Nblk, kcp->Klen))
- goto err;
-
- } // endif Nblk
-
- // Read the entire (small) index
- if (X->Read(g, kcp->To_Keys, nv[0], kcp->Klen))
- goto err;
-
- if (nv[1]) {
- if (!kcp->MakeOffset(g, nv[1] - 1))
- goto err;
-
- // Read the offset array
- if (X->Read(g, kcp->Kof, nv[1], sizeof(int)))
- goto err;
-
- } // endif n[1]
-
- if (!kcp->Prefix)
- // Indicate that the key column value can be found from KXYCOL
- colp->SetKcol(kcp);
-
- if (prev) {
- kcp->Previous = prev;
- prev->Next = kcp;
- } else
- To_KeyCol = kcp;
-
- prev = kcp;
- } // endfor k
-
- To_LastCol = prev;
-
- if (Mul && prev) {
- // Last key offset is the index offset
- kcp->Koff = Offset;
- kcp->Koff.Sub = true;
- } // endif Mul
-
- X->Close();
-
- /*********************************************************************/
- /* No valid record read yet for secondary file. */
- /*********************************************************************/
- Cur_K = Num_K;
- return false;
-
-err:
- Close();
- return true;
- } // end of Init
-
-#else // XMAP
-/***********************************************************************/
-/* Init: Open and Initialize a Key Index. */
-/***********************************************************************/
-bool XINDEX::Init(PGLOBAL g)
- {
- /*********************************************************************/
- /* Table will be accessed through an index table. */
- /* If sorting is required, this will be done later. */
- /*********************************************************************/
- const char *ftype;
- BYTE *mbase;
- char fn[_MAX_PATH];
- int *nv, k, n;
- bool estim;
- PCOL colp;
- PXCOL prev = NULL, kcp = NULL;
- PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
- PDBUSER dup = PlgGetUser(g);
-
- /*********************************************************************/
- /* Get the estimated table size. */
- /* Note: for fixed tables we must use cardinality to avoid the call */
- /* to MaxBlkSize that could reduce the cardinality value. */
- /*********************************************************************/
- if (Tdbp->Cardinality(NULL)) {
- // For DBF tables, Cardinality includes bad or soft deleted lines
- // that are not included in the index, and can be larger then the
- // index size.
- estim = (Tdbp->Ftype == RECFM_DBF);
- n = Tdbp->Cardinality(g); // n is exact table size
- } else {
- // Variable table not optimized
- estim = true; // n is an estimate of the size
- n = Tdbp->GetMaxSize(g);
- } // endif Cardinality
-
- if (n <= 0)
- return !(n == 0); // n < 0 error, n = 0 void table
-
- /*********************************************************************/
- /* Get the first key column. */
- /*********************************************************************/
- if (!Nk || !To_Cols || (!To_Vals && Op != OP_FIRST && Op != OP_FSTDIF)) {
- strcpy(g->Message, MSG(NO_KEY_COL));
- return true; // Error
- } else
- colp = To_Cols[0];
-
- switch (Tdbp->Ftype) {
- case RECFM_VAR: ftype = ".dnx"; break;
- case RECFM_FIX: ftype = ".fnx"; break;
- case RECFM_BIN: ftype = ".bnx"; break;
- case RECFM_VCT: ftype = ".vnx"; break;
- case RECFM_DBF: ftype = ".dbx"; break;
- default:
- sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
- return true;
- } // endswitch Ftype
-
- if (defp->SepIndex()) {
- // Index was save in a separate file
-#if !defined(UNIX)
- char drive[_MAX_DRIVE];
-#else
- char *drive = NULL;
-#endif
- char direc[_MAX_DIR];
- char fname[_MAX_FNAME];
-
- _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
- strcat(strcat(fname, "_"), Xdp->GetName());
- _makepath(fn, drive, direc, fname, ftype);
- } else
- strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
-
- PlugSetPath(fn, fn, Tdbp->GetPath());
-
-#if defined(TRACE)
- printf("Index %s file: %s\n", Xdp->GetName(), fn);
-#endif // TRACE
-
- /*********************************************************************/
- /* Get a view on the part of the index file containing this index. */
- /*********************************************************************/
- if (!(mbase = (BYTE*)X->FileView(g, fn, Defoff, Defhigh, Size)))
- goto err;
-
- // Now start the mapping process.
- nv = (int*)mbase;
- mbase += NZ * sizeof(int);
-
-#if defined(TRACE)
- printf("nv=%d %d %d %d %d %d %d\n",
- nv[0], nv[1], nv[2], nv[3], nv[4], nv[5], nv[6]);
-#endif // TRACE
-
- // The test on ID was suppressed because MariaDB can change an index ID
- // when other indexes are added or deleted
- if (/*nv[0] != ID ||*/ nv[1] != Nk) {
- // Not this index
- sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
-#if defined(TRACE)
- printf("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
-#endif // TRACE
- goto err;
- } // endif nv
-
- if (nv[2]) {
- // Set the offset array memory block
- Offset.Memp = mbase;
- Offset.Size = nv[2] * sizeof(int);
- Offset.Sub = true;
- Mul = true;
- Ndif = nv[2] - 1;
- mbase += Offset.Size;
- } else {
- Mul = false;
- Ndif = nv[3];
- } // endif nv[2]
-
- if (nv[3] < n && estim)
- n = nv[3]; // n was just an evaluated max value
-
- if (nv[3] != n) {
- sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
- goto err;
- } // endif
-
- Num_K = nv[3];
- Incr = nv[4];
- Nblk = nv[5];
- Sblk = nv[6];
-
- if (!Incr) {
- /*******************************************************************/
- /* Point to the storage that contains the file positions. */
- /*******************************************************************/
- Record.Size = Num_K * sizeof(int);
- Record.Memp = mbase;
- Record.Sub = true;
- mbase += Record.Size;
- } else
- Srtd = true; // Sorted positions can be calculated
-
- /*********************************************************************/
- /* Allocate the KXYCOL blocks used to store column values. */
- /*********************************************************************/
- for (k = 0; k < Nk; k++) {
- if (k == Nval)
- To_LastVal = prev;
-
- nv = (int*)mbase;
- mbase += (NW * sizeof(int));
-
- colp = To_Cols[k];
-
- if (nv[4] != colp->GetResultType() || !colp->GetValue() ||
- (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
- sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
- goto err; // Error
- } // endif GetKey
-
- kcp = new(g) KXYCOL(this);
-
- if (!(mbase = kcp->MapInit(g, colp, nv, mbase)))
- goto err;
-
- if (!kcp->Prefix)
- // Indicate that the key column value can be found from KXYCOL
- colp->SetKcol(kcp);
-
- if (prev) {
- kcp->Previous = prev;
- prev->Next = kcp;
- } else
- To_KeyCol = kcp;
-
- prev = kcp;
- } // endfor k
-
- To_LastCol = prev;
-
- if (Mul && prev)
- // Last key offset is the index offset
- kcp->Koff = Offset;
-
- /*********************************************************************/
- /* No valid record read yet for secondary file. */
- /*********************************************************************/
- Cur_K = Num_K;
- return false;
-
-err:
- Close();
- return true;
- } // end of Init
-#endif // XMAP
-
-/***********************************************************************/
-/* Get Ndif and Num_K from the index file. */
-/***********************************************************************/
-bool XINDEX::GetAllSizes(PGLOBAL g, int &ndif, int &numk)
- {
- char *ftype;
- char fn[_MAX_PATH];
- int n, nv[NZ];
- bool estim = false;
- PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
-
- ndif = numk = 0;
-
- /*********************************************************************/
- /* Get the estimated table size. */
- /* Note: for fixed tables we must use cardinality to avoid the call */
- /* to MaxBlkSize that could reduce the cardinality value. */
- /*********************************************************************/
- if (Tdbp->Cardinality(NULL)) {
- // For DBF tables, Cardinality includes bad or soft deleted lines
- // that are not included in the index, and can be larger then the
- // index size.
- estim = (Tdbp->Ftype == RECFM_DBF);
- n = Tdbp->Cardinality(g); // n is exact table size
- } else {
- // Variable table not optimized
- estim = true; // n is an estimate of the size
- n = Tdbp->GetMaxSize(g);
- } // endif Cardinality
-
- if (n <= 0)
- return !(n == 0); // n < 0 error, n = 0 void table
-
- /*********************************************************************/
- /* Check the key part number. */
- /*********************************************************************/
- if (!Nk) {
- strcpy(g->Message, MSG(NO_KEY_COL));
- return true; // Error
- } // endif Nk
-
- switch (Tdbp->Ftype) {
- case RECFM_VAR: ftype = ".dnx"; break;
- case RECFM_FIX: ftype = ".fnx"; break;
- case RECFM_BIN: ftype = ".bnx"; break;
- case RECFM_VCT: ftype = ".vnx"; break;
- case RECFM_DBF: ftype = ".dbx"; break;
- default:
- sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
- return true;
- } // endswitch Ftype
-
- if (defp->SepIndex()) {
- // Index was saved in a separate file
-#if !defined(UNIX)
- char drive[_MAX_DRIVE];
-#else
- char *drive = NULL;
-#endif
- char direc[_MAX_DIR];
- char fname[_MAX_FNAME];
-
- _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
- strcat(strcat(fname, "_"), Xdp->GetName());
- _makepath(fn, drive, direc, fname, ftype);
- } else
- strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
-
- PlugSetPath(fn, fn, Tdbp->GetPath());
-
-#if defined(TRACE)
- printf("Index %s file: %s\n", Xdp->GetName(), fn);
-#endif // TRACE
-
- /*********************************************************************/
- /* Open the index file and check its validity. */
- /*********************************************************************/
- if (X->Open(g, fn, MODE_READ))
- goto err; // No saved values
-
- // Get offset from XDB file
- if (X->Seek(g, Defoff, Defhigh, SEEK_SET))
- goto err;
-
- // Now start the reading process.
- if (X->Read(g, nv, NZ, sizeof(int)))
- goto err;
-
-#if defined(TRACE)
- printf("nv=%d %d %d %d\n", nv[0], nv[1], nv[2], nv[3]);
-#endif // TRACE
-
- // The test on ID was suppressed because MariaDB can change an index ID
- // when other indexes are added or deleted
- if (/*nv[0] != ID ||*/ nv[1] != Nk) {
- sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
-#if defined(TRACE)
- printf("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
-#endif // TRACE
- goto err;
- } // endif
-
- if (nv[2]) {
- Mul = true;
- Ndif = nv[2] - 1; // nv[2] is offset size, equal to Ndif + 1
- } else {
- Mul = false;
- Ndif = nv[3];
- } // endif nv[2]
-
- if (nv[3] < n && estim)
- n = nv[3]; // n was just an evaluated max value
-
- if (nv[3] != n) {
- sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
- goto err;
- } // endif
-
- Num_K = nv[3];
-
- if (Nk > 1) {
- if (nv[2] && X->Seek(g, nv[2] * sizeof(int), 0, SEEK_CUR))
- goto err;
-
- if (!nv[4] && X->Seek(g, Num_K * sizeof(int), 0, SEEK_CUR))
- goto err;
-
- if (X->Read(g, nv, NW, sizeof(int)))
- goto err;
-
- PCOL colp = *To_Cols;
-
- if (nv[4] != colp->GetResultType() ||
- (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
- sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
- goto err; // Error
- } // endif GetKey
-
- Ndif = nv[0];
- } // endif Nk
-
- /*********************************************************************/
- /* Set size values. */
- /*********************************************************************/
- ndif = Ndif;
- numk = Num_K;
- return false;
-
-err:
- X->Close();
- return true;
- } // end of GetAllSizes
-
-/***********************************************************************/
-/* RANGE: Tell how many records exist for a given value, for an array */
-/* of values, or in a given value range. */
-/***********************************************************************/
-int XINDEX::Range(PGLOBAL g, int limit, bool incl)
- {
- int i, k, n = 0;
- PXOB *xp = To_Vals;
- PXCOL kp = To_KeyCol;
- OPVAL op = Op;
-
- switch (limit) {
- case 1: Op = (incl) ? OP_GE : OP_GT; break;
- case 2: Op = (incl) ? OP_GT : OP_GE; break;
- default: return 0;
- } // endswitch limit
-
- /*********************************************************************/
- /* Currently only range of constant values with an EQ operator is */
- /* implemented. Find the number of rows for each given values. */
- /*********************************************************************/
- if (xp[0]->GetType() == TYPE_CONST) {
- for (i = 0; kp; kp = kp->Next) {
- kp->Valp->SetValue_pval(xp[i]->GetValue(), !kp->Prefix);
- if (++i == Nval) break;
- } // endfor kp
-
- if ((k = FastFind(Nval)) < Num_K)
- n = k;
-// if (limit)
-// n = (Mul) ? k : kp->Val_K;
-// else
-// n = (Mul) ? Pof[kp->Val_K + 1] - k : 1;
-
- } else {
- strcpy(g->Message, MSG(RANGE_NO_JOIN));
- n = -1; // Logical error
- } // endif'f Type
-
- Op = op;
- return n;
- } // end of Range
-
-/***********************************************************************/
-/* Return the size of the group (equal values) of the current value. */
-/***********************************************************************/
-int XINDEX::GroupSize(void)
- {
-#if defined(_DEBUG)
- assert(To_LastCol->Val_K >= 0 && To_LastCol->Val_K < Ndif);
-#endif // _DEBUG
-
- if (Nval == Nk)
- return (Pof) ? Pof[To_LastCol->Val_K + 1] - Pof[To_LastCol->Val_K]
- : 1;
-
-#if defined(_DEBUG)
- assert(To_LastVal);
-#endif // _DEBUG
-
- // Index whose only some columns are used
- int ck1, ck2;
-
- ck1 = To_LastVal->Val_K;
- ck2 = ck1 + 1;
-
-#if defined(_DEBUG)
- assert(ck1 >= 0 && ck1 < To_LastVal->Ndf);
-#endif // _DEBUG
-
- for (PXCOL kcp = To_LastVal; kcp; kcp = kcp->Next) {
- ck1 = (kcp->Kof) ? kcp->Kof[ck1] : ck1;
- ck2 = (kcp->Kof) ? kcp->Kof[ck2] : ck2;
- } // endfor kcp
-
- return ck2 - ck1;
- } // end of GroupSize
-
-/***********************************************************************/
-/* Find Cur_K and Val_K's of the next distinct value of the index. */
-/* Returns false if Ok, true if there are no more different values. */
-/***********************************************************************/
-bool XINDEX::NextValDif(void)
- {
- int curk;
- PXCOL kcp = (To_LastVal) ? To_LastVal : To_LastCol;
-
- if (++kcp->Val_K < kcp->Ndf) {
- Cur_K = curk = kcp->Val_K;
-
- // (Cur_K return is currently not used by SQLGBX)
- for (PXCOL kp = kcp; kp; kp = kp->Next)
- Cur_K = (kp->Kof) ? kp->Kof[Cur_K] : Cur_K;
-
- } else
- return true;
-
- for (kcp = kcp->Previous; kcp; kcp = kcp->Previous) {
- if (kcp->Kof && curk < kcp->Kof[kcp->Val_K + 1])
- break; // all previous columns have same value
-
- curk = ++kcp->Val_K; // This is a break, get new column value
- } // endfor kcp
-
- return false;
- } // end of NextValDif
-
-/***********************************************************************/
-/* XINDEX: Find Cur_K and Val_K's of next index entry. */
-/* If eq is true next values must be equal to last ones up to Nval. */
-/* Returns false if Ok, true if there are no more (equal) values. */
-/***********************************************************************/
-bool XINDEX::NextVal(bool eq)
- {
- int n, neq = Nk + 1, curk;
- PXCOL kcp;
-
- if (Cur_K == Num_K)
- return true;
- else
- curk = ++Cur_K;
-
- for (n = Nk, kcp = To_LastCol; kcp; n--, kcp = kcp->Previous) {
- if (kcp->Kof) {
- if (curk == kcp->Kof[kcp->Val_K + 1])
- neq = n;
-
- } else {
-#ifdef _DEBUG
- assert(curk == kcp->Val_K + 1);
-#endif // _DEBUG
- neq = n;
- } // endif Kof
-
-#ifdef _DEBUG
- assert(kcp->Val_K < kcp->Ndf);
-#endif // _DEBUG
-
- // If this is not a break...
- if (neq > n)
- break; // all previous columns have same value
-
- curk = ++kcp->Val_K; // This is a break, get new column value
- } // endfor kcp
-
- // Return true if no more values or, in case of "equal" values,
- // if the last used column value has changed
- return (Cur_K == Num_K || (eq && neq <= Nval));
- } // end of NextVal
-
-/***********************************************************************/
-/* XINDEX: Fetch a physical or logical record. */
-/***********************************************************************/
-int XINDEX::Fetch(PGLOBAL g)
- {
- int n;
- PXCOL kp;
-
- if (Num_K == 0)
- return -1; // means end of file
-
- /*********************************************************************/
- /* Table read through a sorted index. */
- /*********************************************************************/
- switch (Op) {
- case OP_NEXT: // Read next
- if (NextVal(false))
- return -1; // End of indexed file
-
- break;
- case OP_FIRST: // Read first
- for (Cur_K = 0, kp = To_KeyCol; kp; kp = kp->Next)
- kp->Val_K = 0;
-
- Op = OP_NEXT;
- break;
- case OP_SAME: // Read next same
- // Logically the key values should be the same as before
-#if defined(TRACE)
- printf("looking for next same value\n");
-#endif // TRACE
-
- if (NextVal(true)) {
- Op = OP_EQ;
- return -2; // no more equal values
- } // endif NextVal
-
- break;
- case OP_NXTDIF: // Read next dif
-// while (!NextVal(true)) ;
-
-// if (Cur_K >= Num_K)
-// return -1; // End of indexed file
- if (NextValDif())
- return -1; // End of indexed file
-
- break;
- case OP_FSTDIF: // Read first diff
- for (Cur_K = 0, kp = To_KeyCol; kp; kp = kp->Next)
- kp->Val_K = 0;
-
- Op = (Mul || Nval < Nk) ? OP_NXTDIF : OP_NEXT;
- break;
- default: // Should be OP_EQ
-// if (Tbxp->Key_Rank < 0) {
- /***************************************************************/
- /* Look for the first key equal to the link column values */
- /* and return its rank whithin the index table. */
- /***************************************************************/
- for (n = 0, kp = To_KeyCol; n < Nval && kp; n++, kp = kp->Next)
- if (kp->InitFind(g, To_Vals[n]))
- return -1; // No more constant values
-
- Nth++;
-
-#if defined(TRACE)
- printf("Fetch: Looking for new value\n");
-#endif // TRACE
- Cur_K = FastFind(Nval);
-
- if (Cur_K >= Num_K)
- /*************************************************************/
- /* Rank not whithin index table, signal record not found. */
- /*************************************************************/
- return -2;
-
- else if (Mul || Nval < Nk)
- Op = OP_SAME;
-
- } // endswitch Op
-
- /*********************************************************************/
- /* If rank is equal to stored rank, record is already there. */
- /*********************************************************************/
- if (Cur_K == Old_K)
- return -3; // Means record already there
- else
- Old_K = Cur_K; // Store rank of newly read record
-
- /*********************************************************************/
- /* Return the position of the required record. */
- /*********************************************************************/
- return (Incr) ? Cur_K * Incr : To_Rec[Cur_K];
- } // end of Fetch
-
-/***********************************************************************/
-/* FastFind: Returns the index of matching record in a join using an */
-/* optimized algorithm based on dichotomie and optimized comparing. */
-/***********************************************************************/
-int XINDEX::FastFind(int nv)
- {
- register int curk, sup, inf, i= 0, k, n = 2;
- register PXCOL kp, kcp;
-
- assert((int)nv == Nval);
-
- if (Nblk && Op == OP_EQ) {
- // Look in block values to find in which block to search
- sup = Nblk;
- inf = -1;
-
- while (n && sup - inf > 1) {
- i = (inf + sup) >> 1;
-
- n = To_KeyCol->CompBval(i);
-
- if (n < 0)
- sup = i;
- else
- inf = i;
-
- } // endwhile
-
- if (inf < 0)
- return Num_K;
-
-// i = inf;
- inf *= Sblk;
-
- if ((sup = inf + Sblk) > To_KeyCol->Ndf)
- sup = To_KeyCol->Ndf;
-
- inf--;
- } else {
- inf = -1;
- sup = To_KeyCol->Ndf;
- } // endif Nblk
-
- for (k = 0, kcp = To_KeyCol; kcp; kcp = kcp->Next) {
- while (sup - inf > 1) {
- i = (inf + sup) >> 1;
-
- n = kcp->CompVal(i);
-
- if (n < 0)
- sup = i;
- else if (n > 0)
- inf = i;
- else
- break;
-
- } // endwhile
-
- if (n) {
- if (Op != OP_EQ) {
- // Currently only OP_GT or OP_GE
- kcp->Val_K = curk = sup;
-
- // Check for value changes in previous key parts
- for (kp = kcp->Previous; kp; kp = kp->Previous)
- if (kp->Kof && curk < kp->Kof[kp->Val_K + 1])
- break;
- else
- curk = ++kp->Val_K;
-
- n = 0;
- } // endif Op
-
- break;
- } // endif n
-
- kcp->Val_K = i;
-
- if (++k == Nval) {
- if (Op == OP_GT) { // n is always 0
- curk = ++kcp->Val_K; // Increment value by 1
-
- // Check for value changes in previous key parts
- for (kp = kcp->Previous; kp; kp = kp->Previous)
- if (kp->Kof && curk < kp->Kof[kp->Val_K + 1])
- break; // Not changed
- else
- curk = ++kp->Val_K;
-
- } // endif Op
-
- break; // So kcp remains pointing the last tested block
- } // endif k
-
- if (kcp->Kof) {
- inf = kcp->Kof[i] - 1;
- sup = kcp->Kof[i + 1];
- } else {
- inf = i - 1;
- sup = i + 1;
- } // endif Kof
-
- } // endfor k, kcp
-
- if (n) {
- // Record not found
- for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
- kcp->Val_K = kcp->Ndf; // Not a valid value
-
- return Num_K;
- } // endif n
-
- for (curk = kcp->Val_K; kcp; kcp = kcp->Next) {
- kcp->Val_K = curk;
- curk = (kcp->Kof) ? kcp->Kof[kcp->Val_K] : kcp->Val_K;
- } // endfor kcp
-
- return curk;
- } // end of FastFind
-
-/* -------------------------- XINDXS Class --------------------------- */
-
-/***********************************************************************/
-/* XINDXS public constructor. */
-/***********************************************************************/
-XINDXS::XINDXS(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp)
- : XINDEX(tdbp, xdp, pxp, cp, xp)
- {
- Srtd = To_Cols[0]->GetOpt() < 0; // ?????
- } // end of XINDXS constructor
-
-/***********************************************************************/
-/* XINDXS compare routine for C Quick/Insertion sort. */
-/***********************************************************************/
-int XINDXS::Qcompare(int *i1, int *i2)
- {
-#ifdef DEBTRACE
- num_comp++;
-#endif
-
- return To_KeyCol->Compare(*i1, *i2);
- } // end of Qcompare
-
-/***********************************************************************/
-/* Range: Tell how many records exist for given value(s): */
-/* If limit=0 return range for these values. */
-/* If limit=1 return the start of range. */
-/* If limit=2 return the end of range. */
-/***********************************************************************/
-int XINDXS::Range(PGLOBAL g, int limit, bool incl)
- {
- int k, n = 0;
- PXOB xp = To_Vals[0];
- PXCOL kp = To_KeyCol;
- OPVAL op = Op;
-
- switch (limit) {
- case 1: Op = (incl) ? OP_GE : OP_GT; break;
- case 2: Op = (incl) ? OP_GT : OP_GE; break;
- default: Op = OP_EQ;
- } // endswitch limit
-
- /*********************************************************************/
- /* Currently only range of constant values with an EQ operator is */
- /* implemented. Find the number of rows for each given values. */
- /*********************************************************************/
- if (xp->GetType() == TYPE_CONST) {
- kp->Valp->SetValue_pval(xp->GetValue(), !kp->Prefix);
-
- if ((k = FastFind(Nval)) < Num_K)
- if (limit)
- n = (Mul) ? k : kp->Val_K;
- else
- n = (Mul) ? Pof[kp->Val_K + 1] - k : 1;
-
- } else {
- strcpy(g->Message, MSG(RANGE_NO_JOIN));
- n = -1; // Logical error
- } // endif'f Type
-
- Op = op;
- return n;
- } // end of Range
-
-/***********************************************************************/
-/* Return the size of the group (equal values) of the current value. */
-/***********************************************************************/
-int XINDXS::GroupSize(void)
- {
-#if defined(_DEBUG)
- assert(To_KeyCol->Val_K >= 0 && To_KeyCol->Val_K < Ndif);
-#endif // _DEBUG
- return (Pof) ? Pof[To_KeyCol->Val_K + 1] - Pof[To_KeyCol->Val_K]
- : 1;
- } // end of GroupSize
-
-/***********************************************************************/
-/* XINDXS: Find Cur_K and Val_K of next index value. */
-/* If b is true next value must be equal to last one. */
-/* Returns false if Ok, true if there are no more (equal) values. */
-/***********************************************************************/
-bool XINDXS::NextVal(bool eq)
- {
- bool rc;
-
- if (To_KeyCol->Val_K == Ndif)
- return true;
-
- if (Mul) {
- int limit = Pof[To_KeyCol->Val_K + 1];
-
-#ifdef _DEBUG
- assert(Cur_K < limit);
- assert(To_KeyCol->Val_K < Ndif);
-#endif // _DEBUG
-
- if (++Cur_K == limit) {
- To_KeyCol->Val_K++;
- rc = (eq || limit == Num_K);
- } else
- rc = false;
-
- } else
- rc = (To_KeyCol->Val_K = ++Cur_K) == Num_K || eq;
-
- return rc;
- } // end of NextVal
-
-/***********************************************************************/
-/* XINDXS: Fetch a physical or logical record. */
-/***********************************************************************/
-int XINDXS::Fetch(PGLOBAL g)
- {
- if (Num_K == 0)
- return -1; // means end of file
-
- /*********************************************************************/
- /* Table read through a sorted index. */
- /*********************************************************************/
- switch (Op) {
- case OP_NEXT: // Read next
- if (NextVal(false))
- return -1; // End of indexed file
-
- break;
- case OP_FIRST: // Read first
- To_KeyCol->Val_K = Cur_K = 0;
- Op = OP_NEXT;
- break;
- case OP_SAME: // Read next same
-#if defined(TRACE)
-// printf("looking for next same value\n");
-#endif // TRACE
-
- if (!Mul || NextVal(true)) {
- Op = OP_EQ;
- return -2; // No more equal values
- } // endif Mul
-
- break;
- case OP_NXTDIF: // Read next dif
- if (++To_KeyCol->Val_K == Ndif)
- return -1; // End of indexed file
-
- Cur_K = Pof[To_KeyCol->Val_K];
- break;
- case OP_FSTDIF: // Read first diff
- To_KeyCol->Val_K = Cur_K = 0;
- Op = (Mul) ? OP_NXTDIF : OP_NEXT;
- break;
- default: // Should OP_EQ
- /*****************************************************************/
- /* Look for the first key equal to the link column values */
- /* and return its rank whithin the index table. */
- /*****************************************************************/
- if (To_KeyCol->InitFind(g, To_Vals[0]))
- return -1; // No more constant values
- else
- Nth++;
-
-#if defined(TRACE)
- printf("Fetch: Looking for new value\n");
-#endif // TRACE
-
- Cur_K = FastFind(1);
-
- if (Cur_K >= Num_K)
- // Rank not whithin index table, signal record not found
- return -2;
- else if (Mul)
- Op = OP_SAME;
-
- } // endswitch Op
-
- /*********************************************************************/
- /* If rank is equal to stored rank, record is already there. */
- /*********************************************************************/
- if (Cur_K == Old_K)
- return -3; // Means record already there
- else
- Old_K = Cur_K; // Store rank of newly read record
-
- /*********************************************************************/
- /* Return the position of the required record. */
- /*********************************************************************/
- return (Incr) ? Cur_K * Incr : To_Rec[Cur_K];
- } // end of Fetch
-
-/***********************************************************************/
-/* FastFind: Returns the index of matching indexed record using an */
-/* optimized algorithm based on dichotomie and optimized comparing. */
-/***********************************************************************/
-int XINDXS::FastFind(int nk)
- {
- register int sup, inf, i= 0, n = 2;
- register PXCOL kcp = To_KeyCol;
-
- if (Nblk && Op == OP_EQ) {
- // Look in block values to find in which block to search
- sup = Nblk;
- inf = -1;
-
- while (n && sup - inf > 1) {
- i = (inf + sup) >> 1;
-
- n = kcp->CompBval(i);
-
- if (n < 0)
- sup = i;
- else
- inf = i;
-
- } // endwhile
-
- if (inf < 0)
- return Num_K;
-
-// i = inf;
- inf *= Sblk;
-
- if ((sup = inf + Sblk) > Ndif)
- sup = Ndif;
-
- inf--;
- } else {
- inf = -1;
- sup = Ndif;
- } // endif Nblk
-
- while (sup - inf > 1) {
- i = (inf + sup) >> 1;
-
- n = kcp->CompVal(i);
-
- if (n < 0)
- sup = i;
- else if (n > 0)
- inf = i;
- else
- break;
-
- } // endwhile
-
- if (!n && Op == OP_GT) {
- ++i;
- } else if (n && Op != OP_EQ) {
- // Currently only OP_GT or OP_GE
- i = sup;
- n = 0;
- } // endif sup
-
- kcp->Val_K = i; // Used by FillValue
- return ((n) ? Num_K : (Mul) ? Pof[i] : i);
- } // end of FastFind
-
-/* -------------------------- XLOAD Class --------------------------- */
-
-/***********************************************************************/
-/* XLOAD constructor. */
-/***********************************************************************/
-XLOAD::XLOAD(void)
- {
- Hfile = INVALID_HANDLE_VALUE;
-#if defined(WIN32) && defined(XMAP)
- ViewBase = NULL;
-#endif // WIN32 && XMAP
-} // end of XLOAD constructor
-
-/***********************************************************************/
-/* Close the index huge file. */
-/***********************************************************************/
-void XLOAD::Close(void)
- {
- if (Hfile != INVALID_HANDLE_VALUE) {
- CloseFileHandle(Hfile);
- Hfile = INVALID_HANDLE_VALUE;
- } // endif Hfile
-
-#if defined(WIN32) && defined(XMAP)
- if (ViewBase) {
- if (!UnmapViewOfFile(ViewBase))
- printf("Error %d closing Viewmap\n", GetLastError());
-
- ViewBase = NULL;
- } // endif ViewBase
-#endif // WIN32 && XMAP
-
- } // end of Close
-
-/* --------------------------- XFILE Class --------------------------- */
-
-/***********************************************************************/
-/* XFILE constructor. */
-/***********************************************************************/
-XFILE::XFILE(void) : XLOAD()
- {
- Xfile = NULL;
-#if defined(XMAP) && !defined(WIN32)
- Mmp = NULL;
-#endif // XMAP && !WIN32
- } // end of XFILE constructor
-
-/***********************************************************************/
-/* Xopen function: opens a file using native API's. */
-/***********************************************************************/
-bool XFILE::Open(PGLOBAL g, char *filename, MODE mode)
- {
- char *pmod;
-
- /*********************************************************************/
- /* Open the index file according to mode. */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ: pmod = "rb"; break;
- case MODE_WRITE: pmod = "wb"; break;
- case MODE_INSERT: pmod = "ab"; break;
- default:
- sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
- return true;
- } // endswitch mode
-
- if (!(Xfile= global_fopen(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, pmod))) {
-#if defined(TRACE)
- printf("Open: %s\n", g->Message);
-#endif // TRACE
- return true;
- } // endif Xfile
-
- if (mode == MODE_INSERT)
- /*******************************************************************/
- /* Position the cursor at end of file so ftell returns file size. */
- /*******************************************************************/
- if (fseek(Xfile, 0, SEEK_END)) {
- sprintf(g->Message, MSG(FUNC_ERRNO), "Xseek", errno);
- return true;
- } // endif
-
- return false;
- } // end of Open
-
-/***********************************************************************/
-/* Tell were we are in the index file. */
-/***********************************************************************/
-bool XFILE::GetOff(int& low, int& high, PIXDEF sxp)
- {
- if (sxp) {
- low = sxp->GetOffset() + sxp->GetSize();
- high = 0;
- } else
- low = high = 0;
-
- return false;
- } // end of GetOff
-
-/***********************************************************************/
-/* Tell were we are in a huge file. */
-/***********************************************************************/
-bool XFILE::Seek(PGLOBAL g, int low, int high, int origin)
- {
-#if defined(_DEBUG)
- assert(high == 0);
-#endif // !_DEBUG
-
- if (fseek(Xfile, low, origin)) {
- sprintf(g->Message, MSG(FUNC_ERRNO), "Xseek", errno);
- return true;
- } // endif
-
-//ftell(Xfile);
- return false;
- } // end of Seek
-
-/***********************************************************************/
-/* Read from the index file. */
-/***********************************************************************/
-bool XFILE::Read(PGLOBAL g, void *buf, int n, int size)
- {
- if (fread(buf, size, n, Xfile) != (size_t)n) {
- sprintf(g->Message, MSG(XFILE_READERR), errno);
- return true;
- } // endif size
-
- return false;
- } // end of Read
-
-/***********************************************************************/
-/* Write on index file, set rc and return the number of bytes written */
-/***********************************************************************/
-int XFILE::Write(PGLOBAL g, void *buf, int n, int size, bool& rc)
- {
- int niw = (int)fwrite(buf, size, n, Xfile);
-
- if (niw != n) {
- sprintf(g->Message, MSG(XFILE_WRITERR), strerror(errno));
- rc = true;
- } // endif size
-
- return niw * size;
- } // end of Write
-
-/***********************************************************************/
-/* Close the index huge file. */
-/***********************************************************************/
-void XFILE::Close(void)
- {
- XLOAD::Close();
-
- if (Xfile) {
- fclose(Xfile);
- Xfile = NULL;
- } // endif Xfile
-
-#if defined(XMAP) && !defined(WIN32)
- if (Mmp) {
- CloseMemMap(Mmp->memory, Mmp->lenL);
- Mmp = NULL;
- } // endif Mmp
-#endif // XMAP
- } // end of Close
-
-#if defined(XMAP)
-#if defined(WIN32)
-/***********************************************************************/
-/* Return a pointer to the segment at the given offset and size. */
-/***********************************************************************/
-void *XFILE::FileView(PGLOBAL g, char *fn, int loff, int hoff, int size)
- {
- SYSTEM_INFO SysInfo; // system information; used to get the granularity
- char *pData; // pointer to the data
- int iViewDelta; // the offset into the view where the data shows up
- HANDLE hMapFile; // handle for the file's memory-mapped region
- DWORD offset; // Where to start in the index file
- DWORD FileMapSize; // size of the file mapping
- DWORD FileMapStart; // where in the file to start the file map view
- DWORD Granularity; // system allocation granularity
- DWORD MapViewSize; // the size of the view
-
- if (hoff) {
- strcpy(g->Message, MSG(HI_OFFSET_ERR));
- return NULL;
- } // endf hoff
-
- // Open the file in mode read only
- Hfile = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- char buf[512];
- DWORD rc = GetLastError();
-
- sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_READ, fn);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- strcat(g->Message, buf);
- return NULL;
- } // endif Hfile
-
- // Get the system allocation granularity.
- GetSystemInfo(&SysInfo);
- Granularity = SysInfo.dwAllocationGranularity;
-
- // The offset is a 64 byte integer low part
- offset = loff;
-
- // To calculate where to start the file mapping, round down the
- // offset of the data into the file to the nearest multiple of the
- // system allocation granularity.
- FileMapStart = (offset / Granularity) * Granularity;
-
- // Calculate the size of the file mapping view.
- MapViewSize = offset % Granularity + (DWORD)size;
-
- // How large will the file-mapping object be?
- FileMapSize = offset + (DWORD)size;
-
- // The data of interest isn't at the beginning of the
- // view, so determine how far into the view to set the pointer.
- iViewDelta = (int)(offset - FileMapStart);
-
- // Check that the index file is more than large enough
- if (GetFileSize(Hfile, NULL) < FileMapSize) {
- strcpy(g->Message, MSG(XFILE_TOO_SMALL));
- return NULL;
- } // endif FileSize
-
- // Create a file-mapping object for the file.
- hMapFile = CreateFileMapping( Hfile, // current file handle
- NULL, // default security
- PAGE_READONLY, // permission
- 0, // size, high
- FileMapSize, // size, low
- NULL); // name
-
- if (hMapFile == NULL) {
- sprintf(g->Message, MSG(HANDLE_IS_NULL), "hMapFile", GetLastError() );
- return NULL;
- } // endif hMapFile
-
- // Map the view.
- ViewBase = MapViewOfFile(hMapFile, // handle to mapping object
- FILE_MAP_READ, // access mode
- 0, // high-order 32 bits of file offset
- FileMapStart, // low-order 32 bits of file offset
- MapViewSize); // number of bytes to map
-
- if (!ViewBase) {
- sprintf(g->Message, MSG(HANDLE_IS_NULL), "ViewBase", GetLastError());
- return NULL;
- } // endif ViewBase
-
- // Calculate the pointer to the data.
- pData = (char *)ViewBase + iViewDelta;
-
- // close the file-mapping object
- if (!CloseHandle(hMapFile))
- sprintf(g->Message, MSG(MAP_OBJ_ERR), GetLastError());
-
- // close the file itself
- if (!CloseHandle(Hfile))
- sprintf(g->Message, MSG(FILE_CLOSE_ERR), GetLastError());
- else
- Hfile = INVALID_HANDLE_VALUE;
-
- return pData;
- } // end of FileView
-#else // not WIN32
- /*********************************************************************/
- /* Map the entire index. */
- /*********************************************************************/
-void *XFILE::FileView(PGLOBAL g, char *fn, int loff, int hoff, int size)
- {
- HANDLE h;
-
- Mmp = (MMP)PlugSubAlloc(g, NULL, sizeof(MEMMAP));
- h = CreateFileMap(g, filename, Mmp, MODE_READ, false);
-
- if (h == INVALID_HANDLE_VALUE || (!Mmp->lenH && !Mmp->lenL)) {
- if (!(*g->Message))
- strcpy(g->Message, MSG(FILE_MAP_ERR));
-
- CloseFileHandle(h); // Not used anymore
- return NULL; // No saved values
- } // endif h
-
- CloseFileHandle(h); // Not used anymore
- return Mmp->memory;
- } // end of FileView
-#endif // not WIN32
-#endif // XMAP
-
-/* -------------------------- XHUGE Class --------------------------- */
-
-/***********************************************************************/
-/* Xopen function: opens a file using native API's. */
-/***********************************************************************/
-bool XHUGE::Open(PGLOBAL g, char *filename, MODE mode)
- {
- if (Hfile != INVALID_HANDLE_VALUE) {
- sprintf(g->Message, MSG(FILE_OPEN_YET), filename);
- return true;
- } // endif
-
-#if defined(TRACE)
- printf( "Xopen: filename=%s mode=%d\n", filename, mode);
-#endif // TRACE
-
-#if defined(WIN32)
- DWORD rc, access, share, creation;
-
- /*********************************************************************/
- /* Create the file object according to access mode */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- access = GENERIC_READ;
- share = FILE_SHARE_READ;
- creation = OPEN_EXISTING;
- break;
- case MODE_WRITE:
- access = GENERIC_WRITE;
- share = 0;
- creation = CREATE_ALWAYS;
- break;
- case MODE_INSERT:
- access = GENERIC_WRITE;
- share = 0;
- creation = OPEN_EXISTING;
- break;
- default:
- sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
- return true;
- } // endswitch
-
- Hfile = CreateFile(filename, access, share, NULL, creation,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- rc = GetLastError();
- sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
- (LPTSTR)filename, sizeof(filename), NULL);
- strcat(g->Message, filename);
- return true;
- } // endif Hfile
-
-#ifdef DEBTRACE
- fprintf(debug,
- " access=%p share=%p creation=%d handle=%p fn=%s\n",
- access, share, creation, Hfile, filename);
-#endif
-
- if (mode == MODE_INSERT) {
- /*******************************************************************/
- /* In Insert mode we must position the cursor at end of file. */
- /*******************************************************************/
- LONG high = 0;
- DWORD drc, rc = SetFilePointer(Hfile, 0, &high, FILE_END);
-
- if (rc == INVALID_SET_FILE_POINTER && (drc = GetLastError()) != NO_ERROR) {
- sprintf(g->Message, MSG(ERROR_IN_SFP), drc);
- CloseHandle(Hfile);
- Hfile = INVALID_HANDLE_VALUE;
- return true;
- } // endif
-
- } // endif Mode
-
-#else // UNIX
- int rc = 0;
- int oflag = O_LARGEFILE; // Enable file size > 2G
- mode_t pmod = 0;
-
- /*********************************************************************/
- /* Create the file object according to access mode */
- /*********************************************************************/
- switch (mode) {
- case MODE_READ:
- oflag |= O_RDONLY;
- break;
- case MODE_WRITE:
- oflag |= O_WRONLY | O_CREAT;
- pmod = S_IREAD | S_IWRITE;
- break;
- case MODE_INSERT:
- oflag |= (O_WRONLY | O_APPEND);
- break;
- default:
- sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
- return true;
- } // endswitch
-
- Hfile= global_open(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, oflag, pmod);
-
- if (Hfile == INVALID_HANDLE_VALUE) {
- rc = errno;
-#if defined(TRACE)
- printf("Open: %s\n", g->Message);
-#endif // TRACE
- return true;
- } // endif Hfile
-
-#if defined(TRACE)
- printf(" rc=%d oflag=%p mode=%d handle=%d fn=%s\n",
- rc, oflag, mode, Hfile, filename);
-#endif // TRACE
-
-#endif // UNIX
-
- return false;
- } // end of Open
-
-/***********************************************************************/
-/* Get the offset of this index in the index file. */
-/***********************************************************************/
-bool XHUGE::GetOff(int& low, int& high, PIXDEF sxp)
- {
- if (!sxp) {
- low = 0;
- high = 0;
- return false;
- } // endif sxp
-
-#if defined(WIN32)
- LARGE_INTEGER ln;
-
- ln.LowPart = sxp->GetOffset();
- ln.HighPart = sxp->GetOffhigh();
- ln.QuadPart += (LONGLONG)sxp->GetSize();
- low = ln.LowPart;
- high = (int)ln.HighPart;
-#else // UNIX
-#define G4 ((off64_t)0x100 * (off64_t)0x1000000)
-#if defined(TRACE)
- printf("in GetOff...\n");
-#endif // TRACE
- off64_t pos;
-
- pos = (off64_t)sxp->GetOffset() + (off64_t)sxp->GetOffhigh() * G4;
- pos += (off64_t)sxp->GetSize();
- low = (int)(pos % G4);
- high = (int)(pos / G4);
-#endif // UNIX
- return false;
- } // end of GetOff
-
-/***********************************************************************/
-/* Go to position in a huge file. */
-/***********************************************************************/
-bool XHUGE::Seek(PGLOBAL g, int low, int high, int origin)
- {
-#if defined(WIN32)
- LONG hi = high;
- DWORD rc = SetFilePointer(Hfile, low, &hi, origin);
-
- if (rc == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
- sprintf(g->Message, MSG(FUNC_ERROR), "Xseek");
- return true;
- } // endif
-
-#else // UNIX
- off64_t pos = (off64_t)low
- + (off64_t)high * ((off64_t)0x100 * (off64_t)0x1000000);
-
- if (lseek64(Hfile, pos, origin) < 0) {
- sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
-#if defined(TRACE)
- printf("lseek64 error %d\n", errno);
-#endif // TRACE
- return true;
- } // endif lseek64
-
-#if defined(TRACE)
- printf("Seek: low=%d high=%d\n", low, high);
-#endif // TRACE
-#endif // UNIX
-
- return false;
- } // end of Seek
-
-/***********************************************************************/
-/* Read from a huge index file. */
-/***********************************************************************/
-bool XHUGE::Read(PGLOBAL g, void *buf, int n, int size)
- {
- bool rc = false;
-
-#if defined(WIN32)
- bool brc;
- DWORD nbr, count = (DWORD)(n * size);
-
- brc = ReadFile(Hfile, buf, count, &nbr, NULL);
-
- if (brc) {
- if (nbr != count) {
- strcpy(g->Message, MSG(EOF_INDEX_FILE));
- rc = true;
- } // endif nbr
-
- } else {
- char *buf[256];
- DWORD drc = GetLastError();
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)buf, sizeof(buf), NULL);
- sprintf(g->Message, MSG(READ_ERROR), "index file", buf);
- rc = true;
- } // endif brc
-#else // UNIX
- ssize_t count = (ssize_t)(n * size);
-
-#if defined(TRACE)
- printf("Hfile=%d n=%d size=%d count=%d\n", Hfile, n, size, count);
-#endif // TRACE
-
- if (read(Hfile, buf, count) != count) {
- sprintf(g->Message, MSG(READ_ERROR), "Index file", strerror(errno));
-#if defined(TRACE)
- printf("read error %d\n", errno);
-#endif // TRACE
- rc = true;
- } // endif nbr
-#endif // UNIX
-
- return rc;
- } // end of Read
-
-/***********************************************************************/
-/* Write on a huge index file. */
-/***********************************************************************/
-int XHUGE::Write(PGLOBAL g, void *buf, int n, int size, bool& rc)
- {
-#if defined(WIN32)
- bool brc;
- DWORD nbw, count = (DWORD)n * (DWORD) size;
-
- brc = WriteFile(Hfile, buf, count, &nbw, NULL);
-
- if (!brc) {
- char msg[256];
- DWORD drc = GetLastError();
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
- (LPTSTR)msg, sizeof(msg), NULL);
- sprintf(g->Message, MSG(WRITING_ERROR), "index file", msg);
- rc = true;
- } // endif size
-
- return (int)nbw;
-#else // UNIX
- ssize_t nbw;
- size_t count = (size_t)n * (size_t)size;
-
- nbw = write(Hfile, buf, count);
-
- if (nbw != (signed)count) {
- sprintf(g->Message, MSG(WRITING_ERROR),
- "index file", strerror(errno));
- rc = true;
- } // endif nbw
-
- return (int)nbw;
-#endif // UNIX
- } // end of Write
-
-#if defined(XMAP)
-#if defined(WIN32)
-/***********************************************************************/
-/* Return a pointer to the segment at the given offset and size. */
-/***********************************************************************/
-void *XHUGE::FileView(PGLOBAL g, char *fn, int loff, int hoff, int size)
- {
- SYSTEM_INFO SysInfo; // system information; used to get the granularity
- char *pData; // pointer to the data
- int iViewDelta; // the offset into the view where the data shows up
- HANDLE hMapFile; // handle for the file's memory-mapped region
- LARGE_INTEGER lint; // a utility holder
- __int64 offset; // Where to start in the index file
- __int64 FileMapSize; // size of the file mapping
- __int64 FileMapStart; // where in the file to start the file map view
- __int64 Granularity; // system allocation granularity
- DWORD MapViewSize; // the size of the view
-
- // Open the file in mode read only
- if (Open(g, fn, MODE_READ))
- return NULL;
-
- // Get the system allocation granularity.
- GetSystemInfo(&SysInfo);
- Granularity = (__int64)SysInfo.dwAllocationGranularity;
-
- // Calculate the offset as a 64 byte integer
- lint.LowPart = loff;
- lint.HighPart = hoff;
- offset = lint.QuadPart;
-
- // To calculate where to start the file mapping, round down the
- // offset of the data into the file to the nearest multiple of the
- // system allocation granularity.
- FileMapStart = (offset / Granularity) * Granularity;
-
- // Calculate the size of the file mapping view.
- MapViewSize = (DWORD)(offset % Granularity) + (DWORD)size;
-
- // How large will the file-mapping object be?
- FileMapSize = offset + (__int64)size;
-
- // The data of interest isn't at the beginning of the
- // view, so determine how far into the view to set the pointer.
- iViewDelta = (int)(offset - FileMapStart);
-
- // Let the user know that the index file is more than large enough
- lint.LowPart = GetFileSize(Hfile, (LPDWORD)&lint.HighPart);
-
- // Prepare the low and high parts of the size.
- lint.QuadPart = FileMapSize;
-
- // Create a file-mapping object for the file.
- hMapFile = CreateFileMapping( Hfile, // current file handle
- NULL, // default security
- PAGE_READONLY, // permission
- lint.HighPart, // size, high
- lint.LowPart, // size, low
- NULL); // name
-
- if (hMapFile == NULL) {
- sprintf(g->Message, MSG(HANDLE_IS_NULL), "hMapFile", GetLastError());
- return NULL;
- } // endif hMapFile
-
- // Prepare the low and high parts of the starting file offset.
- lint.QuadPart = FileMapStart;
-
- // Map the view.
- ViewBase = MapViewOfFile(hMapFile, // handle to mapping object
- FILE_MAP_READ, // access mode
- lint.HighPart, // high-order 32 bits of file offset
- lint.LowPart, // low-order 32 bits of file offset
- MapViewSize); // number of bytes to map
-
- if (!ViewBase) {
- sprintf(g->Message, MSG(HANDLE_IS_NULL), "ViewBase", GetLastError());
- return NULL;
- } // endif ViewBase
-
- // Calculate the pointer to the data.
- pData = (char *)ViewBase + iViewDelta;
-
- // close the file-mapping object
- if (!CloseHandle(hMapFile))
- sprintf(g->Message, MSG(MAP_OBJ_ERR), GetLastError());
-
- // close the file itself
- if (!CloseHandle(Hfile))
- sprintf(g->Message, MSG(FILE_CLOSE_ERR), GetLastError());
- else
- Hfile = INVALID_HANDLE_VALUE;
-
- return pData;
- } // end of FileView
-#else // not WIN32
-/***********************************************************************/
-/* Don't know whether this is possible for non Windows OS. */
-/***********************************************************************/
-void *XHUGE::FileView(PGLOBAL g, char *fn,
- int loff, int hoff, int size)
- {
- strcpy(g->Message, MSG(NO_PART_MAP));
- return NULL;
- } // end of FileView
-#endif // not WIN32
-#endif // XMAP
-
-/* -------------------------- XXROW Class --------------------------- */
-
-/***********************************************************************/
-/* XXROW Public Constructor. */
-/***********************************************************************/
-XXROW::XXROW(PTDBDOS tdbp) : XXBASE(tdbp, false)
- {
- Tdbp = tdbp;
- Valp = NULL;
- } // end of XXROW constructor
-
-/***********************************************************************/
-/* XXROW Reset: re-initialize a Kindex block. */
-/***********************************************************************/
-void XXROW::Reset(void)
- {
-#if defined(_DEBUG)
- assert(Tdbp->GetLink()); // This a join index
-#endif // _DEBUG
- } // end of Reset
-
-/***********************************************************************/
-/* Init: Open and Initialize a Key Index. */
-/***********************************************************************/
-bool XXROW::Init(PGLOBAL g)
- {
- /*********************************************************************/
- /* Table will be accessed through an index table. */
- /* To_Link should not be NULL. */
- /*********************************************************************/
- if (!Tdbp->GetLink() || Tbxp->GetKnum() != 1)
- return true;
-
- if ((*Tdbp->GetLink())->GetResultType() != TYPE_INT) {
- strcpy(g->Message, MSG(TYPE_MISMATCH));
- return true;
- } else
- Valp = (*Tdbp->GetLink())->GetValue();
-
- if ((Num_K = Tbxp->Cardinality(g)) < 0)
- return true; // Not a fixed file
-
- /*********************************************************************/
- /* The entire table is indexed, no need to construct the index. */
- /*********************************************************************/
- Cur_K = Num_K;
- return false;
- } // end of Init
-
-/***********************************************************************/
-/* RANGE: Tell how many record exist in a given value range. */
-/***********************************************************************/
-int XXROW::Range(PGLOBAL g, int limit, bool incl)
- {
- int n = Valp->GetIntValue();
-
- switch (limit) {
- case 1: n += ((incl) ? 0 : 1); break;
- case 2: n += ((incl) ? 1 : 0); break;
- default: n = 1;
- } // endswitch limit
-
- return n;
- } // end of Range
-
-/***********************************************************************/
-/* XXROW: Fetch a physical or logical record. */
-/***********************************************************************/
-int XXROW::Fetch(PGLOBAL g)
- {
- if (Num_K == 0)
- return -1; // means end of file
-
- /*********************************************************************/
- /* Look for a key equal to the link column of previous table, */
- /* and return its rank whithin the index table. */
- /*********************************************************************/
- Cur_K = FastFind(1);
-
- if (Cur_K >= Num_K)
- /*******************************************************************/
- /* Rank not whithin index table, signal record not found. */
- /*******************************************************************/
- return -2; // Means record not found
-
- /*********************************************************************/
- /* If rank is equal to stored rank, record is already there. */
- /*********************************************************************/
- if (Cur_K == Old_K)
- return -3; // Means record already there
- else
- Old_K = Cur_K; // Store rank of newly read record
-
- return Cur_K;
- } // end of Fetch
-
-/***********************************************************************/
-/* FastFind: Returns the index of matching record in a join. */
-/***********************************************************************/
-int XXROW::FastFind(int nk)
- {
- int n = Valp->GetIntValue();
-
- if (n < 0)
- return (Op == OP_EQ) ? (-1) : 0;
- else if (n > Num_K)
- return Num_K;
- else
- return (Op == OP_GT) ? n : (n - 1);
-
- } // end of FastFind
-
-/* ------------------------- KXYCOL Classes -------------------------- */
-
-/***********************************************************************/
-/* KXYCOL public constructor. */
-/***********************************************************************/
-KXYCOL::KXYCOL(PKXBASE kp) : To_Keys(Keys.Memp),
- Kof((CPINT&)Koff.Memp), To_Bkeys(Bkeys.Memp)
- {
- Next = NULL;
- Previous = NULL;
- Kxp = kp;
- Colp = NULL;
- IsSorted = false;
- Asc = true;
- Keys = Nmblk;
- Kblp = NULL;
- Bkeys = Nmblk;
- Blkp = NULL;
- Valp = NULL;
- Klen = 0;
- Kprec = 0;
- Type = TYPE_ERROR;
- Prefix = false;
- Koff = Nmblk;
- Val_K = 0;
- Ndf = 0;
- Mxs = 0;
- } // end of KXYCOL constructor
-
-/***********************************************************************/
-/* KXYCOL Init: initialize and allocate storage. */
-/* Key length kln can be smaller than column length for CHAR columns. */
-/***********************************************************************/
-bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln)
- {
- int len = colp->GetLength(), prec = colp->GetPrecision();
-
- if (kln && len > kln && colp->GetResultType() == TYPE_STRING) {
- len = kln;
- Prefix = true;
- } // endif kln
-
-#ifdef DEBTRACE
- htrc("KCOL(%p) Init: col=%s n=%d type=%d sm=%d\n",
- this, colp->GetName(), n, colp->GetResultType(), sm);
-#endif
-
- // Allocate the Value object used when moving items
- Type = colp->GetResultType();
-
- if (!(Valp = AllocateValue(g, Type, len, colp->GetPrecision())))
- return true;
-
- Klen = Valp->GetClen();
- Keys.Size = n * Klen;
-
- if (!PlgDBalloc(g, NULL, Keys)) {
- sprintf(g->Message, MSG(KEY_ALLOC_ERROR), Klen, n);
- return true; // Error
- } // endif
-
- // Allocate the Valblock. The last parameter is to have rows filled
- // by blanks (if true) or keep the zero ending char (if false).
- // Currently we set it to true to be compatible with QRY blocks,
- // and the one before last is to enable length/type checking, set to
- // true if not a prefix key.
- Kblp = AllocValBlock(g, To_Keys, Type, n, len, prec, !Prefix, true);
- Asc = sm; // Sort mode: Asc=true Desc=false
- Ndf = n;
-
- // Store this information to avoid sorting when already done
- if (Asc)
- IsSorted = colp->GetOpt() < 0;
-
-//MayHaveNulls = colp->HasNulls();
- return false;
- } // end of Init
-
-#if defined(XMAP)
-/***********************************************************************/
-/* KXYCOL MapInit: initialize and address storage. */
-/* Key length kln can be smaller than column length for CHAR columns. */
-/***********************************************************************/
-BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m)
- {
- int len = colp->GetLength(), prec = colp->GetPrecision();
-
- if (n[3] && colp->GetLength() > n[3]
- && colp->GetResultType() == TYPE_STRING) {
- len = n[3];
- Prefix = true;
- } // endif kln
-
- Type = colp->GetResultType();
-
-#ifdef DEBTRACE
- htrc("MapInit(%p): colp=%p type=%d n=%d len=%d m=%p\n",
- this, colp, Type, n[0], len, m);
-#endif
-
- // Allocate the Value object used when moving items
- Valp = AllocateValue(g, Type, len, prec, NULL);
- Klen = Valp->GetClen();
-
- if (n[2]) {
- Bkeys.Size = n[2] * Klen;
- Bkeys.Memp = m;
- Bkeys.Sub = true;
-
- // Allocate the Valblk containing initial block key values
- Blkp = AllocValBlock(g, To_Bkeys, Type, n[2], len, prec, true, true);
- } // endif nb
-
- Keys.Size = n[0] * Klen;
- Keys.Memp = m + Bkeys.Size;
- Keys.Sub = true;
-
- // Allocate the Valblock. Last two parameters are to have rows filled
- // by blanks (if true) or keep the zero ending char (if false).
- // Currently we set it to true to be compatible with QRY blocks,
- // and last one to enable type checking (no conversion).
- Kblp = AllocValBlock(g, To_Keys, Type, n[0], len, prec, true, true);
-
- if (n[1]) {
- Koff.Size = n[1] * sizeof(int);
- Koff.Memp = m + Bkeys.Size + Keys.Size;
- Koff.Sub = true;
- } // endif n[1]
-
- Ndf = n[0];
- IsSorted = colp->GetOpt() < 0;
- return m + Bkeys.Size + Keys.Size + Koff.Size;
- } // end of MapInit
-#endif // XMAP
-
-/***********************************************************************/
-/* Allocate the offset block used by intermediate key columns. */
-/***********************************************************************/
-int *KXYCOL::MakeOffset(PGLOBAL g, int n)
- {
- if (!Kof) {
- // Calculate the initial size of the offset
- Koff.Size = (n + 1) * sizeof(int);
-
- // Allocate the required memory
- if (!PlgDBalloc(g, NULL, Koff)) {
- strcpy(g->Message, MSG(KEY_ALLOC_ERR));
- return NULL; // Error
- } // endif
-
- } else if (n) {
- // This is a reallocation call
- PlgDBrealloc(g, NULL, Koff, (n + 1) * sizeof(int));
- } else
- PlgDBfree(Koff);
-
- return (int*)Kof;
- } // end of MakeOffset
-
-/***********************************************************************/
-/* Make a front end array of key values that are the first value of */
-/* each blocks (of size n). This to reduce paging in FastFind. */
-/***********************************************************************/
-bool KXYCOL::MakeBlockArray(PGLOBAL g, int nb, int size)
- {
- int i, k;
-
- // Calculate the size of the block array in the index
- Bkeys.Size = nb * Klen;
-
- // Allocate the required memory
- if (!PlgDBalloc(g, NULL, Bkeys)) {
- sprintf(g->Message, MSG(KEY_ALLOC_ERROR), Klen, nb);
- return true; // Error
- } // endif
-
- // Allocate the Valblk used to contains initial block key values
- Blkp = AllocValBlock(g, To_Bkeys, Type, nb, Klen, Kprec);
-
- // Populate the array with values
- for (i = k = 0; i < nb; i++, k += size)
- Blkp->SetValue(Kblp, i, k);
-
- return false;
- } // end of MakeBlockArray
-
-/***********************************************************************/
-/* KXYCOL SetValue: read column value for nth array element. */
-/***********************************************************************/
-void KXYCOL::SetValue(PCOL colp, int i)
- {
-#if defined(_DEBUG)
- assert (Kblp != NULL);
-#endif
-
- Kblp->SetValue(colp->GetValue(), (int)i);
- } // end of SetValue
-
-/***********************************************************************/
-/* InitFind: initialize finding the rank of column value in index. */
-/***********************************************************************/
-bool KXYCOL::InitFind(PGLOBAL g, PXOB xp)
- {
- if (xp->GetType() == TYPE_CONST) {
- if (Kxp->Nth)
- return true;
-
- Valp->SetValue_pval(xp->GetValue(), !Prefix);
- } else {
- xp->Reset();
- xp->Eval(g);
- Valp->SetValue_pval(xp->GetValue(), false);
-// Valp->SetValue_pval(xp->GetValue(), !Prefix);
- } // endif Type
-
- return false;
- } // end of InitFind
-
-/***********************************************************************/
-/* InitBinFind: initialize Value to the value pointed by vp. */
-/***********************************************************************/
-void KXYCOL::InitBinFind(void *vp)
- {
- Valp->SetBinValue(vp);
- } // end of InitBinFind
-
-/***********************************************************************/
-/* KXYCOL FillValue: called by COLBLK::Eval when a column value is */
-/* already in storage in the corresponding KXYCOL. */
-/***********************************************************************/
-void KXYCOL::FillValue(PVAL valp)
- {
- valp->SetValue_pvblk(Kblp, Val_K);
- } // end of FillValue
-
-/***********************************************************************/
-/* KXYCOL: Compare routine for one numeric value. */
-/***********************************************************************/
-int KXYCOL::Compare(int i1, int i2)
- {
- // Do the actual comparison between values.
- register int k = (int)Kblp->CompVal((int)i1, (int)i2);
-
-#ifdef DEBUG2
- htrc("Compare done result=%d\n", k);
-#endif
-
- return (Asc) ? k : -k;
- } // end of Compare
-
-/***********************************************************************/
-/* KXYCOL: Compare the ith key to the stored Value. */
-/***********************************************************************/
-int KXYCOL::CompVal(int i)
- {
- // Do the actual comparison between numerical values.
-#ifdef DEBUG2
- register int k = (int)Kblp->CompVal(Valp, (int)i);
-
- htrc("Compare done result=%d\n", k);
- return k;
-#endif
- return (int)Kblp->CompVal(Valp, (int)i);
- } // end of CompVal
-
-/***********************************************************************/
-/* KXYCOL: Compare the key to the stored block value. */
-/***********************************************************************/
-int KXYCOL::CompBval(int i)
- {
- // Do the actual comparison between key values.
- return (int)Blkp->CompVal(Valp, (int)i);
- } // end of CompBval
-
-/***********************************************************************/
-/* KXYCOL ReAlloc: ReAlloc To_Data if it is not suballocated. */
-/***********************************************************************/
-void KXYCOL::ReAlloc(PGLOBAL g, int n)
- {
- PlgDBrealloc(g, NULL, Keys, n * Klen);
- Kblp->ReAlloc(To_Keys, n);
- Ndf = n;
- } // end of ReAlloc
-
-/***********************************************************************/
-/* KXYCOL FreeData: Free To_Keys if it is not suballocated. */
-/***********************************************************************/
-void KXYCOL::FreeData(void)
- {
- PlgDBfree(Keys);
- Kblp = NULL;
- PlgDBfree(Bkeys);
- Blkp = NULL;
- PlgDBfree(Koff);
- Ndf = 0;
- } // end of FreeData
+/***************** Xindex C++ Class Xindex Code (.CPP) *****************/
+/* Name: XINDEX.CPP Version 2.7 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2004-2012 */
+/* */
+/* This file contains the class XINDEX implementation code. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !WIN32
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* kindex.h is header containing the KINDEX class definition. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "osutil.h"
+#include "maputil.h"
+//nclude "filter.h"
+#include "tabcol.h"
+#include "xindex.h"
+#include "xobject.h"
+//nclude "scalfnc.h"
+//nclude "array.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+
+/***********************************************************************/
+/* Macro or external routine definition */
+/***********************************************************************/
+#define NZ 7
+#define NW 5
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+#endif
+
+/***********************************************************************/
+/* DB static external variables. */
+/***********************************************************************/
+extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
+
+/***********************************************************************/
+/* Last two parameters are true to enable type checking, and last one */
+/* to have rows filled by blanks to be compatible with QRY blocks. */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
+ bool check = true, bool blank = true);
+
+/***********************************************************************/
+/* Check whether we have to create/update permanent indexes. */
+/***********************************************************************/
+int PlgMakeIndex(PGLOBAL g, PSZ name, PIXDEF pxdf, bool add)
+ {
+ int rc;
+ PTABLE tablep;
+ PTDBDOS tdbp;
+ PCATLG cat = PlgGetCatalog(g, true);
+
+ /*********************************************************************/
+ /* Open a new table in mode read and with only the keys columns. */
+ /*********************************************************************/
+ tablep = new(g) XTAB(name);
+
+ if (!(tdbp = (PTDBDOS)cat->GetTable(g, tablep)))
+ rc = RC_NF;
+ else if (!tdbp->GetDef()->Indexable()) {
+ sprintf(g->Message, MSG(TABLE_NO_INDEX), name);
+ rc = RC_NF;
+ } else if ((rc = tdbp->MakeIndex(g, pxdf, add)) == RC_INFO)
+ rc = RC_OK; // No index
+
+ return rc;
+ } // end of PlgMakeIndex
+
+/* -------------------------- Class INDEXDEF ------------------------- */
+
+/***********************************************************************/
+/* INDEXDEF Constructor. */
+/***********************************************************************/
+INDEXDEF::INDEXDEF(char *name, bool uniq, int n)
+ {
+//To_Def = NULL;
+ Next = NULL;
+ ToKeyParts = NULL;
+ Name = name;
+ Unique = uniq;
+ Invalid = false;
+ AutoInc = false;
+ Nparts = 0;
+ ID = n;
+ Offset = 0;
+ Offhigh = 0;
+ Size = 0;
+ MaxSame = 1;
+ } // end of INDEXDEF constructor
+
+/***********************************************************************/
+/* Set the max same values for each colum after making the index. */
+/***********************************************************************/
+void INDEXDEF::SetMxsame(PXINDEX x)
+ {
+ PKPDEF kdp;
+ PXCOL xcp;
+
+ for (kdp = ToKeyParts, xcp = x->To_KeyCol;
+ kdp && xcp; kdp = kdp->Next, xcp = xcp->Next)
+ kdp->Mxsame = xcp->Mxs;
+ } // end of SetMxsame
+
+/* -------------------------- Class KPARTDEF ------------------------- */
+
+/***********************************************************************/
+/* KPARTDEF Constructor. */
+/***********************************************************************/
+KPARTDEF::KPARTDEF(PSZ name, int n)
+ {
+ Next = NULL;
+ Name = name;
+ Mxsame = 0;
+ Ncol = n;
+ Klen = 0;
+ } // end of KPARTDEF constructor
+
+/* -------------------------- XXBASE Class --------------------------- */
+
+/***********************************************************************/
+/* XXBASE public constructor. */
+/***********************************************************************/
+XXBASE::XXBASE(PTDBDOS tbxp, bool b) : CSORT(b),
+ To_Rec((int*&)Record.Memp)
+ {
+ Tbxp = tbxp;
+ Record = Nmblk;
+ Cur_K = -1;
+ Old_K = -1;
+ Num_K = 0;
+ Ndif = 0;
+ Bot = Top = Inf = Sup = 0;
+ Op = OP_EQ;
+ To_KeyCol = NULL;
+ Mul = false;
+ Val_K = -1;
+ Nblk = Sblk = 0;
+ Thresh = 7;
+ ID = -1;
+ Nth = 0;
+ } // end of XXBASE constructor
+
+/***********************************************************************/
+/* Make file output of XINDEX contents. */
+/***********************************************************************/
+void XXBASE::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+ fprintf(f, "%sXINDEX: Tbxp=%p Num=%d\n", m, Tbxp, Num_K);
+ } // end of Print
+
+/***********************************************************************/
+/* Make string output of XINDEX contents. */
+/***********************************************************************/
+void XXBASE::Print(PGLOBAL g, char *ps, uint z)
+ {
+ *ps = '\0';
+ strncat(ps, "Xindex", z);
+ } // end of Print
+
+/* -------------------------- XINDEX Class --------------------------- */
+
+/***********************************************************************/
+/* XINDEX public constructor. */
+/***********************************************************************/
+XINDEX::XINDEX(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp, int k)
+ : XXBASE(tdbp, !xdp->IsUnique())
+ {
+ Xdp = xdp;
+ ID = xdp->GetID();
+ Tdbp = tdbp;
+ X = pxp;
+ To_LastCol = NULL;
+ To_LastVal = NULL;
+ To_Cols = cp;
+ To_Vals = xp;
+ Mul = !xdp->IsUnique();
+ Srtd = false;
+ Nk = xdp->GetNparts();
+ Nval = (k) ? k : Nk;
+ Incr = 0;
+ Defoff = xdp->GetOffset();
+ Defhigh = xdp->GetOffhigh();
+ Size = xdp->GetSize();
+ MaxSame = xdp->GetMaxSame();
+ } // end of XINDEX constructor
+
+/***********************************************************************/
+/* XINDEX Reset: re-initialize a Xindex block. */
+/***********************************************************************/
+void XINDEX::Reset(void)
+ {
+ for (PXCOL kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = kp->Ndf;
+
+ Cur_K = Num_K;
+ Old_K = -1; // Needed to avoid not setting CurBlk for Update
+ Op = (Op == OP_FIRST || Op == OP_NEXT) ? OP_FIRST :
+ (Op == OP_FSTDIF || Op == OP_NXTDIF) ? OP_FSTDIF : OP_EQ;
+ Nth = 0;
+ } // end of Reset
+
+/***********************************************************************/
+/* XINDEX Close: terminate index and free all allocated data. */
+/* Do not reset other values that are used at return to make. */
+/***********************************************************************/
+void XINDEX::Close(void)
+ {
+ // Close file or view of file
+ X->Close();
+
+ // De-allocate data
+ PlgDBfree(Record);
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+
+ // De-allocate Key data
+ for (PXCOL kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->FreeData();
+
+ // Column values cannot be retrieved from key anymore
+ for (int k = 0; k < Nk; k++)
+ To_Cols[k]->SetKcol(NULL);
+
+ } // end of Close
+
+/***********************************************************************/
+/* XINDEX compare routine for C Quick/Insertion sort. */
+/***********************************************************************/
+int XINDEX::Qcompare(int *i1, int *i2)
+ {
+ register int k;
+ register PXCOL kcp;
+
+ for (kcp = To_KeyCol, k = 0; kcp; kcp = kcp->Next)
+ if ((k = kcp->Compare(*i1, *i2)))
+ break;
+
+#ifdef DEBTRACE
+ num_comp++;
+#endif
+
+ return k;
+ } // end of Qcompare
+
+/***********************************************************************/
+/* Make: Make and index on key column(s). */
+/***********************************************************************/
+bool XINDEX::Make(PGLOBAL g, PIXDEF sxp)
+ {
+ /*********************************************************************/
+ /* Table can be accessed through an index. */
+ /*********************************************************************/
+ int k, rc = RC_OK;
+ int *bof, i, j, n, ndf, nkey;
+ PKPDEF kdfp = Xdp->GetToKeyParts();
+ bool brc = true;
+ PCOL colp;
+ PXCOL kp, prev = NULL, kcp = NULL;
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ Defoff = 0;
+ Size = 0; // Void index
+
+ /*********************************************************************/
+ /* Allocate the storage that will contain the keys and the file */
+ /* positions corresponding to them. */
+ /*********************************************************************/
+ if ((n = Tdbp->GetMaxSize(g)) < 0)
+ return true;
+ else if (!n) {
+ Num_K = Ndif = 0;
+ MaxSame = 1;
+
+ // The if condition was suppressed because this may be an existing
+ // index that is now void because all table lines were deleted.
+// if (sxp)
+ goto nox; // Truncate eventually existing index file
+// else
+// return false;
+
+ } // endif n
+
+ // File position must be stored
+ Record.Size = n * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Record)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", n);
+ goto err; // Error
+ } // endif
+
+ /*********************************************************************/
+ /* Allocate the KXYCOL blocks used to store column values. */
+ /*********************************************************************/
+ for (k = 0; k < Nk; k++) {
+ colp = To_Cols[k];
+
+ if (!kdfp) {
+ sprintf(g->Message, MSG(INT_COL_ERROR),
+ (colp) ? colp->GetName() : "???");
+ goto err; // Error
+ } // endif kdfp
+
+ kcp = new(g) KXYCOL(this);
+
+ if (kcp->Init(g, colp, n, true, kdfp->Klen))
+ goto err; // Error
+
+ if (prev) {
+ kcp->Previous = prev;
+ prev->Next = kcp;
+ } else
+ To_KeyCol = kcp;
+
+ prev = kcp;
+ kdfp = kdfp->Next;
+ } // endfor k
+
+ To_LastCol = prev;
+
+ /*********************************************************************/
+ /* Get the starting information for progress. */
+ /*********************************************************************/
+ dup->Step = (char*)PlugSubAlloc(g, NULL, 128);
+ sprintf((char*)dup->Step, MSG(BUILD_INDEX), Xdp->GetName(), Tdbp->Name);
+ dup->ProgMax = Tdbp->GetProgMax(g);
+ dup->ProgCur = 0;
+
+ /*********************************************************************/
+ /* Standard init: read the file and construct the index table. */
+ /* Note: reading will be sequential as To_Kindex is not set. */
+ /*********************************************************************/
+ for (i = nkey = 0; i < n && rc != RC_EF; i++) {
+#if defined(THREAD)
+ if (!dup->Step) {
+ strcpy(g->Message, MSG(QUERY_CANCELLED));
+ longjmp(g->jumper[g->jump_level], 99);
+ } // endif Step
+#endif // THREAD
+
+ /*******************************************************************/
+ /* Read a valid record from table file. */
+ /*******************************************************************/
+ rc = Tdbp->ReadDB(g);
+
+ // Update progress information
+ dup->ProgCur = Tdbp->GetProgCur();
+
+ // Check return code and do whatever must be done according to it
+ switch (rc) {
+ case RC_OK:
+ break;
+ case RC_EF:
+ goto end_of_file;
+ case RC_NF:
+ continue;
+ default:
+ sprintf(g->Message, MSG(RC_READING), rc, Tdbp->Name);
+ goto err;
+ } // endswitch rc
+
+ /*******************************************************************/
+ /* Get and Store the file position of the last read record for */
+ /* future direct access. */
+ /*******************************************************************/
+ To_Rec[nkey] = Tdbp->GetRecpos();
+
+ /*******************************************************************/
+ /* Get the keys and place them in the key blocks. */
+ /*******************************************************************/
+ for (k = 0, kcp = To_KeyCol;
+ k < Nk && kcp;
+ k++, kcp = kcp->Next) {
+ colp = To_Cols[k];
+ colp->Reset();
+
+ colp->ReadColumn(g);
+// if (colp->ReadColumn(g))
+// goto err;
+
+ kcp->SetValue(colp, nkey);
+ } // endfor k
+
+ nkey++; // A new valid key was found
+ } // endfor i
+
+ end_of_file:
+
+ // Update progress information
+ dup->ProgCur = Tdbp->GetProgMax(g);
+
+ /*********************************************************************/
+ /* Record the Index size and eventually resize memory allocation. */
+ /*********************************************************************/
+ if ((Num_K = nkey) < n) {
+ PlgDBrealloc(g, NULL, Record, Num_K * sizeof(int));
+
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->ReAlloc(g, Num_K);
+
+ } // endif Num_K
+
+ /*********************************************************************/
+ /* Sort the index so we can use an optimized Find algorithm. */
+ /* Note: for a unique index we use the non conservative sort */
+ /* version because normally all index values are different. */
+ /* This was set at CSORT class construction. */
+ /* For all indexes, an offset array is made so we can check the */
+ /* uniqueness of unique indexes. */
+ /*********************************************************************/
+ Index.Size = Num_K * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Index)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", Num_K);
+ goto err; // Error
+ } // endif alloc
+
+ Offset.Size = (Num_K + 1) * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Offset)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "offset", Num_K + 1);
+ goto err; // Error
+ } // endif alloc
+
+ // Call the sort program, it returns the number of distinct values
+ if ((Ndif = Qsort(g, Num_K)) < 0)
+ goto err; // Error during sort
+
+ // Check whether the unique index is unique indeed
+ if (!Mul)
+ if (Ndif < Num_K) {
+ strcpy(g->Message, MSG(INDEX_NOT_UNIQ));
+ goto err;
+ } else
+ PlgDBfree(Offset); // Not used anymore
+
+ // Use the index to physically reorder the xindex
+ Srtd = Reorder(g);
+
+ if (Ndif < Num_K) {
+ // Resize the offset array
+ PlgDBrealloc(g, NULL, Offset, (Ndif + 1) * sizeof(int));
+
+ // Initial value of MaxSame
+ MaxSame = Pof[1] - Pof[0];
+
+ // Resize the Key array by only keeping the distinct values
+ for (i = 1; i < Ndif; i++) {
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Move(i, Pof[i]);
+
+ MaxSame = max(MaxSame, Pof[i + 1] - Pof[i]);
+ } // endfor i
+
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->ReAlloc(g, Ndif);
+
+ } else {
+ Mul = false; // Current index is unique
+ PlgDBfree(Offset); // Not used anymore
+ MaxSame = 1; // Reset it when remaking an index
+ } // endif Ndif
+
+ /*********************************************************************/
+ /* Now do the reduction of the index. Indeed a multi-column index */
+ /* can be used for only some of the first columns. For instance if */
+ /* an index is defined for column A, B, C PlugDB can use it for */
+ /* only the column A or the columns A, B. */
+ /* What we do here is to reduce the data so column A will contain */
+ /* only the sorted distinct values of A, B will contain data such */
+ /* as only distinct values of A,B are stored etc. */
+ /* This implies that for each column set an offset array is made */
+ /* except if the subset originally contains unique values. */
+ /*********************************************************************/
+ // Update progress information
+ dup->Step = STEP(REDUCE_INDEX);
+
+ ndf = Ndif;
+ To_LastCol->Mxs = MaxSame;
+
+ for (kcp = To_LastCol->Previous; kcp; kcp = kcp->Previous) {
+ if (!(bof = kcp->MakeOffset(g, ndf)))
+ goto err;
+ else
+ *bof = 0;
+
+ for (n = 0, i = j = 1; i < ndf; i++)
+ for (kp = kcp; kp; kp = kp->Previous)
+ if (kp->Compare(n, i)) {
+ // Values are not equal to last ones
+ bof[j++] = n = i;
+ break;
+ } // endif Compare
+
+ if (j < ndf) {
+ // Sub-index is multiple
+ bof[j] = ndf;
+ ndf = j; // New number of distinct values
+
+ // Resize the Key array by only keeping the distinct values
+ for (kp = kcp; kp; kp = kp->Previous) {
+ for (i = 1; i < ndf; i++)
+ kp->Move(i, bof[i]);
+
+ kp->ReAlloc(g, ndf);
+ } // endif kcp
+
+ // Resize the offset array
+ kcp->MakeOffset(g, ndf);
+
+ // Calculate the max same value for this column
+ kcp->Mxs = ColMaxSame(kcp);
+ } else {
+ // Current sub-index is unique
+ kcp->MakeOffset(g, 0); // The offset is not used anymore
+ kcp->Mxs = 1; // Unique
+ } // endif j
+
+ } // endfor kcp
+
+ /*********************************************************************/
+ /* For sorted columns and fixed record size, file position can be */
+ /* calculated, so the Record array can be discarted. */
+ /* Note: for Num_K = 1 any non null value is Ok. */
+ /*********************************************************************/
+ if (Srtd && Tdbp->Ftype != RECFM_VAR) {
+ Incr = (Num_K > 1) ? To_Rec[1] : Num_K;
+ PlgDBfree(Record);
+ } // endif Srtd
+
+ /*********************************************************************/
+ /* Check whether a two-tier find algorithm can be implemented. */
+ /* It is currently implemented only for single key indexes. */
+ /*********************************************************************/
+ if (Nk == 1 && ndf >= 65536) {
+ // Implement a two-tier find algorithm
+ for (Sblk = 256; (Sblk * Sblk * 4) < ndf; Sblk *= 2) ;
+
+ Nblk = (ndf -1) / Sblk + 1;
+
+ if (To_KeyCol->MakeBlockArray(g, Nblk, Sblk))
+ goto err; // Error
+
+ } // endif Num_K
+
+ nox:
+ /*********************************************************************/
+ /* No valid record read yet for secondary file. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+
+ /*********************************************************************/
+ /* Save the index so it has not to be recalculated. */
+ /*********************************************************************/
+ if (!SaveIndex(g, sxp))
+ brc = false;
+
+ err:
+ // We don't need the index anymore
+ Close();
+ return brc;
+ } // end of Make
+
+/***********************************************************************/
+/* Return the max size of the intermediate column. */
+/***********************************************************************/
+int XINDEX::ColMaxSame(PXCOL kp)
+ {
+ int *kof, i, ck1, ck2, ckn = 1;
+ PXCOL kcp;
+
+ // Calculate the max same value for this column
+ for (i = 0; i < kp->Ndf; i++) {
+ ck1 = i;
+ ck2 = i + 1;
+
+ for (kcp = kp; kcp; kcp = kcp->Next) {
+ if (!(kof = (kcp->Next) ? kcp->Kof : Pof))
+ break;
+
+ ck1 = kof[ck1];
+ ck2 = kof[ck2];
+ } // endfor kcp
+
+ ckn = max(ckn, ck2 - ck1);
+ } // endfor i
+
+ return ckn;
+ } // end of ColMaxSame
+
+/***********************************************************************/
+/* Reorder: use the sort index to reorder the data in storage so */
+/* it will be physically sorted and sort index can be removed. */
+/***********************************************************************/
+bool XINDEX::Reorder(PGLOBAL g)
+ {
+ register int i, j, k, n;
+ bool sorted = true;
+ PXCOL kcp;
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ if (Num_K > 500000) {
+ // Update progress information
+ dup->Step = STEP(REORDER_INDEX);
+ dup->ProgMax = Num_K;
+ dup->ProgCur = 0;
+ } else
+ dup = NULL;
+
+ if (!Pex)
+ return Srtd;
+
+ for (i = 0; i < Num_K; i++) {
+ if (Pex[i] == Num_K) { // Already moved
+ continue;
+ } else if (Pex[i] == i) { // Already placed
+ if (dup)
+ dup->ProgCur++;
+
+ continue;
+ } // endif's Pex
+
+ sorted = false;
+
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Save(i);
+
+ n = To_Rec[i];
+
+ for (j = i;; j = k) {
+ k = Pex[j];
+ Pex[j] = Num_K; // Mark position as set
+
+ if (k == i) {
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Restore(j);
+
+ To_Rec[j] = n;
+ break; // end of loop
+ } else {
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Move(j, k); // Move k to j
+
+ To_Rec[j] = To_Rec[k];
+ } // endif k
+
+ if (dup)
+ dup->ProgCur++;
+
+ } // endfor j
+
+ } // endfor i
+
+ // The index is not used anymore
+ PlgDBfree(Index);
+ return sorted;
+ } // end of Reorder
+
+/***********************************************************************/
+/* Save the index values for this table. */
+/* The problem here is to avoid name duplication, because more than */
+/* one data file can have the same name (but different types) and/or */
+/* the same data file can be used with different block sizes. This is */
+/* why we use Ofn that defaults to the file name but can be set to a */
+/* different name if necessary. */
+/***********************************************************************/
+bool XINDEX::SaveIndex(PGLOBAL g, PIXDEF sxp)
+ {
+ char *ftype;
+ char fn[_MAX_PATH];
+ int n[NZ], nof = (Mul) ? (Ndif + 1) : 0;
+ bool rc = false;
+ PXCOL kcp = To_KeyCol;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+ PDBUSER dup = PlgGetUser(g);
+
+ dup->Step = STEP(SAVING_INDEX);
+ dup->ProgMax = 15 + 16 * Nk;
+ dup->ProgCur = 0;
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if (dup->Catalog->GetSepIndex()) {
+ // Index is saved in a separate file
+#if !defined(UNIX)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ sxp = NULL;
+ } else
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+ if (X->Open(g, fn, (sxp) ? MODE_INSERT : MODE_WRITE)) {
+ printf("%s\n", g->Message);
+ return true;
+ } // endif Open
+
+ if (!Ndif)
+ goto end; // Void index
+
+ // Defoff is the start of the definition in the index file
+ X->GetOff(Defoff, Defhigh, sxp);
+
+#if defined(TRACE)
+ printf("Defoff=%d Defhigh=%d\n", Defoff, Defhigh);
+#endif // TRACE
+
+ /*********************************************************************/
+ /* Write the index values on the index file. */
+ /*********************************************************************/
+ n[0] = ID; // To check validity
+ n[1] = Nk; // The number of indexed columns
+ n[2] = nof; // The offset array size or 0
+ n[3] = Num_K; // The index size
+ n[4] = Incr; // Increment of record positions
+ n[5] = Nblk; n[6] = Sblk;
+
+#if defined(TRACE)
+ printf("Saving index %s\n", Xdp->GetName());
+ printf("ID=%d Nk=%d nof=%d Num_K=%d Incr=%d Nblk=%d Sblk=%d\n",
+ ID, Nk, nof, Num_K, Incr, Nblk, Sblk);
+#endif // TRACE
+
+ Size = X->Write(g, n, NZ, sizeof(int), rc);
+ dup->ProgCur = 1;
+
+ if (Mul) // Write the offset array
+ Size += X->Write(g, Pof, nof, sizeof(int), rc);
+
+ dup->ProgCur = 5;
+
+ if (!Incr) // Write the record position array(s)
+ Size += X->Write(g, To_Rec, Num_K, sizeof(int), rc);
+
+ dup->ProgCur = 15;
+
+ for (; kcp; kcp = kcp->Next) {
+ n[0] = kcp->Ndf; // Number of distinct sub-values
+ n[1] = (kcp->Kof) ? kcp->Ndf + 1 : 0; // 0 if unique
+ n[2] = (kcp == To_KeyCol) ? Nblk : 0;
+ n[3] = kcp->Klen; // To be checked later
+ n[4] = kcp->Type; // To be checked later
+
+ Size += X->Write(g, n, NW, sizeof(int), rc);
+ dup->ProgCur += 1;
+
+ if (n[2])
+ Size += X->Write(g, kcp->To_Bkeys, Nblk, kcp->Klen, rc);
+
+ dup->ProgCur += 5;
+
+ Size += X->Write(g, kcp->To_Keys, n[0], kcp->Klen, rc);
+ dup->ProgCur += 5;
+
+ if (n[1])
+ Size += X->Write(g, kcp->Kof, n[1], sizeof(int), rc);
+
+ dup->ProgCur += 5;
+ } // endfor kcp
+
+#if defined(TRACE)
+ printf("Index %s saved, Size=%d\n", Xdp->GetName(), Size);
+#endif // TRACE
+
+ end:
+ X->Close();
+ return rc;
+ } // end of SaveIndex
+
+#if !defined(XMAP)
+/***********************************************************************/
+/* Init: Open and Initialize a Key Index. */
+/***********************************************************************/
+bool XINDEX::Init(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Table will be accessed through an index table. */
+ /* If sorting is required, this will be done later. */
+ /*********************************************************************/
+ char *ftype;
+ char fn[_MAX_PATH];
+ int k, n, nv[NZ];
+ bool estim = false;
+ PCOL colp;
+ PXCOL prev = NULL, kcp = NULL;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+
+ /*********************************************************************/
+ /* Get the estimated table size. */
+ /* Note: for fixed tables we must use cardinality to avoid the call */
+ /* to MaxBlkSize that could reduce the cardinality value. */
+ /*********************************************************************/
+ if (Tdbp->Cardinality(NULL)) {
+ // For DBF tables, Cardinality includes bad or soft deleted lines
+ // that are not included in the index, and can be larger then the
+ // index size.
+ estim = (Tdbp->Ftype == RECFM_DBF);
+ n = Tdbp->Cardinality(g); // n is exact table size
+ } else {
+ // Variable table not optimized
+ estim = true; // n is an estimate of the size
+ n = Tdbp->GetMaxSize(g);
+ } // endif Cardinality
+
+ if (n <= 0)
+ return !(n == 0); // n < 0 error, n = 0 void table
+
+ /*********************************************************************/
+ /* Get the first key column. */
+ /*********************************************************************/
+ if (!Nk || !To_Cols || (!To_Vals && Op != OP_FIRST && Op != OP_FSTDIF)) {
+ strcpy(g->Message, MSG(NO_KEY_COL));
+ return true; // Error
+ } else
+ colp = To_Cols[0];
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if (defp->SepIndex()) {
+ // Index was saved in a separate file
+#if !defined(UNIX)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ } else
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+#if defined(TRACE)
+ printf("Index %s file: %s\n", Xdp->GetName(), fn);
+#endif // TRACE
+
+ /*********************************************************************/
+ /* Open the index file and check its validity. */
+ /*********************************************************************/
+ if (X->Open(g, fn, MODE_READ))
+ goto err; // No saved values
+
+ // Get offset from XDB file
+ if (X->Seek(g, Defoff, Defhigh, SEEK_SET))
+ goto err;
+
+ // Now start the reading process.
+ if (X->Read(g, nv, NZ, sizeof(int)))
+ goto err;
+
+#if defined(TRACE)
+ printf("nv=%d %d %d %d %d %d %d\n",
+ nv[0], nv[1], nv[2], nv[3], nv[4], nv[5], nv[6]);
+#endif // TRACE
+
+ // The test on ID was suppressed because MariaDB can change an index ID
+ // when other indexes are added or deleted
+ if (/*nv[0] != ID ||*/ nv[1] != Nk) {
+ sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
+#if defined(TRACE)
+ printf("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
+#endif // TRACE
+ goto err;
+ } // endif
+
+ if (nv[2]) {
+ Mul = true;
+ Ndif = nv[2];
+
+ // Allocate the storage that will contain the offset array
+ Offset.Size = Ndif * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Offset)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "offset", Ndif);
+ goto err;
+ } // endif
+
+ if (X->Read(g, Pof, Ndif, sizeof(int)))
+ goto err;
+
+ Ndif--; // nv[2] is offset size, equal to Ndif + 1
+ } else {
+ Mul = false;
+ Ndif = nv[3];
+ } // endif nv[2]
+
+ if (nv[3] < n && estim)
+ n = nv[3]; // n was just an evaluated max value
+
+ if (nv[3] != n) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
+ goto err;
+ } // endif
+
+ Num_K = nv[3];
+ Incr = nv[4];
+ Nblk = nv[5];
+ Sblk = nv[6];
+
+ if (!Incr) {
+ /*******************************************************************/
+ /* Allocate the storage that will contain the file positions. */
+ /*******************************************************************/
+ Record.Size = Num_K * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Record)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", Num_K);
+ goto err;
+ } // endif
+
+ if (X->Read(g, To_Rec, Num_K, sizeof(int)))
+ goto err;
+
+ } else
+ Srtd = true; // Sorted positions can be calculated
+
+ /*********************************************************************/
+ /* Allocate the KXYCOL blocks used to store column values. */
+ /*********************************************************************/
+ for (k = 0; k < Nk; k++) {
+ if (k == Nval)
+ To_LastVal = prev;
+
+ if (X->Read(g, nv, NW, sizeof(int)))
+ goto err;
+
+ colp = To_Cols[k];
+
+ if (nv[4] != colp->GetResultType() || !colp->GetValue() ||
+ (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
+ sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
+ goto err; // Error
+ } // endif GetKey
+
+ kcp = new(g) KXYCOL(this);
+
+ if (kcp->Init(g, colp, nv[0], true, (int)nv[3]))
+ goto err; // Error
+
+ /*******************************************************************/
+ /* Read the index values from the index file. */
+ /*******************************************************************/
+ if (k == 0 && Nblk) {
+ if (kcp->MakeBlockArray(g, Nblk, 0))
+ goto err;
+
+ // Read block values
+ if (X->Read(g, kcp->To_Bkeys, Nblk, kcp->Klen))
+ goto err;
+
+ } // endif Nblk
+
+ // Read the entire (small) index
+ if (X->Read(g, kcp->To_Keys, nv[0], kcp->Klen))
+ goto err;
+
+ if (nv[1]) {
+ if (!kcp->MakeOffset(g, nv[1] - 1))
+ goto err;
+
+ // Read the offset array
+ if (X->Read(g, kcp->Kof, nv[1], sizeof(int)))
+ goto err;
+
+ } // endif n[1]
+
+ if (!kcp->Prefix)
+ // Indicate that the key column value can be found from KXYCOL
+ colp->SetKcol(kcp);
+
+ if (prev) {
+ kcp->Previous = prev;
+ prev->Next = kcp;
+ } else
+ To_KeyCol = kcp;
+
+ prev = kcp;
+ } // endfor k
+
+ To_LastCol = prev;
+
+ if (Mul && prev) {
+ // Last key offset is the index offset
+ kcp->Koff = Offset;
+ kcp->Koff.Sub = true;
+ } // endif Mul
+
+ X->Close();
+
+ /*********************************************************************/
+ /* No valid record read yet for secondary file. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+ return false;
+
+err:
+ Close();
+ return true;
+ } // end of Init
+
+#else // XMAP
+/***********************************************************************/
+/* Init: Open and Initialize a Key Index. */
+/***********************************************************************/
+bool XINDEX::Init(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Table will be accessed through an index table. */
+ /* If sorting is required, this will be done later. */
+ /*********************************************************************/
+ const char *ftype;
+ BYTE *mbase;
+ char fn[_MAX_PATH];
+ int *nv, k, n;
+ bool estim;
+ PCOL colp;
+ PXCOL prev = NULL, kcp = NULL;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+ PDBUSER dup = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Get the estimated table size. */
+ /* Note: for fixed tables we must use cardinality to avoid the call */
+ /* to MaxBlkSize that could reduce the cardinality value. */
+ /*********************************************************************/
+ if (Tdbp->Cardinality(NULL)) {
+ // For DBF tables, Cardinality includes bad or soft deleted lines
+ // that are not included in the index, and can be larger then the
+ // index size.
+ estim = (Tdbp->Ftype == RECFM_DBF);
+ n = Tdbp->Cardinality(g); // n is exact table size
+ } else {
+ // Variable table not optimized
+ estim = true; // n is an estimate of the size
+ n = Tdbp->GetMaxSize(g);
+ } // endif Cardinality
+
+ if (n <= 0)
+ return !(n == 0); // n < 0 error, n = 0 void table
+
+ /*********************************************************************/
+ /* Get the first key column. */
+ /*********************************************************************/
+ if (!Nk || !To_Cols || (!To_Vals && Op != OP_FIRST && Op != OP_FSTDIF)) {
+ strcpy(g->Message, MSG(NO_KEY_COL));
+ return true; // Error
+ } else
+ colp = To_Cols[0];
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if (defp->SepIndex()) {
+ // Index was save in a separate file
+#if !defined(UNIX)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ } else
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+#if defined(TRACE)
+ printf("Index %s file: %s\n", Xdp->GetName(), fn);
+#endif // TRACE
+
+ /*********************************************************************/
+ /* Get a view on the part of the index file containing this index. */
+ /*********************************************************************/
+ if (!(mbase = (BYTE*)X->FileView(g, fn, Defoff, Defhigh, Size)))
+ goto err;
+
+ // Now start the mapping process.
+ nv = (int*)mbase;
+ mbase += NZ * sizeof(int);
+
+#if defined(TRACE)
+ printf("nv=%d %d %d %d %d %d %d\n",
+ nv[0], nv[1], nv[2], nv[3], nv[4], nv[5], nv[6]);
+#endif // TRACE
+
+ // The test on ID was suppressed because MariaDB can change an index ID
+ // when other indexes are added or deleted
+ if (/*nv[0] != ID ||*/ nv[1] != Nk) {
+ // Not this index
+ sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
+#if defined(TRACE)
+ printf("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
+#endif // TRACE
+ goto err;
+ } // endif nv
+
+ if (nv[2]) {
+ // Set the offset array memory block
+ Offset.Memp = mbase;
+ Offset.Size = nv[2] * sizeof(int);
+ Offset.Sub = true;
+ Mul = true;
+ Ndif = nv[2] - 1;
+ mbase += Offset.Size;
+ } else {
+ Mul = false;
+ Ndif = nv[3];
+ } // endif nv[2]
+
+ if (nv[3] < n && estim)
+ n = nv[3]; // n was just an evaluated max value
+
+ if (nv[3] != n) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
+ goto err;
+ } // endif
+
+ Num_K = nv[3];
+ Incr = nv[4];
+ Nblk = nv[5];
+ Sblk = nv[6];
+
+ if (!Incr) {
+ /*******************************************************************/
+ /* Point to the storage that contains the file positions. */
+ /*******************************************************************/
+ Record.Size = Num_K * sizeof(int);
+ Record.Memp = mbase;
+ Record.Sub = true;
+ mbase += Record.Size;
+ } else
+ Srtd = true; // Sorted positions can be calculated
+
+ /*********************************************************************/
+ /* Allocate the KXYCOL blocks used to store column values. */
+ /*********************************************************************/
+ for (k = 0; k < Nk; k++) {
+ if (k == Nval)
+ To_LastVal = prev;
+
+ nv = (int*)mbase;
+ mbase += (NW * sizeof(int));
+
+ colp = To_Cols[k];
+
+ if (nv[4] != colp->GetResultType() || !colp->GetValue() ||
+ (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
+ sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
+ goto err; // Error
+ } // endif GetKey
+
+ kcp = new(g) KXYCOL(this);
+
+ if (!(mbase = kcp->MapInit(g, colp, nv, mbase)))
+ goto err;
+
+ if (!kcp->Prefix)
+ // Indicate that the key column value can be found from KXYCOL
+ colp->SetKcol(kcp);
+
+ if (prev) {
+ kcp->Previous = prev;
+ prev->Next = kcp;
+ } else
+ To_KeyCol = kcp;
+
+ prev = kcp;
+ } // endfor k
+
+ To_LastCol = prev;
+
+ if (Mul && prev)
+ // Last key offset is the index offset
+ kcp->Koff = Offset;
+
+ /*********************************************************************/
+ /* No valid record read yet for secondary file. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+ return false;
+
+err:
+ Close();
+ return true;
+ } // end of Init
+#endif // XMAP
+
+/***********************************************************************/
+/* Get Ndif and Num_K from the index file. */
+/***********************************************************************/
+bool XINDEX::GetAllSizes(PGLOBAL g, int &ndif, int &numk)
+ {
+ char *ftype;
+ char fn[_MAX_PATH];
+ int n, nv[NZ];
+ bool estim = false;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+
+ ndif = numk = 0;
+
+ /*********************************************************************/
+ /* Get the estimated table size. */
+ /* Note: for fixed tables we must use cardinality to avoid the call */
+ /* to MaxBlkSize that could reduce the cardinality value. */
+ /*********************************************************************/
+ if (Tdbp->Cardinality(NULL)) {
+ // For DBF tables, Cardinality includes bad or soft deleted lines
+ // that are not included in the index, and can be larger then the
+ // index size.
+ estim = (Tdbp->Ftype == RECFM_DBF);
+ n = Tdbp->Cardinality(g); // n is exact table size
+ } else {
+ // Variable table not optimized
+ estim = true; // n is an estimate of the size
+ n = Tdbp->GetMaxSize(g);
+ } // endif Cardinality
+
+ if (n <= 0)
+ return !(n == 0); // n < 0 error, n = 0 void table
+
+ /*********************************************************************/
+ /* Check the key part number. */
+ /*********************************************************************/
+ if (!Nk) {
+ strcpy(g->Message, MSG(NO_KEY_COL));
+ return true; // Error
+ } // endif Nk
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if (defp->SepIndex()) {
+ // Index was saved in a separate file
+#if !defined(UNIX)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ } else
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+#if defined(TRACE)
+ printf("Index %s file: %s\n", Xdp->GetName(), fn);
+#endif // TRACE
+
+ /*********************************************************************/
+ /* Open the index file and check its validity. */
+ /*********************************************************************/
+ if (X->Open(g, fn, MODE_READ))
+ goto err; // No saved values
+
+ // Get offset from XDB file
+ if (X->Seek(g, Defoff, Defhigh, SEEK_SET))
+ goto err;
+
+ // Now start the reading process.
+ if (X->Read(g, nv, NZ, sizeof(int)))
+ goto err;
+
+#if defined(TRACE)
+ printf("nv=%d %d %d %d\n", nv[0], nv[1], nv[2], nv[3]);
+#endif // TRACE
+
+ // The test on ID was suppressed because MariaDB can change an index ID
+ // when other indexes are added or deleted
+ if (/*nv[0] != ID ||*/ nv[1] != Nk) {
+ sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
+#if defined(TRACE)
+ printf("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
+#endif // TRACE
+ goto err;
+ } // endif
+
+ if (nv[2]) {
+ Mul = true;
+ Ndif = nv[2] - 1; // nv[2] is offset size, equal to Ndif + 1
+ } else {
+ Mul = false;
+ Ndif = nv[3];
+ } // endif nv[2]
+
+ if (nv[3] < n && estim)
+ n = nv[3]; // n was just an evaluated max value
+
+ if (nv[3] != n) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
+ goto err;
+ } // endif
+
+ Num_K = nv[3];
+
+ if (Nk > 1) {
+ if (nv[2] && X->Seek(g, nv[2] * sizeof(int), 0, SEEK_CUR))
+ goto err;
+
+ if (!nv[4] && X->Seek(g, Num_K * sizeof(int), 0, SEEK_CUR))
+ goto err;
+
+ if (X->Read(g, nv, NW, sizeof(int)))
+ goto err;
+
+ PCOL colp = *To_Cols;
+
+ if (nv[4] != colp->GetResultType() ||
+ (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
+ sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
+ goto err; // Error
+ } // endif GetKey
+
+ Ndif = nv[0];
+ } // endif Nk
+
+ /*********************************************************************/
+ /* Set size values. */
+ /*********************************************************************/
+ ndif = Ndif;
+ numk = Num_K;
+ return false;
+
+err:
+ X->Close();
+ return true;
+ } // end of GetAllSizes
+
+/***********************************************************************/
+/* RANGE: Tell how many records exist for a given value, for an array */
+/* of values, or in a given value range. */
+/***********************************************************************/
+int XINDEX::Range(PGLOBAL g, int limit, bool incl)
+ {
+ int i, k, n = 0;
+ PXOB *xp = To_Vals;
+ PXCOL kp = To_KeyCol;
+ OPVAL op = Op;
+
+ switch (limit) {
+ case 1: Op = (incl) ? OP_GE : OP_GT; break;
+ case 2: Op = (incl) ? OP_GT : OP_GE; break;
+ default: return 0;
+ } // endswitch limit
+
+ /*********************************************************************/
+ /* Currently only range of constant values with an EQ operator is */
+ /* implemented. Find the number of rows for each given values. */
+ /*********************************************************************/
+ if (xp[0]->GetType() == TYPE_CONST) {
+ for (i = 0; kp; kp = kp->Next) {
+ kp->Valp->SetValue_pval(xp[i]->GetValue(), !kp->Prefix);
+ if (++i == Nval) break;
+ } // endfor kp
+
+ if ((k = FastFind(Nval)) < Num_K)
+ n = k;
+// if (limit)
+// n = (Mul) ? k : kp->Val_K;
+// else
+// n = (Mul) ? Pof[kp->Val_K + 1] - k : 1;
+
+ } else {
+ strcpy(g->Message, MSG(RANGE_NO_JOIN));
+ n = -1; // Logical error
+ } // endif'f Type
+
+ Op = op;
+ return n;
+ } // end of Range
+
+/***********************************************************************/
+/* Return the size of the group (equal values) of the current value. */
+/***********************************************************************/
+int XINDEX::GroupSize(void)
+ {
+#if defined(_DEBUG)
+ assert(To_LastCol->Val_K >= 0 && To_LastCol->Val_K < Ndif);
+#endif // _DEBUG
+
+ if (Nval == Nk)
+ return (Pof) ? Pof[To_LastCol->Val_K + 1] - Pof[To_LastCol->Val_K]
+ : 1;
+
+#if defined(_DEBUG)
+ assert(To_LastVal);
+#endif // _DEBUG
+
+ // Index whose only some columns are used
+ int ck1, ck2;
+
+ ck1 = To_LastVal->Val_K;
+ ck2 = ck1 + 1;
+
+#if defined(_DEBUG)
+ assert(ck1 >= 0 && ck1 < To_LastVal->Ndf);
+#endif // _DEBUG
+
+ for (PXCOL kcp = To_LastVal; kcp; kcp = kcp->Next) {
+ ck1 = (kcp->Kof) ? kcp->Kof[ck1] : ck1;
+ ck2 = (kcp->Kof) ? kcp->Kof[ck2] : ck2;
+ } // endfor kcp
+
+ return ck2 - ck1;
+ } // end of GroupSize
+
+/***********************************************************************/
+/* Find Cur_K and Val_K's of the next distinct value of the index. */
+/* Returns false if Ok, true if there are no more different values. */
+/***********************************************************************/
+bool XINDEX::NextValDif(void)
+ {
+ int curk;
+ PXCOL kcp = (To_LastVal) ? To_LastVal : To_LastCol;
+
+ if (++kcp->Val_K < kcp->Ndf) {
+ Cur_K = curk = kcp->Val_K;
+
+ // (Cur_K return is currently not used by SQLGBX)
+ for (PXCOL kp = kcp; kp; kp = kp->Next)
+ Cur_K = (kp->Kof) ? kp->Kof[Cur_K] : Cur_K;
+
+ } else
+ return true;
+
+ for (kcp = kcp->Previous; kcp; kcp = kcp->Previous) {
+ if (kcp->Kof && curk < kcp->Kof[kcp->Val_K + 1])
+ break; // all previous columns have same value
+
+ curk = ++kcp->Val_K; // This is a break, get new column value
+ } // endfor kcp
+
+ return false;
+ } // end of NextValDif
+
+/***********************************************************************/
+/* XINDEX: Find Cur_K and Val_K's of next index entry. */
+/* If eq is true next values must be equal to last ones up to Nval. */
+/* Returns false if Ok, true if there are no more (equal) values. */
+/***********************************************************************/
+bool XINDEX::NextVal(bool eq)
+ {
+ int n, neq = Nk + 1, curk;
+ PXCOL kcp;
+
+ if (Cur_K == Num_K)
+ return true;
+ else
+ curk = ++Cur_K;
+
+ for (n = Nk, kcp = To_LastCol; kcp; n--, kcp = kcp->Previous) {
+ if (kcp->Kof) {
+ if (curk == kcp->Kof[kcp->Val_K + 1])
+ neq = n;
+
+ } else {
+#ifdef _DEBUG
+ assert(curk == kcp->Val_K + 1);
+#endif // _DEBUG
+ neq = n;
+ } // endif Kof
+
+#ifdef _DEBUG
+ assert(kcp->Val_K < kcp->Ndf);
+#endif // _DEBUG
+
+ // If this is not a break...
+ if (neq > n)
+ break; // all previous columns have same value
+
+ curk = ++kcp->Val_K; // This is a break, get new column value
+ } // endfor kcp
+
+ // Return true if no more values or, in case of "equal" values,
+ // if the last used column value has changed
+ return (Cur_K == Num_K || (eq && neq <= Nval));
+ } // end of NextVal
+
+/***********************************************************************/
+/* XINDEX: Fetch a physical or logical record. */
+/***********************************************************************/
+int XINDEX::Fetch(PGLOBAL g)
+ {
+ int n;
+ PXCOL kp;
+
+ if (Num_K == 0)
+ return -1; // means end of file
+
+ /*********************************************************************/
+ /* Table read through a sorted index. */
+ /*********************************************************************/
+ switch (Op) {
+ case OP_NEXT: // Read next
+ if (NextVal(false))
+ return -1; // End of indexed file
+
+ break;
+ case OP_FIRST: // Read first
+ for (Cur_K = 0, kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = 0;
+
+ Op = OP_NEXT;
+ break;
+ case OP_SAME: // Read next same
+ // Logically the key values should be the same as before
+#if defined(TRACE)
+ printf("looking for next same value\n");
+#endif // TRACE
+
+ if (NextVal(true)) {
+ Op = OP_EQ;
+ return -2; // no more equal values
+ } // endif NextVal
+
+ break;
+ case OP_NXTDIF: // Read next dif
+// while (!NextVal(true)) ;
+
+// if (Cur_K >= Num_K)
+// return -1; // End of indexed file
+ if (NextValDif())
+ return -1; // End of indexed file
+
+ break;
+ case OP_FSTDIF: // Read first diff
+ for (Cur_K = 0, kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = 0;
+
+ Op = (Mul || Nval < Nk) ? OP_NXTDIF : OP_NEXT;
+ break;
+ default: // Should be OP_EQ
+// if (Tbxp->Key_Rank < 0) {
+ /***************************************************************/
+ /* Look for the first key equal to the link column values */
+ /* and return its rank whithin the index table. */
+ /***************************************************************/
+ for (n = 0, kp = To_KeyCol; n < Nval && kp; n++, kp = kp->Next)
+ if (kp->InitFind(g, To_Vals[n]))
+ return -1; // No more constant values
+
+ Nth++;
+
+#if defined(TRACE)
+ printf("Fetch: Looking for new value\n");
+#endif // TRACE
+ Cur_K = FastFind(Nval);
+
+ if (Cur_K >= Num_K)
+ /*************************************************************/
+ /* Rank not whithin index table, signal record not found. */
+ /*************************************************************/
+ return -2;
+
+ else if (Mul || Nval < Nk)
+ Op = OP_SAME;
+
+ } // endswitch Op
+
+ /*********************************************************************/
+ /* If rank is equal to stored rank, record is already there. */
+ /*********************************************************************/
+ if (Cur_K == Old_K)
+ return -3; // Means record already there
+ else
+ Old_K = Cur_K; // Store rank of newly read record
+
+ /*********************************************************************/
+ /* Return the position of the required record. */
+ /*********************************************************************/
+ return (Incr) ? Cur_K * Incr : To_Rec[Cur_K];
+ } // end of Fetch
+
+/***********************************************************************/
+/* FastFind: Returns the index of matching record in a join using an */
+/* optimized algorithm based on dichotomie and optimized comparing. */
+/***********************************************************************/
+int XINDEX::FastFind(int nv)
+ {
+ register int curk, sup, inf, i= 0, k, n = 2;
+ register PXCOL kp, kcp;
+
+ assert((int)nv == Nval);
+
+ if (Nblk && Op == OP_EQ) {
+ // Look in block values to find in which block to search
+ sup = Nblk;
+ inf = -1;
+
+ while (n && sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = To_KeyCol->CompBval(i);
+
+ if (n < 0)
+ sup = i;
+ else
+ inf = i;
+
+ } // endwhile
+
+ if (inf < 0)
+ return Num_K;
+
+// i = inf;
+ inf *= Sblk;
+
+ if ((sup = inf + Sblk) > To_KeyCol->Ndf)
+ sup = To_KeyCol->Ndf;
+
+ inf--;
+ } else {
+ inf = -1;
+ sup = To_KeyCol->Ndf;
+ } // endif Nblk
+
+ for (k = 0, kcp = To_KeyCol; kcp; kcp = kcp->Next) {
+ while (sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = kcp->CompVal(i);
+
+ if (n < 0)
+ sup = i;
+ else if (n > 0)
+ inf = i;
+ else
+ break;
+
+ } // endwhile
+
+ if (n) {
+ if (Op != OP_EQ) {
+ // Currently only OP_GT or OP_GE
+ kcp->Val_K = curk = sup;
+
+ // Check for value changes in previous key parts
+ for (kp = kcp->Previous; kp; kp = kp->Previous)
+ if (kp->Kof && curk < kp->Kof[kp->Val_K + 1])
+ break;
+ else
+ curk = ++kp->Val_K;
+
+ n = 0;
+ } // endif Op
+
+ break;
+ } // endif n
+
+ kcp->Val_K = i;
+
+ if (++k == Nval) {
+ if (Op == OP_GT) { // n is always 0
+ curk = ++kcp->Val_K; // Increment value by 1
+
+ // Check for value changes in previous key parts
+ for (kp = kcp->Previous; kp; kp = kp->Previous)
+ if (kp->Kof && curk < kp->Kof[kp->Val_K + 1])
+ break; // Not changed
+ else
+ curk = ++kp->Val_K;
+
+ } // endif Op
+
+ break; // So kcp remains pointing the last tested block
+ } // endif k
+
+ if (kcp->Kof) {
+ inf = kcp->Kof[i] - 1;
+ sup = kcp->Kof[i + 1];
+ } else {
+ inf = i - 1;
+ sup = i + 1;
+ } // endif Kof
+
+ } // endfor k, kcp
+
+ if (n) {
+ // Record not found
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Val_K = kcp->Ndf; // Not a valid value
+
+ return Num_K;
+ } // endif n
+
+ for (curk = kcp->Val_K; kcp; kcp = kcp->Next) {
+ kcp->Val_K = curk;
+ curk = (kcp->Kof) ? kcp->Kof[kcp->Val_K] : kcp->Val_K;
+ } // endfor kcp
+
+ return curk;
+ } // end of FastFind
+
+/* -------------------------- XINDXS Class --------------------------- */
+
+/***********************************************************************/
+/* XINDXS public constructor. */
+/***********************************************************************/
+XINDXS::XINDXS(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp)
+ : XINDEX(tdbp, xdp, pxp, cp, xp)
+ {
+ Srtd = To_Cols[0]->GetOpt() < 0; // ?????
+ } // end of XINDXS constructor
+
+/***********************************************************************/
+/* XINDXS compare routine for C Quick/Insertion sort. */
+/***********************************************************************/
+int XINDXS::Qcompare(int *i1, int *i2)
+ {
+#ifdef DEBTRACE
+ num_comp++;
+#endif
+
+ return To_KeyCol->Compare(*i1, *i2);
+ } // end of Qcompare
+
+/***********************************************************************/
+/* Range: Tell how many records exist for given value(s): */
+/* If limit=0 return range for these values. */
+/* If limit=1 return the start of range. */
+/* If limit=2 return the end of range. */
+/***********************************************************************/
+int XINDXS::Range(PGLOBAL g, int limit, bool incl)
+ {
+ int k, n = 0;
+ PXOB xp = To_Vals[0];
+ PXCOL kp = To_KeyCol;
+ OPVAL op = Op;
+
+ switch (limit) {
+ case 1: Op = (incl) ? OP_GE : OP_GT; break;
+ case 2: Op = (incl) ? OP_GT : OP_GE; break;
+ default: Op = OP_EQ;
+ } // endswitch limit
+
+ /*********************************************************************/
+ /* Currently only range of constant values with an EQ operator is */
+ /* implemented. Find the number of rows for each given values. */
+ /*********************************************************************/
+ if (xp->GetType() == TYPE_CONST) {
+ kp->Valp->SetValue_pval(xp->GetValue(), !kp->Prefix);
+
+ if ((k = FastFind(Nval)) < Num_K)
+ if (limit)
+ n = (Mul) ? k : kp->Val_K;
+ else
+ n = (Mul) ? Pof[kp->Val_K + 1] - k : 1;
+
+ } else {
+ strcpy(g->Message, MSG(RANGE_NO_JOIN));
+ n = -1; // Logical error
+ } // endif'f Type
+
+ Op = op;
+ return n;
+ } // end of Range
+
+/***********************************************************************/
+/* Return the size of the group (equal values) of the current value. */
+/***********************************************************************/
+int XINDXS::GroupSize(void)
+ {
+#if defined(_DEBUG)
+ assert(To_KeyCol->Val_K >= 0 && To_KeyCol->Val_K < Ndif);
+#endif // _DEBUG
+ return (Pof) ? Pof[To_KeyCol->Val_K + 1] - Pof[To_KeyCol->Val_K]
+ : 1;
+ } // end of GroupSize
+
+/***********************************************************************/
+/* XINDXS: Find Cur_K and Val_K of next index value. */
+/* If b is true next value must be equal to last one. */
+/* Returns false if Ok, true if there are no more (equal) values. */
+/***********************************************************************/
+bool XINDXS::NextVal(bool eq)
+ {
+ bool rc;
+
+ if (To_KeyCol->Val_K == Ndif)
+ return true;
+
+ if (Mul) {
+ int limit = Pof[To_KeyCol->Val_K + 1];
+
+#ifdef _DEBUG
+ assert(Cur_K < limit);
+ assert(To_KeyCol->Val_K < Ndif);
+#endif // _DEBUG
+
+ if (++Cur_K == limit) {
+ To_KeyCol->Val_K++;
+ rc = (eq || limit == Num_K);
+ } else
+ rc = false;
+
+ } else
+ rc = (To_KeyCol->Val_K = ++Cur_K) == Num_K || eq;
+
+ return rc;
+ } // end of NextVal
+
+/***********************************************************************/
+/* XINDXS: Fetch a physical or logical record. */
+/***********************************************************************/
+int XINDXS::Fetch(PGLOBAL g)
+ {
+ if (Num_K == 0)
+ return -1; // means end of file
+
+ /*********************************************************************/
+ /* Table read through a sorted index. */
+ /*********************************************************************/
+ switch (Op) {
+ case OP_NEXT: // Read next
+ if (NextVal(false))
+ return -1; // End of indexed file
+
+ break;
+ case OP_FIRST: // Read first
+ To_KeyCol->Val_K = Cur_K = 0;
+ Op = OP_NEXT;
+ break;
+ case OP_SAME: // Read next same
+#if defined(TRACE)
+// printf("looking for next same value\n");
+#endif // TRACE
+
+ if (!Mul || NextVal(true)) {
+ Op = OP_EQ;
+ return -2; // No more equal values
+ } // endif Mul
+
+ break;
+ case OP_NXTDIF: // Read next dif
+ if (++To_KeyCol->Val_K == Ndif)
+ return -1; // End of indexed file
+
+ Cur_K = Pof[To_KeyCol->Val_K];
+ break;
+ case OP_FSTDIF: // Read first diff
+ To_KeyCol->Val_K = Cur_K = 0;
+ Op = (Mul) ? OP_NXTDIF : OP_NEXT;
+ break;
+ default: // Should OP_EQ
+ /*****************************************************************/
+ /* Look for the first key equal to the link column values */
+ /* and return its rank whithin the index table. */
+ /*****************************************************************/
+ if (To_KeyCol->InitFind(g, To_Vals[0]))
+ return -1; // No more constant values
+ else
+ Nth++;
+
+#if defined(TRACE)
+ printf("Fetch: Looking for new value\n");
+#endif // TRACE
+
+ Cur_K = FastFind(1);
+
+ if (Cur_K >= Num_K)
+ // Rank not whithin index table, signal record not found
+ return -2;
+ else if (Mul)
+ Op = OP_SAME;
+
+ } // endswitch Op
+
+ /*********************************************************************/
+ /* If rank is equal to stored rank, record is already there. */
+ /*********************************************************************/
+ if (Cur_K == Old_K)
+ return -3; // Means record already there
+ else
+ Old_K = Cur_K; // Store rank of newly read record
+
+ /*********************************************************************/
+ /* Return the position of the required record. */
+ /*********************************************************************/
+ return (Incr) ? Cur_K * Incr : To_Rec[Cur_K];
+ } // end of Fetch
+
+/***********************************************************************/
+/* FastFind: Returns the index of matching indexed record using an */
+/* optimized algorithm based on dichotomie and optimized comparing. */
+/***********************************************************************/
+int XINDXS::FastFind(int nk)
+ {
+ register int sup, inf, i= 0, n = 2;
+ register PXCOL kcp = To_KeyCol;
+
+ if (Nblk && Op == OP_EQ) {
+ // Look in block values to find in which block to search
+ sup = Nblk;
+ inf = -1;
+
+ while (n && sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = kcp->CompBval(i);
+
+ if (n < 0)
+ sup = i;
+ else
+ inf = i;
+
+ } // endwhile
+
+ if (inf < 0)
+ return Num_K;
+
+// i = inf;
+ inf *= Sblk;
+
+ if ((sup = inf + Sblk) > Ndif)
+ sup = Ndif;
+
+ inf--;
+ } else {
+ inf = -1;
+ sup = Ndif;
+ } // endif Nblk
+
+ while (sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = kcp->CompVal(i);
+
+ if (n < 0)
+ sup = i;
+ else if (n > 0)
+ inf = i;
+ else
+ break;
+
+ } // endwhile
+
+ if (!n && Op == OP_GT) {
+ ++i;
+ } else if (n && Op != OP_EQ) {
+ // Currently only OP_GT or OP_GE
+ i = sup;
+ n = 0;
+ } // endif sup
+
+ kcp->Val_K = i; // Used by FillValue
+ return ((n) ? Num_K : (Mul) ? Pof[i] : i);
+ } // end of FastFind
+
+/* -------------------------- XLOAD Class --------------------------- */
+
+/***********************************************************************/
+/* XLOAD constructor. */
+/***********************************************************************/
+XLOAD::XLOAD(void)
+ {
+ Hfile = INVALID_HANDLE_VALUE;
+#if defined(WIN32) && defined(XMAP)
+ ViewBase = NULL;
+#endif // WIN32 && XMAP
+} // end of XLOAD constructor
+
+/***********************************************************************/
+/* Close the index huge file. */
+/***********************************************************************/
+void XLOAD::Close(void)
+ {
+ if (Hfile != INVALID_HANDLE_VALUE) {
+ CloseFileHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ } // endif Hfile
+
+#if defined(WIN32) && defined(XMAP)
+ if (ViewBase) {
+ if (!UnmapViewOfFile(ViewBase))
+ printf("Error %d closing Viewmap\n", GetLastError());
+
+ ViewBase = NULL;
+ } // endif ViewBase
+#endif // WIN32 && XMAP
+
+ } // end of Close
+
+/* --------------------------- XFILE Class --------------------------- */
+
+/***********************************************************************/
+/* XFILE constructor. */
+/***********************************************************************/
+XFILE::XFILE(void) : XLOAD()
+ {
+ Xfile = NULL;
+#if defined(XMAP) && !defined(WIN32)
+ Mmp = NULL;
+#endif // XMAP && !WIN32
+ } // end of XFILE constructor
+
+/***********************************************************************/
+/* Xopen function: opens a file using native API's. */
+/***********************************************************************/
+bool XFILE::Open(PGLOBAL g, char *filename, MODE mode)
+ {
+ char *pmod;
+
+ /*********************************************************************/
+ /* Open the index file according to mode. */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ: pmod = "rb"; break;
+ case MODE_WRITE: pmod = "wb"; break;
+ case MODE_INSERT: pmod = "ab"; break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
+ return true;
+ } // endswitch mode
+
+ if (!(Xfile= global_fopen(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, pmod))) {
+#if defined(TRACE)
+ printf("Open: %s\n", g->Message);
+#endif // TRACE
+ return true;
+ } // endif Xfile
+
+ if (mode == MODE_INSERT)
+ /*******************************************************************/
+ /* Position the cursor at end of file so ftell returns file size. */
+ /*******************************************************************/
+ if (fseek(Xfile, 0, SEEK_END)) {
+ sprintf(g->Message, MSG(FUNC_ERRNO), "Xseek", errno);
+ return true;
+ } // endif
+
+ return false;
+ } // end of Open
+
+/***********************************************************************/
+/* Tell were we are in the index file. */
+/***********************************************************************/
+bool XFILE::GetOff(int& low, int& high, PIXDEF sxp)
+ {
+ if (sxp) {
+ low = sxp->GetOffset() + sxp->GetSize();
+ high = 0;
+ } else
+ low = high = 0;
+
+ return false;
+ } // end of GetOff
+
+/***********************************************************************/
+/* Tell were we are in a huge file. */
+/***********************************************************************/
+bool XFILE::Seek(PGLOBAL g, int low, int high, int origin)
+ {
+#if defined(_DEBUG)
+ assert(high == 0);
+#endif // !_DEBUG
+
+ if (fseek(Xfile, low, origin)) {
+ sprintf(g->Message, MSG(FUNC_ERRNO), "Xseek", errno);
+ return true;
+ } // endif
+
+//ftell(Xfile);
+ return false;
+ } // end of Seek
+
+/***********************************************************************/
+/* Read from the index file. */
+/***********************************************************************/
+bool XFILE::Read(PGLOBAL g, void *buf, int n, int size)
+ {
+ if (fread(buf, size, n, Xfile) != (size_t)n) {
+ sprintf(g->Message, MSG(XFILE_READERR), errno);
+ return true;
+ } // endif size
+
+ return false;
+ } // end of Read
+
+/***********************************************************************/
+/* Write on index file, set rc and return the number of bytes written */
+/***********************************************************************/
+int XFILE::Write(PGLOBAL g, void *buf, int n, int size, bool& rc)
+ {
+ int niw = (int)fwrite(buf, size, n, Xfile);
+
+ if (niw != n) {
+ sprintf(g->Message, MSG(XFILE_WRITERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ return niw * size;
+ } // end of Write
+
+/***********************************************************************/
+/* Close the index huge file. */
+/***********************************************************************/
+void XFILE::Close(void)
+ {
+ XLOAD::Close();
+
+ if (Xfile) {
+ fclose(Xfile);
+ Xfile = NULL;
+ } // endif Xfile
+
+#if defined(XMAP) && !defined(WIN32)
+ if (Mmp) {
+ CloseMemMap(Mmp->memory, Mmp->lenL);
+ Mmp = NULL;
+ } // endif Mmp
+#endif // XMAP
+ } // end of Close
+
+#if defined(XMAP)
+#if defined(WIN32)
+/***********************************************************************/
+/* Return a pointer to the segment at the given offset and size. */
+/***********************************************************************/
+void *XFILE::FileView(PGLOBAL g, char *fn, int loff, int hoff, int size)
+ {
+ SYSTEM_INFO SysInfo; // system information; used to get the granularity
+ char *pData; // pointer to the data
+ int iViewDelta; // the offset into the view where the data shows up
+ HANDLE hMapFile; // handle for the file's memory-mapped region
+ DWORD offset; // Where to start in the index file
+ DWORD FileMapSize; // size of the file mapping
+ DWORD FileMapStart; // where in the file to start the file map view
+ DWORD Granularity; // system allocation granularity
+ DWORD MapViewSize; // the size of the view
+
+ if (hoff) {
+ strcpy(g->Message, MSG(HI_OFFSET_ERR));
+ return NULL;
+ } // endf hoff
+
+ // Open the file in mode read only
+ Hfile = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ char buf[512];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_READ, fn);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(g->Message, buf);
+ return NULL;
+ } // endif Hfile
+
+ // Get the system allocation granularity.
+ GetSystemInfo(&SysInfo);
+ Granularity = SysInfo.dwAllocationGranularity;
+
+ // The offset is a 64 byte integer low part
+ offset = loff;
+
+ // To calculate where to start the file mapping, round down the
+ // offset of the data into the file to the nearest multiple of the
+ // system allocation granularity.
+ FileMapStart = (offset / Granularity) * Granularity;
+
+ // Calculate the size of the file mapping view.
+ MapViewSize = offset % Granularity + (DWORD)size;
+
+ // How large will the file-mapping object be?
+ FileMapSize = offset + (DWORD)size;
+
+ // The data of interest isn't at the beginning of the
+ // view, so determine how far into the view to set the pointer.
+ iViewDelta = (int)(offset - FileMapStart);
+
+ // Check that the index file is more than large enough
+ if (GetFileSize(Hfile, NULL) < FileMapSize) {
+ strcpy(g->Message, MSG(XFILE_TOO_SMALL));
+ return NULL;
+ } // endif FileSize
+
+ // Create a file-mapping object for the file.
+ hMapFile = CreateFileMapping( Hfile, // current file handle
+ NULL, // default security
+ PAGE_READONLY, // permission
+ 0, // size, high
+ FileMapSize, // size, low
+ NULL); // name
+
+ if (hMapFile == NULL) {
+ sprintf(g->Message, MSG(HANDLE_IS_NULL), "hMapFile", GetLastError() );
+ return NULL;
+ } // endif hMapFile
+
+ // Map the view.
+ ViewBase = MapViewOfFile(hMapFile, // handle to mapping object
+ FILE_MAP_READ, // access mode
+ 0, // high-order 32 bits of file offset
+ FileMapStart, // low-order 32 bits of file offset
+ MapViewSize); // number of bytes to map
+
+ if (!ViewBase) {
+ sprintf(g->Message, MSG(HANDLE_IS_NULL), "ViewBase", GetLastError());
+ return NULL;
+ } // endif ViewBase
+
+ // Calculate the pointer to the data.
+ pData = (char *)ViewBase + iViewDelta;
+
+ // close the file-mapping object
+ if (!CloseHandle(hMapFile))
+ sprintf(g->Message, MSG(MAP_OBJ_ERR), GetLastError());
+
+ // close the file itself
+ if (!CloseHandle(Hfile))
+ sprintf(g->Message, MSG(FILE_CLOSE_ERR), GetLastError());
+ else
+ Hfile = INVALID_HANDLE_VALUE;
+
+ return pData;
+ } // end of FileView
+#else // not WIN32
+ /*********************************************************************/
+ /* Map the entire index. */
+ /*********************************************************************/
+void *XFILE::FileView(PGLOBAL g, char *fn, int loff, int hoff, int size)
+ {
+ HANDLE h;
+
+ Mmp = (MMP)PlugSubAlloc(g, NULL, sizeof(MEMMAP));
+ h = CreateFileMap(g, filename, Mmp, MODE_READ, false);
+
+ if (h == INVALID_HANDLE_VALUE || (!Mmp->lenH && !Mmp->lenL)) {
+ if (!(*g->Message))
+ strcpy(g->Message, MSG(FILE_MAP_ERR));
+
+ CloseFileHandle(h); // Not used anymore
+ return NULL; // No saved values
+ } // endif h
+
+ CloseFileHandle(h); // Not used anymore
+ return Mmp->memory;
+ } // end of FileView
+#endif // not WIN32
+#endif // XMAP
+
+/* -------------------------- XHUGE Class --------------------------- */
+
+/***********************************************************************/
+/* Xopen function: opens a file using native API's. */
+/***********************************************************************/
+bool XHUGE::Open(PGLOBAL g, char *filename, MODE mode)
+ {
+ if (Hfile != INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, MSG(FILE_OPEN_YET), filename);
+ return true;
+ } // endif
+
+#if defined(TRACE)
+ printf( "Xopen: filename=%s mode=%d\n", filename, mode);
+#endif // TRACE
+
+#if defined(WIN32)
+ DWORD rc, access, share, creation;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ access = GENERIC_READ;
+ share = FILE_SHARE_READ;
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_WRITE:
+ access = GENERIC_WRITE;
+ share = 0;
+ creation = CREATE_ALWAYS;
+ break;
+ case MODE_INSERT:
+ access = GENERIC_WRITE;
+ share = 0;
+ creation = OPEN_EXISTING;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
+ return true;
+ } // endswitch
+
+ Hfile = CreateFile(filename, access, share, NULL, creation,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ return true;
+ } // endif Hfile
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ " access=%p share=%p creation=%d handle=%p fn=%s\n",
+ access, share, creation, Hfile, filename);
+#endif
+
+ if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode we must position the cursor at end of file. */
+ /*******************************************************************/
+ LONG high = 0;
+ DWORD drc, rc = SetFilePointer(Hfile, 0, &high, FILE_END);
+
+ if (rc == INVALID_SET_FILE_POINTER && (drc = GetLastError()) != NO_ERROR) {
+ sprintf(g->Message, MSG(ERROR_IN_SFP), drc);
+ CloseHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ return true;
+ } // endif
+
+ } // endif Mode
+
+#else // UNIX
+ int rc = 0;
+ int oflag = O_LARGEFILE; // Enable file size > 2G
+ mode_t pmod = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ oflag |= O_RDONLY;
+ break;
+ case MODE_WRITE:
+ oflag |= O_WRONLY | O_CREAT;
+ pmod = S_IREAD | S_IWRITE;
+ break;
+ case MODE_INSERT:
+ oflag |= (O_WRONLY | O_APPEND);
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
+ return true;
+ } // endswitch
+
+ Hfile= global_open(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, oflag, pmod);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = errno;
+#if defined(TRACE)
+ printf("Open: %s\n", g->Message);
+#endif // TRACE
+ return true;
+ } // endif Hfile
+
+#if defined(TRACE)
+ printf(" rc=%d oflag=%p mode=%d handle=%d fn=%s\n",
+ rc, oflag, mode, Hfile, filename);
+#endif // TRACE
+
+#endif // UNIX
+
+ return false;
+ } // end of Open
+
+/***********************************************************************/
+/* Get the offset of this index in the index file. */
+/***********************************************************************/
+bool XHUGE::GetOff(int& low, int& high, PIXDEF sxp)
+ {
+ if (!sxp) {
+ low = 0;
+ high = 0;
+ return false;
+ } // endif sxp
+
+#if defined(WIN32)
+ LARGE_INTEGER ln;
+
+ ln.LowPart = sxp->GetOffset();
+ ln.HighPart = sxp->GetOffhigh();
+ ln.QuadPart += (LONGLONG)sxp->GetSize();
+ low = ln.LowPart;
+ high = (int)ln.HighPart;
+#else // UNIX
+#define G4 ((off64_t)0x100 * (off64_t)0x1000000)
+#if defined(TRACE)
+ printf("in GetOff...\n");
+#endif // TRACE
+ off64_t pos;
+
+ pos = (off64_t)sxp->GetOffset() + (off64_t)sxp->GetOffhigh() * G4;
+ pos += (off64_t)sxp->GetSize();
+ low = (int)(pos % G4);
+ high = (int)(pos / G4);
+#endif // UNIX
+ return false;
+ } // end of GetOff
+
+/***********************************************************************/
+/* Go to position in a huge file. */
+/***********************************************************************/
+bool XHUGE::Seek(PGLOBAL g, int low, int high, int origin)
+ {
+#if defined(WIN32)
+ LONG hi = high;
+ DWORD rc = SetFilePointer(Hfile, low, &hi, origin);
+
+ if (rc == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
+ sprintf(g->Message, MSG(FUNC_ERROR), "Xseek");
+ return true;
+ } // endif
+
+#else // UNIX
+ off64_t pos = (off64_t)low
+ + (off64_t)high * ((off64_t)0x100 * (off64_t)0x1000000);
+
+ if (lseek64(Hfile, pos, origin) < 0) {
+ sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
+#if defined(TRACE)
+ printf("lseek64 error %d\n", errno);
+#endif // TRACE
+ return true;
+ } // endif lseek64
+
+#if defined(TRACE)
+ printf("Seek: low=%d high=%d\n", low, high);
+#endif // TRACE
+#endif // UNIX
+
+ return false;
+ } // end of Seek
+
+/***********************************************************************/
+/* Read from a huge index file. */
+/***********************************************************************/
+bool XHUGE::Read(PGLOBAL g, void *buf, int n, int size)
+ {
+ bool rc = false;
+
+#if defined(WIN32)
+ bool brc;
+ DWORD nbr, count = (DWORD)(n * size);
+
+ brc = ReadFile(Hfile, buf, count, &nbr, NULL);
+
+ if (brc) {
+ if (nbr != count) {
+ strcpy(g->Message, MSG(EOF_INDEX_FILE));
+ rc = true;
+ } // endif nbr
+
+ } else {
+ char *buf[256];
+ DWORD drc = GetLastError();
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(READ_ERROR), "index file", buf);
+ rc = true;
+ } // endif brc
+#else // UNIX
+ ssize_t count = (ssize_t)(n * size);
+
+#if defined(TRACE)
+ printf("Hfile=%d n=%d size=%d count=%d\n", Hfile, n, size, count);
+#endif // TRACE
+
+ if (read(Hfile, buf, count) != count) {
+ sprintf(g->Message, MSG(READ_ERROR), "Index file", strerror(errno));
+#if defined(TRACE)
+ printf("read error %d\n", errno);
+#endif // TRACE
+ rc = true;
+ } // endif nbr
+#endif // UNIX
+
+ return rc;
+ } // end of Read
+
+/***********************************************************************/
+/* Write on a huge index file. */
+/***********************************************************************/
+int XHUGE::Write(PGLOBAL g, void *buf, int n, int size, bool& rc)
+ {
+#if defined(WIN32)
+ bool brc;
+ DWORD nbw, count = (DWORD)n * (DWORD) size;
+
+ brc = WriteFile(Hfile, buf, count, &nbw, NULL);
+
+ if (!brc) {
+ char msg[256];
+ DWORD drc = GetLastError();
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)msg, sizeof(msg), NULL);
+ sprintf(g->Message, MSG(WRITING_ERROR), "index file", msg);
+ rc = true;
+ } // endif size
+
+ return (int)nbw;
+#else // UNIX
+ ssize_t nbw;
+ size_t count = (size_t)n * (size_t)size;
+
+ nbw = write(Hfile, buf, count);
+
+ if (nbw != (signed)count) {
+ sprintf(g->Message, MSG(WRITING_ERROR),
+ "index file", strerror(errno));
+ rc = true;
+ } // endif nbw
+
+ return (int)nbw;
+#endif // UNIX
+ } // end of Write
+
+#if defined(XMAP)
+#if defined(WIN32)
+/***********************************************************************/
+/* Return a pointer to the segment at the given offset and size. */
+/***********************************************************************/
+void *XHUGE::FileView(PGLOBAL g, char *fn, int loff, int hoff, int size)
+ {
+ SYSTEM_INFO SysInfo; // system information; used to get the granularity
+ char *pData; // pointer to the data
+ int iViewDelta; // the offset into the view where the data shows up
+ HANDLE hMapFile; // handle for the file's memory-mapped region
+ LARGE_INTEGER lint; // a utility holder
+ __int64 offset; // Where to start in the index file
+ __int64 FileMapSize; // size of the file mapping
+ __int64 FileMapStart; // where in the file to start the file map view
+ __int64 Granularity; // system allocation granularity
+ DWORD MapViewSize; // the size of the view
+
+ // Open the file in mode read only
+ if (Open(g, fn, MODE_READ))
+ return NULL;
+
+ // Get the system allocation granularity.
+ GetSystemInfo(&SysInfo);
+ Granularity = (__int64)SysInfo.dwAllocationGranularity;
+
+ // Calculate the offset as a 64 byte integer
+ lint.LowPart = loff;
+ lint.HighPart = hoff;
+ offset = lint.QuadPart;
+
+ // To calculate where to start the file mapping, round down the
+ // offset of the data into the file to the nearest multiple of the
+ // system allocation granularity.
+ FileMapStart = (offset / Granularity) * Granularity;
+
+ // Calculate the size of the file mapping view.
+ MapViewSize = (DWORD)(offset % Granularity) + (DWORD)size;
+
+ // How large will the file-mapping object be?
+ FileMapSize = offset + (__int64)size;
+
+ // The data of interest isn't at the beginning of the
+ // view, so determine how far into the view to set the pointer.
+ iViewDelta = (int)(offset - FileMapStart);
+
+ // Let the user know that the index file is more than large enough
+ lint.LowPart = GetFileSize(Hfile, (LPDWORD)&lint.HighPart);
+
+ // Prepare the low and high parts of the size.
+ lint.QuadPart = FileMapSize;
+
+ // Create a file-mapping object for the file.
+ hMapFile = CreateFileMapping( Hfile, // current file handle
+ NULL, // default security
+ PAGE_READONLY, // permission
+ lint.HighPart, // size, high
+ lint.LowPart, // size, low
+ NULL); // name
+
+ if (hMapFile == NULL) {
+ sprintf(g->Message, MSG(HANDLE_IS_NULL), "hMapFile", GetLastError());
+ return NULL;
+ } // endif hMapFile
+
+ // Prepare the low and high parts of the starting file offset.
+ lint.QuadPart = FileMapStart;
+
+ // Map the view.
+ ViewBase = MapViewOfFile(hMapFile, // handle to mapping object
+ FILE_MAP_READ, // access mode
+ lint.HighPart, // high-order 32 bits of file offset
+ lint.LowPart, // low-order 32 bits of file offset
+ MapViewSize); // number of bytes to map
+
+ if (!ViewBase) {
+ sprintf(g->Message, MSG(HANDLE_IS_NULL), "ViewBase", GetLastError());
+ return NULL;
+ } // endif ViewBase
+
+ // Calculate the pointer to the data.
+ pData = (char *)ViewBase + iViewDelta;
+
+ // close the file-mapping object
+ if (!CloseHandle(hMapFile))
+ sprintf(g->Message, MSG(MAP_OBJ_ERR), GetLastError());
+
+ // close the file itself
+ if (!CloseHandle(Hfile))
+ sprintf(g->Message, MSG(FILE_CLOSE_ERR), GetLastError());
+ else
+ Hfile = INVALID_HANDLE_VALUE;
+
+ return pData;
+ } // end of FileView
+#else // not WIN32
+/***********************************************************************/
+/* Don't know whether this is possible for non Windows OS. */
+/***********************************************************************/
+void *XHUGE::FileView(PGLOBAL g, char *fn,
+ int loff, int hoff, int size)
+ {
+ strcpy(g->Message, MSG(NO_PART_MAP));
+ return NULL;
+ } // end of FileView
+#endif // not WIN32
+#endif // XMAP
+
+/* -------------------------- XXROW Class --------------------------- */
+
+/***********************************************************************/
+/* XXROW Public Constructor. */
+/***********************************************************************/
+XXROW::XXROW(PTDBDOS tdbp) : XXBASE(tdbp, false)
+ {
+ Tdbp = tdbp;
+ Valp = NULL;
+ } // end of XXROW constructor
+
+/***********************************************************************/
+/* XXROW Reset: re-initialize a Kindex block. */
+/***********************************************************************/
+void XXROW::Reset(void)
+ {
+#if defined(_DEBUG)
+ assert(Tdbp->GetLink()); // This a join index
+#endif // _DEBUG
+ } // end of Reset
+
+/***********************************************************************/
+/* Init: Open and Initialize a Key Index. */
+/***********************************************************************/
+bool XXROW::Init(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Table will be accessed through an index table. */
+ /* To_Link should not be NULL. */
+ /*********************************************************************/
+ if (!Tdbp->GetLink() || Tbxp->GetKnum() != 1)
+ return true;
+
+ if ((*Tdbp->GetLink())->GetResultType() != TYPE_INT) {
+ strcpy(g->Message, MSG(TYPE_MISMATCH));
+ return true;
+ } else
+ Valp = (*Tdbp->GetLink())->GetValue();
+
+ if ((Num_K = Tbxp->Cardinality(g)) < 0)
+ return true; // Not a fixed file
+
+ /*********************************************************************/
+ /* The entire table is indexed, no need to construct the index. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+ return false;
+ } // end of Init
+
+/***********************************************************************/
+/* RANGE: Tell how many record exist in a given value range. */
+/***********************************************************************/
+int XXROW::Range(PGLOBAL g, int limit, bool incl)
+ {
+ int n = Valp->GetIntValue();
+
+ switch (limit) {
+ case 1: n += ((incl) ? 0 : 1); break;
+ case 2: n += ((incl) ? 1 : 0); break;
+ default: n = 1;
+ } // endswitch limit
+
+ return n;
+ } // end of Range
+
+/***********************************************************************/
+/* XXROW: Fetch a physical or logical record. */
+/***********************************************************************/
+int XXROW::Fetch(PGLOBAL g)
+ {
+ if (Num_K == 0)
+ return -1; // means end of file
+
+ /*********************************************************************/
+ /* Look for a key equal to the link column of previous table, */
+ /* and return its rank whithin the index table. */
+ /*********************************************************************/
+ Cur_K = FastFind(1);
+
+ if (Cur_K >= Num_K)
+ /*******************************************************************/
+ /* Rank not whithin index table, signal record not found. */
+ /*******************************************************************/
+ return -2; // Means record not found
+
+ /*********************************************************************/
+ /* If rank is equal to stored rank, record is already there. */
+ /*********************************************************************/
+ if (Cur_K == Old_K)
+ return -3; // Means record already there
+ else
+ Old_K = Cur_K; // Store rank of newly read record
+
+ return Cur_K;
+ } // end of Fetch
+
+/***********************************************************************/
+/* FastFind: Returns the index of matching record in a join. */
+/***********************************************************************/
+int XXROW::FastFind(int nk)
+ {
+ int n = Valp->GetIntValue();
+
+ if (n < 0)
+ return (Op == OP_EQ) ? (-1) : 0;
+ else if (n > Num_K)
+ return Num_K;
+ else
+ return (Op == OP_GT) ? n : (n - 1);
+
+ } // end of FastFind
+
+/* ------------------------- KXYCOL Classes -------------------------- */
+
+/***********************************************************************/
+/* KXYCOL public constructor. */
+/***********************************************************************/
+KXYCOL::KXYCOL(PKXBASE kp) : To_Keys(Keys.Memp),
+ Kof((CPINT&)Koff.Memp), To_Bkeys(Bkeys.Memp)
+ {
+ Next = NULL;
+ Previous = NULL;
+ Kxp = kp;
+ Colp = NULL;
+ IsSorted = false;
+ Asc = true;
+ Keys = Nmblk;
+ Kblp = NULL;
+ Bkeys = Nmblk;
+ Blkp = NULL;
+ Valp = NULL;
+ Klen = 0;
+ Kprec = 0;
+ Type = TYPE_ERROR;
+ Prefix = false;
+ Koff = Nmblk;
+ Val_K = 0;
+ Ndf = 0;
+ Mxs = 0;
+ } // end of KXYCOL constructor
+
+/***********************************************************************/
+/* KXYCOL Init: initialize and allocate storage. */
+/* Key length kln can be smaller than column length for CHAR columns. */
+/***********************************************************************/
+bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln)
+ {
+ int len = colp->GetLength(), prec = colp->GetPrecision();
+
+ if (kln && len > kln && colp->GetResultType() == TYPE_STRING) {
+ len = kln;
+ Prefix = true;
+ } // endif kln
+
+#ifdef DEBTRACE
+ htrc("KCOL(%p) Init: col=%s n=%d type=%d sm=%d\n",
+ this, colp->GetName(), n, colp->GetResultType(), sm);
+#endif
+
+ // Allocate the Value object used when moving items
+ Type = colp->GetResultType();
+
+ if (!(Valp = AllocateValue(g, Type, len, colp->GetPrecision())))
+ return true;
+
+ Klen = Valp->GetClen();
+ Keys.Size = n * Klen;
+
+ if (!PlgDBalloc(g, NULL, Keys)) {
+ sprintf(g->Message, MSG(KEY_ALLOC_ERROR), Klen, n);
+ return true; // Error
+ } // endif
+
+ // Allocate the Valblock. The last parameter is to have rows filled
+ // by blanks (if true) or keep the zero ending char (if false).
+ // Currently we set it to true to be compatible with QRY blocks,
+ // and the one before last is to enable length/type checking, set to
+ // true if not a prefix key.
+ Kblp = AllocValBlock(g, To_Keys, Type, n, len, prec, !Prefix, true);
+ Asc = sm; // Sort mode: Asc=true Desc=false
+ Ndf = n;
+
+ // Store this information to avoid sorting when already done
+ if (Asc)
+ IsSorted = colp->GetOpt() < 0;
+
+//MayHaveNulls = colp->HasNulls();
+ return false;
+ } // end of Init
+
+#if defined(XMAP)
+/***********************************************************************/
+/* KXYCOL MapInit: initialize and address storage. */
+/* Key length kln can be smaller than column length for CHAR columns. */
+/***********************************************************************/
+BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m)
+ {
+ int len = colp->GetLength(), prec = colp->GetPrecision();
+
+ if (n[3] && colp->GetLength() > n[3]
+ && colp->GetResultType() == TYPE_STRING) {
+ len = n[3];
+ Prefix = true;
+ } // endif kln
+
+ Type = colp->GetResultType();
+
+#ifdef DEBTRACE
+ htrc("MapInit(%p): colp=%p type=%d n=%d len=%d m=%p\n",
+ this, colp, Type, n[0], len, m);
+#endif
+
+ // Allocate the Value object used when moving items
+ Valp = AllocateValue(g, Type, len, prec, NULL);
+ Klen = Valp->GetClen();
+
+ if (n[2]) {
+ Bkeys.Size = n[2] * Klen;
+ Bkeys.Memp = m;
+ Bkeys.Sub = true;
+
+ // Allocate the Valblk containing initial block key values
+ Blkp = AllocValBlock(g, To_Bkeys, Type, n[2], len, prec, true, true);
+ } // endif nb
+
+ Keys.Size = n[0] * Klen;
+ Keys.Memp = m + Bkeys.Size;
+ Keys.Sub = true;
+
+ // Allocate the Valblock. Last two parameters are to have rows filled
+ // by blanks (if true) or keep the zero ending char (if false).
+ // Currently we set it to true to be compatible with QRY blocks,
+ // and last one to enable type checking (no conversion).
+ Kblp = AllocValBlock(g, To_Keys, Type, n[0], len, prec, true, true);
+
+ if (n[1]) {
+ Koff.Size = n[1] * sizeof(int);
+ Koff.Memp = m + Bkeys.Size + Keys.Size;
+ Koff.Sub = true;
+ } // endif n[1]
+
+ Ndf = n[0];
+ IsSorted = colp->GetOpt() < 0;
+ return m + Bkeys.Size + Keys.Size + Koff.Size;
+ } // end of MapInit
+#endif // XMAP
+
+/***********************************************************************/
+/* Allocate the offset block used by intermediate key columns. */
+/***********************************************************************/
+int *KXYCOL::MakeOffset(PGLOBAL g, int n)
+ {
+ if (!Kof) {
+ // Calculate the initial size of the offset
+ Koff.Size = (n + 1) * sizeof(int);
+
+ // Allocate the required memory
+ if (!PlgDBalloc(g, NULL, Koff)) {
+ strcpy(g->Message, MSG(KEY_ALLOC_ERR));
+ return NULL; // Error
+ } // endif
+
+ } else if (n) {
+ // This is a reallocation call
+ PlgDBrealloc(g, NULL, Koff, (n + 1) * sizeof(int));
+ } else
+ PlgDBfree(Koff);
+
+ return (int*)Kof;
+ } // end of MakeOffset
+
+/***********************************************************************/
+/* Make a front end array of key values that are the first value of */
+/* each blocks (of size n). This to reduce paging in FastFind. */
+/***********************************************************************/
+bool KXYCOL::MakeBlockArray(PGLOBAL g, int nb, int size)
+ {
+ int i, k;
+
+ // Calculate the size of the block array in the index
+ Bkeys.Size = nb * Klen;
+
+ // Allocate the required memory
+ if (!PlgDBalloc(g, NULL, Bkeys)) {
+ sprintf(g->Message, MSG(KEY_ALLOC_ERROR), Klen, nb);
+ return true; // Error
+ } // endif
+
+ // Allocate the Valblk used to contains initial block key values
+ Blkp = AllocValBlock(g, To_Bkeys, Type, nb, Klen, Kprec);
+
+ // Populate the array with values
+ for (i = k = 0; i < nb; i++, k += size)
+ Blkp->SetValue(Kblp, i, k);
+
+ return false;
+ } // end of MakeBlockArray
+
+/***********************************************************************/
+/* KXYCOL SetValue: read column value for nth array element. */
+/***********************************************************************/
+void KXYCOL::SetValue(PCOL colp, int i)
+ {
+#if defined(_DEBUG)
+ assert (Kblp != NULL);
+#endif
+
+ Kblp->SetValue(colp->GetValue(), (int)i);
+ } // end of SetValue
+
+/***********************************************************************/
+/* InitFind: initialize finding the rank of column value in index. */
+/***********************************************************************/
+bool KXYCOL::InitFind(PGLOBAL g, PXOB xp)
+ {
+ if (xp->GetType() == TYPE_CONST) {
+ if (Kxp->Nth)
+ return true;
+
+ Valp->SetValue_pval(xp->GetValue(), !Prefix);
+ } else {
+ xp->Reset();
+ xp->Eval(g);
+ Valp->SetValue_pval(xp->GetValue(), false);
+// Valp->SetValue_pval(xp->GetValue(), !Prefix);
+ } // endif Type
+
+ return false;
+ } // end of InitFind
+
+/***********************************************************************/
+/* InitBinFind: initialize Value to the value pointed by vp. */
+/***********************************************************************/
+void KXYCOL::InitBinFind(void *vp)
+ {
+ Valp->SetBinValue(vp);
+ } // end of InitBinFind
+
+/***********************************************************************/
+/* KXYCOL FillValue: called by COLBLK::Eval when a column value is */
+/* already in storage in the corresponding KXYCOL. */
+/***********************************************************************/
+void KXYCOL::FillValue(PVAL valp)
+ {
+ valp->SetValue_pvblk(Kblp, Val_K);
+ } // end of FillValue
+
+/***********************************************************************/
+/* KXYCOL: Compare routine for one numeric value. */
+/***********************************************************************/
+int KXYCOL::Compare(int i1, int i2)
+ {
+ // Do the actual comparison between values.
+ register int k = (int)Kblp->CompVal((int)i1, (int)i2);
+
+#ifdef DEBUG2
+ htrc("Compare done result=%d\n", k);
+#endif
+
+ return (Asc) ? k : -k;
+ } // end of Compare
+
+/***********************************************************************/
+/* KXYCOL: Compare the ith key to the stored Value. */
+/***********************************************************************/
+int KXYCOL::CompVal(int i)
+ {
+ // Do the actual comparison between numerical values.
+#ifdef DEBUG2
+ register int k = (int)Kblp->CompVal(Valp, (int)i);
+
+ htrc("Compare done result=%d\n", k);
+ return k;
+#endif
+ return (int)Kblp->CompVal(Valp, (int)i);
+ } // end of CompVal
+
+/***********************************************************************/
+/* KXYCOL: Compare the key to the stored block value. */
+/***********************************************************************/
+int KXYCOL::CompBval(int i)
+ {
+ // Do the actual comparison between key values.
+ return (int)Blkp->CompVal(Valp, (int)i);
+ } // end of CompBval
+
+/***********************************************************************/
+/* KXYCOL ReAlloc: ReAlloc To_Data if it is not suballocated. */
+/***********************************************************************/
+void KXYCOL::ReAlloc(PGLOBAL g, int n)
+ {
+ PlgDBrealloc(g, NULL, Keys, n * Klen);
+ Kblp->ReAlloc(To_Keys, n);
+ Ndf = n;
+ } // end of ReAlloc
+
+/***********************************************************************/
+/* KXYCOL FreeData: Free To_Keys if it is not suballocated. */
+/***********************************************************************/
+void KXYCOL::FreeData(void)
+ {
+ PlgDBfree(Keys);
+ Kblp = NULL;
+ PlgDBfree(Bkeys);
+ Blkp = NULL;
+ PlgDBfree(Koff);
+ Ndf = 0;
+ } // end of FreeData
diff --git a/storage/connect/xindex.h b/storage/connect/xindex.h
index c60ec7ab743..d0e55f488dc 100644
--- a/storage/connect/xindex.h
+++ b/storage/connect/xindex.h
@@ -1,487 +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__
+/*************** 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__
diff --git a/storage/connect/xobject.cpp b/storage/connect/xobject.cpp
index db4c4a6980e..093fe8cb103 100644
--- a/storage/connect/xobject.cpp
+++ b/storage/connect/xobject.cpp
@@ -1,178 +1,178 @@
-/************ Xobject C++ Functions Source Code File (.CPP) ************/
-/* Name: XOBJECT.CPP Version 2.2 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
-/* */
-/* This file contains base XOBJECT class functions. */
-/* Also here is the implementation of the CONSTANT class. */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include 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 "xobject.h"
-
-/***********************************************************************/
-/* Macro definitions. */
-/***********************************************************************/
-#if defined(_DEBUG) || defined(DEBTRACE)
-#define ASSERT(B) assert(B);
-#else
-#define ASSERT(B)
-#endif
-
-/***********************************************************************/
-/* The one and only needed void object. */
-/***********************************************************************/
-XVOID Xvoid;
-PXOB const pXVOID = &Xvoid; // Pointer used by other classes
-
-/* ------------------------- Class XOBJECT --------------------------- */
-
-/***********************************************************************/
-/* GetCharValue: returns the Result value as a char string. */
-/* Using GetCharValue provides no conversion from numeric types. */
-/***********************************************************************/
-PSZ XOBJECT::GetCharValue(void)
- {
- ASSERT(Value)
- return Value->GetCharValue();
- } // end of GetCharValue()
-
-/***********************************************************************/
-/* GetShortValue: returns the Result value as a short integer. */
-/***********************************************************************/
-short XOBJECT::GetShortValue(void)
- {
- ASSERT(Value)
- return Value->GetShortValue();
- } // end of GetShortValue
-
-/***********************************************************************/
-/* GetIntValue: returns the Result value as a int integer. */
-/***********************************************************************/
-int XOBJECT::GetIntValue(void)
- {
- ASSERT(Value)
- return Value->GetIntValue();
- } // end of GetIntValue
-
-/***********************************************************************/
-/* GetFloatValue: returns the Result value as a double float. */
-/***********************************************************************/
-double XOBJECT::GetFloatValue(void)
- {
- ASSERT(Value)
- return Value->GetFloatValue();
- } // end of GetFloatValue
-
-/* ------------------------- Class CONSTANT -------------------------- */
-
-/***********************************************************************/
-/* CONSTANT public constructor. */
-/***********************************************************************/
-CONSTANT::CONSTANT(PGLOBAL g, void *value, short type)
- {
- if (!(Value = AllocateValue(g, value, (int)type)))
- longjmp(g->jumper[g->jump_level], TYPE_CONST);
-
- Constant = true;
- } // end of CONSTANT constructor
-
-/***********************************************************************/
-/* CONSTANT public constructor. */
-/***********************************************************************/
-CONSTANT::CONSTANT(PGLOBAL g, int n)
- {
- if (!(Value = AllocateValue(g, &n, TYPE_INT)))
- longjmp(g->jumper[g->jump_level], TYPE_CONST);
-
- Constant = true;
- } // end of CONSTANT constructor
-
-/***********************************************************************/
-/* GetLengthEx: returns an evaluation of the constant string length. */
-/* Note: When converting from token to string, length has to be */
-/* specified but we need the domain length, not the value length. */
-/***********************************************************************/
-int CONSTANT::GetLengthEx(void)
- {
- return Value->GetValLen();
- } // end of GetLengthEx
-
-/***********************************************************************/
-/* Convert a constant to the given type. */
-/***********************************************************************/
-void CONSTANT::Convert(PGLOBAL g, int newtype)
- {
- if (Value->GetType() != newtype)
- if (!(Value = AllocateValue(g, Value, newtype)))
- longjmp(g->jumper[g->jump_level], TYPE_CONST);
-
- } // end of Convert
-
-/***********************************************************************/
-/* Compare: returns true if this object is equivalent to xp. */
-/***********************************************************************/
-bool CONSTANT::Compare(PXOB xp)
- {
- if (this == xp)
- return true;
- else if (xp->GetType() != TYPE_CONST)
- return false;
- else
- return Value->IsEqual(xp->GetValue(), true);
-
- } // end of Compare
-
-/***********************************************************************/
-/* Rephrase: temporary implementation used by PlugRephraseSQL. */
-/***********************************************************************/
-bool CONSTANT::Rephrase(PGLOBAL g, PSZ work)
- {
- switch (Value->GetType()) {
- case TYPE_STRING:
- sprintf(work + strlen(work), "'%s'", Value->GetCharValue());
- break;
- case TYPE_SHORT:
- sprintf(work + strlen(work), "%hd", Value->GetShortValue());
- break;
- case TYPE_INT:
- case TYPE_DATE:
- sprintf(work + strlen(work), "%d", Value->GetIntValue());
- break;
- case TYPE_FLOAT:
- sprintf(work + strlen(work), "%lf", Value->GetFloatValue());
- break;
- default:
- sprintf(g->Message, MSG(BAD_CONST_TYPE), Value->GetType());
- return false;
- } // endswitch
-
- return false;
- } // end of Rephrase
-
-/***********************************************************************/
-/* Make file output of a constant object. */
-/***********************************************************************/
-void CONSTANT::Print(PGLOBAL g, FILE *f, uint n)
- {
- Value->Print(g, f, n);
- } /* end of Print */
-
-/***********************************************************************/
-/* Make string output of a constant object. */
-/***********************************************************************/
-void CONSTANT::Print(PGLOBAL g, char *ps, uint z)
- {
- Value->Print(g, ps, z);
- } /* end of Print */
+/************ Xobject C++ Functions Source Code File (.CPP) ************/
+/* Name: XOBJECT.CPP Version 2.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
+/* */
+/* This file contains base XOBJECT class functions. */
+/* Also here is the implementation of the CONSTANT class. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include 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 "xobject.h"
+
+/***********************************************************************/
+/* Macro definitions. */
+/***********************************************************************/
+#if defined(_DEBUG) || defined(DEBTRACE)
+#define ASSERT(B) assert(B);
+#else
+#define ASSERT(B)
+#endif
+
+/***********************************************************************/
+/* The one and only needed void object. */
+/***********************************************************************/
+XVOID Xvoid;
+PXOB const pXVOID = &Xvoid; // Pointer used by other classes
+
+/* ------------------------- Class XOBJECT --------------------------- */
+
+/***********************************************************************/
+/* GetCharValue: returns the Result value as a char string. */
+/* Using GetCharValue provides no conversion from numeric types. */
+/***********************************************************************/
+PSZ XOBJECT::GetCharValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetCharValue();
+ } // end of GetCharValue()
+
+/***********************************************************************/
+/* GetShortValue: returns the Result value as a short integer. */
+/***********************************************************************/
+short XOBJECT::GetShortValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetShortValue();
+ } // end of GetShortValue
+
+/***********************************************************************/
+/* GetIntValue: returns the Result value as a int integer. */
+/***********************************************************************/
+int XOBJECT::GetIntValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetIntValue();
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* GetFloatValue: returns the Result value as a double float. */
+/***********************************************************************/
+double XOBJECT::GetFloatValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetFloatValue();
+ } // end of GetFloatValue
+
+/* ------------------------- Class CONSTANT -------------------------- */
+
+/***********************************************************************/
+/* CONSTANT public constructor. */
+/***********************************************************************/
+CONSTANT::CONSTANT(PGLOBAL g, void *value, short type)
+ {
+ if (!(Value = AllocateValue(g, value, (int)type)))
+ longjmp(g->jumper[g->jump_level], TYPE_CONST);
+
+ Constant = true;
+ } // end of CONSTANT constructor
+
+/***********************************************************************/
+/* CONSTANT public constructor. */
+/***********************************************************************/
+CONSTANT::CONSTANT(PGLOBAL g, int n)
+ {
+ if (!(Value = AllocateValue(g, &n, TYPE_INT)))
+ longjmp(g->jumper[g->jump_level], TYPE_CONST);
+
+ Constant = true;
+ } // end of CONSTANT constructor
+
+/***********************************************************************/
+/* GetLengthEx: returns an evaluation of the constant string length. */
+/* Note: When converting from token to string, length has to be */
+/* specified but we need the domain length, not the value length. */
+/***********************************************************************/
+int CONSTANT::GetLengthEx(void)
+ {
+ return Value->GetValLen();
+ } // end of GetLengthEx
+
+/***********************************************************************/
+/* Convert a constant to the given type. */
+/***********************************************************************/
+void CONSTANT::Convert(PGLOBAL g, int newtype)
+ {
+ if (Value->GetType() != newtype)
+ if (!(Value = AllocateValue(g, Value, newtype)))
+ longjmp(g->jumper[g->jump_level], TYPE_CONST);
+
+ } // end of Convert
+
+/***********************************************************************/
+/* Compare: returns true if this object is equivalent to xp. */
+/***********************************************************************/
+bool CONSTANT::Compare(PXOB xp)
+ {
+ if (this == xp)
+ return true;
+ else if (xp->GetType() != TYPE_CONST)
+ return false;
+ else
+ return Value->IsEqual(xp->GetValue(), true);
+
+ } // end of Compare
+
+/***********************************************************************/
+/* Rephrase: temporary implementation used by PlugRephraseSQL. */
+/***********************************************************************/
+bool CONSTANT::Rephrase(PGLOBAL g, PSZ work)
+ {
+ switch (Value->GetType()) {
+ case TYPE_STRING:
+ sprintf(work + strlen(work), "'%s'", Value->GetCharValue());
+ break;
+ case TYPE_SHORT:
+ sprintf(work + strlen(work), "%hd", Value->GetShortValue());
+ break;
+ case TYPE_INT:
+ case TYPE_DATE:
+ sprintf(work + strlen(work), "%d", Value->GetIntValue());
+ break;
+ case TYPE_FLOAT:
+ sprintf(work + strlen(work), "%lf", Value->GetFloatValue());
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_CONST_TYPE), Value->GetType());
+ return false;
+ } // endswitch
+
+ return false;
+ } // end of Rephrase
+
+/***********************************************************************/
+/* Make file output of a constant object. */
+/***********************************************************************/
+void CONSTANT::Print(PGLOBAL g, FILE *f, uint n)
+ {
+ Value->Print(g, f, n);
+ } /* end of Print */
+
+/***********************************************************************/
+/* Make string output of a constant object. */
+/***********************************************************************/
+void CONSTANT::Print(PGLOBAL g, char *ps, uint z)
+ {
+ Value->Print(g, ps, z);
+ } /* end of Print */
diff --git a/storage/connect/xobject.h b/storage/connect/xobject.h
index c713d92249f..7b4a444b295 100644
--- a/storage/connect/xobject.h
+++ b/storage/connect/xobject.h
@@ -1,136 +1,136 @@
-/*************** Xobject H Declares Source Code File (.H) **************/
-/* Name: XOBJECT.H Version 2.3 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
-/* */
-/* This file contains the XOBJECT and derived classes declares. */
-/***********************************************************************/
-
-#ifndef __XOBJECT__H
-#define __XOBJECT__H
-
-/***********************************************************************/
-/* Include required application header files */
-/* block.h is header containing Block global declarations. */
-/***********************************************************************/
-#include "block.h"
-#include "value.h"
-
-/***********************************************************************/
-/* Types used in some class definitions. */
-/***********************************************************************/
-typedef struct _tabdesc *PTABD; // For friend setting
-
-/***********************************************************************/
-/* The pointer to the one and only needed void object. */
-/***********************************************************************/
-extern PXOB const pXVOID;
-
-/***********************************************************************/
-/* Class XOBJECT is the base class for all classes that can be used */
-/* in evaluation operations: FILTER, EXPRESSION, SCALF, FNC, COLBLK, */
-/* SELECT, FILTER as well as all the constant object types. */
-/***********************************************************************/
-class DllExport XOBJECT : public BLOCK {
- public:
- XOBJECT(void) {Value = NULL; Constant = false;}
-
- // Implementation
- PVAL GetValue(void) {return Value;}
- bool IsConstant(void) {return Constant;}
- virtual int GetType(void) {return TYPE_XOBJECT;}
- virtual int GetResultType(void) {return TYPE_VOID;}
- virtual int GetKey(void) {return 0;}
-#if defined(_DEBUG)
- virtual void SetKey(int k) {assert(false);}
-#else // !_DEBUG
- virtual void SetKey(int k) {} // Only defined for COLBLK
-#endif // !_DEBUG
- virtual int GetLength(void) = 0;
- virtual int GetLengthEx(void) = 0;
- virtual PSZ GetCharValue(void);
- virtual short GetShortValue(void);
- virtual int GetIntValue(void);
- virtual double GetFloatValue(void);
- virtual int GetPrecision(void) = 0;
-
- // Methods
- virtual void Reset(void) {}
- virtual bool Compare(PXOB) = 0;
- virtual bool Init(PGLOBAL) {return false;}
- virtual bool Eval(PGLOBAL) {return false;}
- virtual bool SetFormat(PGLOBAL, FORMAT&) = 0;
- virtual int CheckColumn(PGLOBAL, PSQL, PXOB &, int &) {return 0;}
- virtual int RefNum(PSQL) {return 0;}
- virtual void AddTdb(PSQL, PTDB *, int&) {}
- virtual PXOB SetSelect(PGLOBAL, PSQL, bool) {return this;}
- virtual PXOB CheckSubQuery(PGLOBAL, PSQL) {return this;}
- virtual bool CheckLocal(PTDB) {return true;}
- virtual int CheckSpcCol(PTDB, int) {return 2;}
- virtual bool CheckSort(PTDB) {return false;}
- virtual bool VerifyColumn(PTBX txp) {return false;}
- virtual bool VerifyTdb(PTDB& tdbp) {return false;}
- virtual bool IsColInside(PCOL colp) {return false;}
- virtual void MarkCol(ushort) {}
-
- protected:
- PVAL Value; // The current value of the object.
- bool Constant; // true for an object having a constant value.
- }; // end of class XOBJECT
-
-/***********************************************************************/
-/* Class XVOID: represent a void (null) object. */
-/* Used to represent a void parameter for count(*) or for a filter. */
-/***********************************************************************/
-class DllExport XVOID : public XOBJECT {
- public:
- XVOID(void) {Constant = true;}
-
- // Implementation
- virtual int GetType(void) {return TYPE_VOID;}
- virtual int GetLength(void) {return 0;}
- virtual int GetLengthEx(void) {return 0;}
- virtual PSZ GetCharValue(void) {return NULL;}
- virtual int GetIntValue(void) {return 0;}
- virtual double GetFloatValue(void) {return 0.0;}
- virtual int GetPrecision() {return 0;}
-
- // Methods
- virtual bool Compare(PXOB xp) {return xp->GetType() == TYPE_VOID;}
- virtual bool SetFormat(PGLOBAL, FORMAT&) {return true;}
- virtual int CheckSpcCol(PTDB, int) {return 0;}
- }; // end of class XVOID
-
-
-/***********************************************************************/
-/* Class CONSTANT: represents a constant XOBJECT of any value type. */
-/* Note that the CONSTANT class is a friend of the VALUE class; */
-/***********************************************************************/
-class DllExport CONSTANT : public XOBJECT {
- public:
- CONSTANT(PGLOBAL g, void *value, short type);
- CONSTANT(PGLOBAL g, int n);
- CONSTANT(PVAL valp) {Value = valp; Constant = true;}
-
- // Implementation
- virtual int GetType(void) {return TYPE_CONST;}
- virtual int GetResultType(void) {return Value->Type;}
- virtual int GetLength(void) {return Value->GetValLen();}
- virtual int GetPrecision() {return Value->GetValPrec();}
- virtual int GetLengthEx(void);
-
- // Methods
- virtual bool Compare(PXOB xp);
- virtual bool SetFormat(PGLOBAL g, FORMAT& fmt)
- {return Value->SetConstFormat(g, fmt);}
- virtual int CheckSpcCol(PTDB, int) {return 1;}
- void Convert(PGLOBAL g, int newtype);
- bool Rephrase(PGLOBAL g, PSZ work);
- void SetValue(PVAL vp) {Value = vp;}
- virtual bool VerifyColumn(PTBX txp) {return true;}
- virtual bool VerifyTdb(PTDB& tdbp) {return true;}
- virtual void Print(PGLOBAL g, FILE *, uint);
- virtual void Print(PGLOBAL g, char *, uint);
- }; // end of class CONSTANT
-
-#endif
+/*************** Xobject H Declares Source Code File (.H) **************/
+/* Name: XOBJECT.H Version 2.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2012 */
+/* */
+/* This file contains the XOBJECT and derived classes declares. */
+/***********************************************************************/
+
+#ifndef __XOBJECT__H
+#define __XOBJECT__H
+
+/***********************************************************************/
+/* Include required application header files */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#include "block.h"
+#include "value.h"
+
+/***********************************************************************/
+/* Types used in some class definitions. */
+/***********************************************************************/
+typedef struct _tabdesc *PTABD; // For friend setting
+
+/***********************************************************************/
+/* The pointer to the one and only needed void object. */
+/***********************************************************************/
+extern PXOB const pXVOID;
+
+/***********************************************************************/
+/* Class XOBJECT is the base class for all classes that can be used */
+/* in evaluation operations: FILTER, EXPRESSION, SCALF, FNC, COLBLK, */
+/* SELECT, FILTER as well as all the constant object types. */
+/***********************************************************************/
+class DllExport XOBJECT : public BLOCK {
+ public:
+ XOBJECT(void) {Value = NULL; Constant = false;}
+
+ // Implementation
+ PVAL GetValue(void) {return Value;}
+ bool IsConstant(void) {return Constant;}
+ virtual int GetType(void) {return TYPE_XOBJECT;}
+ virtual int GetResultType(void) {return TYPE_VOID;}
+ virtual int GetKey(void) {return 0;}
+#if defined(_DEBUG)
+ virtual void SetKey(int k) {assert(false);}
+#else // !_DEBUG
+ virtual void SetKey(int k) {} // Only defined for COLBLK
+#endif // !_DEBUG
+ virtual int GetLength(void) = 0;
+ virtual int GetLengthEx(void) = 0;
+ virtual PSZ GetCharValue(void);
+ virtual short GetShortValue(void);
+ virtual int GetIntValue(void);
+ virtual double GetFloatValue(void);
+ virtual int GetPrecision(void) = 0;
+
+ // Methods
+ virtual void Reset(void) {}
+ virtual bool Compare(PXOB) = 0;
+ virtual bool Init(PGLOBAL) {return false;}
+ virtual bool Eval(PGLOBAL) {return false;}
+ virtual bool SetFormat(PGLOBAL, FORMAT&) = 0;
+ virtual int CheckColumn(PGLOBAL, PSQL, PXOB &, int &) {return 0;}
+ virtual int RefNum(PSQL) {return 0;}
+ virtual void AddTdb(PSQL, PTDB *, int&) {}
+ virtual PXOB SetSelect(PGLOBAL, PSQL, bool) {return this;}
+ virtual PXOB CheckSubQuery(PGLOBAL, PSQL) {return this;}
+ virtual bool CheckLocal(PTDB) {return true;}
+ virtual int CheckSpcCol(PTDB, int) {return 2;}
+ virtual bool CheckSort(PTDB) {return false;}
+ virtual bool VerifyColumn(PTBX txp) {return false;}
+ virtual bool VerifyTdb(PTDB& tdbp) {return false;}
+ virtual bool IsColInside(PCOL colp) {return false;}
+ virtual void MarkCol(ushort) {}
+
+ protected:
+ PVAL Value; // The current value of the object.
+ bool Constant; // true for an object having a constant value.
+ }; // end of class XOBJECT
+
+/***********************************************************************/
+/* Class XVOID: represent a void (null) object. */
+/* Used to represent a void parameter for count(*) or for a filter. */
+/***********************************************************************/
+class DllExport XVOID : public XOBJECT {
+ public:
+ XVOID(void) {Constant = true;}
+
+ // Implementation
+ virtual int GetType(void) {return TYPE_VOID;}
+ virtual int GetLength(void) {return 0;}
+ virtual int GetLengthEx(void) {return 0;}
+ virtual PSZ GetCharValue(void) {return NULL;}
+ virtual int GetIntValue(void) {return 0;}
+ virtual double GetFloatValue(void) {return 0.0;}
+ virtual int GetPrecision() {return 0;}
+
+ // Methods
+ virtual bool Compare(PXOB xp) {return xp->GetType() == TYPE_VOID;}
+ virtual bool SetFormat(PGLOBAL, FORMAT&) {return true;}
+ virtual int CheckSpcCol(PTDB, int) {return 0;}
+ }; // end of class XVOID
+
+
+/***********************************************************************/
+/* Class CONSTANT: represents a constant XOBJECT of any value type. */
+/* Note that the CONSTANT class is a friend of the VALUE class; */
+/***********************************************************************/
+class DllExport CONSTANT : public XOBJECT {
+ public:
+ CONSTANT(PGLOBAL g, void *value, short type);
+ CONSTANT(PGLOBAL g, int n);
+ CONSTANT(PVAL valp) {Value = valp; Constant = true;}
+
+ // Implementation
+ virtual int GetType(void) {return TYPE_CONST;}
+ virtual int GetResultType(void) {return Value->Type;}
+ virtual int GetLength(void) {return Value->GetValLen();}
+ virtual int GetPrecision() {return Value->GetValPrec();}
+ virtual int GetLengthEx(void);
+
+ // Methods
+ virtual bool Compare(PXOB xp);
+ virtual bool SetFormat(PGLOBAL g, FORMAT& fmt)
+ {return Value->SetConstFormat(g, fmt);}
+ virtual int CheckSpcCol(PTDB, int) {return 1;}
+ void Convert(PGLOBAL g, int newtype);
+ bool Rephrase(PGLOBAL g, PSZ work);
+ void SetValue(PVAL vp) {Value = vp;}
+ virtual bool VerifyColumn(PTBX txp) {return true;}
+ virtual bool VerifyTdb(PTDB& tdbp) {return true;}
+ virtual void Print(PGLOBAL g, FILE *, uint);
+ virtual void Print(PGLOBAL g, char *, uint);
+ }; // end of class CONSTANT
+
+#endif
diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h
index 52b784d8b32..73af45c7e0a 100644
--- a/storage/connect/xtable.h
+++ b/storage/connect/xtable.h
@@ -1,201 +1,201 @@
-/**************** Table H Declares Source Code File (.H) ***************/
-/* Name: TABLE.H Version 2.2 */
-/* */
-/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */
-/* */
-/* This file contains the TBX, OPJOIN and TDB class definitions. */
-/***********************************************************************/
-#if !defined(TABLE_DEFINED)
-#define TABLE_DEFINED
-
-
-/***********************************************************************/
-/* Include required application header files */
-/* block.h is header containing Block global declarations. */
-/***********************************************************************/
-#include "assert.h"
-#include "block.h"
-
-//pedef class INDEXDEF *PIXDEF;
-typedef char *PFIL; // Specific to CONNECT
-
-/***********************************************************************/
-/* Definition of class TBX (pure virtual class for TDB and OPJOIN) */
-/***********************************************************************/
-class DllExport TBX: public BLOCK { // Base class for OPJOIN and TDB classes.
- public:
- // Constructors
- TBX(void);
- TBX(PTBX txp);
-
- // Implementation
- inline PTBX GetOrig(void) {return To_Orig;}
- inline TUSE GetUse(void) {return Use;}
- inline void SetUse(TUSE n) {Use = n;}
- inline PFIL GetFilter(void) {return To_Filter;}
- inline void SetOrig(PTBX txp) {To_Orig = txp;}
- inline void SetFilter(PFIL fp) {To_Filter = fp;}
-//inline JTYPE GetJtype(void) {return Jtype;}
-//inline void SetJtype(JTYPE jt) {Jtype = jt;}
-//inline PFIL GetNoleft(void) {return To_Noleft;}
-//inline void SetNoleft(PFIL fp) {To_Noleft = fp;}
-
- // Methods
- virtual bool IsSame(PTBX tp) {return tp == this;}
-//virtual bool Include(PTBX tbxp) = 0;
-//virtual bool CheckFilter(void) = 0;
- virtual int GetTdb_No(void) = 0; // Convenience during conversion
- virtual PTDB GetNext(void) = 0;
-//virtual int GetMaxSame(PGLOBAL) = 0;
- virtual int Cardinality(PGLOBAL) = 0;
- virtual int GetMaxSize(PGLOBAL) = 0;
- virtual int GetProgMax(PGLOBAL) = 0;
- virtual int GetProgCur(void) = 0;
- virtual int GetBadLines(void) {return 0;}
-//virtual bool IsJoin(void) = 0;
- virtual PTBX Copy(PTABS t) = 0;
-
- protected:
-//virtual void PrepareFilters(PGLOBAL g) = 0;
-
- protected:
- // Members
- PTBX To_Orig; // Pointer to original if it is a copy
- PFIL To_Filter;
-//PFIL To_Noleft; // To filter not involved in LEFT JOIN
-//JTYPE Jtype;
- TUSE Use;
- }; // end of class TBX
-
-/***********************************************************************/
-/* Definition of class TDB with all its method functions. */
-/***********************************************************************/
-class DllExport TDB: public TBX { // Table Descriptor Block.
- public:
- // Constructors
- TDB(PTABDEF tdp = NULL);
- TDB(PTDB tdbp);
-
- // Implementation
- static void SetTnum(int n) {Tnum = n;}
- inline LPCSTR GetName(void) {return Name;}
- inline PTABLE GetTable(void) {return To_Table;}
- inline PCOL GetColumns(void) {return Columns;}
- inline int GetDegree(void) {return Degree;}
- inline MODE GetMode(void) {return Mode;}
- inline void SetNext(PTDB tdbp) {Next = tdbp;}
- inline void SetName(LPCSTR name) {Name = name;}
- inline void SetTable(PTABLE tablep) {To_Table = tablep;}
- inline void SetColumns(PCOL colp) {Columns = colp;}
- inline void SetDegree(int degree) {Degree = degree;}
- inline void SetMode(MODE mode) {Mode = mode;}
-
- //Properties
- virtual int GetTdb_No(void) {return Tdb_No;}
- virtual PTDB GetNext(void) {return Next;}
- virtual PCATLG GetCat(void) {return NULL;}
-
- // Methods
- virtual AMT GetAmType(void) {return TYPE_AM_ERROR;}
- virtual bool GetBlockValues(PGLOBAL g) {return false;}
- virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;}
- virtual int RowNumber(PGLOBAL g, bool b = false);
- virtual bool IsReadOnly(void) {return true;}
- virtual PTDB Duplicate(PGLOBAL g) {return NULL;}
- virtual PTDB CopyOne(PTABS t) {return this;}
- virtual PTBX Copy(PTABS t);
- virtual void PrintAM(FILE *f, char *m)
- {fprintf(f, "%s AM(%d)\n", m, GetAmType());}
- virtual void Print(PGLOBAL g, FILE *f, uint n);
- virtual void Print(PGLOBAL g, char *ps, uint z);
-
- // Database pure virtual routines
- virtual PCOL ColDB(PGLOBAL g, PSZ name, int num) = 0;
- virtual void MarkDB(PGLOBAL, PTDB) = 0;
- virtual bool OpenDB(PGLOBAL) = 0;
- virtual int ReadDB(PGLOBAL) = 0;
- virtual int WriteDB(PGLOBAL) = 0;
- virtual int DeleteDB(PGLOBAL, int) = 0;
- virtual void CloseDB(PGLOBAL) = 0;
- virtual int CheckWrite(PGLOBAL g) {return 0;}
-
- // Database routines
- bool OpenTable(PGLOBAL g, PSQL sqlp, MODE mode);
- void CloseTable(PGLOBAL g);
-
- protected:
- // Members
- static int Tnum; // Used to generate Tdb_no's
- const int Tdb_No; // GetTdb_No() is always 0 for OPJOIN
- PTDB Next; // Next in linearized queries
- PTABLE To_Table; // Points to the XTAB object
- LPCSTR Name; // Table name
- PCOL Columns; // Points to the first column of the table
- MODE Mode; // 10 Read, 30 Update, 40 Insert, 50 Delete
- int Degree; // Number of columns
- }; // end of class TDB
-
-/***********************************************************************/
-/* This is the base class for all query tables (except decode). */
-/***********************************************************************/
-class DllExport TDBASE : public TDB {
- friend class INDEXDEF;
- friend class XINDEX;
- friend class XINDXS;
- public:
- // Constructor
- TDBASE(PTABDEF tdp = NULL);
- TDBASE(PTDBASE tdbp);
-
- // Implementation
- inline int GetKnum(void) {return Knum;}
- inline PTABDEF GetDef(void) {return To_Def;}
- inline PKXBASE GetKindex(void) {return To_Kindex;}
- inline PCOL GetSetCols(void) {return To_SetCols;}
- inline void SetSetCols(PCOL colp) {To_SetCols = colp;}
-
- // Properties
- void SetKindex(PKXBASE kxp);
- PCOL Key(int i) {return (To_Key_Col) ? To_Key_Col[i] : NULL;}
-
- // Methods
- virtual bool IsUsingTemp(PGLOBAL g) {return false;}
- virtual PCATLG GetCat(void);
- virtual PSZ GetPath(void);
- virtual void PrintAM(FILE *f, char *m);
- virtual RECFM GetFtype(void) {return RECFM_NAF;}
- virtual int GetAffectedRows(void) {return -1;}
- virtual int GetRecpos(void) = 0;
- virtual bool SetRecpos(PGLOBAL g, int recpos);
- virtual bool IsReadOnly(void) {return Read_Only;}
- virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);}
- virtual int GetProgCur(void) {return GetRecpos();}
- virtual PSZ GetFile(PGLOBAL g) {return "Not a file";}
- virtual int GetRemote(void) {return 0;}
- virtual void SetFile(PGLOBAL g, PSZ fn) {}
- virtual void ResetDB(void) {}
- virtual void ResetSize(void) {MaxSize = -1;}
- virtual void RestoreNrec(void) {}
- virtual int ResetTableOpt(PGLOBAL g, bool dox);
-
- // Database routines
- virtual PCOL ColDB(PGLOBAL g, PSZ name, int num);
- virtual PCOL MakeCol(PGLOBAL, PCOLDEF, PCOL, int)
- {assert(false); return NULL;}
- virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL colp);
- virtual PCOL InsertSpcBlk(PGLOBAL g, PCOLUMN cp);
- virtual void MarkDB(PGLOBAL g, PTDB tdb2);
-
- protected:
- // Members
- PTABDEF To_Def; // Points to catalog description block
- PXOB *To_Link; // Points to column of previous relations
- PCOL *To_Key_Col; // Points to key columns in current file
- PKXBASE To_Kindex; // Points to table key index
- PCOL To_SetCols; // Points to updated columns
- int MaxSize; // Max size in number of lines
- int Knum; // Size of key arrays
- bool Read_Only; // True for read only tables
- }; // end of class TDBASE
-
-#endif // TABLE_DEFINED
+/**************** Table H Declares Source Code File (.H) ***************/
+/* Name: TABLE.H Version 2.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */
+/* */
+/* This file contains the TBX, OPJOIN and TDB class definitions. */
+/***********************************************************************/
+#if !defined(TABLE_DEFINED)
+#define TABLE_DEFINED
+
+
+/***********************************************************************/
+/* Include required application header files */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#include "assert.h"
+#include "block.h"
+
+//pedef class INDEXDEF *PIXDEF;
+typedef char *PFIL; // Specific to CONNECT
+
+/***********************************************************************/
+/* Definition of class TBX (pure virtual class for TDB and OPJOIN) */
+/***********************************************************************/
+class DllExport TBX: public BLOCK { // Base class for OPJOIN and TDB classes.
+ public:
+ // Constructors
+ TBX(void);
+ TBX(PTBX txp);
+
+ // Implementation
+ inline PTBX GetOrig(void) {return To_Orig;}
+ inline TUSE GetUse(void) {return Use;}
+ inline void SetUse(TUSE n) {Use = n;}
+ inline PFIL GetFilter(void) {return To_Filter;}
+ inline void SetOrig(PTBX txp) {To_Orig = txp;}
+ inline void SetFilter(PFIL fp) {To_Filter = fp;}
+//inline JTYPE GetJtype(void) {return Jtype;}
+//inline void SetJtype(JTYPE jt) {Jtype = jt;}
+//inline PFIL GetNoleft(void) {return To_Noleft;}
+//inline void SetNoleft(PFIL fp) {To_Noleft = fp;}
+
+ // Methods
+ virtual bool IsSame(PTBX tp) {return tp == this;}
+//virtual bool Include(PTBX tbxp) = 0;
+//virtual bool CheckFilter(void) = 0;
+ virtual int GetTdb_No(void) = 0; // Convenience during conversion
+ virtual PTDB GetNext(void) = 0;
+//virtual int GetMaxSame(PGLOBAL) = 0;
+ virtual int Cardinality(PGLOBAL) = 0;
+ virtual int GetMaxSize(PGLOBAL) = 0;
+ virtual int GetProgMax(PGLOBAL) = 0;
+ virtual int GetProgCur(void) = 0;
+ virtual int GetBadLines(void) {return 0;}
+//virtual bool IsJoin(void) = 0;
+ virtual PTBX Copy(PTABS t) = 0;
+
+ protected:
+//virtual void PrepareFilters(PGLOBAL g) = 0;
+
+ protected:
+ // Members
+ PTBX To_Orig; // Pointer to original if it is a copy
+ PFIL To_Filter;
+//PFIL To_Noleft; // To filter not involved in LEFT JOIN
+//JTYPE Jtype;
+ TUSE Use;
+ }; // end of class TBX
+
+/***********************************************************************/
+/* Definition of class TDB with all its method functions. */
+/***********************************************************************/
+class DllExport TDB: public TBX { // Table Descriptor Block.
+ public:
+ // Constructors
+ TDB(PTABDEF tdp = NULL);
+ TDB(PTDB tdbp);
+
+ // Implementation
+ static void SetTnum(int n) {Tnum = n;}
+ inline LPCSTR GetName(void) {return Name;}
+ inline PTABLE GetTable(void) {return To_Table;}
+ inline PCOL GetColumns(void) {return Columns;}
+ inline int GetDegree(void) {return Degree;}
+ inline MODE GetMode(void) {return Mode;}
+ inline void SetNext(PTDB tdbp) {Next = tdbp;}
+ inline void SetName(LPCSTR name) {Name = name;}
+ inline void SetTable(PTABLE tablep) {To_Table = tablep;}
+ inline void SetColumns(PCOL colp) {Columns = colp;}
+ inline void SetDegree(int degree) {Degree = degree;}
+ inline void SetMode(MODE mode) {Mode = mode;}
+
+ //Properties
+ virtual int GetTdb_No(void) {return Tdb_No;}
+ virtual PTDB GetNext(void) {return Next;}
+ virtual PCATLG GetCat(void) {return NULL;}
+
+ // Methods
+ virtual AMT GetAmType(void) {return TYPE_AM_ERROR;}
+ virtual bool GetBlockValues(PGLOBAL g) {return false;}
+ virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;}
+ virtual int RowNumber(PGLOBAL g, bool b = false);
+ virtual bool IsReadOnly(void) {return true;}
+ virtual PTDB Duplicate(PGLOBAL g) {return NULL;}
+ virtual PTDB CopyOne(PTABS t) {return this;}
+ virtual PTBX Copy(PTABS t);
+ virtual void PrintAM(FILE *f, char *m)
+ {fprintf(f, "%s AM(%d)\n", m, GetAmType());}
+ virtual void Print(PGLOBAL g, FILE *f, uint n);
+ virtual void Print(PGLOBAL g, char *ps, uint z);
+
+ // Database pure virtual routines
+ virtual PCOL ColDB(PGLOBAL g, PSZ name, int num) = 0;
+ virtual void MarkDB(PGLOBAL, PTDB) = 0;
+ virtual bool OpenDB(PGLOBAL) = 0;
+ virtual int ReadDB(PGLOBAL) = 0;
+ virtual int WriteDB(PGLOBAL) = 0;
+ virtual int DeleteDB(PGLOBAL, int) = 0;
+ virtual void CloseDB(PGLOBAL) = 0;
+ virtual int CheckWrite(PGLOBAL g) {return 0;}
+
+ // Database routines
+ bool OpenTable(PGLOBAL g, PSQL sqlp, MODE mode);
+ void CloseTable(PGLOBAL g);
+
+ protected:
+ // Members
+ static int Tnum; // Used to generate Tdb_no's
+ const int Tdb_No; // GetTdb_No() is always 0 for OPJOIN
+ PTDB Next; // Next in linearized queries
+ PTABLE To_Table; // Points to the XTAB object
+ LPCSTR Name; // Table name
+ PCOL Columns; // Points to the first column of the table
+ MODE Mode; // 10 Read, 30 Update, 40 Insert, 50 Delete
+ int Degree; // Number of columns
+ }; // end of class TDB
+
+/***********************************************************************/
+/* This is the base class for all query tables (except decode). */
+/***********************************************************************/
+class DllExport TDBASE : public TDB {
+ friend class INDEXDEF;
+ friend class XINDEX;
+ friend class XINDXS;
+ public:
+ // Constructor
+ TDBASE(PTABDEF tdp = NULL);
+ TDBASE(PTDBASE tdbp);
+
+ // Implementation
+ inline int GetKnum(void) {return Knum;}
+ inline PTABDEF GetDef(void) {return To_Def;}
+ inline PKXBASE GetKindex(void) {return To_Kindex;}
+ inline PCOL GetSetCols(void) {return To_SetCols;}
+ inline void SetSetCols(PCOL colp) {To_SetCols = colp;}
+
+ // Properties
+ void SetKindex(PKXBASE kxp);
+ PCOL Key(int i) {return (To_Key_Col) ? To_Key_Col[i] : NULL;}
+
+ // Methods
+ virtual bool IsUsingTemp(PGLOBAL g) {return false;}
+ virtual PCATLG GetCat(void);
+ virtual PSZ GetPath(void);
+ virtual void PrintAM(FILE *f, char *m);
+ virtual RECFM GetFtype(void) {return RECFM_NAF;}
+ virtual int GetAffectedRows(void) {return -1;}
+ virtual int GetRecpos(void) = 0;
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+ virtual bool IsReadOnly(void) {return Read_Only;}
+ virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);}
+ virtual int GetProgCur(void) {return GetRecpos();}
+ virtual PSZ GetFile(PGLOBAL g) {return "Not a file";}
+ virtual int GetRemote(void) {return 0;}
+ virtual void SetFile(PGLOBAL g, PSZ fn) {}
+ virtual void ResetDB(void) {}
+ virtual void ResetSize(void) {MaxSize = -1;}
+ virtual void RestoreNrec(void) {}
+ virtual int ResetTableOpt(PGLOBAL g, bool dox);
+
+ // Database routines
+ virtual PCOL ColDB(PGLOBAL g, PSZ name, int num);
+ virtual PCOL MakeCol(PGLOBAL, PCOLDEF, PCOL, int)
+ {assert(false); return NULL;}
+ virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL colp);
+ virtual PCOL InsertSpcBlk(PGLOBAL g, PCOLUMN cp);
+ virtual void MarkDB(PGLOBAL g, PTDB tdb2);
+
+ protected:
+ // Members
+ PTABDEF To_Def; // Points to catalog description block
+ PXOB *To_Link; // Points to column of previous relations
+ PCOL *To_Key_Col; // Points to key columns in current file
+ PKXBASE To_Kindex; // Points to table key index
+ PCOL To_SetCols; // Points to updated columns
+ int MaxSize; // Max size in number of lines
+ int Knum; // Size of key arrays
+ bool Read_Only; // True for read only tables
+ }; // end of class TDBASE
+
+#endif // TABLE_DEFINED