mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
merge
This commit is contained in:
1204
mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result
Normal file
1204
mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result
Normal file
File diff suppressed because it is too large
Load Diff
44
mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test
Normal file
44
mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test
Normal 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;
|
@ -137,7 +137,9 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
|
|||||||
char* output,
|
char* output,
|
||||||
size_t ilen,
|
size_t ilen,
|
||||||
size_t olen,
|
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));
|
DBUG_PRINT("ha_ibmdb2i::convertFieldChars",("Direction: %d; length = %d", direction, ilen));
|
||||||
|
|
||||||
@ -157,26 +159,26 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
|
|||||||
size_t initOLen= olen;
|
size_t initOLen= olen;
|
||||||
size_t substitutedChars = 0;
|
size_t substitutedChars = 0;
|
||||||
int rc = iconv(conversion, (char**)&input, &ilen, &output, &olen, &substitutedChars );
|
int rc = iconv(conversion, (char**)&input, &ilen, &output, &olen, &substitutedChars );
|
||||||
|
if (outDataLen) *outDataLen = initOLen - olen;
|
||||||
|
if (substChars) *substChars = substitutedChars;
|
||||||
if (unlikely(rc < 0))
|
if (unlikely(rc < 0))
|
||||||
{
|
{
|
||||||
int er = errno;
|
int er = errno;
|
||||||
if (er == EILSEQ)
|
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);
|
return (DB2I_ERR_ILL_CHAR);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
getErrTxt(DB2I_ERR_ICONV,er);
|
if (!tacitErrors) getErrTxt(DB2I_ERR_ICONV,er);
|
||||||
return (DB2I_ERR_ICONV);
|
return (DB2I_ERR_ICONV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unlikely(substitutedChars))
|
if (unlikely(substitutedChars) && (!tacitErrors))
|
||||||
{
|
{
|
||||||
warning(ha_thd(), DB2I_ERR_SUB_CHARS, table->field[fieldID]->field_name);
|
warning(ha_thd(), DB2I_ERR_SUB_CHARS, table->field[fieldID]->field_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outDataLen) *outDataLen = initOLen - olen;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -555,12 +557,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||||||
return 1;
|
return 1;
|
||||||
if (fieldCharSet->mbmaxlen > 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
|
sprintf(stringBuildBuffer, "GRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
|
||||||
db2Ccsid = 13488;
|
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)
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
||||||
{
|
{
|
||||||
sprintf(stringBuildBuffer, "CHAR(%d)", max(fieldLength, 1)); // Number of bytes
|
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 (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
|
sprintf(stringBuildBuffer, "VARGRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
|
||||||
db2Ccsid = 13488;
|
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)
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
||||||
{
|
{
|
||||||
sprintf(stringBuildBuffer, "VARCHAR(%d)", max(fieldLength, 1)); // Number of bytes
|
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 (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 ");
|
sprintf(stringBuildBuffer, "LONG VARGRAPHIC ");
|
||||||
db2Ccsid = 13488;
|
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)
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
||||||
{
|
{
|
||||||
sprintf(stringBuildBuffer, "LONG VARCHAR ");
|
sprintf(stringBuildBuffer, "LONG VARCHAR ");
|
||||||
@ -639,12 +641,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||||||
|
|
||||||
if (fieldCharSet->mbmaxlen > 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, "DBCLOB(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
|
sprintf(stringBuildBuffer, "DBCLOB(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
|
||||||
db2Ccsid = 13488;
|
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)
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
||||||
{
|
{
|
||||||
sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of bytes
|
sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of bytes
|
||||||
@ -671,11 +673,15 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||||||
return rtnCode;
|
return rtnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether there is a character conversion available.
|
if (db2Ccsid != 1208 &&
|
||||||
iconv_t temp;
|
db2Ccsid != 13488)
|
||||||
int32 rc = getConversion(toDB2, fieldCharSet, db2Ccsid, temp);
|
{
|
||||||
if (unlikely(rc))
|
// Check whether there is a character conversion available.
|
||||||
return rc;
|
iconv_t temp;
|
||||||
|
int32 rc = getConversion(toDB2, fieldCharSet, db2Ccsid, temp);
|
||||||
|
if (unlikely(rc))
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(stringBuildBuffer, " CCSID %d ", db2Ccsid);
|
sprintf(stringBuildBuffer, " CCSID %d ", db2Ccsid);
|
||||||
mapping.append(stringBuildBuffer);
|
mapping.append(stringBuildBuffer);
|
||||||
|
@ -220,6 +220,7 @@ INTERN size_t myconv_dmap(myconv_t cd,
|
|||||||
} else {
|
} else {
|
||||||
*pOut=dmapS2S[*pIn];
|
*pOut=dmapS2S[*pIn];
|
||||||
if (*pOut == 0x00) {
|
if (*pOut == 0x00) {
|
||||||
|
errno=EILSEQ; /* 116 */
|
||||||
*outBytesLeft-=(*inBytesLeft-inLen);
|
*outBytesLeft-=(*inBytesLeft-inLen);
|
||||||
*inBytesLeft=inLen;
|
*inBytesLeft=inLen;
|
||||||
*outBuf=pOut;
|
*outBuf=pOut;
|
||||||
|
@ -51,7 +51,6 @@ static inline int getKeyCntFromMap(key_part_map keypart_map)
|
|||||||
return (cnt);
|
return (cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief
|
@brief
|
||||||
Given a starting key and an ending key, estimate the number of rows that
|
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);
|
DB2Field& db2Field = db2Table->db2Field(field->field_index);
|
||||||
litDefPtr->DataType = db2Field.getType();
|
litDefPtr->DataType = db2Field.getType();
|
||||||
/*
|
/*
|
||||||
Convert the literal to DB2 format.
|
Convert the literal to DB2 format
|
||||||
*/
|
*/
|
||||||
rc = convertMySQLtoDB2(field,
|
if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
|
||||||
db2Field,
|
(field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
|
||||||
literalPtr,
|
(litDefPtr->DataType == QMY_CHAR ||
|
||||||
(uchar*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
|
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;
|
if (rc != 0) break;
|
||||||
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
|
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
|
||||||
litDefPtr->Length = db2Field.getByteLengthInRecord();
|
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
|
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
|
/* 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
|
Convert the literal to DB2 format
|
||||||
*/
|
*/
|
||||||
rc = convertMySQLtoDB2(field,
|
if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
|
||||||
db2Field,
|
(field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
|
||||||
literalPtr,
|
(litDefPtr->DataType == QMY_CHAR ||
|
||||||
(uchar*)maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
|
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;
|
if (rc != 0) break;
|
||||||
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
|
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
|
||||||
litDefPtr->Length = db2Field.getByteLengthInRecord();
|
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
|
literalPtr = literalPtr + litDefPtr->Length; // Bump pointer for next literal
|
||||||
}
|
}
|
||||||
boundsPtr->HiBound.Position = literalCnt;
|
boundsPtr->HiBound.Position = literalCnt;
|
||||||
|
@ -383,7 +383,15 @@ private:
|
|||||||
int32 prepareWriteBufferForLobs();
|
int32 prepareWriteBufferForLobs();
|
||||||
uint32 adjustLobBuffersForRead();
|
uint32 adjustLobBuffersForRead();
|
||||||
bool lobFieldsRequested();
|
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
|
Fast integer log2 function
|
||||||
|
Reference in New Issue
Block a user