Commit b9c91090 authored by Olivier Bertrand's avatar Olivier Bertrand

Fix a bug in BIN buffer initialisation (in FIXFAM::AllocateBuffer)

  modified:   storage/connect/filamfix.cpp

Second version of BIN table new field format (1st one was buggy)
  modified:   storage/connect/tabfix.cpp
  modified:   storage/connect/tabfix.h

Make bin.test not to fail in big-endian machines
  modified:   storage/connect/mysql-test/connect/r/bin.result
  modified:   storage/connect/mysql-test/connect/t/bin.test

Fix a bug causing wrong default offset to be generated when virtual
or special columns were placed beetween standard columns. Also
calculate the good offset for BIN columns with new field format.
  modified:   storage/connect/reldef.cpp
parent e6b60ee5
......@@ -46,6 +46,7 @@
#include "plgdbsem.h"
#include "filamfix.h"
#include "tabdos.h"
#include "tabfix.h"
#include "osutil.h"
#ifndef INVALID_SET_FILE_POINTER
......@@ -133,18 +134,35 @@ bool FIXFAM::AllocateBuffer(PGLOBAL g)
if (Tdbp->GetFtype() == RECFM_BIN) {
// The buffer must be prepared depending on column types
int n = 0;
bool b = false;
PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
PCOLDEF cdp;
// PCOLDEF cdp;
PBINCOL colp;
// Prepare the first line of the buffer
memset(To_Buf, 0, Buflen);
#if 0
for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext()) {
if (IsTypeNum(cdp->GetType()))
memset(To_Buf + cdp->GetOffset(), ' ', cdp->GetClen());
if (!IsTypeNum(cdp->GetType())) {
memset(To_Buf + cdp->GetOffset(), ' ', cdp->GetClen());
b = true;
} // endif not num
n = MY_MAX(n, cdp->GetPoff() + cdp->GetClen());
n = MY_MAX(n, cdp->GetOffset() + cdp->GetClen());
} // endfor cdp
#endif // 0
for (colp = (PBINCOL)Tdbp->GetColumns(); colp;
colp = (PBINCOL)colp->GetNext())
if (!colp->IsSpecial()) {
if (!IsTypeNum(colp->GetResultType())) {
memset(To_Buf + colp->GetDeplac(), ' ', colp->GetLength());
b = true;
} // endif not num
n = MY_MAX(n, colp->GetDeplac() + colp->GetFileSize());
} // endif !special
// We do this for binary table because the lrecl can have been
// specified with additional space to include line ending.
......@@ -156,9 +174,10 @@ bool FIXFAM::AllocateBuffer(PGLOBAL g)
} // endif n
// Now repeat this for the whole buffer
for (int len = Lrecl; len <= Buflen - Lrecl; len += Lrecl)
memcpy(To_Buf + len, To_Buf, Lrecl);
if (b)
// Now repeat this for the whole buffer
for (int len = Lrecl; len <= Buflen - Lrecl; len += Lrecl)
memcpy(To_Buf + len, To_Buf, Lrecl);
} else {
memset(To_Buf, ' ', Buflen);
......
......@@ -14,11 +14,11 @@ SET time_zone='+00:00';
CREATE TABLE t1
(
fig INT(4) NOT NULL FIELD_FORMAT='C',
name CHAR(10) not null,
birth DATE NOT NULL,
id CHAR(5) NOT NULL FIELD_FORMAT='S',
name CHAR(10) NOT NULL,
birth DATE NOT NULL FIELD_FORMAT='L',
id CHAR(5) NOT NULL FIELD_FORMAT='L2',
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
dept INT(4) NOT NULL FIELD_FORMAT='L2'
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
SELECT * FROM t1;
fig name birth id salary dept
......@@ -41,11 +41,11 @@ DROP TABLE t1;
CREATE TABLE t1
(
fig INT(4) NOT NULL FIELD_FORMAT='C',
name CHAR(10) not null,
birth DATE NOT NULL,
id CHAR(5) NOT NULL FIELD_FORMAT='S',
name CHAR(10) NOT NULL,
birth DATE NOT NULL FIELD_FORMAT='L',
id CHAR(5) NOT NULL FIELD_FORMAT='L2',
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
dept INT(4) NOT NULL FIELD_FORMAT='L2'
) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat';
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ERROR HY000: Table 't1' is read only
......@@ -55,10 +55,10 @@ Table Create Table
t1 CREATE TABLE `t1` (
`fig` int(4) NOT NULL `FIELD_FORMAT`='C',
`name` char(10) NOT NULL,
`birth` date NOT NULL,
`id` char(5) NOT NULL `FIELD_FORMAT`='S',
`birth` date NOT NULL `FIELD_FORMAT`='L',
`id` char(5) NOT NULL `FIELD_FORMAT`='L2',
`salary` double(9,2) NOT NULL DEFAULT '0.00' `FIELD_FORMAT`='F',
`dept` int(4) NOT NULL `FIELD_FORMAT`='S'
`dept` int(4) NOT NULL `FIELD_FORMAT`='L2'
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=BIN `FILE_NAME`='Testbal.dat' `READONLY`=NO
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
SELECT * FROM t1;
......@@ -74,10 +74,10 @@ Table Create Table
t1 CREATE TABLE `t1` (
`fig` int(4) NOT NULL `FIELD_FORMAT`='C',
`name` char(10) NOT NULL,
`birth` date NOT NULL,
`id` char(5) NOT NULL `FIELD_FORMAT`='S',
`birth` date NOT NULL `FIELD_FORMAT`='L',
`id` char(5) NOT NULL `FIELD_FORMAT`='L2',
`salary` double(9,2) NOT NULL DEFAULT '0.00' `FIELD_FORMAT`='F',
`dept` int(4) NOT NULL `FIELD_FORMAT`='S'
`dept` int(4) NOT NULL `FIELD_FORMAT`='L2'
) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=BIN `FILE_NAME`='Testbal.dat' `READONLY`=YES
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ERROR HY000: Table 't1' is read only
......
let $MYSQLD_DATADIR= `select @@datadir`;
--copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
--echo #
--echo # Testing errors
--echo #
CREATE TABLE t1
(
ID INT NOT NULL
) Engine=CONNECT TABLE_TYPE=BIN FILE_NAME='nonexistent.txt';
--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
# TODO: check why this is needed for Windows
--replace_result Open(rt) Open(rb)
SELECT * FROM t1;
DROP TABLE t1;
SET time_zone='+00:00';
CREATE TABLE t1
(
fig INT(4) NOT NULL FIELD_FORMAT='C',
name CHAR(10) not null,
birth DATE NOT NULL,
id CHAR(5) NOT NULL FIELD_FORMAT='S',
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
SELECT * FROM t1;
--error ER_GET_ERRMSG
INSERT INTO t1 VALUES (55555,'RONALD','1980-02-26','3333',4444.44,555);
INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # Testing READONLY tables
--echo #
CREATE TABLE t1
(
fig INT(4) NOT NULL FIELD_FORMAT='C',
name CHAR(10) not null,
birth DATE NOT NULL,
id CHAR(5) NOT NULL FIELD_FORMAT='S',
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='S'
) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat';
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ALTER TABLE t1 READONLY=NO;
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=YES;
SHOW CREATE TABLE t1;
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
DROP TABLE t1;
--echo #
--echo # Testing that the underlying file is created
--echo #
CREATE TABLE t1
(
c CHAR(4) NOT NULL FIELD_FORMAT='C'
) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='bin2.dat';
INSERT INTO t1 VALUES (10),(20),(300),(4000);
SELECT * FROM t1;
DROP TABLE t1;
#
# Clean up
#
--remove_file $MYSQLD_DATADIR/test/Testbal.dat
--remove_file $MYSQLD_DATADIR/test/bin2.dat
let $MYSQLD_DATADIR= `select @@datadir`;
--copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
--echo #
--echo # Testing errors
--echo #
CREATE TABLE t1
(
ID INT NOT NULL
) Engine=CONNECT TABLE_TYPE=BIN FILE_NAME='nonexistent.txt';
--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
# TODO: check why this is needed for Windows
--replace_result Open(rt) Open(rb)
SELECT * FROM t1;
DROP TABLE t1;
SET time_zone='+00:00';
CREATE TABLE t1
(
fig INT(4) NOT NULL FIELD_FORMAT='C',
name CHAR(10) NOT NULL,
birth DATE NOT NULL FIELD_FORMAT='L',
id CHAR(5) NOT NULL FIELD_FORMAT='L2',
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='L2'
) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
SELECT * FROM t1;
--error ER_GET_ERRMSG
INSERT INTO t1 VALUES (55555,'RONALD','1980-02-26','3333',4444.44,555);
INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # Testing READONLY tables
--echo #
CREATE TABLE t1
(
fig INT(4) NOT NULL FIELD_FORMAT='C',
name CHAR(10) NOT NULL,
birth DATE NOT NULL FIELD_FORMAT='L',
id CHAR(5) NOT NULL FIELD_FORMAT='L2',
salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
dept INT(4) NOT NULL FIELD_FORMAT='L2'
) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat';
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
ALTER TABLE t1 READONLY=NO;
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
SELECT * FROM t1;
ALTER TABLE t1 READONLY=YES;
SHOW CREATE TABLE t1;
--error ER_OPEN_AS_READONLY
INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
DROP TABLE t1;
--echo #
--echo # Testing that the underlying file is created
--echo #
CREATE TABLE t1
(
c CHAR(4) NOT NULL FIELD_FORMAT='C'
) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='bin2.dat';
INSERT INTO t1 VALUES (10),(20),(300),(4000);
SELECT * FROM t1;
DROP TABLE t1;
#
# Clean up
#
--remove_file $MYSQLD_DATADIR/test/Testbal.dat
--remove_file $MYSQLD_DATADIR/test/bin2.dat
......@@ -322,7 +322,7 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
if ((nof= cdp->Define(g, NULL, pcf, poff)) < 0)
return -1; // Error, probably unhandled type
else if (nof)
else
loff= cdp->GetOffset();
switch (tc) {
......@@ -334,15 +334,23 @@ int TABDEF::GetColCatInfo(PGLOBAL g)
// Field width is the internal representation width
// that can also depend on the column format
switch (cdp->Fmt ? *cdp->Fmt : 'X') {
case 'X': nof= cdp->Clen;
case 'C': break;
case 'R':
case 'F':
case 'L':
// 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;
default: /* New format */
for (nof= 0, i= 0; cdp->Fmt[i]; i++)
if (isdigit(cdp->Fmt[i]))
nof= (nof * 10 + (cdp->Fmt[i] - 48));
if (!nof)
nof= cdp->Clen;
} // endswitch Fmt
default:
......@@ -745,7 +753,8 @@ int COLDEF::Define(PGLOBAL g, void *, PCOLINFO cfp, int poff)
if (cfp->Datefmt)
Decode = (PSZ)PlugDup(g, cfp->Datefmt);
} // endif special
} else
Offset = poff;
if (cfp->Fieldfmt)
Fmt = (PSZ)PlugDup(g, cfp->Fieldfmt);
......
......@@ -377,8 +377,8 @@ BINCOL::BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am)
char *fmt = cdp->GetFmt();
Buff = NULL;
M = GetTypeSize(Buf_Type, Long);
Lim = M;
M = GetTypeSize(Buf_Type, sizeof(longlong));
Lim = 0;
if (fmt) {
Fmt = 'H';
......@@ -396,7 +396,7 @@ BINCOL::BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PSZ am)
} else if (Fmt == 'L' || Fmt == 'B' || Fmt == 'H') {
// This is a new format
if (!N)
N = GetTypeSize(Buf_Type, 0);
N = GetTypeSize(Buf_Type, Long);
if (Fmt == 'H')
Fmt = Endian;
......@@ -439,23 +439,6 @@ void BINCOL::SetEndian(void)
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 */
/* read from the corresponding table and extract from it the field */
......@@ -488,8 +471,21 @@ void BINCOL::ReadColumn(PGLOBAL g)
/* Set Value from the line field. */
/*********************************************************************/
if (N) {
NumCpy(p, Buff);
Value->SetBinValue(Buff);
for (int i = 0; i < Lim; i++)
if (Fmt == 'B' && Endian == 'L')
Buff[i] = p[N - i - 1];
else if (Fmt == 'L' && Endian == 'B')
Buff[M - i - 1] = p[i];
else if (Endian == 'B')
Buff[M - i - 1] = p[N - i - 1];
else
Buff[i] = p[i];
if (IsTypeChar(Buf_Type))
Value->SetValue(*(longlong*)Buff);
else
Value->SetBinValue(Buff);
} else switch (Fmt) {
case 'X': // Standard not converted values
Value->SetBinValue(p);
......@@ -565,14 +561,24 @@ void BINCOL::WriteColumn(PGLOBAL g)
/* Conversion occurs if the external format Fmt is specified. */
/*********************************************************************/
if (N) {
if (Value->GetBinValue(Buff, M, Status)) {
if (IsTypeChar(Buf_Type))
*(longlong *)Buff = Value->GetBigintValue();
else 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);
for (int i = 0; i < Lim; i++)
if (Fmt == 'B' && Endian == 'L')
p[N - i - 1] = Buff[i];
else if (Fmt == 'L' && Endian == 'B')
p[i] = Buff[M - i - 1];
else if (Endian == 'B')
p[N - i - 1] = Buff[M - i - 1];
else
p[i] = Buff[i];
} else switch (Fmt) {
case 'X':
......@@ -619,7 +625,7 @@ void BINCOL::WriteColumn(PGLOBAL g)
break;
case 'B': // Large (big) integer
if (Status)
*(longlong *)p = (longlong)Value->GetBigintValue();
*(longlong *)p = Value->GetBigintValue();
break;
case 'F': // Float
......
/*************** TabDos H Declares Source Code File (.H) ***************/
/* Name: TABFIX.H Version 2.3 */
/* Name: TABFIX.H Version 2.4 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 1999-2012 */
/* (C) Copyright to the author Olivier BERTRAND 1999-2015 */
/* */
/* This file contains the TDBFIX and (FIX/BIN)COL classes declares. */
/***********************************************************************/
......@@ -12,7 +12,7 @@
typedef class FIXCOL *PFIXCOL;
typedef class BINCOL *PBINCOL;
typedef class TXTFAM *PTXF;
typedef class TXTFAM *PTXF;
/***********************************************************************/
/* This is the DOS/UNIX Access Method class declaration for files */
......@@ -68,17 +68,19 @@ class DllExport BINCOL : public DOSCOL {
BINCOL(BINCOL *colp, PTDB tdbp); // Constructor used in copy process
// Implementation
virtual int GetAmType(void) {return TYPE_AM_BIN;}
virtual int GetAmType(void) {return TYPE_AM_BIN;}
int GetDeplac(void) {return Deplac;}
int GetFileSize(void)
{return N ? N : GetTypeSize(Buf_Type, Long);}
// Methods
virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g);
virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g);
// Static
static void SetEndian(void);
static void SetEndian(void);
protected:
void NumCpy(char *from, char *to);
BINCOL(void) {} // Default constructor not to be used
// Members
......@@ -86,8 +88,8 @@ class DllExport BINCOL : public DOSCOL {
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
int M; // The buffer type size
int Lim; // Min(N,M)
}; // 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