mirror of
https://github.com/MariaDB/server.git
synced 2026-04-29 03:35:34 +02:00
Import the ibmdb2i-ga4-src snapshot from IBM
This commit is contained in:
parent
338aefcb38
commit
a5216560d0
18 changed files with 837 additions and 301 deletions
|
|
@ -65,6 +65,11 @@ public:
|
|||
len = size;
|
||||
if (protectBuf)
|
||||
mprotect(protectedPage(), 0x1000, PROT_NONE);
|
||||
#ifndef DBUG_OFF
|
||||
// Prevents a problem with DBUG_PRINT over-reading in recent versions of
|
||||
// MySQL
|
||||
*((char*)protectedPage()-1) = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -703,7 +703,7 @@ static int32 openNewConversion(enum_conversionDirection direction,
|
|||
*/
|
||||
int32 getConversion(enum_conversionDirection direction, const CHARSET_INFO* cs, uint16 db2CCSID, iconv_t& conversion)
|
||||
{
|
||||
DBUG_ENTER("db2i_charsetSupport::convChars");
|
||||
DBUG_ENTER("db2i_charsetSupport::getConversion");
|
||||
|
||||
int32 rc;
|
||||
|
||||
|
|
|
|||
|
|
@ -277,33 +277,32 @@ static int32 getAssociatedSortSequence(const CHARSET_INFO *fieldCharSet, const c
|
|||
|
||||
This function accumulates information about a key as it is called for each
|
||||
field composing the key. The caller should invoke the function for each field
|
||||
and (with the exception of the curField parm) preserve the values for the
|
||||
and (with the exception of the charset parm) preserve the values for the
|
||||
parms across invocations, until a particular key has been evaluated. Once
|
||||
the last field in the key has been evaluated, the fileSortSequence and
|
||||
fileSortSequenceLibrary parms will contain the correct information for
|
||||
creating the corresponding DB2 key.
|
||||
|
||||
@param curField The field under consideration
|
||||
@param charset The character set under consideration
|
||||
@param[in, out] fileSortSequenceType The type of the current key's sort seq
|
||||
@param[in, out] fileSortSequence The IBM i identifier for the DB2 sort sequence
|
||||
that corresponds
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
int32 updateAssociatedSortSequence(const Field *curField,
|
||||
int32 updateAssociatedSortSequence(const CHARSET_INFO* charset,
|
||||
char* fileSortSequenceType,
|
||||
char* fileSortSequence,
|
||||
char* fileSortSequenceLibrary)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::updateAssociatedSortSequence");
|
||||
DBUG_ASSERT(curField);
|
||||
CHARSET_INFO* fieldCharSet = curField->charset();
|
||||
if (strcmp(fieldCharSet->csname,"binary") != 0)
|
||||
DBUG_ASSERT(charset);
|
||||
if (strcmp(charset->csname,"binary") != 0)
|
||||
{
|
||||
char newSortSequence[11] = "";
|
||||
char newSortSequenceType = ' ';
|
||||
const char* foundSortSequence;
|
||||
int rc = getAssociatedSortSequence(fieldCharSet, &foundSortSequence);
|
||||
int rc = getAssociatedSortSequence(charset, &foundSortSequence);
|
||||
if (rc) DBUG_RETURN (rc);
|
||||
switch(foundSortSequence[0])
|
||||
{
|
||||
|
|
@ -313,11 +312,11 @@ int32 updateAssociatedSortSequence(const Field *curField,
|
|||
break;
|
||||
case 'Q': // Non-ICU sort sequence
|
||||
strcat(newSortSequence,foundSortSequence);
|
||||
if ((fieldCharSet->state & MY_CS_BINSORT) != 0)
|
||||
if ((charset->state & MY_CS_BINSORT) != 0)
|
||||
{
|
||||
strcat(newSortSequence,"U");
|
||||
}
|
||||
else if ((fieldCharSet->state & MY_CS_CSSORT) != 0)
|
||||
else if ((charset->state & MY_CS_CSSORT) != 0)
|
||||
{
|
||||
strcat(newSortSequence,"U");
|
||||
}
|
||||
|
|
@ -329,7 +328,7 @@ int32 updateAssociatedSortSequence(const Field *curField,
|
|||
break;
|
||||
default: // ICU sort sequence
|
||||
{
|
||||
if ((fieldCharSet->state & MY_CS_CSSORT) == 0)
|
||||
if ((charset->state & MY_CS_CSSORT) == 0)
|
||||
{
|
||||
if (osVersion.v >= 6)
|
||||
strcat(newSortSequence,"I34"); // ICU 3.4
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ OF SUCH DAMAGE.
|
|||
#include "db2i_global.h"
|
||||
#include "mysql_priv.h"
|
||||
|
||||
int32 updateAssociatedSortSequence(const Field *curField, char* fileSortSequenceType, char* fileSortSequence, char* fileSortSequenceLibrary);
|
||||
int32 updateAssociatedSortSequence(const CHARSET_INFO* charset,
|
||||
char* fileSortSequenceType,
|
||||
char* fileSortSequence,
|
||||
char* fileSortSequenceLibrary);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ int ha_ibmdb2i::buildDB2ConstraintString(LEX* lex,
|
|||
{
|
||||
if (strcmp((*field)->field_name, curColumn->field_name) == 0)
|
||||
{
|
||||
int rc = updateAssociatedSortSequence((*field),
|
||||
int rc = updateAssociatedSortSequence((*field)->charset(),
|
||||
fileSortSequenceType,
|
||||
fileSortSequence,
|
||||
fileSortSequenceLibrary);
|
||||
|
|
@ -447,14 +447,13 @@ int ha_ibmdb2i::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_lis
|
|||
cst_name* fieldName; // Pointer to field name structure
|
||||
const char *method;
|
||||
ulong methodLen;
|
||||
bool gotShare = FALSE; // Indicator for local get_share
|
||||
char* tempPtr; // Temp pointer for traversing constraint space
|
||||
char convName[128];
|
||||
|
||||
// Allocate space to retrieve the DB2 constraint information.
|
||||
if (!(share = get_share(table_share->path.str, table)))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
// Allocate space to retrieve the DB2 constraint information.
|
||||
constraintSpaceLength = 5000; // Try allocating 5000 bytes and see if enough.
|
||||
|
||||
constraintSpace.alloc(constraintSpaceLength);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ OF SUCH DAMAGE.
|
|||
#include "db2i_errors.h"
|
||||
#include "wchar.h"
|
||||
|
||||
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";
|
||||
|
||||
|
||||
/**
|
||||
Put a BCD digit into a BCD string.
|
||||
|
||||
|
|
@ -149,7 +155,6 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
|
|||
}
|
||||
|
||||
size_t initOLen= olen;
|
||||
ilen = min(ilen, olen); // Handle partial translation
|
||||
size_t substitutedChars = 0;
|
||||
int rc = iconv(conversion, (char**)&input, &ilen, &output, &olen, &substitutedChars );
|
||||
if (unlikely(rc < 0))
|
||||
|
|
@ -176,6 +181,178 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
|
|||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Convert a MySQL field definition into its corresponding DB2 type.
|
||||
|
|
@ -189,10 +366,15 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
|
|||
int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
||||
String& mapping,
|
||||
enum_TimeFormat timeFormat,
|
||||
enum_BlobMapping blobMapping)
|
||||
enum_BlobMapping blobMapping,
|
||||
enum_ZeroDate zeroDateHandling,
|
||||
bool propagateDefaults,
|
||||
enum_YearFormat yearFormat)
|
||||
{
|
||||
char stringBuildBuffer[257];
|
||||
uint32 fieldLength;
|
||||
bool defaultNeedsQuotes = false;
|
||||
uint16 db2Ccsid = 0;
|
||||
|
||||
CHARSET_INFO* fieldCharSet = field->charset();
|
||||
switch (field->type())
|
||||
|
|
@ -257,19 +439,69 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
mapping.append(STRING_WITH_LEN("DATE"));
|
||||
defaultNeedsQuotes = true;
|
||||
break;
|
||||
case MYSQL_TYPE_TIME:
|
||||
if (timeFormat == TIME_OF_DAY)
|
||||
{
|
||||
mapping.append(STRING_WITH_LEN("TIME"));
|
||||
defaultNeedsQuotes = true;
|
||||
}
|
||||
else
|
||||
mapping.append(STRING_WITH_LEN("INTEGER"));
|
||||
break;
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
mapping.append(STRING_WITH_LEN("TIMESTAMP"));
|
||||
mapping.append(STRING_WITH_LEN("TIMESTAMP"));
|
||||
defaultNeedsQuotes = true;
|
||||
break;
|
||||
case MYSQL_TYPE_YEAR:
|
||||
mapping.append(STRING_WITH_LEN("CHAR(4) CCSID 1208"));
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case MYSQL_TYPE_BIT:
|
||||
sprintf(stringBuildBuffer, "BINARY(%d)", (field->max_display_length() / 8) + 1);
|
||||
|
|
@ -286,6 +518,8 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||
}
|
||||
else
|
||||
{
|
||||
defaultNeedsQuotes = true;
|
||||
|
||||
fieldLength = field->max_display_length(); // Get field byte length
|
||||
|
||||
if (fieldCharSet == &my_charset_bin)
|
||||
|
|
@ -300,12 +534,11 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||
{
|
||||
sprintf(stringBuildBuffer, "VARBINARY(%d)", max(fieldLength, 1));
|
||||
}
|
||||
/* else if (blobMapping == AS_VARCHAR &&
|
||||
get_blob_type_from_length(fieldLength) == MYSQL_TYPE_BLOB)
|
||||
else if (blobMapping == AS_VARCHAR &&
|
||||
(field->flags & PART_KEY_FLAG))
|
||||
{
|
||||
sprintf(stringBuildBuffer, "LONG VARBINARY ", max(fieldLength, 1));
|
||||
sprintf(stringBuildBuffer, "LONG VARBINARY ");
|
||||
}
|
||||
*/
|
||||
else
|
||||
{
|
||||
fieldLength = min(MAX_BLOB_LENGTH, fieldLength);
|
||||
|
|
@ -316,7 +549,6 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||
}
|
||||
else
|
||||
{
|
||||
uint16 db2Ccsid = 0; // No override CCSID
|
||||
if (field->type() == MYSQL_TYPE_STRING)
|
||||
{
|
||||
if (fieldLength > MAX_CHAR_LENGTH)
|
||||
|
|
@ -375,7 +607,7 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||
}
|
||||
}
|
||||
else if (blobMapping == AS_VARCHAR &&
|
||||
get_blob_type_from_length(fieldLength) == MYSQL_TYPE_BLOB)
|
||||
(field->flags & PART_KEY_FLAG))
|
||||
{
|
||||
if (fieldCharSet->mbmaxlen > 1)
|
||||
{
|
||||
|
|
@ -447,6 +679,13 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
|
|||
|
||||
}
|
||||
|
||||
if (propagateDefaults)
|
||||
get_field_default_value(field,
|
||||
mapping,
|
||||
defaultNeedsQuotes,
|
||||
db2Ccsid,
|
||||
(zeroDateHandling==SUBSTITUTE_0001_01_01));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -552,7 +791,6 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
|
|||
case MYSQL_TYPE_DATETIME:
|
||||
{
|
||||
String tempString(27);
|
||||
const char* ZERO_VALUE = "0000-00-00 00:00:00";
|
||||
if (data == NULL)
|
||||
{
|
||||
field->val_str(&tempString, &tempString);
|
||||
|
|
@ -563,10 +801,15 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
|
|||
}
|
||||
memset(db2Buf, '0', 26);
|
||||
memcpy(db2Buf, tempString.ptr(), tempString.length());
|
||||
if (strncmp(db2Buf,ZERO_VALUE,strlen(ZERO_VALUE)) == 0)
|
||||
if (strncmp(db2Buf,ZERO_DATETIME_VALUE,strlen(ZERO_DATETIME_VALUE)) == 0)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_INVALID_COL_VALUE,ZERO_VALUE,field->field_name);
|
||||
return(DB2I_ERR_INVALID_COL_VALUE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
(db2Buf)[10] = '-';
|
||||
(db2Buf)[13] = (db2Buf)[16] = (db2Buf)[19] = '.';
|
||||
|
|
@ -620,7 +863,6 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
|
|||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
{
|
||||
const char* ZERO_VALUE = "0000-00-00";
|
||||
String tempString(11);
|
||||
if (data == NULL)
|
||||
{
|
||||
|
|
@ -631,10 +873,15 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
|
|||
field->val_str(&tempString, data);
|
||||
}
|
||||
memcpy(db2Buf, tempString.ptr(), 10);
|
||||
if (strncmp(db2Buf,ZERO_VALUE,strlen(ZERO_VALUE)) == 0)
|
||||
if (strncmp(db2Buf,ZERO_DATE_VALUE,strlen(ZERO_DATE_VALUE)) == 0)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_INVALID_COL_VALUE,ZERO_VALUE,field->field_name);
|
||||
return(DB2I_ERR_INVALID_COL_VALUE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
convertNumericToEbcdicFast(db2Buf,10);
|
||||
|
|
@ -668,20 +915,28 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
|
|||
case MYSQL_TYPE_YEAR:
|
||||
{
|
||||
String tempString(5);
|
||||
if (data == NULL)
|
||||
if (db2Field.getType() == QMY_CHAR)
|
||||
{
|
||||
field->val_str(&tempString, (String*)NULL);
|
||||
if (data == NULL)
|
||||
{
|
||||
field->val_str(&tempString, (String*)NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
field->val_str(&tempString, data);
|
||||
}
|
||||
memcpy(db2Buf, tempString.ptr(), 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
field->val_str(&tempString, data);
|
||||
uint8 temp = *(uint8*)(data == NULL ? field->ptr : data);
|
||||
*(uint16*)(db2Buf) = (temp ? temp + 1900 : 0);
|
||||
}
|
||||
memcpy(db2Buf, tempString.ptr(), 4);
|
||||
}
|
||||
break;
|
||||
case MYSQL_TYPE_BIT:
|
||||
{
|
||||
int bytesToCopy = (db2Field.getByteLengthInRecord()-1) / 8 + 1;
|
||||
int bytesToCopy = db2Field.getByteLengthInRecord();
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
|
|
@ -745,10 +1000,18 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
|
|||
break;
|
||||
case MYSQL_TYPE_BLOB:
|
||||
{
|
||||
DBUG_ASSERT(data == NULL);
|
||||
bytesToStore = ((Field_blob*)field)->get_length();
|
||||
bytesToPad = maxDisplayLength - bytesToStore;
|
||||
((Field_blob*)field)->get_ptr((uchar**)&dataToStore);
|
||||
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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1028,6 +1291,10 @@ int32 ha_ibmdb2i::convertDB2toMySQL(const DB2Field& db2Field, Field* field, cons
|
|||
a2toi_ebcdic((uchar*)bufPtr+5) * 100 +
|
||||
a2toi_ebcdic((uchar*)bufPtr+8);
|
||||
|
||||
if (cachedZeroDateOption == SUBSTITUTE_0001_01_01 &&
|
||||
value == (10000 + 100 + 1))
|
||||
value = 0;
|
||||
|
||||
storeRC = field->store(value);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1054,19 +1321,30 @@ int32 ha_ibmdb2i::convertDB2toMySQL(const DB2Field& db2Field, Field* field, cons
|
|||
(a2toi_ebcdic((uchar*)bufPtr+11) * 10000 +
|
||||
a2toi_ebcdic((uchar*)bufPtr+14) * 100 +
|
||||
a2toi_ebcdic((uchar*)bufPtr+17));
|
||||
|
||||
if (cachedZeroDateOption == SUBSTITUTE_0001_01_01 &&
|
||||
value == (10000 + 100 + 1) * 1000000LL)
|
||||
value = 0;
|
||||
|
||||
storeRC = field->store(value);
|
||||
}
|
||||
break;
|
||||
case MYSQL_TYPE_YEAR:
|
||||
{
|
||||
storeRC = field->store(bufPtr, 4, &my_charset_bin);
|
||||
if (db2Field.getType() == QMY_CHAR)
|
||||
{
|
||||
storeRC = field->store(bufPtr, 4, &my_charset_bin);
|
||||
}
|
||||
else
|
||||
{
|
||||
storeRC = field->store(*((uint16*)bufPtr));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MYSQL_TYPE_BIT:
|
||||
{
|
||||
uint64 temp= 0;
|
||||
int bytesToCopy= (db2Field.getByteLengthInRecord()-1) / 8 + 1;
|
||||
int bytesToCopy= db2Field.getByteLengthInRecord();
|
||||
memcpy(((char*)&temp) + (sizeof(temp) - bytesToCopy), bufPtr, bytesToCopy);
|
||||
storeRC = field->store(temp, TRUE);
|
||||
}
|
||||
|
|
@ -1163,6 +1441,6 @@ int32 ha_ibmdb2i::convertDB2toMySQL(const DB2Field& db2Field, Field* field, cons
|
|||
{
|
||||
invalidDataFound = true;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ static const char* engineErrors[MAX_MSGSTRING] =
|
|||
{"Error in iconv() function during character set conversion (errno = %d)"},
|
||||
{"Error from Get Encoding Scheme (QTQGESP) API: %d, %d, %d"},
|
||||
{"Error from Get Related Default CCSID (QTQGRDC) API: %d, %d, %d"},
|
||||
{"Invalid value '%-.128s' for column '%.192s'"},
|
||||
{"Data out of range for column '%.192s'"},
|
||||
{"Schema name '%.128s' exceeds maximum length of %d characters"},
|
||||
{"Multiple collations not supported in a single index"},
|
||||
{"Multiple collations not supported in a single index or constraint"},
|
||||
{"Sort sequence was not found"},
|
||||
{"One or more characters in column %.128s were substituted during conversion"},
|
||||
{"A decimal column exceeded the maximum precision. Data may be truncated."},
|
||||
|
|
@ -76,6 +76,7 @@ static const char* engineErrors[MAX_MSGSTRING] =
|
|||
{"A duplicate key was encountered for index '%.128s'"},
|
||||
{"A table with the same name exists but has incompatible column definitions."},
|
||||
{"The created table was discovered as an existing DB2 object."},
|
||||
{"Some attribute(s) defined for column '%.128s' may not be honored by accesses from DB2."},
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ enum DB2I_errors
|
|||
DB2I_ERR_UNKNOWN_IDX,
|
||||
DB2I_ERR_DISCOVERY_MISMATCH,
|
||||
DB2I_ERR_WARN_CREATE_DISCOVER,
|
||||
DB2I_LAST_ERR = DB2I_ERR_WARN_CREATE_DISCOVER
|
||||
DB2I_ERR_WARN_COL_ATTRS,
|
||||
DB2I_LAST_ERR = DB2I_ERR_WARN_COL_ATTRS
|
||||
};
|
||||
|
||||
void getErrTxt(int errcode, ...);
|
||||
|
|
@ -86,6 +87,7 @@ void reportSystemAPIError(int errCode, const Qmy_Error_output *errInfo);
|
|||
void warning(THD *thd, int errCode, ...);
|
||||
|
||||
const char* DB2I_SQL0350 = "\xE2\xD8\xD3\xF0\xF3\xF5\xF0"; // SQL0350 in EBCDIC
|
||||
|
||||
const char* DB2I_CPF503A = "\xC3\xD7\xC6\xF5\xF0\xF3\xC1"; // CPF503A in EBCDIC
|
||||
const char* DB2I_SQL0538 = "\xE2\xD8\xD3\xF0\xF5\xF3\xF8"; // SQL0538 in EBCDIC
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -96,11 +96,12 @@ int32 db2i_table::initDB2Objects(const char* path)
|
|||
|
||||
physicalFile = new db2i_file(this);
|
||||
physicalFile->fillILEDefn(&fileDefnSpace[0], true);
|
||||
|
||||
if (fileObjects > 1)
|
||||
|
||||
logicalFileCount = mysqlTable->keys;
|
||||
if (logicalFileCount > 0)
|
||||
{
|
||||
logicalFiles = new db2i_file*[fileObjects - 1];
|
||||
for (int k = 0; k < mysqlTable->keys; k++)
|
||||
logicalFiles = new db2i_file*[logicalFileCount];
|
||||
for (int k = 0; k < logicalFileCount; k++)
|
||||
{
|
||||
logicalFiles[k] = new db2i_file(this, k);
|
||||
logicalFiles[k]->fillILEDefn(&fileDefnSpace[k+1], false);
|
||||
|
|
@ -111,16 +112,29 @@ int32 db2i_table::initDB2Objects(const char* path)
|
|||
size_t formatSpaceLen = sizeof(format_hdr_t) + mysqlTable->fields * sizeof(DB2Field);
|
||||
formatSpace.alloc(formatSpaceLen);
|
||||
|
||||
int rc = db2i_ileBridge::getBridgeForThread()->allocateFileDefn(fileDefnSpace,
|
||||
fileDefnHandles,
|
||||
fileObjects,
|
||||
db2LibNameEbcdic,
|
||||
strlen(db2LibNameEbcdic),
|
||||
formatSpace,
|
||||
formatSpaceLen);
|
||||
int rc = db2i_ileBridge::getBridgeForThread()->
|
||||
expectErrors(QMY_ERR_RTNFMT)->
|
||||
allocateFileDefn(fileDefnSpace,
|
||||
fileDefnHandles,
|
||||
fileObjects,
|
||||
db2LibNameEbcdic,
|
||||
strlen(db2LibNameEbcdic),
|
||||
formatSpace,
|
||||
formatSpaceLen);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
// We have to handle a format space error as a special case of a FID
|
||||
// mismatch. We should only get the space error if columns have been added
|
||||
// to the DB2 table without MySQL's knowledge, which is effectively a
|
||||
// FID problem.
|
||||
if (rc == QMY_ERR_RTNFMT)
|
||||
{
|
||||
rc = QMY_ERR_LVLID_MISMATCH;
|
||||
getErrTxt(rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
convFromEbcdic(((format_hdr_t*)formatSpace)->FilLvlId, fileLevelID, sizeof(fileLevelID));
|
||||
|
||||
|
|
@ -274,7 +288,7 @@ db2i_table::~db2i_table()
|
|||
|
||||
if (logicalFiles)
|
||||
{
|
||||
for (int k = 0; k < mysqlTable->keys; ++k)
|
||||
for (int k = 0; k < logicalFileCount; ++k)
|
||||
{
|
||||
delete logicalFiles[k];
|
||||
}
|
||||
|
|
@ -302,11 +316,40 @@ void db2i_table::getDB2QualifiedNameFromPath(const char* path, char* to)
|
|||
}
|
||||
|
||||
|
||||
size_t db2i_table::smartFilenameToTableName(const char *in, char* out, size_t outlen)
|
||||
{
|
||||
if (strchr(in, '@') == NULL)
|
||||
{
|
||||
return filename_to_tablename(in, out, outlen);
|
||||
}
|
||||
|
||||
char* test = (char*) my_malloc(outlen, MYF(MY_WME));
|
||||
|
||||
filename_to_tablename(in, test, outlen);
|
||||
|
||||
char* cur = test;
|
||||
|
||||
while (*cur)
|
||||
{
|
||||
if ((*cur <= 0x20) || (*cur >= 0x80))
|
||||
{
|
||||
strncpy(out, in, outlen);
|
||||
my_free(test, MYF(0));
|
||||
return min(outlen, strlen(out));
|
||||
}
|
||||
++cur;
|
||||
}
|
||||
|
||||
strncpy(out, test, outlen);
|
||||
my_free(test, MYF(0));
|
||||
return min(outlen, strlen(out));
|
||||
}
|
||||
|
||||
void db2i_table::filenameToTablename(const char* in, char* out, size_t outlen)
|
||||
{
|
||||
if (strchr(in, '#') == NULL)
|
||||
{
|
||||
filename_to_tablename(in, out, outlen);
|
||||
smartFilenameToTableName(in, out, outlen);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +369,7 @@ void db2i_table::filenameToTablename(const char* in, char* out, size_t outlen)
|
|||
memcpy(temp, part1, min(outlen, part2 - part1));
|
||||
temp[min(outlen-1, part2-part1)] = 0;
|
||||
|
||||
int32 accumLen = filename_to_tablename(temp, out, outlen);
|
||||
int32 accumLen = smartFilenameToTableName(temp, out, outlen);
|
||||
|
||||
if (part2 && (accumLen + 4 < outlen))
|
||||
{
|
||||
|
|
@ -337,7 +380,7 @@ void db2i_table::filenameToTablename(const char* in, char* out, size_t outlen)
|
|||
memcpy(temp, part3, min(outlen, part4-part3));
|
||||
temp[min(outlen-1, part4-part3)] = 0;
|
||||
|
||||
accumLen += filename_to_tablename(temp, strend(out), outlen-accumLen);
|
||||
accumLen += smartFilenameToTableName(temp, strend(out), outlen-accumLen);
|
||||
|
||||
if (part4 && (accumLen + (strend(in) - part4 + 1) < outlen))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@ private:
|
|||
|
||||
void findConversionDefinition(enum_conversionDirection direction, uint16 fieldID);
|
||||
static void filenameToTablename(const char* in, char* out, size_t outlen);
|
||||
static size_t smartFilenameToTableName(const char *in, char* out, size_t outlen);
|
||||
void convertNativeToSQLName(const char* input,
|
||||
char* output)
|
||||
{
|
||||
|
|
@ -301,6 +302,7 @@ private:
|
|||
iconv_t* conversionDefinitions[2];
|
||||
|
||||
const TABLE_SHARE* mysqlTable;
|
||||
uint16 logicalFileCount;
|
||||
char* db2LibNameEbcdic; // Quoted and in EBCDIC
|
||||
char* db2LibNameAscii;
|
||||
char* db2TableNameEbcdic;
|
||||
|
|
@ -326,22 +328,18 @@ private:
|
|||
*/
|
||||
class db2i_file
|
||||
{
|
||||
enum RowFormats
|
||||
{
|
||||
readOnly = 0,
|
||||
readWrite,
|
||||
maxRowFormats
|
||||
};
|
||||
|
||||
public:
|
||||
mutable struct RowFormat
|
||||
struct RowFormat
|
||||
{
|
||||
uint16 readRowLen;
|
||||
uint16 readRowNullOffset;
|
||||
uint16 writeRowLen;
|
||||
uint16 writeRowNullOffset;
|
||||
char inited;
|
||||
} formats[maxRowFormats];
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// Construct an instance for a physical file.
|
||||
db2i_file(db2i_table* table);
|
||||
|
|
@ -375,31 +373,29 @@ public:
|
|||
|
||||
// This obtains the row layout associated with a particular access intent for
|
||||
// an open instance of the file.
|
||||
int useFile(FILE_HANDLE instanceHandle,
|
||||
char intent,
|
||||
char commitLevel,
|
||||
const RowFormat** activeFormat) const
|
||||
int obtainRowFormat(FILE_HANDLE instanceHandle,
|
||||
char intent,
|
||||
char commitLevel,
|
||||
const RowFormat** activeFormat) const
|
||||
{
|
||||
DBUG_ENTER("db2i_file::useFile");
|
||||
DBUG_ENTER("db2i_file::obtainRowFormat");
|
||||
RowFormat* rowFormat;
|
||||
|
||||
if (intent == QMY_UPDATABLE)
|
||||
rowFormat = &(formats[readWrite]);
|
||||
else if (intent == QMY_READ_ONLY)
|
||||
rowFormat = &(formats[readOnly]);
|
||||
else
|
||||
DBUG_ASSERT(0);
|
||||
|
||||
if (!rowFormat->inited)
|
||||
if (unlikely(!rowFormat->inited))
|
||||
{
|
||||
int rc;
|
||||
rc = db2i_ileBridge::getBridgeForThread()->initFileForIO(instanceHandle,
|
||||
intent,
|
||||
commitLevel,
|
||||
&(rowFormat->writeRowLen),
|
||||
&(rowFormat->writeRowNullOffset),
|
||||
&(rowFormat->readRowLen),
|
||||
&(rowFormat->readRowNullOffset));
|
||||
int rc = db2i_ileBridge::getBridgeForThread()->
|
||||
initFileForIO(instanceHandle,
|
||||
intent,
|
||||
commitLevel,
|
||||
&(rowFormat->writeRowLen),
|
||||
&(rowFormat->writeRowNullOffset),
|
||||
&(rowFormat->readRowLen),
|
||||
&(rowFormat->readRowNullOffset));
|
||||
if (rc) DBUG_RETURN(rc);
|
||||
rowFormat->inited = 1;
|
||||
}
|
||||
|
|
@ -426,6 +422,15 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
enum RowFormats
|
||||
{
|
||||
readOnly = 0,
|
||||
readWrite,
|
||||
maxRowFormats
|
||||
};
|
||||
|
||||
mutable RowFormat formats[maxRowFormats];
|
||||
|
||||
void commonCtorInit();
|
||||
|
||||
char* db2FileName; // Quoted and in EBCDIC
|
||||
|
|
|
|||
|
|
@ -894,6 +894,7 @@ int32 db2i_ileBridge::savepoint(uint8 function,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static ILEMemHandle traceSpcHandle;
|
||||
/**
|
||||
Do initialization for the QMY_* APIs.
|
||||
|
||||
|
|
@ -902,7 +903,8 @@ int32 db2i_ileBridge::savepoint(uint8 function,
|
|||
|
||||
@return 0 if successful; error otherwise
|
||||
*/
|
||||
int32 db2i_ileBridge::initILE(const char* aspName)
|
||||
int32 db2i_ileBridge::initILE(const char* aspName,
|
||||
uint16* traceCtlPtr)
|
||||
{
|
||||
// We forego the typical thread-based parms space because MySQL doesn't
|
||||
// allow us to clean it up before checking for memory leaks. As a result
|
||||
|
|
@ -916,6 +918,8 @@ int32 db2i_ileBridge::initILE(const char* aspName)
|
|||
return rc;
|
||||
}
|
||||
|
||||
registerPtr(traceCtlPtr, &traceSpcHandle);
|
||||
|
||||
struct ParmBlock
|
||||
{
|
||||
Qmy_MINI0100 parms;
|
||||
|
|
@ -935,6 +939,9 @@ int32 db2i_ileBridge::initILE(const char* aspName)
|
|||
memset(paddedName, ' ', sizeof(paddedName));
|
||||
memcpy(paddedName, aspName, strlen(aspName));
|
||||
convToEbcdic(paddedName, parmBlock->parms.RDBName, strlen(paddedName));
|
||||
|
||||
parmBlock->parms.RDBNamLen = strlen(paddedName);
|
||||
parmBlock->parms.TrcSpcHnd = traceSpcHandle;
|
||||
|
||||
rc = doIt();
|
||||
|
||||
|
|
@ -963,6 +970,8 @@ int32 db2i_ileBridge::exitILE()
|
|||
{
|
||||
reportSystemAPIError(rc, (Qmy_Error_output_t*)parmBlock->outParms);
|
||||
}
|
||||
|
||||
unregisterPtr(traceSpcHandle);
|
||||
|
||||
DBUG_PRINT("db2i_ileBridge::exitILE", ("Registered ptrs remaining: %d", registeredPtrs));
|
||||
#ifndef DBUG_OFF
|
||||
|
|
@ -1267,7 +1276,7 @@ int32 db2i_ileBridge::quiesceFileInstance(FILE_HANDLE rfileHandle)
|
|||
return rc;
|
||||
}
|
||||
|
||||
void db2i_ileBridge::PreservedHandleList::add(const char* newname, FILE_HANDLE newhandle)
|
||||
void db2i_ileBridge::PreservedHandleList::add(const char* newname, FILE_HANDLE newhandle, IBMDB2I_SHARE* share)
|
||||
{
|
||||
NameHandlePair *newPair = (NameHandlePair*)my_malloc(sizeof(NameHandlePair), MYF(MY_WME));
|
||||
|
||||
|
|
@ -1276,11 +1285,12 @@ void db2i_ileBridge::PreservedHandleList::add(const char* newname, FILE_HANDLE n
|
|||
|
||||
strcpy(newPair->name, newname);
|
||||
newPair->handle = newhandle;
|
||||
newPair->share = share;
|
||||
DBUG_PRINT("db2i_ileBridge", ("Added handle %d for %s", uint32(newhandle), newname));
|
||||
}
|
||||
|
||||
|
||||
FILE_HANDLE db2i_ileBridge::PreservedHandleList::findAndRemove(const char* fileName)
|
||||
FILE_HANDLE db2i_ileBridge::PreservedHandleList::findAndRemove(const char* fileName, IBMDB2I_SHARE** share)
|
||||
{
|
||||
NameHandlePair* current = head;
|
||||
NameHandlePair* prev = NULL;
|
||||
|
|
@ -1291,6 +1301,7 @@ FILE_HANDLE db2i_ileBridge::PreservedHandleList::findAndRemove(const char* fileN
|
|||
if (strcmp(fileName, current->name) == 0)
|
||||
{
|
||||
FILE_HANDLE tmp = current->handle;
|
||||
*share = current->share;
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
if (current == head)
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ enum db2i_InfoRequestSpec
|
|||
};
|
||||
|
||||
extern handlerton *ibmdb2i_hton;
|
||||
struct IBMDB2I_SHARE;
|
||||
|
||||
const uint32 db2i_ileBridge_MAX_INPARM_SIZE = 512;
|
||||
const uint32 db2i_ileBridge_MAX_OUTPARM_SIZE = 512;
|
||||
|
|
@ -220,7 +221,8 @@ public:
|
|||
uint32* outLen,
|
||||
uint32* outCnt);
|
||||
int32 optimizeTable(FILE_HANDLE rfileHandle);
|
||||
static int32 initILE(const char* aspName);
|
||||
static int32 initILE(const char* aspName,
|
||||
uint16* traceCtlPtr);
|
||||
int32 initFileForIO(FILE_HANDLE rfileHandle,
|
||||
char accessIntent,
|
||||
char commitLevel,
|
||||
|
|
@ -336,9 +338,9 @@ public:
|
|||
@param newhandle The handle associated with newname
|
||||
|
||||
*/
|
||||
void preserveHandle(const char* newname, FILE_HANDLE newhandle)
|
||||
void preserveHandle(const char* newname, FILE_HANDLE newhandle, IBMDB2I_SHARE* share)
|
||||
{
|
||||
pendingLockedHandles.add(newname, newhandle);
|
||||
pendingLockedHandles.add(newname, newhandle, share);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -348,9 +350,10 @@ public:
|
|||
|
||||
@return The handle associated with name
|
||||
*/
|
||||
FILE_HANDLE findAndRemovePreservedHandle(const char* name)
|
||||
FILE_HANDLE findAndRemovePreservedHandle(const char* name, IBMDB2I_SHARE** share)
|
||||
{
|
||||
return pendingLockedHandles.findAndRemove(name);
|
||||
FILE_HANDLE hdl = pendingLockedHandles.findAndRemove(name, share);
|
||||
return hdl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -380,7 +383,7 @@ public:
|
|||
|
||||
@return A pointer to the 7 character message ID.
|
||||
*/
|
||||
const char* getErrorMsgID()
|
||||
static const char* getErrorMsgID()
|
||||
{
|
||||
return ((Qmy_Error_output_t*)parms()->outParms)->MsgId;
|
||||
}
|
||||
|
|
@ -413,6 +416,13 @@ public:
|
|||
return HA_ERR_NO_SUCH_TABLE;
|
||||
case QMY_ERR_NON_UNIQUE_KEY:
|
||||
return ER_DUP_ENTRY;
|
||||
case QMY_ERR_MSGID:
|
||||
{
|
||||
if (memcmp(getErrorMsgID(), DB2I_CPF503A, 7) == 0)
|
||||
return HA_ERR_ROW_IS_REFERENCED;
|
||||
if (memcmp(getErrorMsgID(), DB2I_SQL0538, 7) == 0)
|
||||
return HA_ERR_CANNOT_ADD_FOREIGN;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -458,14 +468,15 @@ private:
|
|||
{
|
||||
friend db2i_ileBridge* db2i_ileBridge::createNewBridge(CONNECTION_HANDLE);
|
||||
public:
|
||||
void add(const char* newname, FILE_HANDLE newhandle);
|
||||
FILE_HANDLE findAndRemove(const char* fileName);
|
||||
void add(const char* newname, FILE_HANDLE newhandle, IBMDB2I_SHARE* share);
|
||||
FILE_HANDLE findAndRemove(const char* fileName, IBMDB2I_SHARE** share);
|
||||
|
||||
private:
|
||||
struct NameHandlePair
|
||||
{
|
||||
char name[FN_REFLEN];
|
||||
FILE_HANDLE handle;
|
||||
IBMDB2I_SHARE* share;
|
||||
NameHandlePair* next;
|
||||
}* head;
|
||||
} pendingLockedHandles;
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ void IOAsyncReadBuffer::newReadRequest(FILE_HANDLE infile,
|
|||
int fildes[2];
|
||||
int ileDescriptor = QMY_REUSE;
|
||||
|
||||
closePipe();
|
||||
interruptRead();
|
||||
|
||||
if (likely(useAsync))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -73,10 +73,12 @@ class IORowBuffer
|
|||
Sets up the buffer to hold the size indicated.
|
||||
|
||||
@param rowLen length of the rows that will be stored in this buffer
|
||||
@param nullMapOffset position of null map within each row
|
||||
@param size buffer size requested
|
||||
*/
|
||||
void allocBuf(uint32 rowLen, uint32 size)
|
||||
void allocBuf(uint32 rowLen, uint16 nullMapOffset, uint32 size)
|
||||
{
|
||||
nullOffset = nullMapOffset;
|
||||
uint32 newSize = size + sizeof(BufferHdr_t);
|
||||
// If the internal structure of the row is changing, we need to
|
||||
// remember this and notify the subclasses via initAfterAllocate();
|
||||
|
|
@ -129,7 +131,9 @@ class IORowBuffer
|
|||
};
|
||||
|
||||
uint32 getRowCapacity() const {return rowCapacity;}
|
||||
|
||||
uint32 getRowNullOffset() const {return nullOffset;}
|
||||
uint32 getRowLength() const {return rowLength;}
|
||||
|
||||
protected:
|
||||
/**
|
||||
Called prior to freeing buffer storage so that subclasses can do
|
||||
|
|
@ -150,6 +154,7 @@ class IORowBuffer
|
|||
uint32 allocSize;
|
||||
uint32 rowCapacity;
|
||||
uint32 rowLength;
|
||||
uint16 nullOffset;
|
||||
uint32& usedRows() const { return ((BufferHdr_t*)(char*)data)->UsedRowCnt; }
|
||||
uint32& maxRows() const {return ((BufferHdr_t*)(char*)data)->MaxRowCnt; }
|
||||
};
|
||||
|
|
@ -207,7 +212,7 @@ class IOReadBuffer : public IORowBuffer
|
|||
IOReadBuffer() {;}
|
||||
IOReadBuffer(uint32 rows, uint32 rowLength)
|
||||
{
|
||||
allocBuf(rows, rows * rowLength);
|
||||
allocBuf(rows, 0, rows * rowLength);
|
||||
maxRows() = rows;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,4 +92,16 @@ bool convertMySQLNameToDB2Name(const char* input,
|
|||
return (o <= outlen-1);
|
||||
}
|
||||
|
||||
bool isUpperOrQuote(const CHARSET_INFO* cs, const char* s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
if (my_isupper(cs, *s) || (*s == '"'))
|
||||
++s;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -140,6 +140,17 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
|
|||
}
|
||||
keyCnt = maxKeyCnt >= minKeyCnt ? maxKeyCnt : minKeyCnt;
|
||||
|
||||
/*
|
||||
Handle the special case where MySQL does not pass either a min or max
|
||||
key range. In this case, set the key count to 1 (knowing that there
|
||||
is at least one key field) to flow through and create one bounds structure.
|
||||
When both the min and max key ranges are nil, the bounds structure will
|
||||
specify positive and negative infinity and DB2 will estimate the total
|
||||
number of rows. */
|
||||
|
||||
if (keyCnt == 0)
|
||||
keyCnt = 1;
|
||||
|
||||
/*
|
||||
Allocate the space needed to pass range information to DB2. The
|
||||
space must be large enough to store the following:
|
||||
|
|
@ -196,8 +207,7 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
|
|||
estimate. If one bound is null, both bounds must be null. When the bound
|
||||
is not null, the data offset and length must be set, and the literal
|
||||
value stored for access by DB2.
|
||||
*/
|
||||
|
||||
*/
|
||||
for (int partsInUse = 0; partsInUse < keyCnt; ++partsInUse)
|
||||
{
|
||||
Field *field= curKey.key_part[partsInUse].field;
|
||||
|
|
@ -298,19 +308,28 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
|
|||
else
|
||||
tempLen = field->field_length;
|
||||
|
||||
if (litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR ||
|
||||
(strncmp(fieldCharSet->csname, "utf8", sizeof("utf8")) == 0))
|
||||
{
|
||||
/* 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)) *
|
||||
(litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR ? 1 : 2));
|
||||
endOfLiteralPtr = tempPtr + ((uint32_t)(endOfMinPtr - tempMinPtr));
|
||||
}
|
||||
else
|
||||
{
|
||||
endOfMinPtr = (char*)wmemchr((wchar_t*)tempMinPtr,field->charset()->min_sort_char,tempLen/2);
|
||||
if (endOfMinPtr)
|
||||
endOfLiteralPtr = tempPtr + (endOfMinPtr - tempMinPtr);
|
||||
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 */
|
||||
|
|
@ -354,6 +373,11 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
|
|||
}
|
||||
else // max_key field is not null
|
||||
{
|
||||
if (boundsPtr->LoBound.IsNull[0] == QMY_YES) // select where x < 10 or x is null
|
||||
{
|
||||
rc = HA_POS_ERROR;
|
||||
break;
|
||||
}
|
||||
if (!reuseLiteral)
|
||||
{
|
||||
if (literalCnt)
|
||||
|
|
@ -381,7 +405,7 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
|
|||
litDefPtr->DataType == QMY_GRAPHIC || litDefPtr->DataType == QMY_VARGRAPHIC))
|
||||
{
|
||||
if (litDefPtr->DataType == QMY_VARCHAR || litDefPtr->DataType == QMY_VARGRAPHIC)
|
||||
{
|
||||
{
|
||||
tempPtr = literalPtr + sizeof(uint16);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ static MYSQL_SYSVAR_STR(rdb_name, ibmdb2i_rdb_name,
|
|||
|
||||
static MYSQL_THDVAR_BOOL(transaction_unsafe,
|
||||
0,
|
||||
"True auto-commit mode.",
|
||||
"Disable support for commitment control",
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE);
|
||||
|
|
@ -113,16 +113,16 @@ static MYSQL_THDVAR_UINT(max_write_buffer_size,
|
|||
64*1024*1024,
|
||||
1);
|
||||
|
||||
static MYSQL_THDVAR_BOOL(create_time_columns_as_TOD,
|
||||
static MYSQL_THDVAR_BOOL(compat_opt_time_as_duration,
|
||||
0,
|
||||
"Control how new TIME columns should be defined in DB2. 1=time-of-day (default), 0=duration.",
|
||||
"Control how new TIME columns should be defined in DB2. 0=time-of-day (default), 1=duration.",
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE);
|
||||
FALSE);
|
||||
|
||||
static MYSQL_THDVAR_UINT(map_blob_to_varchar,
|
||||
static MYSQL_THDVAR_UINT(compat_opt_year_as_int,
|
||||
0,
|
||||
"Control how new TEXT columns should be defined in DB2. 0=CLOB (default), 1=VARCHAR",
|
||||
"Control how new YEAR columns should be defined in DB2. 0=CHAR(4) (default), 1=SMALLINT.",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
|
|
@ -130,6 +130,33 @@ static MYSQL_THDVAR_UINT(map_blob_to_varchar,
|
|||
1,
|
||||
1);
|
||||
|
||||
static MYSQL_THDVAR_UINT(compat_opt_blob_cols,
|
||||
0,
|
||||
"Control how new TEXT and BLOB columns should be defined in DB2. 0=CLOB/BLOB (default), 1=VARCHAR/VARBINARY",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1);
|
||||
|
||||
static MYSQL_THDVAR_UINT(compat_opt_allow_zero_date_vals,
|
||||
0,
|
||||
"Allow substitute values to be used when storing a column with a 0000-00-00 date component. 0=No substitution (default), 1=Substitute '0001-01-01'",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1);
|
||||
|
||||
static MYSQL_THDVAR_BOOL(propagate_default_col_vals,
|
||||
0,
|
||||
"Should DEFAULT column values be propagated to the DB2 table definition.",
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE);
|
||||
|
||||
static my_bool ibmdb2i_assume_exclusive_use;
|
||||
static MYSQL_SYSVAR_BOOL(assume_exclusive_use, ibmdb2i_assume_exclusive_use,
|
||||
0,
|
||||
|
|
@ -155,7 +182,7 @@ static MYSQL_THDVAR_UINT(create_index_option,
|
|||
1,
|
||||
1);
|
||||
|
||||
static MYSQL_THDVAR_UINT(discovery_mode,
|
||||
/* static MYSQL_THDVAR_UINT(discovery_mode,
|
||||
0,
|
||||
"Unsupported",
|
||||
NULL,
|
||||
|
|
@ -163,6 +190,17 @@ static MYSQL_THDVAR_UINT(discovery_mode,
|
|||
0,
|
||||
0,
|
||||
1,
|
||||
1); */
|
||||
|
||||
static uint32 ibmdb2i_system_trace;
|
||||
static MYSQL_SYSVAR_UINT(system_trace_level, ibmdb2i_system_trace,
|
||||
0,
|
||||
"Set system tracing level",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
63,
|
||||
1);
|
||||
|
||||
|
||||
|
|
@ -276,7 +314,7 @@ static int ibmdb2i_init_func(void *p)
|
|||
ibmdb2i_rdb_name[i] = my_toupper(system_charset_info, (uchar)ibmdb2i_rdb_name[i]);
|
||||
}
|
||||
|
||||
rc = db2i_ileBridge::initILE(ibmdb2i_rdb_name);
|
||||
rc = db2i_ileBridge::initILE(ibmdb2i_rdb_name, (uint16*)(((char*)&ibmdb2i_system_trace)+2));
|
||||
if (rc == 0)
|
||||
{
|
||||
was_ILE_inited = true;
|
||||
|
|
@ -294,7 +332,7 @@ static int ibmdb2i_done_func(void *p)
|
|||
|
||||
if (ibmdb2i_open_tables.records)
|
||||
error= 1;
|
||||
|
||||
|
||||
if (was_ILE_inited)
|
||||
db2i_ileBridge::exitILE();
|
||||
|
||||
|
|
@ -386,6 +424,8 @@ int ha_ibmdb2i::free_share(IBMDB2I_SHARE *share)
|
|||
thr_lock_delete(&share->lock);
|
||||
pthread_mutex_destroy(&share->mutex);
|
||||
my_free(share, MYF(0));
|
||||
pthread_mutex_unlock(&ibmdb2i_mutex);
|
||||
return 1;
|
||||
}
|
||||
pthread_mutex_unlock(&ibmdb2i_mutex);
|
||||
|
||||
|
|
@ -528,6 +568,8 @@ ha_ibmdb2i::ha_ibmdb2i(handlerton *hton, TABLE_SHARE *table_arg)
|
|||
|
||||
ha_ibmdb2i::~ha_ibmdb2i()
|
||||
{
|
||||
DBUG_ASSERT(activeReferences == 0 || outstanding_start_bulk_insert);
|
||||
|
||||
if (indexHandles)
|
||||
my_free(indexHandles, MYF(0));
|
||||
if (indexReadSizeEstimates)
|
||||
|
|
@ -554,13 +596,17 @@ int ha_ibmdb2i::open(const char *name, int mode, uint test_if_locked)
|
|||
|
||||
initBridge();
|
||||
|
||||
if (!(share = get_share(name, table)))
|
||||
dataHandle = bridge()->findAndRemovePreservedHandle(name, &share);
|
||||
|
||||
if (share)
|
||||
db2Table = share->db2Table;
|
||||
|
||||
if (!share && (!(share = get_share(name, table))))
|
||||
DBUG_RETURN(my_errno);
|
||||
thr_lock_data_init(&share->lock,&lock,NULL);
|
||||
|
||||
info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
|
||||
|
||||
dataHandle = bridge()->findAndRemovePreservedHandle(name);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
|
@ -572,13 +618,17 @@ int ha_ibmdb2i::close(void)
|
|||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::close");
|
||||
int32 rc = 0;
|
||||
|
||||
bool preserveShare = false;
|
||||
|
||||
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread();
|
||||
|
||||
if (dataHandle)
|
||||
{
|
||||
if (bridge->expectErrors(QMY_ERR_PEND_LOCKS)->deallocateFile(dataHandle, FALSE) == QMY_ERR_PEND_LOCKS)
|
||||
bridge->preserveHandle(share->table_name, dataHandle);
|
||||
{
|
||||
bridge->preserveHandle(share->table_name, dataHandle, share);
|
||||
preserveShare = true;
|
||||
}
|
||||
dataHandle = 0;
|
||||
}
|
||||
|
||||
|
|
@ -592,7 +642,11 @@ int ha_ibmdb2i::close(void)
|
|||
|
||||
cleanupBuffers();
|
||||
|
||||
free_share(share);
|
||||
if (!preserveShare)
|
||||
{
|
||||
if (free_share(share))
|
||||
share = NULL;
|
||||
}
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
|
@ -608,58 +662,60 @@ int ha_ibmdb2i::write_row(uchar * buf)
|
|||
DBUG_RETURN( last_start_bulk_insert_rc );
|
||||
|
||||
ha_statistic_increment(&SSV::ha_write_count);
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
bool fileHandleNeedsRelease = false;
|
||||
|
||||
if (!activeHandle)
|
||||
{
|
||||
rc = useDataFile(QMY_UPDATABLE);
|
||||
rc = useDataFile();
|
||||
if (rc) DBUG_RETURN(rc);
|
||||
fileHandleNeedsRelease = true;
|
||||
}
|
||||
|
||||
if (!outstanding_start_bulk_insert)
|
||||
prepWriteBuffer(1);
|
||||
rc = prepWriteBuffer(1, getFileForActiveHandle());
|
||||
|
||||
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
|
||||
table->timestamp_field->set_time();
|
||||
|
||||
char* writeBuffer = activeWriteBuf->addRow();
|
||||
rc = prepareRowForWrite(writeBuffer,
|
||||
writeBuffer+activeFormat->writeRowNullOffset,
|
||||
true);
|
||||
if (rc == 0)
|
||||
if (!rc)
|
||||
{
|
||||
// If we are doing block inserts, if the MI is supposed to generate an auto_increment
|
||||
// (i.e. identity column) value for this record, and if this is not the first record in
|
||||
// the block, then store the value (that the MI will generate for the identity column)
|
||||
// into the MySQL write buffer. We can predetermine the value because the file is locked.
|
||||
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
|
||||
table->timestamp_field->set_time();
|
||||
|
||||
if ((autoIncLockAcquired) && (default_identity_value) && (got_auto_inc_values))
|
||||
{
|
||||
if (unlikely((next_identity_value - 1) ==
|
||||
maxValueForField(table->next_number_field)))
|
||||
{
|
||||
rc = QMY_ERR_MAXVALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = table->next_number_field->store((longlong) next_identity_value, TRUE);
|
||||
next_identity_value = next_identity_value + incrementByValue;
|
||||
char* writeBuffer = activeWriteBuf->addRow();
|
||||
rc = prepareRowForWrite(writeBuffer,
|
||||
writeBuffer+activeWriteBuf->getRowNullOffset(),
|
||||
true);
|
||||
if (rc == 0)
|
||||
{
|
||||
// If we are doing block inserts, if the MI is supposed to generate an auto_increment
|
||||
// (i.e. identity column) value for this record, and if this is not the first record in
|
||||
// the block, then store the value (that the MI will generate for the identity column)
|
||||
// into the MySQL write buffer. We can predetermine the value because the file is locked.
|
||||
|
||||
if ((autoIncLockAcquired) && (default_identity_value) && (got_auto_inc_values))
|
||||
{
|
||||
if (unlikely((next_identity_value - 1) ==
|
||||
maxValueForField(table->next_number_field)))
|
||||
{
|
||||
rc = QMY_ERR_MAXVALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = table->next_number_field->store((longlong) next_identity_value, TRUE);
|
||||
next_identity_value = next_identity_value + incrementByValue;
|
||||
}
|
||||
}
|
||||
// If the buffer is full, or if we locked the file and this is the first or last row
|
||||
// of a blocked insert, then flush the buffer.
|
||||
if (!rc && (activeWriteBuf->endOfBuffer()) ||
|
||||
((autoIncLockAcquired) &&
|
||||
((!got_auto_inc_values))) ||
|
||||
(returnDupKeysImmediately))
|
||||
rc = flushWrite(activeHandle, buf);
|
||||
}
|
||||
// If the buffer is full, or if we locked the file and this is the first or last row
|
||||
// of a blocked insert, then flush the buffer.
|
||||
if (!rc && (activeWriteBuf->endOfBuffer()) ||
|
||||
((autoIncLockAcquired) &&
|
||||
((!got_auto_inc_values))) ||
|
||||
(returnDupKeysImmediately))
|
||||
rc = flushWrite(activeHandle, buf);
|
||||
else
|
||||
activeWriteBuf->deleteRow();
|
||||
}
|
||||
else
|
||||
activeWriteBuf->deleteRow();
|
||||
|
||||
|
||||
if (fileHandleNeedsRelease)
|
||||
releaseActiveHandle();
|
||||
|
|
@ -748,7 +804,7 @@ int ha_ibmdb2i::update_row(const uchar * old_data, uchar * new_data)
|
|||
|
||||
char* writeBuf = activeWriteBuf->addRow();
|
||||
rc = prepareRowForWrite(writeBuf,
|
||||
writeBuf+activeFormat->writeRowNullOffset,
|
||||
writeBuf+activeWriteBuf->getRowNullOffset(),
|
||||
onDupUpdate);
|
||||
|
||||
char* lastDupKeyNamePtr = NULL;
|
||||
|
|
@ -819,9 +875,28 @@ int ha_ibmdb2i::index_init(uint idx, bool sorted)
|
|||
|
||||
active_index=idx;
|
||||
|
||||
rc = useIndexFile(accessIntent, idx);
|
||||
if (accessIntent != QMY_READ_ONLY)
|
||||
prepWriteBuffer(1);
|
||||
rc = useIndexFile(idx);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
// THD* thd = ha_thd();
|
||||
// if (accessIntent == QMY_UPDATABLE &&
|
||||
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
|
||||
// !THDVAR(thd, transaction_unsafe))
|
||||
// {
|
||||
// readAccessIntent = QMY_READ_ONLY;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
readAccessIntent = accessIntent;
|
||||
// }
|
||||
|
||||
if (!rc && accessIntent != QMY_READ_ONLY)
|
||||
rc = prepWriteBuffer(1, db2Table->indexFile(idx));
|
||||
|
||||
if (rc)
|
||||
releaseIndexFile(idx);
|
||||
}
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
|
@ -839,16 +914,18 @@ int ha_ibmdb2i::index_read(uchar * buf, const uchar * key,
|
|||
int rc;
|
||||
|
||||
ha_rows estimatedRows = getIndexReadEstimate(active_index);
|
||||
rc = prepReadBuffer(estimatedRows);
|
||||
rc = prepReadBuffer(estimatedRows, db2Table->indexFile(active_index), readAccessIntent);
|
||||
if (unlikely(rc)) DBUG_RETURN(rc);
|
||||
|
||||
DBUG_ASSERT(activeReadBuf);
|
||||
|
||||
keyBuf.allocBuf(activeFormat->readRowLen, activeFormat->readRowLen);
|
||||
keyBuf.allocBuf(activeReadBuf->getRowLength(),
|
||||
activeReadBuf->getRowNullOffset(),
|
||||
activeReadBuf->getRowLength());
|
||||
keyBuf.zeroBuf();
|
||||
|
||||
char* db2KeyBufPtr = keyBuf.ptr();
|
||||
char* nullKeyMap = db2KeyBufPtr + activeFormat->readRowNullOffset;
|
||||
char* nullKeyMap = db2KeyBufPtr + activeReadBuf->getRowNullOffset();
|
||||
|
||||
const uchar* keyBegin = key;
|
||||
int partsInUse;
|
||||
|
|
@ -990,7 +1067,9 @@ int ha_ibmdb2i::index_first(uchar * buf)
|
|||
|
||||
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
|
||||
|
||||
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER);
|
||||
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER,
|
||||
db2Table->indexFile(active_index),
|
||||
readAccessIntent);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
|
|
@ -1010,7 +1089,9 @@ int ha_ibmdb2i::index_last(uchar * buf)
|
|||
|
||||
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
|
||||
|
||||
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER);
|
||||
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER,
|
||||
db2Table->indexFile(active_index),
|
||||
readAccessIntent);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
|
|
@ -1044,19 +1125,30 @@ int ha_ibmdb2i::rnd_init(bool scan)
|
|||
{
|
||||
rowsToBlockOnRead = DEFAULT_MAX_ROWS_TO_BUFFER;
|
||||
}
|
||||
|
||||
rc = useDataFile(accessIntent);
|
||||
|
||||
if (rc == 0)
|
||||
rc = useDataFile();
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
if (accessIntent != QMY_READ_ONLY)
|
||||
prepWriteBuffer(1);
|
||||
rc = prepReadBuffer(rowsToBlockOnRead);
|
||||
|
||||
if (rc == 0 && scan)
|
||||
{
|
||||
// THD* thd = ha_thd();
|
||||
// if (accessIntent == QMY_UPDATABLE &&
|
||||
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
|
||||
// !THDVAR(thd, transaction_unsafe))
|
||||
// {
|
||||
// readAccessIntent = QMY_READ_ONLY;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
readAccessIntent = accessIntent;
|
||||
// }
|
||||
|
||||
rc = prepReadBuffer(rowsToBlockOnRead, db2Table->dataFile(), readAccessIntent);
|
||||
|
||||
if (!rc && accessIntent != QMY_READ_ONLY)
|
||||
rc = prepWriteBuffer(1, db2Table->dataFile());
|
||||
|
||||
if (!rc && scan)
|
||||
doInitialRead(QMY_FIRST, rowsToBlockOnRead);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
releaseDataFile();
|
||||
|
|
@ -1167,7 +1259,10 @@ int ha_ibmdb2i::rnd_pos(uchar * buf, uchar *pos)
|
|||
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
rc = prepReadBuffer(1);
|
||||
rc = prepReadBuffer(1, getFileForActiveHandle(), accessIntent);
|
||||
|
||||
if (likely(rc == 0) && accessIntent == QMY_UPDATABLE)
|
||||
rc = prepWriteBuffer(1, getFileForActiveHandle());
|
||||
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
|
|
@ -1181,7 +1276,7 @@ int ha_ibmdb2i::rnd_pos(uchar * buf, uchar *pos)
|
|||
{
|
||||
rrnAssocHandle = activeHandle;
|
||||
const char* readBuf = activeReadBuf->getRowN(0);
|
||||
rc = mungeDB2row(buf, readBuf, readBuf + activeFormat->readRowNullOffset, false);
|
||||
rc = mungeDB2row(buf, readBuf, readBuf + activeReadBuf->getRowNullOffset(), false);
|
||||
releaseRowNeeded = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1450,7 +1545,9 @@ int ha_ibmdb2i::getNextIdVal(ulonglong *value)
|
|||
|
||||
char queryBuffer[MAX_DB2_COLNAME_LENGTH + MAX_DB2_QUALIFIEDNAME_LENGTH + 64];
|
||||
strcpy(queryBuffer, " SELECT CAST(MAX( ");
|
||||
convertMySQLNameToDB2Name(table->found_next_number_field->field_name, strend(queryBuffer), MAX_DB2_COLNAME_LENGTH+1);
|
||||
convertMySQLNameToDB2Name(table->found_next_number_field->field_name,
|
||||
strend(queryBuffer),
|
||||
MAX_DB2_COLNAME_LENGTH+1);
|
||||
strcat(queryBuffer, ") AS BIGINT) FROM ");
|
||||
db2Table->getDB2QualifiedName(strend(queryBuffer));
|
||||
DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer));
|
||||
|
|
@ -1621,7 +1718,9 @@ int ha_ibmdb2i::reset_auto_increment(ulonglong value)
|
|||
query.append(fileName);
|
||||
query.append(STRING_WITH_LEN(" ALTER COLUMN "));
|
||||
char colName[MAX_DB2_COLNAME_LENGTH+1];
|
||||
convertMySQLNameToDB2Name(table->found_next_number_field->field_name, colName, sizeof(colName));
|
||||
convertMySQLNameToDB2Name(table->found_next_number_field->field_name,
|
||||
colName,
|
||||
sizeof(colName));
|
||||
query.append(colName);
|
||||
|
||||
char restart_value[22];
|
||||
|
|
@ -1637,10 +1736,10 @@ int ha_ibmdb2i::reset_auto_increment(ulonglong value)
|
|||
|
||||
rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(),
|
||||
sqlStream.getStatementCount(),
|
||||
getCommitLevel(),
|
||||
FALSE,
|
||||
QMY_NONE, //getCommitLevel(),
|
||||
FALSE,
|
||||
FALSE,
|
||||
TRUE, //FALSE,
|
||||
dataHandle);
|
||||
if (rc == 0)
|
||||
db2Table->updateStartId(value);
|
||||
|
|
@ -1657,7 +1756,8 @@ int ha_ibmdb2i::reset_auto_increment(ulonglong value)
|
|||
bool ha_ibmdb2i::get_error_message(int error, String *buf)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::get_error_message");
|
||||
if (error >= DB2I_FIRST_ERR && error <= DB2I_LAST_ERR)
|
||||
if ((error >= DB2I_FIRST_ERR && error <= DB2I_LAST_ERR) ||
|
||||
(error >= QMY_ERR_MIN && error <= QMY_ERR_MAX))
|
||||
{
|
||||
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(ha_thd());
|
||||
char* errMsg = bridge->getErrorStorage();
|
||||
|
|
@ -1773,7 +1873,9 @@ int ha_ibmdb2i::external_lock(THD *thd, int lock_type)
|
|||
(command == SQLCOM_LOCK_TABLES ? QMY_NO : QMY_YES));
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Cache this away so we don't have to access it on each row operation
|
||||
cachedZeroDateOption = (enum_ZeroDate)THDVAR(thd, compat_opt_allow_zero_date_vals);
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
|
@ -1834,9 +1936,16 @@ int ha_ibmdb2i::delete_table(const char *name)
|
|||
if (rc == 0)
|
||||
{
|
||||
db2i_table::deleteAssocFiles(name);
|
||||
FILE_HANDLE savedHandle = bridge->findAndRemovePreservedHandle(name);
|
||||
if (savedHandle)
|
||||
bridge->deallocateFile(savedHandle, TRUE);
|
||||
}
|
||||
|
||||
FILE_HANDLE savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
|
||||
while (savedHandle)
|
||||
{
|
||||
bridge->deallocateFile(savedHandle, TRUE);
|
||||
DBUG_ASSERT(share);
|
||||
if (free_share(share))
|
||||
share = NULL;
|
||||
savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
|
||||
}
|
||||
|
||||
my_errno = rc;
|
||||
|
|
@ -2012,7 +2121,8 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
|
||||
if (osVersion.v < 6)
|
||||
{
|
||||
if (strlen(libName) > MAX_DB2_V5R4_LIBNAME_LENGTH)
|
||||
if (strlen(libName) >
|
||||
MAX_DB2_V5R4_LIBNAME_LENGTH + (isUpperOrQuote(system_charset_info, libName) ? 2 : 0))
|
||||
{
|
||||
getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V5R4_LIBNAME_LENGTH);
|
||||
DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
|
||||
|
|
@ -2043,9 +2153,12 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
query.append(STRING_WITH_LEN(" ("));
|
||||
|
||||
THD* thd = ha_thd();
|
||||
enum_TimeFormat timeFormat = (THDVAR(thd, create_time_columns_as_TOD) ? TIME_OF_DAY : DURATION);
|
||||
enum_BlobMapping blobMapping = (enum_BlobMapping)(THDVAR(thd, map_blob_to_varchar));
|
||||
|
||||
enum_TimeFormat timeFormat = (enum_TimeFormat)(THDVAR(thd, compat_opt_time_as_duration));
|
||||
enum_YearFormat yearFormat = (enum_YearFormat)(THDVAR(thd, compat_opt_year_as_int));
|
||||
enum_BlobMapping blobMapping = (enum_BlobMapping)(THDVAR(thd, compat_opt_blob_cols));
|
||||
enum_ZeroDate zeroDate = (enum_ZeroDate)(THDVAR(thd, compat_opt_allow_zero_date_vals));
|
||||
bool propagateDefaults = THDVAR(thd, propagate_default_col_vals);
|
||||
|
||||
Field **field;
|
||||
for (field= table_arg->field; *field; field++)
|
||||
{
|
||||
|
|
@ -2061,7 +2174,13 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
query.append(colName);
|
||||
query.append(' ');
|
||||
|
||||
if (rc = getFieldTypeMapping(*field, query, timeFormat, blobMapping))
|
||||
if (rc = getFieldTypeMapping(*field,
|
||||
query,
|
||||
timeFormat,
|
||||
blobMapping,
|
||||
zeroDate,
|
||||
propagateDefaults,
|
||||
yearFormat))
|
||||
DBUG_RETURN(rc);
|
||||
|
||||
if ( (*field)->flags & NOT_NULL_FLAG )
|
||||
|
|
@ -2105,43 +2224,35 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
bool primaryHasStringField = false;
|
||||
|
||||
String primaryKeyQuery;
|
||||
primaryKeyQuery.length(0);
|
||||
if (table_arg->s->primary_key != MAX_KEY && !isTemporary)
|
||||
{
|
||||
KEY& curKey = table_arg->key_info[table_arg->s->primary_key];
|
||||
primaryKeyQuery.append(STRING_WITH_LEN(" PRIMARY KEY( "));
|
||||
query.append(STRING_WITH_LEN(", PRIMARY KEY( "));
|
||||
for (int j = 0; j < curKey.key_parts; ++j)
|
||||
{
|
||||
if (j != 0)
|
||||
{
|
||||
primaryKeyQuery.append( STRING_WITH_LEN(" , ") );
|
||||
query.append( STRING_WITH_LEN(" , ") );
|
||||
}
|
||||
Field* field = curKey.key_part[j].field;
|
||||
convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
|
||||
primaryKeyQuery.append(colName);
|
||||
rc = updateAssociatedSortSequence(field,
|
||||
&fileSortSequenceType,
|
||||
fileSortSequence,
|
||||
fileSortSequenceLibrary);
|
||||
if (rc) DBUG_RETURN (rc);
|
||||
}
|
||||
primaryKeyQuery.append(STRING_WITH_LEN(" ) "));
|
||||
}
|
||||
|
||||
bool needAlterForPrimaryKey = FALSE;
|
||||
if ((fileSortSequence[0] != '*') && (fileSortSequence[0] != 'Q')) // An ICU sort sequence
|
||||
{
|
||||
needAlterForPrimaryKey = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (primaryKeyQuery.length() > 0)
|
||||
{
|
||||
query.append(STRING_WITH_LEN(" , "));
|
||||
query.append(primaryKeyQuery);
|
||||
query.append(colName);
|
||||
enum_field_types type = field->real_type();
|
||||
if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_BLOB ||
|
||||
type == MYSQL_TYPE_STRING)
|
||||
{
|
||||
rc = updateAssociatedSortSequence(field->charset(),
|
||||
&fileSortSequenceType,
|
||||
fileSortSequence,
|
||||
fileSortSequenceLibrary);
|
||||
if (rc) DBUG_RETURN (rc);
|
||||
primaryHasStringField = true;
|
||||
}
|
||||
}
|
||||
query.append(STRING_WITH_LEN(" ) "));
|
||||
}
|
||||
|
||||
rc = buildDB2ConstraintString(thd->lex,
|
||||
|
|
@ -2162,20 +2273,6 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
SqlStatementStream sqlStream(query.length());
|
||||
sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
|
||||
|
||||
|
||||
|
||||
if (needAlterForPrimaryKey == TRUE && !isTemporary)
|
||||
{
|
||||
rc = buildCreateIndexStatement(sqlStream,
|
||||
table_arg->key_info[table_arg->s->primary_key],
|
||||
true,
|
||||
libName,
|
||||
fileName);
|
||||
if (rc) DBUG_RETURN (rc);
|
||||
}
|
||||
|
||||
uint i = 0;
|
||||
|
||||
for (uint i = 0; i < table_arg->s->keys; ++i)
|
||||
{
|
||||
if (i != table_arg->s->primary_key || isTemporary)
|
||||
|
|
@ -2193,8 +2290,8 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
|
||||
initBridge();
|
||||
|
||||
if (THDVAR(thd, discovery_mode) == 1)
|
||||
bridge()->expectErrors(QMY_ERR_TABLE_EXISTS);
|
||||
// if (THDVAR(thd, discovery_mode) == 1)
|
||||
// bridge()->expectErrors(QMY_ERR_TABLE_EXISTS);
|
||||
|
||||
rc = bridge()->execSQL(sqlStream.getPtrToData(),
|
||||
sqlStream.getStatementCount(),
|
||||
|
|
@ -2209,8 +2306,8 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
my_error(ER_BLOB_USED_AS_KEY, MYF(0), "*unknown*");
|
||||
rc = ER_BLOB_USED_AS_KEY;
|
||||
}
|
||||
else if (unlikely(rc == QMY_ERR_TABLE_EXISTS) &&
|
||||
THDVAR(thd, discovery_mode) == 1)
|
||||
/* else if (unlikely(rc == QMY_ERR_TABLE_EXISTS) &&
|
||||
THDVAR(thd, discovery_mode) == 1)
|
||||
{
|
||||
db2i_table* temp = new db2i_table(table_arg->s, name);
|
||||
int32 rc = temp->fastInitForCreate(name);
|
||||
|
|
@ -2221,6 +2318,7 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
|
|||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
*/
|
||||
|
||||
if (!rc && !isTemporary)
|
||||
{
|
||||
|
|
@ -2483,9 +2581,9 @@ void ha_ibmdb2i::start_bulk_insert(ha_rows rows)
|
|||
|
||||
if (activeHandle == 0)
|
||||
{
|
||||
last_start_bulk_insert_rc = useDataFile(QMY_UPDATABLE);
|
||||
last_start_bulk_insert_rc = useDataFile();
|
||||
if (last_start_bulk_insert_rc == 0)
|
||||
prepWriteBuffer(rows);
|
||||
last_start_bulk_insert_rc = prepWriteBuffer(rows, db2Table->dataFile());
|
||||
}
|
||||
|
||||
if (last_start_bulk_insert_rc == 0)
|
||||
|
|
@ -2519,12 +2617,18 @@ int ha_ibmdb2i::end_bulk_insert()
|
|||
}
|
||||
|
||||
|
||||
int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead)
|
||||
int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::prepReadBuffer");
|
||||
DBUG_ASSERT((accessIntent == QMY_READ_ONLY || accessIntent == QMY_UPDATABLE) && rowsToRead > 0);
|
||||
DBUG_ASSERT(rowsToRead > 0);
|
||||
|
||||
int rc = 0;
|
||||
THD* thd = ha_thd();
|
||||
char cmtLvl = getCommitLevel(thd);
|
||||
|
||||
const db2i_file::RowFormat* format;
|
||||
int rc = file->obtainRowFormat(activeHandle, intent, cmtLvl, &format);
|
||||
|
||||
if (unlikely(rc)) DBUG_RETURN(rc);
|
||||
|
||||
if (lobFieldsRequested())
|
||||
{
|
||||
|
|
@ -2534,10 +2638,8 @@ int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead)
|
|||
|
||||
rowsToRead = min(stats.records+1,min(rowsToRead, DEFAULT_MAX_ROWS_TO_BUFFER));
|
||||
|
||||
THD* thd = ha_thd();
|
||||
|
||||
uint bufSize = min((activeFormat->readRowLen * rowsToRead), THDVAR(thd, max_read_buffer_size));
|
||||
multiRowReadBuf.allocBuf(activeFormat->readRowLen, bufSize);
|
||||
uint bufSize = min((format->readRowLen * rowsToRead), THDVAR(thd, max_read_buffer_size));
|
||||
multiRowReadBuf.allocBuf(format->readRowLen, format->readRowNullOffset, bufSize);
|
||||
activeReadBuf = &multiRowReadBuf;
|
||||
|
||||
if (db2Table->hasBlobs())
|
||||
|
|
@ -2547,28 +2649,42 @@ int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead)
|
|||
rc = prepareReadBufferForLobs();
|
||||
if (rc) DBUG_RETURN(rc);
|
||||
}
|
||||
activeReadBuf->update(accessIntent, &releaseRowNeeded, getCommitLevel(thd));
|
||||
|
||||
// if (accessIntent == QMY_UPDATABLE &&
|
||||
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
|
||||
// !THDVAR(thd, transaction_unsafe))
|
||||
// activeReadBuf->update(QMY_READ_ONLY, &releaseRowNeeded, QMY_REPEATABLE_READ);
|
||||
// else
|
||||
activeReadBuf->update(intent, &releaseRowNeeded, cmtLvl);
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
|
||||
void ha_ibmdb2i::prepWriteBuffer(ha_rows rowsToWrite)
|
||||
int ha_ibmdb2i::prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::prepWriteBuffer");
|
||||
DBUG_ASSERT(accessIntent == QMY_UPDATABLE && rowsToWrite > 0);
|
||||
|
||||
rowsToWrite = min(rowsToWrite, DEFAULT_MAX_ROWS_TO_BUFFER);
|
||||
const db2i_file::RowFormat* format;
|
||||
int rc = file->obtainRowFormat(activeHandle,
|
||||
QMY_UPDATABLE,
|
||||
getCommitLevel(ha_thd()),
|
||||
&format);
|
||||
|
||||
uint bufSize = min((activeFormat->writeRowLen * rowsToWrite), THDVAR(ha_thd(), max_write_buffer_size));
|
||||
multiRowWriteBuf.allocBuf(activeFormat->writeRowLen, bufSize);
|
||||
if (unlikely(rc)) DBUG_RETURN(rc);
|
||||
|
||||
rowsToWrite = min(rowsToWrite, DEFAULT_MAX_ROWS_TO_BUFFER);
|
||||
|
||||
uint bufSize = min((format->writeRowLen * rowsToWrite), THDVAR(ha_thd(), max_write_buffer_size));
|
||||
multiRowWriteBuf.allocBuf(format->writeRowLen, format->writeRowNullOffset, bufSize);
|
||||
activeWriteBuf = &multiRowWriteBuf;
|
||||
|
||||
if (!blobWriteBuffers && db2Table->hasBlobs())
|
||||
{
|
||||
blobWriteBuffers = new ValidatedPointer<char>[db2Table->getBlobCount()];
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2621,7 +2737,7 @@ int ha_ibmdb2i::flushWrite(FILE_HANDLE fileHandle, uchar* buf )
|
|||
readAllColumns = true;
|
||||
mungeDB2row(buf,
|
||||
badRow,
|
||||
badRow + activeFormat->writeRowNullOffset,
|
||||
badRow + activeWriteBuf->getRowNullOffset(),
|
||||
true);
|
||||
readAllColumns = savedReadAllColumns;
|
||||
|
||||
|
|
@ -2770,7 +2886,7 @@ int ha_ibmdb2i::prepareReadBufferForLobs()
|
|||
activeReadBuf->setRowsToProcess((activeLobFields ? 1 : activeReadBuf->getRowCapacity()));
|
||||
int rc = bridge()->objectOverride(activeHandle,
|
||||
activeReadBuf->ptr(),
|
||||
activeFormat->readRowLen);
|
||||
activeReadBuf->getRowLength());
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
|
|
@ -2898,7 +3014,10 @@ int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream,
|
|||
Field* field = key.key_part[j].field;
|
||||
convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
|
||||
fieldDefinition.append(colName);
|
||||
rc = updateAssociatedSortSequence(field,&fileSortSequenceType,fileSortSequence,fileSortSequenceLibrary);
|
||||
rc = updateAssociatedSortSequence(field->charset(),
|
||||
&fileSortSequenceType,
|
||||
fileSortSequence,
|
||||
fileSortSequenceLibrary);
|
||||
if (rc) DBUG_RETURN (rc);
|
||||
}
|
||||
fieldDefinition.append(STRING_WITH_LEN(" ) "));
|
||||
|
|
@ -3098,7 +3217,7 @@ double ha_ibmdb2i::read_time(uint index, uint ranges, ha_rows rows)
|
|||
DBUG_RETURN(cost);
|
||||
}
|
||||
|
||||
int ha_ibmdb2i::useIndexFile(char intent, int idx)
|
||||
int ha_ibmdb2i::useIndexFile(int idx)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::useIndexFile");
|
||||
|
||||
|
|
@ -3112,16 +3231,8 @@ int ha_ibmdb2i::useIndexFile(char intent, int idx)
|
|||
|
||||
if (rc == 0)
|
||||
{
|
||||
rc = db2Table->indexFile(idx)->useFile(indexHandles[idx],
|
||||
intent,
|
||||
getCommitLevel(),
|
||||
&activeFormat);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
activeHandle = indexHandles[idx];
|
||||
bumpInUseCounter(1);
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
|
|
@ -3141,11 +3252,15 @@ static struct st_mysql_sys_var* ibmdb2i_system_variables[] = {
|
|||
MYSQL_SYSVAR(max_read_buffer_size),
|
||||
MYSQL_SYSVAR(max_write_buffer_size),
|
||||
MYSQL_SYSVAR(async_enabled),
|
||||
MYSQL_SYSVAR(create_time_columns_as_TOD),
|
||||
MYSQL_SYSVAR(assume_exclusive_use),
|
||||
MYSQL_SYSVAR(map_blob_to_varchar),
|
||||
MYSQL_SYSVAR(compat_opt_blob_cols),
|
||||
MYSQL_SYSVAR(compat_opt_time_as_duration),
|
||||
MYSQL_SYSVAR(compat_opt_allow_zero_date_vals),
|
||||
MYSQL_SYSVAR(compat_opt_year_as_int),
|
||||
MYSQL_SYSVAR(propagate_default_col_vals),
|
||||
MYSQL_SYSVAR(create_index_option),
|
||||
MYSQL_SYSVAR(discovery_mode),
|
||||
// MYSQL_SYSVAR(discovery_mode),
|
||||
MYSQL_SYSVAR(system_trace_level),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -3160,7 +3275,7 @@ mysql_declare_plugin(ibmdb2i)
|
|||
"IBMDB2I",
|
||||
"The IBM development team in Rochester, Minnesota",
|
||||
"IBM DB2 for i Storage Engine",
|
||||
PLUGIN_LICENSE_PROPRIETARY,
|
||||
PLUGIN_LICENSE_GPL,
|
||||
ibmdb2i_init_func, /* Plugin Init */
|
||||
ibmdb2i_done_func, /* Plugin Deinit */
|
||||
0x0100 /* 1.0 */,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ OF SUCH DAMAGE.
|
|||
It is used to describe the underlying table definition, and it caches
|
||||
table statistics.
|
||||
*/
|
||||
typedef struct st_ibmdb2i_share {
|
||||
struct IBMDB2I_SHARE {
|
||||
char *table_name;
|
||||
uint table_name_length,use_count;
|
||||
pthread_mutex_t mutex;
|
||||
|
|
@ -110,7 +110,7 @@ typedef struct st_ibmdb2i_share {
|
|||
ulong data_file_length;
|
||||
} cachedStats;
|
||||
|
||||
} IBMDB2I_SHARE;
|
||||
};
|
||||
|
||||
class ha_ibmdb2i: public handler
|
||||
{
|
||||
|
|
@ -143,16 +143,15 @@ class ha_ibmdb2i: public handler
|
|||
// Array of file handles belonging to the underlying LFs
|
||||
FILE_HANDLE* indexHandles;
|
||||
|
||||
// Pointer to a definition of the layout of the row buffer for the file
|
||||
// described by activeHandle
|
||||
const db2i_file::RowFormat* activeFormat;
|
||||
|
||||
// Flag to indicate whether a call needs to be made to unlock a row when
|
||||
// a read operation has ended. DB2 will handle row unlocking as we move
|
||||
// through rows, but if an operation ends before we reach the end of a file,
|
||||
// DB2 needs to know to unlock the last row read.
|
||||
bool releaseRowNeeded;
|
||||
|
||||
// Pointer to a definition of the layout of the row buffer for the file
|
||||
// described by activeHandle
|
||||
const db2i_file::RowFormat* activeFormat;
|
||||
|
||||
IORowBuffer keyBuf;
|
||||
uint32 keyLen;
|
||||
|
|
@ -190,6 +189,7 @@ class ha_ibmdb2i: public handler
|
|||
// The access intent indicated by the last external_locks() call.
|
||||
// May be either QMY_READ or QMY_UPDATABLE
|
||||
char accessIntent;
|
||||
char readAccessIntent;
|
||||
|
||||
ha_rows* indexReadSizeEstimates;
|
||||
|
||||
|
|
@ -361,6 +361,20 @@ private:
|
|||
AS_VARCHAR
|
||||
};
|
||||
|
||||
enum enum_ZeroDate
|
||||
{
|
||||
NO_SUBSTITUTE,
|
||||
SUBSTITUTE_0001_01_01
|
||||
};
|
||||
|
||||
enum enum_YearFormat
|
||||
{
|
||||
CHAR4,
|
||||
SMALLINT
|
||||
};
|
||||
|
||||
enum_ZeroDate cachedZeroDateOption;
|
||||
|
||||
IBMDB2I_SHARE *get_share(const char *table_name, TABLE *table);
|
||||
int free_share(IBMDB2I_SHARE *share);
|
||||
int32 mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs);
|
||||
|
|
@ -396,10 +410,9 @@ private:
|
|||
}
|
||||
|
||||
|
||||
int useDataFile(char intent)
|
||||
int useDataFile()
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::useDataFile");
|
||||
DBUG_PRINT("ha_ibmdb2i::useDataFile", ("Intent: %d", intent));
|
||||
|
||||
int rc = 0;
|
||||
if (!dataHandle)
|
||||
|
|
@ -408,20 +421,11 @@ private:
|
|||
DBUG_RETURN(0);
|
||||
|
||||
DBUG_ASSERT(activeHandle == 0);
|
||||
|
||||
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
rc = db2Table->dataFile()->useFile(dataHandle,
|
||||
intent,
|
||||
getCommitLevel(),
|
||||
&activeFormat);
|
||||
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
activeHandle = dataHandle;
|
||||
bumpInUseCounter(1);
|
||||
}
|
||||
activeHandle = dataHandle;
|
||||
bumpInUseCounter(1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
|
|
@ -448,7 +452,7 @@ private:
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
int useIndexFile(char intent, int idx);
|
||||
int useIndexFile(int idx);
|
||||
|
||||
void releaseIndexFile(int idx)
|
||||
{
|
||||
|
|
@ -526,7 +530,10 @@ private:
|
|||
int getFieldTypeMapping(Field* field,
|
||||
String& mapping,
|
||||
enum_TimeFormat timeFormate,
|
||||
enum_BlobMapping blobMapping);
|
||||
enum_BlobMapping blobMapping,
|
||||
enum_ZeroDate zeroDateHandling,
|
||||
bool propagateDefaults,
|
||||
enum_YearFormat yearFormat);
|
||||
|
||||
int getKeyFromName(const char* name, size_t len);
|
||||
|
||||
|
|
@ -564,6 +571,9 @@ private:
|
|||
{
|
||||
DBUG_ASSERT(activeReadBuf->rowCount() == 1);
|
||||
row = activeReadBuf->readNextRow(orientation, currentRRN);
|
||||
|
||||
if (unlikely(!row))
|
||||
rc = activeReadBuf->lastrc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -571,7 +581,7 @@ private:
|
|||
if (likely(rc == 0))
|
||||
{
|
||||
rrnAssocHandle = activeHandle;
|
||||
rc = mungeDB2row(destination, row, row+activeFormat->readRowNullOffset, false);
|
||||
rc = mungeDB2row(destination, row, row+activeReadBuf->getRowNullOffset(), false);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -631,7 +641,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
int rc = file->useFile(handle, intent, getCommitLevel(), &activeFormat);
|
||||
int rc = file->obtainRowFormat(handle, intent, getCommitLevel(), &activeFormat);
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
activeHandle = handle;
|
||||
|
|
@ -641,12 +651,25 @@ private:
|
|||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
int prepReadBuffer(ha_rows rowsToRead);
|
||||
void prepWriteBuffer(ha_rows rowsToWrite);
|
||||
const db2i_file* getFileForActiveHandle() const
|
||||
{
|
||||
if (activeHandle == dataHandle)
|
||||
return db2Table->dataFile();
|
||||
else
|
||||
for (uint i = 0; i < table_share->keys; ++i)
|
||||
if (indexHandles[i] == activeHandle)
|
||||
return db2Table->indexFile(i);
|
||||
DBUG_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent);
|
||||
int prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file);
|
||||
|
||||
void invalidateCachedStats()
|
||||
{
|
||||
share->cachedStats.invalidate(rowCount | deletedRowCount | objLength | meanRowLen | ioCount);
|
||||
share->cachedStats.invalidate(rowCount | deletedRowCount | objLength |
|
||||
meanRowLen | ioCount);
|
||||
}
|
||||
|
||||
void warnIfInvalidData()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue