Commit e6b60ee5 authored by Olivier Bertrand's avatar Olivier Bertrand

Make BIN table files more flexible with new column format.

In particular enable to set length and endian setting.
This should solve all problems on IBM390s machines.
  modified:   storage/connect/ha_connect.cc
  modified:   storage/connect/tabfix.cpp
  modified:   storage/connect/tabfix.h

Make DBF tables to be usable in big-endian machines (test version)
  modified:   storage/connect/filamdbf.cpp

Ignore git files on storage/connect
  modified:   .gitignore
parent 3810fefc
...@@ -151,6 +151,7 @@ sql/mysqld ...@@ -151,6 +151,7 @@ sql/mysqld
sql/sql_builtin.cc sql/sql_builtin.cc
sql/sql_yacc.cc sql/sql_yacc.cc
sql/sql_yacc.h sql/sql_yacc.h
storage/connect/.*
storage/heap/hp_test1 storage/heap/hp_test1
storage/heap/hp_test2 storage/heap/hp_test2
storage/maria/aria_chk storage/maria/aria_chk
......
...@@ -74,16 +74,28 @@ typedef struct _dbfheader { ...@@ -74,16 +74,28 @@ typedef struct _dbfheader {
//uchar Dbfox :4; /* FoxPro if equal to 3 */ //uchar Dbfox :4; /* FoxPro if equal to 3 */
uchar Version; /* Version information flags */ uchar Version; /* Version information flags */
char Filedate[3]; /* date, YYMMDD, binary. YY=year-1900 */ char Filedate[3]; /* date, YYMMDD, binary. YY=year-1900 */
uint Records; /* records in the file */ private:
ushort Headlen; /* bytes in the header */ /* The following four members are stored in little-endian format on disk */
ushort Reclen; /* bytes in a record */ char m_RecordsBuf[4]; /* records in the file */
ushort Fields; /* Reserved but used to store fields */ char m_HeadlenBuf[2]; /* bytes in the header */
char m_ReclenBuf[2]; /* bytes in a record */
char m_FieldsBuf[2]; /* Reserved but used to store fields */
public:
char Incompleteflag; /* 01 if incomplete, else 00 */ char Incompleteflag; /* 01 if incomplete, else 00 */
char Encryptflag; /* 01 if encrypted, else 00 */ char Encryptflag; /* 01 if encrypted, else 00 */
char Reserved2[12]; /* for LAN use */ char Reserved2[12]; /* for LAN use */
char Mdxflag; /* 01 if production .mdx, else 00 */ char Mdxflag; /* 01 if production .mdx, else 00 */
char Language; /* Codepage */ char Language; /* Codepage */
char Reserved3[2]; char Reserved3[2];
uint Records(void) const {return uint4korr(m_RecordsBuf);}
ushort Headlen(void) const {return uint2korr(m_HeadlenBuf);}
ushort Reclen(void) const {return uint2korr(m_ReclenBuf);}
ushort Fields(void) const {return uint2korr(m_FieldsBuf);}
void SetHeadlen(ushort num) {int2store(m_HeadlenBuf, num);}
void SetReclen(ushort num) {int2store(m_ReclenBuf, num);}
void SetFields(ushort num) {int2store(m_FieldsBuf, num);}
} DBFHEADER; } DBFHEADER;
/****************************************************************************/ /****************************************************************************/
...@@ -115,7 +127,6 @@ typedef struct _descriptor { ...@@ -115,7 +127,6 @@ typedef struct _descriptor {
/* Side effects: */ /* Side effects: */
/* Moves file pointer to byte 32; fills buffer at buf with */ /* Moves file pointer to byte 32; fills buffer at buf with */
/* first 32 bytes of file. */ /* first 32 bytes of file. */
/* Converts numeric values to platform byte ordering (LE in file) */
/****************************************************************************/ /****************************************************************************/
static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf) static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf)
{ {
...@@ -143,13 +154,8 @@ static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf) ...@@ -143,13 +154,8 @@ static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf)
} else } else
strcpy(g->Message, MSG(DBASE_FILE)); strcpy(g->Message, MSG(DBASE_FILE));
// Convert numeric fields to have them in platform byte ordering
buf->Records = uint4korr(&buf->Records);
buf->Headlen = uint2korr(&buf->Headlen);
buf->Reclen = uint2korr(&buf->Reclen);
// Check last byte(s) of header // Check last byte(s) of header
if (fseek(file, buf->Headlen - dbc, SEEK_SET) != 0) { if (fseek(file, buf->Headlen() - dbc, SEEK_SET) != 0) {
sprintf(g->Message, MSG(BAD_HEADER), fn); sprintf(g->Message, MSG(BAD_HEADER), fn);
return RC_FX; return RC_FX;
} // endif fseek } // endif fseek
...@@ -169,7 +175,7 @@ static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf) ...@@ -169,7 +175,7 @@ static int dbfhead(PGLOBAL g, FILE *file, PSZ fn, DBFHEADER *buf)
} // endif endmark } // endif endmark
// Calculate here the number of fields while we have the dbc info // Calculate here the number of fields while we have the dbc info
buf->Fields = (buf->Headlen - dbc - 1) / 32; buf->SetFields((buf->Headlen() - dbc - 1) / 32);
fseek(file, HEADLEN, SEEK_SET); fseek(file, HEADLEN, SEEK_SET);
return rc; return rc;
} // end of dbfhead } // end of dbfhead
...@@ -225,7 +231,7 @@ PQRYRES DBFColumns(PGLOBAL g, char *dp, const char *fn, bool info) ...@@ -225,7 +231,7 @@ PQRYRES DBFColumns(PGLOBAL g, char *dp, const char *fn, bool info)
/************************************************************************/ /************************************************************************/
/* Allocate the structures used to refer to the result set. */ /* Allocate the structures used to refer to the result set. */
/************************************************************************/ /************************************************************************/
fields = mainhead.Fields; fields = mainhead.Fields();
} else } else
fields = 0; fields = 0;
...@@ -242,11 +248,11 @@ PQRYRES DBFColumns(PGLOBAL g, char *dp, const char *fn, bool info) ...@@ -242,11 +248,11 @@ PQRYRES DBFColumns(PGLOBAL g, char *dp, const char *fn, bool info)
if (trace) { if (trace) {
htrc("Structure of %s\n", filename); htrc("Structure of %s\n", filename);
htrc("headlen=%hd reclen=%hd degree=%d\n", htrc("headlen=%hd reclen=%hd degree=%d\n",
mainhead.Headlen, mainhead.Reclen, fields); mainhead.Headlen(), mainhead.Reclen(), fields);
htrc("flags(iem)=%d,%d,%d cp=%d\n", mainhead.Incompleteflag, htrc("flags(iem)=%d,%d,%d cp=%d\n", mainhead.Incompleteflag,
mainhead.Encryptflag, mainhead.Mdxflag, mainhead.Language); mainhead.Encryptflag, mainhead.Mdxflag, mainhead.Language);
htrc("%hd records, last changed %02d/%02d/%d\n", htrc("%hd records, last changed %02d/%02d/%d\n",
mainhead.Records, mainhead.Filedate[1], mainhead.Filedate[2], mainhead.Records(), mainhead.Filedate[1], mainhead.Filedate[2],
mainhead.Filedate[0] + (mainhead.Filedate[0] <= 30) ? 2000 : 1900); mainhead.Filedate[0] + (mainhead.Filedate[0] <= 30) ? 2000 : 1900);
htrc("Field Type Offset Len Dec Set Mdx\n"); htrc("Field Type Offset Len Dec Set Mdx\n");
} // endif trace } // endif trace
...@@ -404,13 +410,13 @@ int DBFBASE::ScanHeader(PGLOBAL g, PSZ fname, int lrecl, char *defpath) ...@@ -404,13 +410,13 @@ int DBFBASE::ScanHeader(PGLOBAL g, PSZ fname, int lrecl, char *defpath)
} else if (rc == RC_FX) } else if (rc == RC_FX)
return -1; return -1;
if ((int)header.Reclen != lrecl) { if ((int)header.Reclen() != lrecl) {
sprintf(g->Message, MSG(BAD_LRECL), lrecl, header.Reclen); sprintf(g->Message, MSG(BAD_LRECL), lrecl, header.Reclen());
return -1; return -1;
} // endif Lrecl } // endif Lrecl
Records = (int)header.Records; Records = (int)header.Records();
return (int)header.Headlen; return (int)header.Headlen();
} // end of ScanHeader } // end of ScanHeader
/* ---------------------------- Class DBFFAM ------------------------------ */ /* ---------------------------- Class DBFFAM ------------------------------ */
...@@ -571,8 +577,8 @@ bool DBFFAM::AllocateBuffer(PGLOBAL g) ...@@ -571,8 +577,8 @@ bool DBFFAM::AllocateBuffer(PGLOBAL g)
header->Filedate[0] = datm->tm_year - 100; header->Filedate[0] = datm->tm_year - 100;
header->Filedate[1] = datm->tm_mon + 1; header->Filedate[1] = datm->tm_mon + 1;
header->Filedate[2] = datm->tm_mday; header->Filedate[2] = datm->tm_mday;
int2store(&header->Headlen, hlen); header->SetHeadlen((ushort)hlen);
int2store(&header->Reclen, reclen); header->SetReclen((ushort)reclen);
descp = (DESCRIPTOR*)header; descp = (DESCRIPTOR*)header;
// Currently only standard Xbase types are supported // Currently only standard Xbase types are supported
...@@ -633,13 +639,13 @@ bool DBFFAM::AllocateBuffer(PGLOBAL g) ...@@ -633,13 +639,13 @@ bool DBFFAM::AllocateBuffer(PGLOBAL g)
DBFHEADER header; DBFHEADER header;
if ((rc = dbfhead(g, Stream, Tdbp->GetFile(g), &header)) == RC_OK) { if ((rc = dbfhead(g, Stream, Tdbp->GetFile(g), &header)) == RC_OK) {
if (Lrecl != (int)header.Reclen) { if (Lrecl != (int)header.Reclen()) {
sprintf(g->Message, MSG(BAD_LRECL), Lrecl, header.Reclen); sprintf(g->Message, MSG(BAD_LRECL), Lrecl, header.Reclen());
return true; return true;
} // endif Lrecl } // endif Lrecl
Records = (int)header.Records; Records = (int)header.Records();
Headlen = (int)header.Headlen; Headlen = (int)header.Headlen();
} else if (rc == RC_NF) { } else if (rc == RC_NF) {
Records = 0; Records = 0;
Headlen = 0; Headlen = 0;
...@@ -735,7 +741,7 @@ bool DBFFAM::CopyHeader(PGLOBAL g) ...@@ -735,7 +741,7 @@ bool DBFFAM::CopyHeader(PGLOBAL g)
if (Headlen) { if (Headlen) {
void *hdr = PlugSubAlloc(g, NULL, Headlen); void *hdr = PlugSubAlloc(g, NULL, Headlen);
size_t n, hlen = (size_t)Headlen; size_t n, hlen = (size_t)Headlen;
int pos = ftell(Stream); int pos = ftell(Stream);
if (fseek(Stream, 0, SEEK_SET)) if (fseek(Stream, 0, SEEK_SET))
strcpy(g->Message, "Seek error in CopyHeader"); strcpy(g->Message, "Seek error in CopyHeader");
...@@ -869,12 +875,14 @@ void DBFFAM::CloseTableFile(PGLOBAL g, bool abort) ...@@ -869,12 +875,14 @@ void DBFFAM::CloseTableFile(PGLOBAL g, bool abort)
if (n > Records) { if (n > Records) {
// Update the number of rows in the file header // Update the number of rows in the file header
char filename[_MAX_PATH], nRecords[4]; char filename[_MAX_PATH];
int4store(&nRecords, n);
PlugSetPath(filename, To_File, Tdbp->GetPath()); PlugSetPath(filename, To_File, Tdbp->GetPath());
if ((Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r+b"))) if ((Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r+b")))
{ {
char nRecords[4];
int4store(nRecords, n);
fseek(Stream, 4, SEEK_SET); // Get header.Records position fseek(Stream, 4, SEEK_SET); // Get header.Records position
fwrite(nRecords, sizeof(nRecords), 1, Stream); fwrite(nRecords, sizeof(nRecords), 1, Stream);
fclose(Stream); fclose(Stream);
...@@ -951,13 +959,13 @@ bool DBMFAM::AllocateBuffer(PGLOBAL g) ...@@ -951,13 +959,13 @@ bool DBMFAM::AllocateBuffer(PGLOBAL g)
/************************************************************************/ /************************************************************************/
DBFHEADER *hp = (DBFHEADER*)Memory; DBFHEADER *hp = (DBFHEADER*)Memory;
if (Lrecl != (int)uint2korr(&hp->Reclen)) { if (Lrecl != (int)hp->Reclen()) {
sprintf(g->Message, MSG(BAD_LRECL), Lrecl, uint2korr(&hp->Reclen)); sprintf(g->Message, MSG(BAD_LRECL), Lrecl, hp->Reclen());
return true; return true;
} // endif Lrecl } // endif Lrecl
Records = (int)uint4korr(&hp->Records); Records = (int)hp->Records();
Headlen = (int)uint2korr(&hp->Headlen); Headlen = (int)hp->Headlen();
} // endif Headlen } // endif Headlen
/**************************************************************************/ /**************************************************************************/
...@@ -1011,7 +1019,7 @@ int DBMFAM::ReadBuffer(PGLOBAL g) ...@@ -1011,7 +1019,7 @@ int DBMFAM::ReadBuffer(PGLOBAL g)
/* Data Base delete line routine for DBF access methods. */ /* Data Base delete line routine for DBF access methods. */
/* Deleted lines are just flagged in the first buffer character. */ /* Deleted lines are just flagged in the first buffer character. */
/****************************************************************************/ /****************************************************************************/
int DBMFAM::DeleteRecords(PGLOBAL, int irc) int DBMFAM::DeleteRecords(PGLOBAL g, int irc)
{ {
if (irc == RC_OK) if (irc == RC_OK)
*Fpos = '*'; *Fpos = '*';
......
...@@ -153,6 +153,7 @@ ...@@ -153,6 +153,7 @@
#endif // LIBXML2_SUPPORT #endif // LIBXML2_SUPPORT
#include "taboccur.h" #include "taboccur.h"
#include "tabpivot.h" #include "tabpivot.h"
#include "tabfix.h"
#define my_strupr(p) my_caseup_str(default_charset_info, (p)); #define my_strupr(p) my_caseup_str(default_charset_info, (p));
#define my_strlwr(p) my_casedn_str(default_charset_info, (p)); #define my_strlwr(p) my_casedn_str(default_charset_info, (p));
...@@ -656,6 +657,7 @@ static int connect_init_func(void *p) ...@@ -656,6 +657,7 @@ static int connect_init_func(void *p)
sql_print_information("connect_init: hton=%p", p); sql_print_information("connect_init: hton=%p", p);
DTVAL::SetTimeShift(); // Initialize time zone shift once for all DTVAL::SetTimeShift(); // Initialize time zone shift once for all
BINCOL::SetEndian(); // Initialize host endian setting
DBUG_RETURN(0); DBUG_RETURN(0);
} // end of connect_init_func } // end of connect_init_func
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
extern int num_read, num_there, num_eq[2]; // Statistics extern int num_read, num_there, num_eq[2]; // Statistics
static const longlong M2G = 0x80000000; static const longlong M2G = 0x80000000;
static const longlong M4G = (longlong)2 * M2G; static const longlong M4G = (longlong)2 * M2G;
char BINCOL::Endian = 'H';
/***********************************************************************/ /***********************************************************************/
/* External function. */ /* External function. */
...@@ -373,18 +374,88 @@ int TDBFIX::WriteDB(PGLOBAL g) ...@@ -373,18 +374,88 @@ int TDBFIX::WriteDB(PGLOBAL g)
BINCOL::BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am) BINCOL::BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am)
: DOSCOL(g, cdp, tp, cp, i, am) : DOSCOL(g, cdp, tp, cp, i, am)
{ {
Fmt = (cdp->GetFmt()) ? toupper(*cdp->GetFmt()) : 'X'; char *fmt = cdp->GetFmt();
Buff = NULL;
M = GetTypeSize(Buf_Type, Long);
Lim = M;
if (fmt) {
Fmt = 'H';
for (N = 0, i = 0; fmt[i]; i++)
if (isdigit(fmt[i]))
N = (N * 10 + (fmt[i] - 48));
else
Fmt = toupper(fmt[i]);
if (N == GetTypeSize(Buf_Type, -1) && (Fmt == 'H' || Fmt == Endian)) {
// New format is a no op
N = 0;
Fmt = 'X';
} else if (Fmt == 'L' || Fmt == 'B' || Fmt == 'H') {
// This is a new format
if (!N)
N = GetTypeSize(Buf_Type, 0);
if (Fmt == 'H')
Fmt = Endian;
Buff = (char*)PlugSubAlloc(g, NULL, M);
memset(Buff, 0, M);
Lim = MY_MIN(N, M);
} // endif Fmt
} else {
N = 0;
Fmt = 'X';
} // endif fmt
} // end of BINCOL constructor } // end of BINCOL constructor
/***********************************************************************/ /***********************************************************************/
/* FIXCOL constructor used for copying columns. */ /* BINCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */ /* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/ /***********************************************************************/
BINCOL::BINCOL(BINCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) BINCOL::BINCOL(BINCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
{ {
Fmt = col1->Fmt; Fmt = col1->Fmt;
N = col1->N;
M = col1->M;
Lim = col1->Lim;
} // end of BINCOL copy constructor } // end of BINCOL copy constructor
/***********************************************************************/
/* Set Endian according to the host setting. */
/***********************************************************************/
void BINCOL::SetEndian(void)
{
union {
short S;
char C[sizeof(short)];
};
S = 1;
Endian = (C[0] == 1) ? 'L' : 'B';
} // end of SetEndian
/***********************************************************************/
/* Copy according to Endian settings and sizes. */
/***********************************************************************/
void BINCOL::NumCpy(char *from, char *to)
{
for (int i = 0; i < Lim; i++)
if (Fmt == 'B' && Endian == 'L')
to[i] = from[N - i - 1];
else if (Fmt == 'L' && Endian == 'B')
to[N - i - 1] = from[i];
else if (Endian == 'B')
to[M - i - 1] = from[N - i - 1];
else
to[i] = from[i];
} // end of NumCpy
/***********************************************************************/ /***********************************************************************/
/* ReadColumn: what this routine does is to access the last line */ /* ReadColumn: what this routine does is to access the last line */
/* read from the corresponding table and extract from it the field */ /* read from the corresponding table and extract from it the field */
...@@ -416,19 +487,22 @@ void BINCOL::ReadColumn(PGLOBAL g) ...@@ -416,19 +487,22 @@ void BINCOL::ReadColumn(PGLOBAL g)
/*********************************************************************/ /*********************************************************************/
/* Set Value from the line field. */ /* Set Value from the line field. */
/*********************************************************************/ /*********************************************************************/
switch (Fmt) { if (N) {
NumCpy(p, Buff);
Value->SetBinValue(Buff);
} else switch (Fmt) {
case 'X': // Standard not converted values case 'X': // Standard not converted values
Value->SetBinValue(p); Value->SetBinValue(p);
break; break;
case 'S': // Short integer case 'S': // Short integer
Value->SetValue((int)*(short*)p); Value->SetValue(*(short*)p);
break; break;
case 'T': // Tiny integer case 'T': // Tiny integer
Value->SetValue((int)*p); Value->SetValue(*p);
break; break;
case 'L': // Long Integer // case 'L': // Long Integer
strcpy(g->Message, "Format L is deprecated, use I"); // strcpy(g->Message, "Format L is deprecated, use I");
longjmp(g->jumper[g->jump_level], 11); // longjmp(g->jumper[g->jump_level], 11);
case 'I': // Integer case 'I': // Integer
Value->SetValue(*(int*)p); Value->SetValue(*(int*)p);
break; break;
...@@ -490,14 +564,24 @@ void BINCOL::WriteColumn(PGLOBAL g) ...@@ -490,14 +564,24 @@ void BINCOL::WriteColumn(PGLOBAL g)
/* Updating will be done only during the second pass (Status=true) */ /* Updating will be done only during the second pass (Status=true) */
/* Conversion occurs if the external format Fmt is specified. */ /* Conversion occurs if the external format Fmt is specified. */
/*********************************************************************/ /*********************************************************************/
switch (Fmt) { if (N) {
if (Value->GetBinValue(Buff, M, Status)) {
sprintf(g->Message, MSG(BIN_F_TOO_LONG),
Name, Value->GetSize(), M);
longjmp(g->jumper[g->jump_level], 31);
} // endif Buff
if (Status)
NumCpy(Buff, p);
} else switch (Fmt) {
case 'X': case 'X':
// Standard not converted values // Standard not converted values
if (Value->GetBinValue(p, Long, Status)) { if (Value->GetBinValue(p, Long, Status)) {
sprintf(g->Message, MSG(BIN_F_TOO_LONG), sprintf(g->Message, MSG(BIN_F_TOO_LONG),
Name, Value->GetSize(), Long); Name, Value->GetSize(), Long);
longjmp(g->jumper[g->jump_level], 31); longjmp(g->jumper[g->jump_level], 31);
} // endif Fmt } // endif p
break; break;
case 'S': // Short integer case 'S': // Short integer
......
...@@ -74,11 +74,20 @@ class DllExport BINCOL : public DOSCOL { ...@@ -74,11 +74,20 @@ class DllExport BINCOL : public DOSCOL {
virtual void ReadColumn(PGLOBAL g); virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g);
// Static
static void SetEndian(void);
protected: protected:
void NumCpy(char *from, char *to);
BINCOL(void) {} // Default constructor not to be used BINCOL(void) {} // Default constructor not to be used
// Members // Members
char Fmt; // The column numeric format static char Endian; // The host endian setting (L or B)
char *Buff; // Utility buffer
char Fmt; // The file endian setting or old format
int N; // The number of bytes in the file
int M; // The column type size
int Lim; // Used in NumCpy
}; // end of class BINCOL }; // end of class BINCOL
/***********************************************************************/ /***********************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment