1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

atuomerge

This commit is contained in:
Georgi Kodinov
2009-07-07 17:14:21 +03:00
6 changed files with 1596 additions and 112 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
source suite/ibmdb2i/include/have_ibmdb2i.inc;
source suite/ibmdb2i/include/have_i61.inc;
--disable_warnings
drop table if exists t1, ffd, fd;
--enable_warnings
--disable_abort_on_error
--error 0,255
exec system "DLTF QGPL/FFDOUT" > /dev/null;
--error 0,255
exec system "DLTF QGPL/FDOUT" > /dev/null;
--enable_abort_on_error
let $count= query_get_value(select count(*) from information_schema.COLLATIONS where COLLATION_NAME <> "binary", count(*),1);
while ($count)
{
let $collation = query_get_value(select COLLATION_NAME from information_schema.COLLATIONS where COLLATION_NAME <> "binary" order by COLLATION_NAME desc, COLLATION_NAME, $count);
error 0,1005,2504,2028;
eval CREATE TABLE t1 ($collation integer, c char(10), v varchar(20), index(c), index(v)) collate $collation engine=ibmdb2i;
if (!$mysql_errno)
{
insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
insert into t1 select * from t1;
explain select c,v from t1 force index(c) where c like "ab%";
explain select c,v from t1 force index(v) where v like "de%";
drop table t1;
eval create table t1 ($collation char(10) primary key) collate $collation engine=ibmdb2i;
system system "DSPFFD FILE(\"test\"/\"t1\") OUTPUT(*OUTFILE) OUTFILE(QGPL/FFDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
system system "DSPFD FILE(\"test\"/\"t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
drop table t1;
}
dec $count;
}
create table ffd (WHCHD1 CHAR(20), WHCSID decimal(5,0)) engine=ibmdb2i;
system system "CPYF FROMFILE(QGPL/FFDOUT) TOFILE(\"test\"/\"ffd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
system system "CPYF FROMFILE(QGPL/FDOUT) TOFILE(\"test\"/\"fd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
create temporary table intermed (row integer key auto_increment, cs char(30), ccsid integer);
insert into intermed (cs, ccsid) select * from ffd;
create temporary table intermed2 (row integer key auto_increment, srtseq char(10));
insert into intermed2 (srtseq) select * from fd;
select ccsid, cs, srtseq from intermed inner join intermed2 on intermed.row = intermed2.row;
drop table ffd, fd;

View File

@ -137,7 +137,9 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
char* output,
size_t ilen,
size_t olen,
size_t* outDataLen)
size_t* outDataLen,
bool tacitErrors,
size_t* substChars)
{
DBUG_PRINT("ha_ibmdb2i::convertFieldChars",("Direction: %d; length = %d", direction, ilen));
@ -157,27 +159,27 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
size_t initOLen= olen;
size_t substitutedChars = 0;
int rc = iconv(conversion, (char**)&input, &ilen, &output, &olen, &substitutedChars );
if (outDataLen) *outDataLen = initOLen - olen;
if (substChars) *substChars = substitutedChars;
if (unlikely(rc < 0))
{
int er = errno;
if (er == EILSEQ)
{
getErrTxt(DB2I_ERR_ILL_CHAR, table->field[fieldID]->field_name);
if (!tacitErrors) getErrTxt(DB2I_ERR_ILL_CHAR, table->field[fieldID]->field_name);
return (DB2I_ERR_ILL_CHAR);
}
else
{
getErrTxt(DB2I_ERR_ICONV,er);
if (!tacitErrors) getErrTxt(DB2I_ERR_ICONV,er);
return (DB2I_ERR_ICONV);
}
}
if (unlikely(substitutedChars))
if (unlikely(substitutedChars) && (!tacitErrors))
{
warning(ha_thd(), DB2I_ERR_SUB_CHARS, table->field[fieldID]->field_name);
}
if (outDataLen) *outDataLen = initOLen - olen;
return (0);
}
@ -555,12 +557,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
return 1;
if (fieldCharSet->mbmaxlen > 1)
{
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "GRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
db2Ccsid = 13488;
}
else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "CHAR(%d)", max(fieldLength, 1)); // Number of bytes
@ -584,12 +586,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
{
if (fieldCharSet->mbmaxlen > 1)
{
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "VARGRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
db2Ccsid = 13488;
}
else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "VARCHAR(%d)", max(fieldLength, 1)); // Number of bytes
@ -611,12 +613,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
{
if (fieldCharSet->mbmaxlen > 1)
{
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "LONG VARGRAPHIC ");
db2Ccsid = 13488;
}
else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "LONG VARCHAR ");
@ -639,12 +641,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
if (fieldCharSet->mbmaxlen > 1)
{
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "DBCLOB(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
db2Ccsid = 13488;
}
else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of bytes
@ -671,11 +673,15 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
return rtnCode;
}
if (db2Ccsid != 1208 &&
db2Ccsid != 13488)
{
// Check whether there is a character conversion available.
iconv_t temp;
int32 rc = getConversion(toDB2, fieldCharSet, db2Ccsid, temp);
if (unlikely(rc))
return rc;
}
sprintf(stringBuildBuffer, " CCSID %d ", db2Ccsid);
mapping.append(stringBuildBuffer);

