2009-02-15 03:18:30 +01:00
|
|
|
/*
|
|
|
|
Licensed Materials - Property of IBM
|
|
|
|
DB2 Storage Engine Enablement
|
|
|
|
Copyright IBM Corporation 2007,2008
|
|
|
|
All rights reserved
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
are permitted provided that the following conditions are met:
|
|
|
|
(a) Redistributions of source code must retain this list of conditions, the
|
|
|
|
copyright notice in section {d} below, and the disclaimer following this
|
|
|
|
list of conditions.
|
|
|
|
(b) Redistributions in binary form must reproduce this list of conditions, the
|
|
|
|
copyright notice in section (d) below, and the disclaimer following this
|
|
|
|
list of conditions, in the documentation and/or other materials provided
|
|
|
|
with the distribution.
|
|
|
|
(c) The name of IBM may not be used to endorse or promote products derived from
|
|
|
|
this software without specific prior written permission.
|
|
|
|
(d) The text of the required copyright notice is:
|
|
|
|
Licensed Materials - Property of IBM
|
|
|
|
DB2 Storage Engine Enablement
|
|
|
|
Copyright IBM Corporation 2007,2008
|
|
|
|
All rights reserved
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
|
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
|
|
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
|
|
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
|
|
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
|
|
OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "db2i_ileBridge.h"
|
|
|
|
#include "mysql_priv.h"
|
|
|
|
#include "db2i_charsetSupport.h"
|
|
|
|
#include "ctype.h"
|
|
|
|
#include "ha_ibmdb2i.h"
|
|
|
|
#include "db2i_errors.h"
|
|
|
|
#include "wchar.h"
|
|
|
|
|
2009-03-09 15:20:14 -06:00
|
|
|
const char ZERO_DATETIME_VALUE[] = "0000-00-00 00:00:00";
|
|
|
|
const char ZERO_DATETIME_VALUE_SUBST[] = "0001-01-01 00:00:00";
|
|
|
|
const char ZERO_DATE_VALUE[] = "0000-00-00";
|
|
|
|
const char ZERO_DATE_VALUE_SUBST[] = "0001-01-01";
|
|
|
|
|
|
|
|
|
2009-02-15 03:18:30 +01:00
|
|
|
/**
|
|
|
|
Put a BCD digit into a BCD string.
|
|
|
|
|
|
|
|
@param[out] bcdString The BCD string to be modified
|
|
|
|
@param pos The position within the string to be updated.
|
|
|
|
@param val The value to be assigned into the string at pos.
|
|
|
|
*/
|
|
|
|
static inline void bcdAssign(char* bcdString, uint pos, uint val)
|
|
|
|
{
|
|
|
|
bcdString[pos/2] |= val << ((pos % 2) ? 0 : 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Read a BCD digit from a BCD string.
|
|
|
|
|
|
|
|
@param[out] bcdString The BCD string to be read
|
|
|
|
@param pos The position within the string to be read.
|
|
|
|
|
|
|
|
@return bcdGet The value of the BCD digit at pos.
|
|
|
|
*/
|
|
|
|
static inline uint bcdGet(const char* bcdString, uint pos)
|
|
|
|
{
|
|
|
|
return (bcdString[pos/2] >> ((pos % 2) ? 0 : 4)) & 0xf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
In-place convert a number in ASCII represenation to EBCDIC representation.
|
|
|
|
|
|
|
|
@param string The string of ASCII characters
|
|
|
|
@param len The length of string
|
|
|
|
*/
|
|
|
|
static inline void convertNumericToEbcdicFast(char* string, int len)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < len; ++i, ++string)
|
|
|
|
{
|
|
|
|
switch(*string)
|
|
|
|
{
|
|
|
|
case '-':
|
|
|
|
*string = 0x60; break;
|
|
|
|
case ':':
|
|
|
|
*string = 0x7A; break;
|
|
|
|
case '.':
|
|
|
|
*string = 0x4B; break;
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(isdigit(*string));
|
|
|
|
*string += 0xF0 - '0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
atoi()-like function for a 4-character EBCDIC string.
|
|
|
|
|
|
|
|
@param string The EBCDIC string
|
|
|
|
@return a4toi_ebcdic The decimal value of the EBCDIC string
|
|
|
|
*/
|
|
|
|
static inline uint16 a4toi_ebcdic(const uchar* string)
|
|
|
|
{
|
|
|
|
return ((string[0]-0xF0) * 1000 +
|
|
|
|
(string[1]-0xF0) * 100 +
|
|
|
|
(string[2]-0xF0) * 10 +
|
|
|
|
(string[3]-0xF0));
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
atoi()-like function for a 4-character EBCDIC string.
|
|
|
|
|
|
|
|
@param string The EBCDIC string
|
|
|
|
@return a4toi_ebcdic The decimal value of the EBCDIC string
|
|
|
|
*/
|
|
|
|
static inline uint8 a2toi_ebcdic(const uchar* string)
|
|
|
|
{
|
|
|
|
return ((string[0]-0xF0) * 10 +
|
|
|
|
(string[1]-0xF0));
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
Perform character conversion for textual field data.
|
|
|
|
*/
|
|
|
|
int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
|
|
|
|
uint16 fieldID,
|
|
|
|
const char* input,
|
|
|
|
char* output,
|
|
|
|
size_t ilen,
|
|
|
|
size_t olen,
|
|
|
|
size_t* outDataLen)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("ha_ibmdb2i::convertFieldChars",("Direction: %d; length = %d", direction, ilen));
|
|
|
|
|
|
|
|
if (unlikely(ilen == 0))
|
|
|
|
{
|
|
|
|
if (outDataLen) *outDataLen = 0;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
iconv_t& conversion = db2Table->getConversionDefinition(direction, fieldID);
|
|
|
|
|
|
|
|
if (unlikely(conversion == (iconv_t)(-1)))
|
|
|
|
{
|
2009-05-05 15:03:52 +05:30
|
|
|
return (DB2I_ERR_UNSUPP_CHARSET);
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t initOLen= olen;
|
|
|
|
size_t substitutedChars = 0;
|
|
|
|
int rc = iconv(conversion, (char**)&input, &ilen, &output, &olen, &substitutedChars );
|
|
|
|
if (unlikely(rc < 0))
|
|
|
|
{
|
|
|
|
int er = errno;
|
|
|
|
if (er == EILSEQ)
|
|
|
|
{
|
|
|
|
getErrTxt(DB2I_ERR_ILL_CHAR, table->field[fieldID]->field_name);
|
|
|
|
return (DB2I_ERR_ILL_CHAR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
getErrTxt(DB2I_ERR_ICONV,er);
|
|
|
|
return (DB2I_ERR_ICONV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (unlikely(substitutedChars))
|
|
|
|
{
|
|
|
|
warning(ha_thd(), DB2I_ERR_SUB_CHARS, table->field[fieldID]->field_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (outDataLen) *outDataLen = initOLen - olen;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2009-03-09 15:20:14 -06:00
|
|
|
/**
|
|
|
|
Append the appropriate default value clause onto a CREATE TABLE definition
|
|
|
|
|
|
|
|
This was inspired by get_field_default_value in sql/sql_show.cc.
|
|
|
|
|
|
|
|
@param field The field whose value is to be obtained
|
|
|
|
@param statement The string to receive the DEFAULT clause
|
|
|
|
@param quoteIt Does the data type require single quotes around the value?
|
|
|
|
@param ccsid The ccsid of the field value (if a string type); 0 if no conversion needed
|
|
|
|
*/
|
|
|
|
static void get_field_default_value(Field *field,
|
|
|
|
String &statement,
|
|
|
|
bool quoteIt,
|
|
|
|
uint32 ccsid,
|
|
|
|
bool substituteZeroDates)
|
|
|
|
{
|
|
|
|
if ((field->type() != FIELD_TYPE_BLOB &&
|
|
|
|
!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
|
|
|
|
field->unireg_check != Field::NEXT_NUMBER))
|
|
|
|
{
|
|
|
|
my_ptrdiff_t old_ptr= (my_ptrdiff_t) (field->table->s->default_values - field->table->record[0]);
|
|
|
|
field->move_field_offset(old_ptr);
|
|
|
|
|
|
|
|
String defaultClause(64);
|
|
|
|
defaultClause.length(0);
|
|
|
|
defaultClause.append(" DEFAULT ");
|
|
|
|
if (!field->is_null())
|
|
|
|
{
|
|
|
|
my_bitmap_map *old_map = tmp_use_all_columns(field->table, field->table->read_set);
|
|
|
|
char tmp[MAX_FIELD_WIDTH];
|
|
|
|
|
|
|
|
if (field->real_type() == MYSQL_TYPE_ENUM ||
|
|
|
|
field->real_type() == MYSQL_TYPE_SET)
|
|
|
|
{
|
|
|
|
CHARSET_INFO *cs= &my_charset_bin;
|
|
|
|
uint len = (uint)(cs->cset->longlong10_to_str)(cs,tmp,sizeof(tmp), 10, field->val_int());
|
|
|
|
tmp[len]=0;
|
|
|
|
defaultClause.append(tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
String type(tmp, sizeof(tmp), field->charset());
|
|
|
|
field->val_str(&type);
|
|
|
|
if (type.length())
|
|
|
|
{
|
|
|
|
if (field->type() == MYSQL_TYPE_DATE &&
|
|
|
|
memcmp(type.ptr(), STRING_WITH_LEN(ZERO_DATE_VALUE)) == 0)
|
|
|
|
{
|
|
|
|
if (substituteZeroDates)
|
|
|
|
type.set(STRING_WITH_LEN(ZERO_DATE_VALUE_SUBST), field->charset());
|
|
|
|
else
|
|
|
|
{
|
|
|
|
warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((field->type() == MYSQL_TYPE_DATETIME ||
|
|
|
|
field->type() == MYSQL_TYPE_TIMESTAMP) &&
|
|
|
|
memcmp(type.ptr(), STRING_WITH_LEN(ZERO_DATETIME_VALUE)) == 0)
|
|
|
|
{
|
|
|
|
if (substituteZeroDates)
|
|
|
|
type.set(STRING_WITH_LEN(ZERO_DATETIME_VALUE_SUBST), field->charset());
|
|
|
|
else
|
|
|
|
{
|
|
|
|
warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (field->type() != MYSQL_TYPE_STRING &&
|
|
|
|
field->type() != MYSQL_TYPE_VARCHAR &&
|
|
|
|
field->type() != MYSQL_TYPE_BLOB &&
|
|
|
|
field->type() != MYSQL_TYPE_BIT)
|
|
|
|
{
|
|
|
|
if (quoteIt)
|
|
|
|
defaultClause.append('\'');
|
|
|
|
defaultClause.append(type);
|
|
|
|
if (quoteIt)
|
|
|
|
defaultClause.append('\'');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int length;
|
|
|
|
char* out;
|
|
|
|
|
|
|
|
// If a ccsid is specified, we need to make sure that the DEFAULT
|
|
|
|
// string is converted to that encoding.
|
|
|
|
if (ccsid != 0)
|
|
|
|
{
|
|
|
|
iconv_t iconvD;
|
|
|
|
if (getConversion(toDB2, field->charset(), ccsid, iconvD))
|
|
|
|
{
|
|
|
|
warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ilen = type.length();
|
|
|
|
size_t olen = 6 * ilen;
|
|
|
|
size_t origOlen = olen;
|
|
|
|
const char* in = type.ptr();
|
|
|
|
const char* tempIn = in;
|
|
|
|
out = (char*)my_malloc(olen, MYF(MY_WME));
|
|
|
|
char* tempOut = out;
|
|
|
|
size_t substitutedChars;
|
|
|
|
|
|
|
|
if (iconv(iconvD, (char**)&tempIn, &ilen, &tempOut, &olen, &substitutedChars) < 0)
|
|
|
|
{
|
|
|
|
warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
my_free(out, MYF(0));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Now we process the converted string to represent it as
|
|
|
|
// hexadecimal values.
|
|
|
|
|
|
|
|
length = origOlen - olen;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
length = type.length();
|
|
|
|
out = (char*)my_malloc(length*2, MYF(MY_WME));
|
|
|
|
memcpy(out, (char*)type.ptr(), length);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length > 16370)
|
|
|
|
{
|
|
|
|
warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
my_free(out, MYF(0));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ccsid == 1200)
|
|
|
|
defaultClause.append("ux'");
|
|
|
|
else if (ccsid == 13488)
|
|
|
|
defaultClause.append("gx'");
|
|
|
|
else if (field->charset() == &my_charset_bin)
|
|
|
|
defaultClause.append("binary(x'");
|
|
|
|
else
|
|
|
|
defaultClause.append("x'");
|
|
|
|
|
|
|
|
const char hexMap[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
|
|
|
for (int c = length-1; c >= 0; --c)
|
|
|
|
{
|
|
|
|
out[c*2+1] = hexMap[out[c] & 0xF];
|
|
|
|
out[c*2] = hexMap[out[c] >> 4];
|
|
|
|
}
|
|
|
|
|
|
|
|
defaultClause.append(out, length*2);
|
|
|
|
defaultClause.append('\'');
|
|
|
|
if (field->charset() == &my_charset_bin)
|
|
|
|
defaultClause.append(")");
|
|
|
|
|
|
|
|
my_free(out, MYF(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
defaultClause.length(0);
|
|
|
|
}
|
|
|
|
tmp_restore_column_map(field->table->read_set, old_map);
|
|
|
|
}
|
|
|
|
else if (field->maybe_null())
|
|
|
|
defaultClause.append(STRING_WITH_LEN("NULL"));
|
|
|
|
|
|
|
|
if (old_ptr)
|
|
|
|
field->move_field_offset(-old_ptr);
|
|
|
|
|
|
|
|
statement.append(defaultClause);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-02-15 03:18:30 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Convert a MySQL field definition into its corresponding DB2 type.
|
|
|
|
|
|
|
|
The result will be appended to mapping as a DB2 SQL phrase.
|
|
|
|
|
|
|
|
@param field The MySQL field to be evaluated
|
|
|
|
@param[out] mapping The receiver for the DB2 SQL syntax
|
|
|
|
@param timeFormat The format to be used for mapping the TIME type
|
|
|
|
*/
|
|
|
|
int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|
|
|
String& mapping,
|
|
|
|
enum_TimeFormat timeFormat,
|
2009-03-09 15:20:14 -06:00
|
|
|
enum_BlobMapping blobMapping,
|
|
|
|
enum_ZeroDate zeroDateHandling,
|
|
|
|
bool propagateDefaults,
|
|
|
|
enum_YearFormat yearFormat)
|
2009-02-15 03:18:30 +01:00
|
|
|
{
|
|
|
|
char stringBuildBuffer[257];
|
|
|
|
uint32 fieldLength;
|
2009-03-09 15:20:14 -06:00
|
|
|
bool defaultNeedsQuotes = false;
|
|
|
|
uint16 db2Ccsid = 0;
|
2009-02-15 03:18:30 +01:00
|
|
|
|
|
|
|
CHARSET_INFO* fieldCharSet = field->charset();
|
|
|
|
switch (field->type())
|
|
|
|
{
|
|
|
|
case MYSQL_TYPE_NEWDECIMAL:
|
|
|
|
{
|
|
|
|
uint precision= ((Field_new_decimal*)field)->precision;
|
|
|
|
uint scale= field->decimals();
|
|
|
|
|
|
|
|
if (precision <= MAX_DEC_PRECISION)
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer,"DECIMAL(%d, %d)",precision,scale);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (scale > precision - MAX_DEC_PRECISION)
|
|
|
|
{
|
|
|
|
scale = scale - (precision - MAX_DEC_PRECISION);
|
|
|
|
precision = MAX_DEC_PRECISION;
|
|
|
|
sprintf(stringBuildBuffer,"DECIMAL(%d, %d)",precision,scale);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return HA_ERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
warning(ha_thd(), DB2I_ERR_PRECISION);
|
|
|
|
}
|
|
|
|
|
|
|
|
mapping.append(stringBuildBuffer);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TINY:
|
|
|
|
mapping.append(STRING_WITH_LEN("SMALLINT"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_SHORT:
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
mapping.append(STRING_WITH_LEN("INT"));
|
|
|
|
else
|
|
|
|
mapping.append(STRING_WITH_LEN("SMALLINT"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_LONG:
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
mapping.append(STRING_WITH_LEN("BIGINT"));
|
|
|
|
else
|
|
|
|
mapping.append(STRING_WITH_LEN("INT"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
|
|
mapping.append(STRING_WITH_LEN("REAL"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DOUBLE:
|
|
|
|
mapping.append(STRING_WITH_LEN("DOUBLE"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_LONGLONG:
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
mapping.append(STRING_WITH_LEN("DECIMAL(20,0)"));
|
|
|
|
else
|
|
|
|
mapping.append(STRING_WITH_LEN("BIGINT"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_INT24:
|
|
|
|
mapping.append(STRING_WITH_LEN("INTEGER"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DATE:
|
|
|
|
case MYSQL_TYPE_NEWDATE:
|
|
|
|
mapping.append(STRING_WITH_LEN("DATE"));
|
2009-03-09 15:20:14 -06:00
|
|
|
defaultNeedsQuotes = true;
|
2009-02-15 03:18:30 +01:00
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TIME:
|
|
|
|
if (timeFormat == TIME_OF_DAY)
|
2009-03-09 15:20:14 -06:00
|
|
|
{
|
2009-02-15 03:18:30 +01:00
|
|
|
mapping.append(STRING_WITH_LEN("TIME"));
|
2009-03-09 15:20:14 -06:00
|
|
|
defaultNeedsQuotes = true;
|
|
|
|
}
|
2009-02-15 03:18:30 +01:00
|
|
|
else
|
|
|
|
mapping.append(STRING_WITH_LEN("INTEGER"));
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
2009-03-09 15:20:14 -06:00
|
|
|
mapping.append(STRING_WITH_LEN("TIMESTAMP"));
|
|
|
|
defaultNeedsQuotes = true;
|
2009-02-15 03:18:30 +01:00
|
|
|
break;
|
2009-03-09 15:20:14 -06:00
|
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
|
|
mapping.append(STRING_WITH_LEN("TIMESTAMP"));
|
|
|
|
|
|
|
|
if (table_share->timestamp_field == field && propagateDefaults)
|
|
|
|
{
|
|
|
|
switch (((Field_timestamp*)field)->get_auto_set_type())
|
|
|
|
{
|
|
|
|
case TIMESTAMP_NO_AUTO_SET:
|
|
|
|
break;
|
|
|
|
case TIMESTAMP_AUTO_SET_ON_INSERT:
|
|
|
|
mapping.append(STRING_WITH_LEN(" DEFAULT CURRENT_TIMESTAMP"));
|
|
|
|
break;
|
|
|
|
case TIMESTAMP_AUTO_SET_ON_UPDATE:
|
|
|
|
if (osVersion.v >= 6 &&
|
|
|
|
!field->is_null())
|
|
|
|
{
|
|
|
|
mapping.append(STRING_WITH_LEN(" GENERATED BY DEFAULT FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP"));
|
|
|
|
warning(ha_thd(), DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
warning(ha_thd(), DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
break;
|
|
|
|
case TIMESTAMP_AUTO_SET_ON_BOTH:
|
|
|
|
if (osVersion.v >= 6 &&
|
|
|
|
!field->is_null())
|
|
|
|
mapping.append(STRING_WITH_LEN(" GENERATED BY DEFAULT FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP"));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mapping.append(STRING_WITH_LEN(" DEFAULT CURRENT_TIMESTAMP"));
|
|
|
|
warning(ha_thd(), DB2I_ERR_WARN_COL_ATTRS, field->field_name);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
defaultNeedsQuotes = true;
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_YEAR:
|
|
|
|
if (yearFormat == CHAR4)
|
|
|
|
{
|
|
|
|
mapping.append(STRING_WITH_LEN("CHAR(4) CCSID 1208"));
|
|
|
|
defaultNeedsQuotes = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mapping.append(STRING_WITH_LEN("SMALLINT"));
|
|
|
|
defaultNeedsQuotes = false;
|
|
|
|
}
|
2009-02-15 03:18:30 +01:00
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_BIT:
|
|
|
|
sprintf(stringBuildBuffer, "BINARY(%d)", (field->max_display_length() / 8) + 1);
|
|
|
|
mapping.append(stringBuildBuffer);
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
case MYSQL_TYPE_VARCHAR:
|
|
|
|
case MYSQL_TYPE_STRING:
|
|
|
|
{
|
|
|
|
if (field->real_type() == MYSQL_TYPE_ENUM ||
|
|
|
|
field->real_type() == MYSQL_TYPE_SET)
|
|
|
|
{
|
|
|
|
mapping.append(STRING_WITH_LEN("BIGINT"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
defaultNeedsQuotes = true;
|
|
|
|
|
2009-02-15 03:18:30 +01:00
|
|
|
fieldLength = field->max_display_length(); // Get field byte length
|
|
|
|
|
|
|
|
if (fieldCharSet == &my_charset_bin)
|
|
|
|
{
|
|
|
|
if (field->type() == MYSQL_TYPE_STRING)
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "BINARY(%d)", max(fieldLength, 1));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fieldLength <= MAX_VARCHAR_LENGTH)
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "VARBINARY(%d)", max(fieldLength, 1));
|
|
|
|
}
|
2009-03-09 15:20:14 -06:00
|
|
|
else if (blobMapping == AS_VARCHAR &&
|
|
|
|
(field->flags & PART_KEY_FLAG))
|
2009-02-15 03:18:30 +01:00
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
sprintf(stringBuildBuffer, "LONG VARBINARY ");
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fieldLength = min(MAX_BLOB_LENGTH, fieldLength);
|
|
|
|
sprintf(stringBuildBuffer, "BLOB(%d)", max(fieldLength, 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mapping.append(stringBuildBuffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (field->type() == MYSQL_TYPE_STRING)
|
|
|
|
{
|
|
|
|
if (fieldLength > MAX_CHAR_LENGTH)
|
|
|
|
return 1;
|
|
|
|
if (fieldCharSet->mbmaxlen > 1)
|
|
|
|
{
|
|
|
|
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 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 &&
|
|
|
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "CHAR(%d)", max(fieldLength, 1)); // Number of bytes
|
|
|
|
db2Ccsid = 1208;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "GRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
|
|
|
|
db2Ccsid = 1200;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "CHAR(%d)", max(fieldLength, 1));
|
|
|
|
}
|
|
|
|
mapping.append(stringBuildBuffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fieldLength <= MAX_VARCHAR_LENGTH)
|
|
|
|
{
|
|
|
|
if (fieldCharSet->mbmaxlen > 1)
|
|
|
|
{
|
|
|
|
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 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 &&
|
|
|
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "VARCHAR(%d)", max(fieldLength, 1)); // Number of bytes
|
|
|
|
db2Ccsid = 1208;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "VARGRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
|
|
|
|
db2Ccsid = 1200;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "VARCHAR(%d)", max(fieldLength, 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (blobMapping == AS_VARCHAR &&
|
2009-03-09 15:20:14 -06:00
|
|
|
(field->flags & PART_KEY_FLAG))
|
2009-02-15 03:18:30 +01:00
|
|
|
{
|
|
|
|
if (fieldCharSet->mbmaxlen > 1)
|
|
|
|
{
|
|
|
|
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "LONG VARGRAPHIC ");
|
|
|
|
db2Ccsid = 13488;
|
|
|
|
}
|
|
|
|
else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
|
|
|
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "LONG VARCHAR ");
|
|
|
|
db2Ccsid = 1208;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "LONG VARGRAPHIC ");
|
|
|
|
db2Ccsid = 1200;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "LONG VARCHAR ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fieldLength = min(MAX_BLOB_LENGTH, fieldLength);
|
|
|
|
|
|
|
|
if (fieldCharSet->mbmaxlen > 1)
|
|
|
|
{
|
|
|
|
if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 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 &&
|
|
|
|
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of bytes
|
|
|
|
db2Ccsid = 1208;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "DBCLOB(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
|
|
|
|
db2Ccsid = 1200;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of characters
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mapping.append(stringBuildBuffer);
|
|
|
|
}
|
|
|
|
if (db2Ccsid == 0) // If not overriding CCSID
|
|
|
|
{
|
|
|
|
int32 rtnCode = convertIANAToDb2Ccsid(fieldCharSet->csname, &db2Ccsid);
|
|
|
|
if (rtnCode)
|
|
|
|
return rtnCode;
|
|
|
|
}
|
2009-05-05 15:03:52 +05:30
|
|
|
|
|
|
|
// Check whether there is a character conversion available.
|
|
|
|
iconv_t temp;
|
|
|
|
int32 rc = getConversion(toDB2, fieldCharSet, db2Ccsid, temp);
|
|
|
|
if (unlikely(rc))
|
|
|
|
return rc;
|
|
|
|
|
2009-02-15 03:18:30 +01:00
|
|
|
sprintf(stringBuildBuffer, " CCSID %d ", db2Ccsid);
|
|
|
|
mapping.append(stringBuildBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-03-09 15:20:14 -06:00
|
|
|
if (propagateDefaults)
|
|
|
|
get_field_default_value(field,
|
|
|
|
mapping,
|
|
|
|
defaultNeedsQuotes,
|
|
|
|
db2Ccsid,
|
|
|
|
(zeroDateHandling==SUBSTITUTE_0001_01_01));
|
|
|
|
|
2009-02-15 03:18:30 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Convert MySQL field data into the equivalent DB2 format
|
|
|
|
|
|
|
|
@param field The MySQL field to be converted
|
|
|
|
@param db2Field The corresponding DB2 field definition
|
|
|
|
@param db2Buf The buffer to receive the converted data
|
|
|
|
@param data NULL if field points to the correct data; otherwise,
|
|
|
|
the data to be converted (for use with keys)
|
|
|
|
*/
|
|
|
|
int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char* db2Buf, const uchar* data)
|
|
|
|
{
|
|
|
|
enum_field_types fieldType = field->type();
|
|
|
|
switch (fieldType)
|
|
|
|
{
|
|
|
|
case MYSQL_TYPE_NEWDECIMAL:
|
|
|
|
{
|
|
|
|
uint precision= ((Field_new_decimal*)field)->precision;
|
|
|
|
uint scale= field->decimals();
|
|
|
|
uint db2Precision = min(precision, MAX_DEC_PRECISION);
|
|
|
|
uint truncationAmount = precision - db2Precision;
|
|
|
|
|
|
|
|
if (scale >= truncationAmount)
|
|
|
|
{
|
|
|
|
String tempString(precision+2);
|
|
|
|
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
field->val_str((String*)&tempString, (String*)(NULL));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, data);
|
|
|
|
}
|
|
|
|
const char* temp = tempString.ptr();
|
|
|
|
char packed[32];
|
|
|
|
memset(&packed, 0, sizeof(packed));
|
|
|
|
|
|
|
|
int bcdPos = db2Precision - (db2Precision % 2 ? 1 : 0);
|
|
|
|
bcdAssign(packed, bcdPos+1, (temp[0] == '-' ? 0xD : 0xF));
|
|
|
|
|
|
|
|
int strPos=tempString.length() - 1 - truncationAmount;
|
|
|
|
|
|
|
|
for (;strPos >= 0 && bcdPos >= 0; strPos--)
|
|
|
|
{
|
|
|
|
if (my_isdigit(&my_charset_latin1, temp[strPos]))
|
|
|
|
{
|
|
|
|
bcdAssign(packed, bcdPos, temp[strPos]-'0');
|
|
|
|
--bcdPos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memcpy(db2Buf, &packed, (db2Precision/2)+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TINY:
|
|
|
|
{
|
|
|
|
int16 temp = (data == NULL ? field->val_int() : field->val_int(data));
|
|
|
|
memcpy(db2Buf , &temp, sizeof(temp));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_SHORT:
|
|
|
|
{
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
{
|
|
|
|
memset(db2Buf, 0, 2);
|
|
|
|
memcpy(db2Buf+2, (data == NULL ? field->ptr : data), 2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(db2Buf, (data == NULL ? field->ptr : data), 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_LONG:
|
|
|
|
{
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
{
|
|
|
|
memset(db2Buf, 0, 4);
|
|
|
|
memcpy(db2Buf+4, (data == NULL ? field->ptr : data), 4);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(db2Buf, (data == NULL ? field->ptr : data), 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
|
|
{
|
|
|
|
memcpy(db2Buf, (data == NULL ? field->ptr : data), 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DOUBLE:
|
|
|
|
{
|
|
|
|
memcpy(db2Buf, (data == NULL ? field->ptr : data), 8);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
|
|
|
{
|
|
|
|
String tempString(27);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, &tempString);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, data);
|
|
|
|
}
|
|
|
|
memset(db2Buf, '0', 26);
|
|
|
|
memcpy(db2Buf, tempString.ptr(), tempString.length());
|
2009-03-09 15:20:14 -06:00
|
|
|
if (strncmp(db2Buf,ZERO_DATETIME_VALUE,strlen(ZERO_DATETIME_VALUE)) == 0)
|
2009-02-15 03:18:30 +01:00
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
if (cachedZeroDateOption == SUBSTITUTE_0001_01_01)
|
|
|
|
memcpy(db2Buf, ZERO_DATETIME_VALUE_SUBST, sizeof(ZERO_DATETIME_VALUE_SUBST));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
getErrTxt(DB2I_ERR_INVALID_COL_VALUE, field->field_name);
|
|
|
|
return(DB2I_ERR_INVALID_COL_VALUE);
|
|
|
|
}
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
(db2Buf)[10] = '-';
|
|
|
|
(db2Buf)[13] = (db2Buf)[16] = (db2Buf)[19] = '.';
|
|
|
|
|
|
|
|
convertNumericToEbcdicFast(db2Buf, 26);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_LONGLONG:
|
|
|
|
{
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
{
|
|
|
|
char temp[23];
|
|
|
|
String tempString(temp, sizeof(temp), &my_charset_latin1);
|
|
|
|
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
field->val_str((String*)&tempString, (String*)(NULL));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, data);
|
|
|
|
}
|
|
|
|
char packed[11];
|
|
|
|
memset(packed, 0, sizeof(packed));
|
|
|
|
bcdAssign(packed, 21, (temp[0] == '-' ? 0xD : 0xF));
|
|
|
|
int strPos=tempString.length()-1;
|
|
|
|
int bcdPos=20;
|
|
|
|
|
|
|
|
for (;strPos >= 0; strPos--)
|
|
|
|
{
|
|
|
|
if (my_isdigit(&my_charset_latin1, temp[strPos]))
|
|
|
|
{
|
|
|
|
bcdAssign(packed, bcdPos, temp[strPos]-'0');
|
|
|
|
--bcdPos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memcpy(db2Buf, &packed, 11);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*(uint64*)db2Buf = *(uint64*)(data == NULL ? field->ptr : data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_INT24:
|
|
|
|
{
|
|
|
|
int32 temp= (data == NULL ? field->val_int() : field->val_int(data));
|
|
|
|
memcpy(db2Buf , &temp, sizeof(temp));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DATE:
|
|
|
|
case MYSQL_TYPE_NEWDATE:
|
|
|
|
{
|
|
|
|
String tempString(11);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, (String*)NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, data);
|
|
|
|
}
|
|
|
|
memcpy(db2Buf, tempString.ptr(), 10);
|
2009-03-09 15:20:14 -06:00
|
|
|
if (strncmp(db2Buf,ZERO_DATE_VALUE,strlen(ZERO_DATE_VALUE)) == 0)
|
2009-02-15 03:18:30 +01:00
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
if (cachedZeroDateOption == SUBSTITUTE_0001_01_01)
|
|
|
|
memcpy(db2Buf, ZERO_DATE_VALUE_SUBST, sizeof(ZERO_DATE_VALUE_SUBST));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
getErrTxt(DB2I_ERR_INVALID_COL_VALUE,field->field_name);
|
|
|
|
return(DB2I_ERR_INVALID_COL_VALUE);
|
|
|
|
}
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
convertNumericToEbcdicFast(db2Buf,10);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TIME:
|
|
|
|
{
|
|
|
|
if (db2Field.getType() == QMY_TIME)
|
|
|
|
{
|
|
|
|
String tempString(10);
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, (String*)NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, data);
|
|
|
|
}
|
|
|
|
memcpy(db2Buf, tempString.ptr(), 8);
|
|
|
|
(db2Buf)[2]=(db2Buf)[5] = '.';
|
|
|
|
|
|
|
|
convertNumericToEbcdicFast(db2Buf, 8);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int32 temp = sint3korr(data == NULL ? field->ptr : data);
|
|
|
|
memcpy(db2Buf, &temp, sizeof(temp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_YEAR:
|
|
|
|
{
|
|
|
|
String tempString(5);
|
2009-03-09 15:20:14 -06:00
|
|
|
if (db2Field.getType() == QMY_CHAR)
|
2009-02-15 03:18:30 +01:00
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, (String*)NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
field->val_str(&tempString, data);
|
|
|
|
}
|
|
|
|
memcpy(db2Buf, tempString.ptr(), 4);
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
uint8 temp = *(uint8*)(data == NULL ? field->ptr : data);
|
|
|
|
*(uint16*)(db2Buf) = (temp ? temp + 1900 : 0);
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_BIT:
|
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
int bytesToCopy = db2Field.getByteLengthInRecord();
|
2009-02-15 03:18:30 +01:00
|
|
|
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
uint64 temp = field->val_int();
|
|
|
|
memcpy(db2Buf,
|
|
|
|
((char*)&temp) + (sizeof(temp) - bytesToCopy),
|
|
|
|
bytesToCopy);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(db2Buf,
|
|
|
|
data,
|
|
|
|
bytesToCopy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_VARCHAR:
|
|
|
|
case MYSQL_TYPE_STRING:
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
{
|
|
|
|
if (field->real_type() == MYSQL_TYPE_ENUM ||
|
|
|
|
field->real_type() == MYSQL_TYPE_SET)
|
|
|
|
{
|
|
|
|
int64 temp= (data == NULL ? field->val_int() : field->val_int(data));
|
|
|
|
*(int64*)db2Buf = temp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const uchar* dataToStore;
|
|
|
|
uint32 bytesToStore;
|
|
|
|
uint32 bytesToPad = 0;
|
|
|
|
CHARSET_INFO* fieldCharSet = field->charset();
|
|
|
|
uint32 maxDisplayLength = field->max_display_length();
|
|
|
|
switch (fieldType)
|
|
|
|
{
|
|
|
|
case MYSQL_TYPE_STRING:
|
|
|
|
{
|
|
|
|
bytesToStore = maxDisplayLength;
|
|
|
|
if (data == NULL)
|
|
|
|
dataToStore = field->ptr;
|
|
|
|
else
|
|
|
|
dataToStore = data;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_VARCHAR:
|
|
|
|
{
|
|
|
|
|
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
bytesToStore = field->data_length();
|
|
|
|
dataToStore = field->ptr + ((Field_varstring*)field)->length_bytes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Key lens are stored little-endian
|
|
|
|
bytesToStore = *(uint8*)data + ((*(uint8*)(data+1)) << 8);
|
|
|
|
dataToStore = data + 2;
|
|
|
|
}
|
|
|
|
bytesToPad = maxDisplayLength - bytesToStore;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
if (data == NULL)
|
|
|
|
{
|
|
|
|
bytesToStore = ((Field_blob*)field)->get_length();
|
|
|
|
bytesToPad = maxDisplayLength - bytesToStore;
|
|
|
|
((Field_blob*)field)->get_ptr((uchar**)&dataToStore);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Key lens are stored little-endian
|
|
|
|
bytesToStore = *(uint8*)data + ((*(uint8*)(data+1)) << 8);
|
|
|
|
dataToStore = data + 2;
|
|
|
|
}
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 rc;
|
|
|
|
uint16 db2FieldType = db2Field.getType();
|
|
|
|
switch(db2FieldType)
|
|
|
|
{
|
|
|
|
case QMY_CHAR:
|
|
|
|
if (maxDisplayLength == 0)
|
|
|
|
bytesToPad = 1;
|
|
|
|
case QMY_VARCHAR:
|
|
|
|
if (db2FieldType == QMY_VARCHAR)
|
|
|
|
{
|
|
|
|
db2Buf += sizeof(uint16);
|
|
|
|
bytesToPad = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bytesToStore > db2Field.getDataLengthInRecord())
|
|
|
|
{
|
|
|
|
bytesToStore = db2Field.getDataLengthInRecord();
|
|
|
|
field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fieldCharSet == &my_charset_bin) // If binary
|
|
|
|
{
|
|
|
|
if (bytesToStore)
|
|
|
|
memcpy(db2Buf, dataToStore, bytesToStore);
|
|
|
|
if (bytesToPad)
|
|
|
|
memset(db2Buf + bytesToStore, 0x00, bytesToPad);
|
|
|
|
}
|
|
|
|
else if (db2Field.getCCSID() == 1208) // utf8
|
|
|
|
{
|
|
|
|
if (bytesToStore)
|
|
|
|
memcpy(db2Buf, dataToStore, bytesToStore);
|
|
|
|
if (bytesToPad)
|
|
|
|
memset(db2Buf + bytesToStore, ' ', bytesToPad);
|
|
|
|
}
|
|
|
|
else // single-byte ASCII to EBCDIC
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(fieldCharSet->mbmaxlen == 1);
|
|
|
|
if (bytesToStore)
|
|
|
|
{
|
|
|
|
rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore, db2Buf, bytesToStore, bytesToStore, NULL);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
if (bytesToPad)
|
|
|
|
memset(db2Buf + bytesToStore, 0x40, bytesToPad);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (db2FieldType == QMY_VARCHAR)
|
|
|
|
*(uint16*)(db2Buf - sizeof(uint16)) = bytesToStore;
|
|
|
|
break;
|
|
|
|
case QMY_VARGRAPHIC:
|
|
|
|
db2Buf += sizeof(uint16);
|
|
|
|
bytesToPad = 0;
|
|
|
|
case QMY_GRAPHIC:
|
|
|
|
if (maxDisplayLength == 0 && db2FieldType == QMY_GRAPHIC)
|
|
|
|
bytesToPad = 2;
|
|
|
|
|
|
|
|
if (db2Field.getCCSID() == 13488)
|
|
|
|
{
|
|
|
|
if (bytesToStore)
|
|
|
|
memcpy(db2Buf, dataToStore, bytesToStore);
|
|
|
|
if (bytesToPad)
|
2009-05-29 15:01:00 +05:30
|
|
|
memset16((db2Buf + bytesToStore), 0x0020, bytesToPad/2);
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t db2BytesToStore;
|
|
|
|
size_t maxDb2BytesToStore;
|
|
|
|
|
|
|
|
if (maxDisplayLength == 0 && db2FieldType == QMY_GRAPHIC)
|
|
|
|
maxDb2BytesToStore = 2;
|
|
|
|
else
|
|
|
|
maxDb2BytesToStore = min(((bytesToStore * 2) / fieldCharSet->mbminlen),
|
|
|
|
((maxDisplayLength * 2) / fieldCharSet->mbmaxlen));
|
|
|
|
|
|
|
|
if (bytesToStore == 0)
|
|
|
|
db2BytesToStore = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore, db2Buf, bytesToStore, maxDb2BytesToStore, &db2BytesToStore);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
bytesToStore = db2BytesToStore;
|
|
|
|
}
|
|
|
|
if (db2BytesToStore < maxDb2BytesToStore) // If need to pad
|
2009-05-29 15:01:00 +05:30
|
|
|
memset16((db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2);
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (db2FieldType == QMY_VARGRAPHIC)
|
|
|
|
*(uint16*)(db2Buf-sizeof(uint16)) = bytesToStore/2;
|
|
|
|
break;
|
|
|
|
case QMY_BLOBCLOB:
|
|
|
|
case QMY_DBCLOB:
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(data == NULL);
|
|
|
|
DB2LobField* lobField = (DB2LobField*)(db2Buf + db2Field.calcBlobPad());
|
|
|
|
|
|
|
|
if ((fieldCharSet == &my_charset_bin) || // binary or
|
|
|
|
(db2Field.getCCSID()==13488) ||
|
|
|
|
(db2Field.getCCSID()==1208)) // binary UTF8
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char* temp;
|
|
|
|
int32 rc;
|
|
|
|
size_t db2BytesToStore;
|
|
|
|
if (fieldCharSet->mbmaxlen == 1) // single-byte ASCII to EBCDIC
|
|
|
|
{
|
|
|
|
temp = getCharacterConversionBuffer(field->field_index, bytesToStore);
|
|
|
|
rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore,temp,bytesToStore, bytesToStore, NULL);
|
|
|
|
if (rc)
|
|
|
|
return (rc);
|
|
|
|
}
|
|
|
|
else // Else Far East, special UTF8 or non-special UTF8/UCS2
|
|
|
|
{
|
|
|
|
size_t maxDb2BytesToStore;
|
|
|
|
maxDb2BytesToStore = min(((bytesToStore * 2) / fieldCharSet->mbminlen),
|
|
|
|
((maxDisplayLength * 2) / fieldCharSet->mbmaxlen));
|
|
|
|
temp = getCharacterConversionBuffer(field->field_index, maxDb2BytesToStore);
|
|
|
|
rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore,temp,bytesToStore, maxDb2BytesToStore, &db2BytesToStore);
|
|
|
|
if (rc)
|
|
|
|
return (rc);
|
|
|
|
bytesToStore = db2BytesToStore;
|
|
|
|
}
|
|
|
|
dataToStore = (uchar*)temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 blobID = db2Table->getBlobIdFromField(field->field_index);
|
|
|
|
if (blobWriteBuffers[blobID] != (char*)dataToStore)
|
|
|
|
blobWriteBuffers[blobID].reassign((char*)dataToStore);
|
|
|
|
if ((void*)blobWriteBuffers[blobID])
|
|
|
|
lobField->dataHandle = (ILEMemHandle)blobWriteBuffers[blobID];
|
|
|
|
else
|
|
|
|
lobField->dataHandle = 0;
|
|
|
|
lobField->length = bytesToStore / (db2FieldType == QMY_DBCLOB ? 2 : 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ha_thd()->is_error());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Convert DB2 field data into the equivalent MySQL format
|
|
|
|
|
|
|
|
@param db2Field The DB2 field definition
|
|
|
|
@param field The MySQL field to receive the converted data
|
|
|
|
@param buf The DB2 data to be converted
|
|
|
|
*/
|
|
|
|
int32 ha_ibmdb2i::convertDB2toMySQL(const DB2Field& db2Field, Field* field, const char* buf)
|
|
|
|
{
|
|
|
|
int32 storeRC = 0; // Result of the field->store() operation
|
|
|
|
|
|
|
|
const char* bufPtr = buf + db2Field.getBufferOffset();
|
|
|
|
|
|
|
|
switch (field->type())
|
|
|
|
{
|
|
|
|
case MYSQL_TYPE_NEWDECIMAL:
|
|
|
|
{
|
|
|
|
uint precision= ((Field_new_decimal*)field)->precision;
|
|
|
|
uint scale= field->decimals();
|
|
|
|
uint db2Precision = min(precision, MAX_DEC_PRECISION);
|
|
|
|
uint decimalPlace = precision-scale+1;
|
|
|
|
char temp[80];
|
|
|
|
|
|
|
|
if (precision <= MAX_DEC_PRECISION ||
|
|
|
|
scale > precision - MAX_DEC_PRECISION)
|
|
|
|
{
|
|
|
|
uint numNibbles = db2Precision + (db2Precision % 2 ? 0 : 1);
|
|
|
|
|
|
|
|
temp[0] = (bcdGet(bufPtr, numNibbles) == 0xD ? '-' : ' ');
|
|
|
|
int strPos=1;
|
|
|
|
int bcdPos=(db2Precision % 2 ? 0 : 1);
|
|
|
|
|
|
|
|
for (;bcdPos < numNibbles; bcdPos++, strPos++)
|
|
|
|
{
|
|
|
|
if (strPos == decimalPlace)
|
|
|
|
{
|
|
|
|
temp[strPos] = '.';
|
|
|
|
strPos++;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp[strPos] = bcdGet(bufPtr, bcdPos) + '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
temp[strPos] = 0;
|
|
|
|
|
|
|
|
storeRC = field->store(temp, strPos, &my_charset_latin1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TINY:
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int16*)bufPtr, ((Field_num*)field)->unsigned_flag);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_SHORT:
|
|
|
|
{
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int32*)bufPtr, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int16*)bufPtr, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_LONG:
|
|
|
|
{
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int64*)bufPtr, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int32*)bufPtr, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(float*)bufPtr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DOUBLE:
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(double*)bufPtr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_LONGLONG:
|
|
|
|
{
|
|
|
|
char temp[23];
|
|
|
|
if (((Field_num*)field)->unsigned_flag)
|
|
|
|
{
|
|
|
|
temp[0] = (bcdGet(bufPtr, 21) == 0xD ? '-' : ' ');
|
|
|
|
int strPos=1;
|
|
|
|
int bcdPos=0;
|
|
|
|
|
|
|
|
for (;bcdPos <= 20; bcdPos++, strPos++)
|
|
|
|
{
|
|
|
|
temp[strPos] = bcdGet(bufPtr, bcdPos) + '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
temp[strPos] = 0;
|
|
|
|
|
|
|
|
storeRC = field->store(temp, strPos, &my_charset_latin1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int64*)bufPtr, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_INT24:
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int32*)bufPtr, ((Field_num*)field)->unsigned_flag);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DATE:
|
|
|
|
case MYSQL_TYPE_NEWDATE:
|
|
|
|
{
|
|
|
|
longlong value= a4toi_ebcdic((uchar*)bufPtr) * 10000 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+5) * 100 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+8);
|
|
|
|
|
2009-03-09 15:20:14 -06:00
|
|
|
if (cachedZeroDateOption == SUBSTITUTE_0001_01_01 &&
|
|
|
|
value == (10000 + 100 + 1))
|
|
|
|
value = 0;
|
|
|
|
|
2009-02-15 03:18:30 +01:00
|
|
|
storeRC = field->store(value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TIME:
|
|
|
|
{
|
|
|
|
if (db2Field.getType() == QMY_TIME)
|
|
|
|
{
|
|
|
|
longlong value= a2toi_ebcdic((uchar*)bufPtr) * 10000 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+3) * 100 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+6);
|
|
|
|
|
|
|
|
storeRC = field->store(value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
storeRC = field->store(*((int32*)bufPtr));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
|
|
|
{
|
|
|
|
longlong value= (a4toi_ebcdic((uchar*)bufPtr) * 10000 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+5) * 100 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+8)) * 1000000LL +
|
|
|
|
(a2toi_ebcdic((uchar*)bufPtr+11) * 10000 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+14) * 100 +
|
|
|
|
a2toi_ebcdic((uchar*)bufPtr+17));
|
2009-03-09 15:20:14 -06:00
|
|
|
|
|
|
|
if (cachedZeroDateOption == SUBSTITUTE_0001_01_01 &&
|
|
|
|
value == (10000 + 100 + 1) * 1000000LL)
|
|
|
|
value = 0;
|
2009-02-15 03:18:30 +01:00
|
|
|
|
|
|
|
storeRC = field->store(value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_YEAR:
|
|
|
|
{
|
2009-03-09 15:20:14 -06:00
|
|
|
if (db2Field.getType() == QMY_CHAR)
|
|
|
|
{
|
|
|
|
storeRC = field->store(bufPtr, 4, &my_charset_bin);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
storeRC = field->store(*((uint16*)bufPtr));
|
|
|
|
}
|
2009-02-15 03:18:30 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_BIT:
|
|
|
|
{
|
|
|
|
uint64 temp= 0;
|
2009-03-09 15:20:14 -06:00
|
|
|
int bytesToCopy= db2Field.getByteLengthInRecord();
|
2009-02-15 03:18:30 +01:00
|
|
|
memcpy(((char*)&temp) + (sizeof(temp) - bytesToCopy), bufPtr, bytesToCopy);
|
|
|
|
storeRC = field->store(temp, TRUE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_VARCHAR:
|
|
|
|
case MYSQL_TYPE_STRING:
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
{
|
|
|
|
if (field->real_type() == MYSQL_TYPE_ENUM ||
|
|
|
|
field->real_type() == MYSQL_TYPE_SET)
|
|
|
|
{
|
|
|
|
storeRC = field->store(*(int64*)bufPtr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
const char* dataToStore = NULL;
|
|
|
|
uint32 bytesToStore = 0;
|
|
|
|
CHARSET_INFO* fieldCharSet = field->charset();
|
|
|
|
switch(db2Field.getType())
|
|
|
|
{
|
|
|
|
case QMY_CHAR:
|
|
|
|
case QMY_GRAPHIC:
|
|
|
|
{
|
|
|
|
bytesToStore = db2Field.getByteLengthInRecord();
|
|
|
|
if (bytesToStore == 0)
|
|
|
|
bytesToStore = 1;
|
|
|
|
dataToStore = bufPtr;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case QMY_VARCHAR:
|
|
|
|
{
|
|
|
|
bytesToStore = *(uint16*)bufPtr;
|
|
|
|
dataToStore = bufPtr+sizeof(uint16);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case QMY_VARGRAPHIC:
|
|
|
|
{
|
|
|
|
/* For VARGRAPHIC, convert the number of double-byte characters
|
|
|
|
to the number of bytes. */
|
|
|
|
bytesToStore = (*(uint16*)bufPtr)*2;
|
|
|
|
dataToStore = bufPtr+sizeof(uint16);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case QMY_DBCLOB:
|
|
|
|
case QMY_BLOBCLOB:
|
|
|
|
{
|
|
|
|
DB2LobField* lobField = (DB2LobField* )(bufPtr + db2Field.calcBlobPad());
|
|
|
|
bytesToStore = lobField->length * (db2Field.getType() == QMY_DBCLOB ? 2 : 1);
|
|
|
|
dataToStore = (char*)blobReadBuffers->getBufferPtr(field->field_index);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fieldCharSet != &my_charset_bin) && // not binary &
|
|
|
|
(db2Field.getCCSID() != 13488) && // not UCS2 &
|
|
|
|
(db2Field.getCCSID() != 1208))
|
|
|
|
{
|
|
|
|
char* temp;
|
|
|
|
size_t db2BytesToStore;
|
|
|
|
int rc;
|
|
|
|
if (fieldCharSet->mbmaxlen > 1)
|
|
|
|
{
|
|
|
|
size_t maxDb2BytesToStore = ((bytesToStore / 2) * fieldCharSet->mbmaxlen); // Worst case for number of bytes
|
|
|
|
temp = getCharacterConversionBuffer(field->field_index, maxDb2BytesToStore);
|
|
|
|
rc = convertFieldChars(toMySQL, field->field_index, dataToStore, temp, bytesToStore, maxDb2BytesToStore, &db2BytesToStore);
|
|
|
|
bytesToStore = db2BytesToStore;
|
|
|
|
}
|
|
|
|
else // single-byte ASCII to EBCDIC
|
|
|
|
{
|
|
|
|
temp = getCharacterConversionBuffer(field->field_index, bytesToStore);
|
|
|
|
rc = convertFieldChars(toMySQL, field->field_index, dataToStore, temp, bytesToStore, bytesToStore, NULL);
|
|
|
|
}
|
|
|
|
if (rc)
|
|
|
|
return (rc);
|
|
|
|
dataToStore = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((field)->flags & BLOB_FLAG)
|
|
|
|
((Field_blob*)(field))->set_ptr(bytesToStore, (uchar*)dataToStore);
|
|
|
|
else
|
|
|
|
storeRC = field->store(dataToStore, bytesToStore, &my_charset_bin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (storeRC)
|
|
|
|
{
|
|
|
|
invalidDataFound = true;
|
|
|
|
}
|
2009-03-09 15:20:14 -06:00
|
|
|
|
2009-02-15 03:18:30 +01:00
|
|
|
return 0;
|
|
|
|
}
|