2
Licensed Materials - Property of IBM
3
DB2 Storage Engine Enablement
4
Copyright IBM Corporation 2007,2008
7
Redistribution and use in source and binary forms, with or without modification,
8
are permitted provided that the following conditions are met:
9
(a) Redistributions of source code must retain this list of conditions, the
10
copyright notice in section {d} below, and the disclaimer following this
12
(b) Redistributions in binary form must reproduce this list of conditions, the
13
copyright notice in section (d) below, and the disclaimer following this
14
list of conditions, in the documentation and/or other materials provided
15
with the distribution.
16
(c) The name of IBM may not be used to endorse or promote products derived from
17
this software without specific prior written permission.
18
(d) The text of the required copyright notice is:
19
Licensed Materials - Property of IBM
20
DB2 Storage Engine Enablement
21
Copyright IBM Corporation 2007,2008
24
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
25
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
38
#include "db2i_file.h"
39
#include "db2i_charsetSupport.h"
40
#include "db2i_collationSupport.h"
41
#include "db2i_misc.h"
42
#include "db2i_errors.h"
45
db2i_table::db2i_table(const TABLE_SHARE* myTable, const char* path) :
50
blobFieldActualSizes(NULL),
53
db2TableNameSQLAscii(NULL),
54
db2LibNameSQLAscii(NULL)
56
char asciiLibName[MAX_DB2_SCHEMANAME_LENGTH + 1];
57
getDB2LibNameFromPath(path, asciiLibName, ASCII_NATIVE);
59
char asciiFileName[MAX_DB2_FILENAME_LENGTH + 1];
60
getDB2FileNameFromPath(path, asciiFileName, ASCII_NATIVE);
62
size_t libNameLen = strlen(asciiLibName);
63
size_t fileNameLen = strlen(asciiFileName);
65
db2LibNameEbcdic=(char *)
66
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
67
&db2LibNameEbcdic, libNameLen+1,
68
&db2LibNameAscii, libNameLen+1,
69
&db2LibNameSQLAscii, libNameLen*2 + 1,
70
&db2TableNameEbcdic, fileNameLen+1,
71
&db2TableNameAscii, fileNameLen+1,
72
&db2TableNameSQLAscii, fileNameLen*2 + 1,
75
if (likely(db2LibNameEbcdic))
77
memcpy(db2LibNameAscii, asciiLibName, libNameLen);
78
convertNativeToSQLName(db2LibNameAscii, db2LibNameSQLAscii);
79
convToEbcdic(db2LibNameAscii, db2LibNameEbcdic, libNameLen);
80
memcpy(db2TableNameAscii, asciiFileName, fileNameLen);
81
convertNativeToSQLName(db2TableNameAscii, db2TableNameSQLAscii);
82
convToEbcdic(db2TableNameAscii, db2TableNameEbcdic, fileNameLen);
85
conversionDefinitions[toMySQL] = NULL;
86
conversionDefinitions[toDB2] = NULL;
88
isTemporaryTable = (strstr(mysqlTable->path.str, mysql_tmpdir) == mysqlTable->path.str);
92
int32 db2i_table::initDB2Objects(const char* path)
94
uint fileObjects = 1 + mysqlTable->keys;
95
ValidatedPointer<ShrDef> fileDefnSpace(sizeof(ShrDef) * fileObjects);
97
physicalFile = new db2i_file(this);
98
physicalFile->fillILEDefn(&fileDefnSpace[0], true);
100
logicalFileCount = mysqlTable->keys;
101
if (logicalFileCount > 0)
103
logicalFiles = new db2i_file*[logicalFileCount];
104
for (int k = 0; k < logicalFileCount; k++)
106
logicalFiles[k] = new db2i_file(this, k);
107
logicalFiles[k]->fillILEDefn(&fileDefnSpace[k+1], false);
111
ValidatedPointer<FILE_HANDLE> fileDefnHandles(sizeof(FILE_HANDLE) * fileObjects);
112
size_t formatSpaceLen = sizeof(format_hdr_t) + mysqlTable->fields * sizeof(DB2Field);
113
formatSpace.alloc(formatSpaceLen);
115
int rc = db2i_ileBridge::getBridgeForThread()->
116
expectErrors(QMY_ERR_RTNFMT)->
117
allocateFileDefn(fileDefnSpace,
121
strlen(db2LibNameEbcdic),
127
// We have to handle a format space error as a special case of a FID
128
// mismatch. We should only get the space error if columns have been added
129
// to the DB2 table without MySQL's knowledge, which is effectively a
131
if (rc == QMY_ERR_RTNFMT)
133
rc = QMY_ERR_LVLID_MISMATCH;
139
convFromEbcdic(((format_hdr_t*)formatSpace)->FilLvlId, fileLevelID, sizeof(fileLevelID));
141
if (!doFileIDsMatch(path))
143
getErrTxt(QMY_ERR_LVLID_MISMATCH);
144
return QMY_ERR_LVLID_MISMATCH;
147
physicalFile->setMasterDefnHandle(fileDefnHandles[0]);
148
for (int k = 0; k < mysqlTable->keys; k++)
150
logicalFiles[k]->setMasterDefnHandle(fileDefnHandles[k+1]);
153
db2StartId = (uint64)(((format_hdr_t*)formatSpace)->StartIdVal);
154
db2Fields = (DB2Field*)((char*)(void*)formatSpace + ((format_hdr_t*)formatSpace)->ColDefOff);
156
uint fields = mysqlTable->fields;
157
for (int i = 0; i < fields; ++i)
159
if (db2Field(i).isBlob())
167
blobFieldActualSizes = (uint*)my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
168
&blobFieldActualSizes, blobFieldCount * sizeof(uint),
169
&blobFields, blobFieldCount * sizeof(uint16),
173
for (int i = 0; i < fields; ++i)
175
if (db2Field(i).isBlob())
182
my_multi_malloc(MYF(MY_WME),
183
&conversionDefinitions[toMySQL], fields * sizeof(iconv_t),
184
&conversionDefinitions[toDB2], fields * sizeof(iconv_t),
186
for (int i = 0; i < fields; ++i)
188
conversionDefinitions[toMySQL][i] = (iconv_t)(-1);
189
conversionDefinitions[toDB2][i] = (iconv_t)(-1);
195
int db2i_table::fastInitForCreate(const char* path)
197
ValidatedPointer<ShrDef> fileDefnSpace(sizeof(ShrDef));
199
physicalFile = new db2i_file(this);
200
physicalFile->fillILEDefn(fileDefnSpace, true);
202
ValidatedPointer<FILE_HANDLE> fileDefnHandles(sizeof(FILE_HANDLE));
204
size_t formatSpaceLen = sizeof(format_hdr_t) +
205
mysqlTable->fields * sizeof(DB2Field);
206
formatSpace.alloc(formatSpaceLen);
208
int rc = db2i_ileBridge::getBridgeForThread()->allocateFileDefn(fileDefnSpace,
212
strlen(db2LibNameEbcdic),
219
convFromEbcdic(((format_hdr_t*)formatSpace)->FilLvlId, fileLevelID, sizeof(fileLevelID));
220
doFileIDsMatch(path);
225
bool db2i_table::doFileIDsMatch(const char* path)
227
char name_buff[FN_REFLEN];
229
fn_format(name_buff, path, "", FID_EXT, (MY_REPLACE_EXT | MY_UNPACK_FILENAME));
231
File fd = my_open(name_buff, O_RDONLY, MYF(0));
237
fd = my_create(name_buff, 0, O_WRONLY, MYF(MY_WME));
241
// TODO: Report errno here
244
my_write(fd, (uchar*)fileLevelID, sizeof(fileLevelID), MYF(MY_WME));
245
my_close(fd, MYF(0));
250
// TODO: Report errno here
255
char diskFID[sizeof(fileLevelID)];
259
if (my_read(fd, (uchar*)diskFID, sizeof(diskFID), MYF(MY_WME)) == sizeof(diskFID) &&
260
(memcmp(diskFID, fileLevelID, sizeof(diskFID)) == 0))
263
my_close(fd, MYF(0));
268
void db2i_table::deleteAssocFiles(const char* name)
270
char name_buff[FN_REFLEN];
271
fn_format(name_buff, name, "", FID_EXT, (MY_REPLACE_EXT | MY_UNPACK_FILENAME));
272
my_delete(name_buff, MYF(0));
275
void db2i_table::renameAssocFiles(const char* from, const char* to)
277
rename_file_ext(from, to, FID_EXT);
281
db2i_table::~db2i_table()
283
if (blobFieldActualSizes)
284
my_free(blobFieldActualSizes, MYF(0));
286
if (conversionDefinitions[toMySQL])
287
my_free(conversionDefinitions[toMySQL], MYF(0));
291
for (int k = 0; k < logicalFileCount; ++k)
293
delete logicalFiles[k];
296
delete[] logicalFiles;
300
my_free(db2LibNameEbcdic, 0);
303
void db2i_table::getDB2QualifiedName(char* to)
305
strcat(to, getDB2LibName(ASCII_SQL));
307
strcat(to, getDB2TableName(ASCII_SQL));
311
void db2i_table::getDB2QualifiedNameFromPath(const char* path, char* to)
313
getDB2LibNameFromPath(path, to);
315
getDB2FileNameFromPath(path, strend(to));
319
size_t db2i_table::smartFilenameToTableName(const char *in, char* out, size_t outlen)
321
if (strchr(in, '@') == NULL)
323
return filename_to_tablename(in, out, outlen);
326
char* test = (char*) my_malloc(outlen, MYF(MY_WME));
328
filename_to_tablename(in, test, outlen);
334
if ((*cur <= 0x20) || (*cur >= 0x80))
336
strncpy(out, in, outlen);
337
my_free(test, MYF(0));
338
return min(outlen, strlen(out));
343
strncpy(out, test, outlen);
344
my_free(test, MYF(0));
345
return min(outlen, strlen(out));
348
void db2i_table::filenameToTablename(const char* in, char* out, size_t outlen)
350
if (strchr(in, '#') == NULL)
352
smartFilenameToTableName(in, out, outlen);
356
char* temp = (char*)sql_alloc(outlen);
358
const char* part1, *part2, *part3, *part4;
360
part2 = strstr(part1, "#P#");
364
part4 = strchr(part3, '#');
369
memcpy(temp, part1, min(outlen, part2 - part1));
370
temp[min(outlen-1, part2-part1)] = 0;
372
int32 accumLen = smartFilenameToTableName(temp, out, outlen);
374
if (part2 && (accumLen + 4 < outlen))
379
memset(temp, 0, min(outlen, part2-part1));
380
memcpy(temp, part3, min(outlen, part4-part3));
381
temp[min(outlen-1, part4-part3)] = 0;
383
accumLen += smartFilenameToTableName(temp, strend(out), outlen-accumLen);
385
if (part4 && (accumLen + (strend(in) - part4 + 1) < outlen))
392
void db2i_table::getDB2LibNameFromPath(const char* path, char* lib, NameFormatFlags format)
394
if (strstr(path, mysql_tmpdir) == path)
396
strcpy(lib, DB2I_TEMP_TABLE_SCHEMA);
400
const char* c = strend(path) - 1;
401
while (c > path && *c != '\\' && *c != '/')
406
const char* dbEnd = c;
409
} while (c >= path && *c != '\\' && *c != '/');
413
const char* dbStart = c+1;
414
char fileName[FN_REFLEN];
415
memcpy(fileName, dbStart, dbEnd - dbStart);
416
fileName[dbEnd-dbStart] = 0;
418
char dbName[MAX_DB2_SCHEMANAME_LENGTH+1];
419
filenameToTablename(fileName, dbName , sizeof(dbName));
421
convertMySQLNameToDB2Name(dbName, lib, sizeof(dbName), true, (format==ASCII_SQL) );
424
DBUG_ASSERT(0); // This should never happen!
429
void db2i_table::getDB2FileNameFromPath(const char* path, char* file, NameFormatFlags format)
431
const char* fileEnd = strend(path);
432
const char* c = fileEnd;
433
while (c > path && *c != '\\' && *c != '/')
438
const char* fileStart = c+1;
439
char fileName[FN_REFLEN];
440
memcpy(fileName, fileStart, fileEnd - fileStart);
441
fileName[fileEnd - fileStart] = 0;
442
char db2Name[MAX_DB2_FILENAME_LENGTH+1];
443
filenameToTablename(fileName, db2Name, sizeof(db2Name));
444
convertMySQLNameToDB2Name(db2Name, file, sizeof(db2Name), true, (format==ASCII_SQL) );
448
// Generates the DB2 index name when given the MySQL index and table names.
449
int32 db2i_table::appendQualifiedIndexFileName(const char* indexName,
450
const char* tableName,
452
NameFormatFlags format,
453
enum_DB2I_INDEX_TYPE type)
455
char generatedName[MAX_DB2_FILENAME_LENGTH+1];
456
strncpy(generatedName, indexName, DB2I_INDEX_NAME_LENGTH_TO_PRESERVE);
457
generatedName[DB2I_INDEX_NAME_LENGTH_TO_PRESERVE] = 0;
458
char* endOfGeneratedName;
460
if (type == typeDefault)
462
strcat(generatedName, DB2I_DEFAULT_INDEX_NAME_DELIMITER);
463
endOfGeneratedName = strend(generatedName);
465
else if (type != typeNone)
467
strcat(generatedName, DB2I_ADDL_INDEX_NAME_DELIMITER);
468
endOfGeneratedName = strend(generatedName);
469
*(endOfGeneratedName-2) = char(type);
472
uint lenWithoutFile = endOfGeneratedName - generatedName;
474
char strippedTableName[MAX_DB2_FILENAME_LENGTH+1];
475
if (format == ASCII_SQL)
477
strcpy(strippedTableName, tableName);
478
stripExtraQuotes(strippedTableName+1, sizeof(strippedTableName));
479
tableName = strippedTableName;
482
if (strlen(tableName) > (MAX_DB2_FILENAME_LENGTH-lenWithoutFile))
485
strncat(generatedName,
487
min(strlen(tableName), (MAX_DB2_FILENAME_LENGTH-lenWithoutFile))-2 );
489
char finalName[MAX_DB2_FILENAME_LENGTH+1];
490
convertMySQLNameToDB2Name(generatedName, finalName, sizeof(finalName), true, (format==ASCII_SQL));
491
to.append(finalName);
497
void db2i_table::findConversionDefinition(enum_conversionDirection direction, uint16 fieldID)
499
getConversion(direction,
500
mysqlTable->field[fieldID]->charset(),
501
db2Field(fieldID).getCCSID(),
502
conversionDefinitions[direction][fieldID]);
506
db2i_file::db2i_file(db2i_table* table) : db2Table(table)
510
DBUG_ASSERT(table->getMySQLTable()->table_name.length <= MAX_DB2_FILENAME_LENGTH-2);
512
db2FileName = (char*)table->getDB2TableName(db2i_table::EBCDIC_NATIVE);
515
db2i_file::db2i_file(db2i_table* table, int index) : db2Table(table)
519
if ((index == table->getMySQLTable()->primary_key) && !table->isTemporary())
521
db2FileName = (char*)table->getDB2TableName(db2i_table::EBCDIC_NATIVE);
525
// Generate the index name (in index___table form); quote and EBCDICize it.
526
String qualifiedPath;
527
qualifiedPath.length(0);
529
const char* asciiFileName = table->getDB2TableName(db2i_table::ASCII_NATIVE);
531
db2i_table::appendQualifiedIndexFileName(table->getMySQLTable()->key_info[index].name,
534
db2i_table::ASCII_NATIVE,
537
db2FileName = (char*)my_malloc(qualifiedPath.length()+1, MYF(MY_WME | MY_ZEROFILL));
538
convToEbcdic(qualifiedPath.ptr(), db2FileName, qualifiedPath.length());
542
void db2i_file::commonCtorInit()
545
memset(&formats, 0, maxRowFormats*sizeof(RowFormat));
549
void db2i_file::fillILEDefn(ShrDef* defn, bool readInArrivalSeq)
551
defn->ObjNamLen = strlen(db2FileName);
552
DBUG_ASSERT(defn->ObjNamLen <= sizeof(defn->ObjNam));
553
memcpy(defn->ObjNam, db2FileName, defn->ObjNamLen);
554
defn->ArrSeq[0] = (readInArrivalSeq ? QMY_YES : QMY_NO);