View File

@ -220,6 +220,7 @@ INTERN size_t myconv_dmap(myconv_t cd,
} else {
*pOut=dmapS2S[*pIn];
if (*pOut == 0x00) {
errno=EILSEQ; /* 116 */
*outBytesLeft-=(*inBytesLeft-inLen);
*inBytesLeft=inLen;
*outBuf=pOut;

View File

@ -51,7 +51,6 @@ static inline int getKeyCntFromMap(key_part_map keypart_map)
return (cnt);
}
/**
@brief
Given a starting key and an ending key, estimate the number of rows that
@ -270,81 +269,163 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
DB2Field& db2Field = db2Table->db2Field(field->field_index);
litDefPtr->DataType = db2Field.getType();
/*
Convert the literal to DB2 format.
Convert the literal to DB2 format
*/
if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
(field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
(litDefPtr->DataType == QMY_CHAR ||
litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_GRAPHIC ||
litDefPtr->DataType == QMY_VARGRAPHIC))
{
// Most of the code is required by the considerable wrangling needed
// to prepare partial keys for use by DB2
// 1. UTF8 (CCSID 1208) data can be copied across unmodified if it is
// utf8_bin. Otherwise, we need to convert the min and max
// characters into the min and max characters employed
// by the DB2 sort sequence. This is complicated by the fact that
// the character widths are not always equal.
// 2. Likewise, UCS2 (CCSID 13488) data can be copied across unmodified
// if it is ucs2_bin or ucs2_general_ci. Otherwise, we need to
// convert the min and max characters into the min and max characters
// employed by the DB2 sort sequence.
// 3. All other data will use standard iconv conversions. If an
// unconvertible character is encountered, we assume it is the min
// char and fill the remainder of the DB2 key with 0s. This may not
// always be accurate, but it is probably sufficient for range
// estimations.
const char* keyData = minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
char* db2Data = literalPtr;
uint16 outLen = db2Field.getByteLengthInRecord();
uint16 inLen;
if (litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_VARGRAPHIC)
{
inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
keyData += 2;
outLen -= sizeof(uint16);
db2Data += sizeof(uint16);
}
else
{
inLen = field->max_display_length();
}
size_t convertedBytes = 0;
if (db2Field.getCCSID() == 1208)
{
DBUG_ASSERT(inLen <= outLen);
if (strcmp(field->charset()->name, "utf8_bin"))
{
const char* end = keyData+inLen;
const char* curKey = keyData;
char* curDB2 = db2Data;
uint32 min = field->charset()->min_sort_char;
while ((curKey < end) && (curDB2 < db2Data+outLen-3))
{
my_wc_t temp;
int len = field->charset()->cset->mb_wc(field->charset(),
&temp,
(const uchar*)curKey,
(const uchar*)end);
if (temp != min)
{
DBUG_ASSERT(len <= 3);
switch (len)
{
case 3: *(curDB2+2) = *(curKey+2);
case 2: *(curDB2+1) = *(curKey+1);
case 1: *(curDB2) = *(curKey);
}
curDB2 += len;
}
else
{
*(curDB2++) = 0xEF;
*(curDB2++) = 0xBF;
*(curDB2++) = 0xBF;
}
curKey += len;
}
convertedBytes = curDB2 - db2Data;
}
else
{
memcpy(db2Data, keyData, inLen);
convertedBytes = inLen;
}
rc = 0;
}
else if (db2Field.getCCSID() == 13488)
{
DBUG_ASSERT(inLen <= outLen);
if (strcmp(field->charset()->name, "ucs2_bin") &&
strcmp(field->charset()->name, "ucs2_general_ci"))
{
const char* end = keyData+inLen;
const uint16* curKey = (uint16*)keyData;
uint16* curDB2 = (uint16*)db2Data;
uint16 min = field->charset()->min_sort_char;
while (curKey < (uint16*)end)
{
if (*curKey != min)
*curDB2 = *curKey;
else
*curDB2 = 0xFFFF;
++curKey;
++curDB2;
}
}
else
{
memcpy(db2Data, keyData, inLen);
}
convertedBytes = inLen;
rc = 0;
}
else
{
rc = convertFieldChars(toDB2,
field->field_index,
keyData,
db2Data,
inLen,
outLen,
&convertedBytes,
true);
if (rc == DB2I_ERR_ILL_CHAR)
{
// If an illegal character is encountered, we fill the remainder
// of the key with 0x00. This was implemented as a corollary to
// Bug#45012, though it should probably remain even after that
// bug is fixed.
memset(db2Data+convertedBytes, 0x00, outLen-convertedBytes);
convertedBytes = outLen;
rc = 0;
}
}
if (!rc &&
(litDefPtr->DataType == QMY_VARGRAPHIC ||
litDefPtr->DataType == QMY_VARCHAR))
{
*(uint16*)(db2Data-sizeof(uint16)) =
convertedBytes / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
}
}
else // Non-character fields
{
rc = convertMySQLtoDB2(field,
db2Field,
literalPtr,
(uchar*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
}
if (rc != 0) break;
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
litDefPtr->Length = db2Field.getByteLengthInRecord();
tempLen = litDefPtr->Length;
/*
Do additional conversion of a character or graphic value.
*/
CHARSET_INFO* fieldCharSet = field->charset();
if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
(field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
(litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_GRAPHIC || litDefPtr->DataType == QMY_VARGRAPHIC))
{
if (litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_VARGRAPHIC)
tempPtr = literalPtr + sizeof(uint16);
else
tempPtr = literalPtr;
/* The following code checks to determine if MySQL is passing a
partial key. DB2 will accept a partial field value, but only
in the last field position of the key composite (and only if
there is no ICU sort sequence on the index). */
tempMinPtr = (char*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
if (field->type() == MYSQL_TYPE_VARCHAR)
{
/* MySQL always stores key lengths as 2 bytes, little-endian. */
tempLen = *(uint8*)tempMinPtr + ((*(uint8*)(tempMinPtr+1)) << 8);
tempMinPtr = (char*)((char*)tempMinPtr + 2);
}
else
tempLen = field->field_length;
/* Determine if we are dealing with a partial key and if so, find the end of the partial key. */
if (litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR )
{ /* Char or varchar. If UTF8, no conversion is done to DB2 graphic.) */
endOfMinPtr = (char*)memchr(tempMinPtr,field->charset()->min_sort_char,tempLen);
if (endOfMinPtr)
endOfLiteralPtr = tempPtr + ((uint32_t)(endOfMinPtr - tempMinPtr));
}
else
{
if (strncmp(fieldCharSet->csname, "utf8", sizeof("utf8")) == 0)
{ /* The MySQL charset is UTF8 but we are converting to graphic on DB2. Divide number of UTF8 bytes
by 3 to get the number of characters, then multiple by 2 for double-byte graphic.*/
endOfMinPtr = (char*)memchr(tempMinPtr,field->charset()->min_sort_char,tempLen);
if (endOfMinPtr)
endOfLiteralPtr = tempPtr + (((uint32_t)((endOfMinPtr - tempMinPtr)) / 3) * 2);
}
else
{ /* The DB2 data type is graphic or vargraphic, and we are not converting from UTF8 to graphic. */
endOfMinPtr = (char*)wmemchr((wchar_t*)tempMinPtr,field->charset()->min_sort_char,tempLen/2);
if (endOfMinPtr)
endOfLiteralPtr = tempPtr + (endOfMinPtr - tempMinPtr);
}
}
/* Enforce here that a partial is only allowed on the last field position
of the key composite */
if (endOfLiteralPtr)
{
if ((partsInUse + 1) < minKeyCnt)
{
rc = HA_POS_ERROR;
break;
}
endByte = endOfLiteralPtr - tempPtr;
/* We're making an assumption that if MySQL gives us a partial key,
the length of the partial is the same for both the min_key and max_key. */
}
}
literalPtr = literalPtr + litDefPtr->Length; // Bump pointer for next literal
}
/* If there is a max_key value for this field, and if the max_key value is
@ -389,28 +470,168 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
/*
Convert the literal to DB2 format
*/
if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
(field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
(litDefPtr->DataType == QMY_CHAR ||
litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_GRAPHIC ||
litDefPtr->DataType == QMY_VARGRAPHIC))
{
// We need to handle char fields in a special way in order to account
// for partial keys. Refer to the note above for a description of the
// basic design.
char* keyData = maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
char* db2Data = literalPtr;
uint16 outLen = db2Field.getByteLengthInRecord();
uint16 inLen;
if (litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_VARGRAPHIC)
{
inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
keyData += 2;
outLen -= sizeof(uint16);
db2Data += sizeof(uint16);
}
else
{
inLen = field->max_display_length();
}
size_t convertedBytes;
if (db2Field.getCCSID() == 1208)
{
if (strcmp(field->charset()->name, "utf8_bin"))
{
const char* end = keyData+inLen;
const char* curKey = keyData;
char* curDB2 = db2Data;
uint32 max = field->charset()->max_sort_char;
while (curKey < end && (curDB2 < db2Data+outLen-3))
{
my_wc_t temp;
int len = field->charset()->cset->mb_wc(field->charset(), &temp, (const uchar*)curKey, (const uchar*)end);
if (temp != max)
{
DBUG_ASSERT(len <= 3);
switch (len)
{
case 3: *(curDB2+2) = *(curKey+2);
case 2: *(curDB2+1) = *(curKey+1);
case 1: *(curDB2) = *(curKey);
}
curDB2 += len;
}
else
{
*(curDB2++) = 0xE4;
*(curDB2++) = 0xB6;
*(curDB2++) = 0xBF;
}
curKey += len;
}
convertedBytes = curDB2 - db2Data;
}
else
{
DBUG_ASSERT(inLen <= outLen);
memcpy(db2Data, keyData, inLen);
convertedBytes = inLen;
}
rc = 0;
}
else if (db2Field.getCCSID() == 13488)
{
if (strcmp(field->charset()->name, "ucs2_bin") &&
strcmp(field->charset()->name, "ucs2_general_ci"))
{
char* end = keyData+inLen;
uint16* curKey = (uint16*)keyData;
uint16* curDB2 = (uint16*)db2Data;
uint16 max = field->charset()->max_sort_char;
while (curKey < (uint16*)end)
{
if (*curKey != max)
*curDB2 = *curKey;
else
*curDB2 = 0x4DBF;
++curKey;
++curDB2;
}
}
else
{
memcpy(db2Data, keyData, outLen);
}
rc = 0;
}
else
{
size_t substituteChars = 0;
rc = convertFieldChars(toDB2,
field->field_index,
keyData,
db2Data,
inLen,
outLen,
&convertedBytes,
true,
&substituteChars);
if (rc == DB2I_ERR_ILL_CHAR)
{
// If an illegal character is encountered, we fill the remainder
// of the key with 0xFF. This was implemented to work around
// Bug#45012, though it should probably remain even after that
// bug is fixed.
memset(db2Data+convertedBytes, 0xFF, outLen-convertedBytes);
rc = 0;
}
else if ((substituteChars &&
(litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_CHAR)) ||
strcmp(field->charset()->name, "cp1251_bulgarian_ci") == 0)
{
// When iconv translates the max_sort_char with a substitute
// character, we have no way to know whether this affects
// the sort order of the key. Therefore, to be safe, when
// we know that substitute characters have been used in a
// single-byte string, we traverse the translated key
// in reverse, replacing substitue characters with 0xFF, which
// always sorts with the greatest weight in DB2 sort sequences.
// cp1251_bulgarian_ci is also handled this way because the
// max_sort_char is a control character which does not sort
// equivalently in DB2.
DBUG_ASSERT(inLen == outLen);
char* tmpKey = keyData + inLen - 1;
char* tmpDB2 = db2Data + outLen - 1;
while (*tmpKey == field->charset()->max_sort_char &&
*tmpDB2 != 0xFF)
{
*tmpDB2 = 0xFF;
--tmpKey;
--tmpDB2;
}
}
}
if (!rc &&
(litDefPtr->DataType == QMY_VARGRAPHIC ||
litDefPtr->DataType == QMY_VARCHAR))
{
*(uint16*)(db2Data-sizeof(uint16)) =
outLen / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
}
}
else
{
rc = convertMySQLtoDB2(field,
db2Field,
literalPtr,
(uchar*)maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
}
if (rc != 0) break;
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
litDefPtr->Length = db2Field.getByteLengthInRecord();
tempLen = litDefPtr->Length;
/*
Now convert a character or graphic value.
*/
if ((field->type() != MYSQL_TYPE_BIT) &&
(litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR ||
litDefPtr->DataType == QMY_GRAPHIC || litDefPtr->DataType == QMY_VARGRAPHIC))
{
if (litDefPtr->DataType == QMY_VARCHAR || litDefPtr->DataType == QMY_VARGRAPHIC)
{
tempPtr = literalPtr + sizeof(uint16);
}
else
tempPtr = literalPtr;
}
literalPtr = literalPtr + litDefPtr->Length; // Bump pointer for next literal
}
boundsPtr->HiBound.Position = literalCnt;

View File

@ -383,7 +383,15 @@ private:
int32 prepareWriteBufferForLobs();
uint32 adjustLobBuffersForRead();
bool lobFieldsRequested();
int convertFieldChars(enum_conversionDirection direction, uint16 fieldID, const char* input, char* output, size_t ilen, size_t olen, size_t* outDataLen);
int convertFieldChars(enum_conversionDirection direction,
uint16 fieldID,
const char* input,
char* output,
size_t ilen,
size_t olen,
size_t* outDataLen,
bool tacitErrors=FALSE,
size_t* substChars=NULL);
/**
Fast integer log2 function