diff options
Diffstat (limited to 'storage/ibmdb2i/db2i_file.cc')
-rw-r--r-- | storage/ibmdb2i/db2i_file.cc | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/storage/ibmdb2i/db2i_file.cc b/storage/ibmdb2i/db2i_file.cc new file mode 100644 index 00000000000..2ce78f18d21 --- /dev/null +++ b/storage/ibmdb2i/db2i_file.cc @@ -0,0 +1,513 @@ +/* +Licensed Materials - Property of IBM +DB2 Storage Engine Enablement +Copyright IBM Corporation 2007,2008 +All rights reserved + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + (a) Redistributions of source code must retain this list of conditions, the + copyright notice in section {d} below, and the disclaimer following this + list of conditions. + (b) Redistributions in binary form must reproduce this list of conditions, the + copyright notice in section (d) below, and the disclaimer following this + list of conditions, in the documentation and/or other materials provided + with the distribution. + (c) The name of IBM may not be used to endorse or promote products derived from + this software without specific prior written permission. + (d) The text of the required copyright notice is: + Licensed Materials - Property of IBM + DB2 Storage Engine Enablement + Copyright IBM Corporation 2007,2008 + All rights reserved + +THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + + + +#include "db2i_file.h" +#include "db2i_charsetSupport.h" +#include "db2i_collationSupport.h" +#include "db2i_misc.h" +#include "db2i_errors.h" +#include "my_dir.h" + +db2i_table::db2i_table(const TABLE_SHARE* myTable, const char* path) : + mysqlTable(myTable), + db2StartId(0), + blobFieldCount(0), + blobFields(NULL), + blobFieldActualSizes(NULL), + logicalFiles(NULL), + physicalFile(NULL), + db2TableNameSQLAscii(NULL), + db2LibNameSQLAscii(NULL) +{ + char asciiLibName[MAX_DB2_SCHEMANAME_LENGTH + 1]; + getDB2LibNameFromPath(path, asciiLibName, ASCII_NATIVE); + + char asciiFileName[MAX_DB2_FILENAME_LENGTH + 1]; + getDB2FileNameFromPath(path, asciiFileName, ASCII_NATIVE); + + size_t libNameLen = strlen(asciiLibName); + size_t fileNameLen = strlen(asciiFileName); + + db2LibNameEbcdic=(char *) + my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + &db2LibNameEbcdic, libNameLen+1, + &db2LibNameAscii, libNameLen+1, + &db2LibNameSQLAscii, libNameLen*2 + 1, + &db2TableNameEbcdic, fileNameLen+1, + &db2TableNameAscii, fileNameLen+1, + &db2TableNameSQLAscii, fileNameLen*2 + 1, + NullS); + + if (likely(db2LibNameEbcdic)) + { + memcpy(db2LibNameAscii, asciiLibName, libNameLen); + convertNativeToSQLName(db2LibNameAscii, db2LibNameSQLAscii); + convToEbcdic(db2LibNameAscii, db2LibNameEbcdic, libNameLen); + memcpy(db2TableNameAscii, asciiFileName, fileNameLen); + convertNativeToSQLName(db2TableNameAscii, db2TableNameSQLAscii); + convToEbcdic(db2TableNameAscii, db2TableNameEbcdic, fileNameLen); + } + + conversionDefinitions[toMySQL] = NULL; + conversionDefinitions[toDB2] = NULL; + + isTemporaryTable = (strstr(mysqlTable->path.str, mysql_tmpdir) == mysqlTable->path.str); +} + + +int32 db2i_table::initDB2Objects(const char* path) +{ + uint fileObjects = 1 + mysqlTable->keys; + ValidatedPointer<ShrDef> fileDefnSpace(sizeof(ShrDef) * fileObjects); + + physicalFile = new db2i_file(this); + physicalFile->fillILEDefn(&fileDefnSpace[0], true); + + if (fileObjects > 1) + { + logicalFiles = new db2i_file*[fileObjects - 1]; + for (int k = 0; k < mysqlTable->keys; k++) + { + logicalFiles[k] = new db2i_file(this, k); + logicalFiles[k]->fillILEDefn(&fileDefnSpace[k+1], false); + } + } + + ValidatedPointer<FILE_HANDLE> fileDefnHandles(sizeof(FILE_HANDLE) * fileObjects); + 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); + + if (rc) + return rc; + + convFromEbcdic(((format_hdr_t*)formatSpace)->FilLvlId, fileLevelID, sizeof(fileLevelID)); + + if (!doFileIDsMatch(path)) + { + getErrTxt(QMY_ERR_LVLID_MISMATCH); + return QMY_ERR_LVLID_MISMATCH; + } + + physicalFile->setMasterDefnHandle(fileDefnHandles[0]); + for (int k = 0; k < mysqlTable->keys; k++) + { + logicalFiles[k]->setMasterDefnHandle(fileDefnHandles[k+1]); + } + + db2StartId = (uint64)(((format_hdr_t*)formatSpace)->StartIdVal); + db2Fields = (DB2Field*)((char*)(void*)formatSpace + ((format_hdr_t*)formatSpace)->ColDefOff); + + uint fields = mysqlTable->fields; + for (int i = 0; i < fields; ++i) + { + if (db2Field(i).isBlob()) + { + blobFieldCount++; + } + } + + if (blobFieldCount) + { + blobFieldActualSizes = (uint*)my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + &blobFieldActualSizes, blobFieldCount * sizeof(uint), + &blobFields, blobFieldCount * sizeof(uint16), + NullS); + + int b = 0; + for (int i = 0; i < fields; ++i) + { + if (db2Field(i).isBlob()) + { + blobFields[b++] = i; + } + } + } + + my_multi_malloc(MYF(MY_WME), + &conversionDefinitions[toMySQL], fields * sizeof(iconv_t), + &conversionDefinitions[toDB2], fields * sizeof(iconv_t), + NullS); + for (int i = 0; i < fields; ++i) + { + conversionDefinitions[toMySQL][i] = (iconv_t)(-1); + conversionDefinitions[toDB2][i] = (iconv_t)(-1); + } + + return 0; +} + +int db2i_table::fastInitForCreate(const char* path) +{ + ValidatedPointer<ShrDef> fileDefnSpace(sizeof(ShrDef)); + + physicalFile = new db2i_file(this); + physicalFile->fillILEDefn(fileDefnSpace, true); + + ValidatedPointer<FILE_HANDLE> fileDefnHandles(sizeof(FILE_HANDLE)); + + size_t formatSpaceLen = sizeof(format_hdr_t) + + mysqlTable->fields * sizeof(DB2Field); + formatSpace.alloc(formatSpaceLen); + + int rc = db2i_ileBridge::getBridgeForThread()->allocateFileDefn(fileDefnSpace, + fileDefnHandles, + 1, + db2LibNameEbcdic, + strlen(db2LibNameEbcdic), + formatSpace, + formatSpaceLen); + + if (rc) + return rc; + + convFromEbcdic(((format_hdr_t*)formatSpace)->FilLvlId, fileLevelID, sizeof(fileLevelID)); + doFileIDsMatch(path); + + return 0; +} + +bool db2i_table::doFileIDsMatch(const char* path) +{ + char name_buff[FN_REFLEN]; + + fn_format(name_buff, path, "", FID_EXT, (MY_REPLACE_EXT | MY_UNPACK_FILENAME)); + + File fd = my_open(name_buff, O_RDONLY, MYF(0)); + + if (fd == -1) + { + if (errno == ENOENT) + { + fd = my_create(name_buff, 0, O_WRONLY, MYF(MY_WME)); + + if (fd == -1) + { + // TODO: Report errno here + return false; + } + my_write(fd, (uchar*)fileLevelID, sizeof(fileLevelID), MYF(MY_WME)); + my_close(fd, MYF(0)); + return true; + } + else + { + // TODO: Report errno here + return false; + } + } + + char diskFID[sizeof(fileLevelID)]; + + bool match = false; + + if (my_read(fd, (uchar*)diskFID, sizeof(diskFID), MYF(MY_WME)) == sizeof(diskFID) && + (memcmp(diskFID, fileLevelID, sizeof(diskFID)) == 0)) + match = true; + + my_close(fd, MYF(0)); + + return match; +} + +void db2i_table::deleteAssocFiles(const char* name) +{ + char name_buff[FN_REFLEN]; + fn_format(name_buff, name, "", FID_EXT, (MY_REPLACE_EXT | MY_UNPACK_FILENAME)); + my_delete(name_buff, MYF(0)); +} + +void db2i_table::renameAssocFiles(const char* from, const char* to) +{ + rename_file_ext(from, to, FID_EXT); +} + + +db2i_table::~db2i_table() +{ + if (blobFieldActualSizes) + my_free(blobFieldActualSizes, MYF(0)); + + if (conversionDefinitions[toMySQL]) + my_free(conversionDefinitions[toMySQL], MYF(0)); + + if (logicalFiles) + { + for (int k = 0; k < mysqlTable->keys; ++k) + { + delete logicalFiles[k]; + } + + delete[] logicalFiles; + } + delete physicalFile; + + my_free(db2LibNameEbcdic, 0); +} + +void db2i_table::getDB2QualifiedName(char* to) +{ + strcat(to, getDB2LibName(ASCII_SQL)); + strcat(to, "."); + strcat(to, getDB2TableName(ASCII_SQL)); +} + + +void db2i_table::getDB2QualifiedNameFromPath(const char* path, char* to) +{ + getDB2LibNameFromPath(path, to); + strcat(to, "."); + getDB2FileNameFromPath(path, strend(to)); +} + + +void db2i_table::filenameToTablename(const char* in, char* out, size_t outlen) +{ + if (strchr(in, '#') == NULL) + { + filename_to_tablename(in, out, outlen); + return; + } + + char* temp = (char*)sql_alloc(outlen); + + const char* part1, *part2, *part3, *part4; + part1 = in; + part2 = strstr(part1, "#P#"); + if (part2); + { + part3 = part2 + 3; + part4 = strchr(part3, '#'); + if (!part4) + part4 = strend(in); + } + + memcpy(temp, part1, min(outlen, part2 - part1)); + temp[min(outlen-1, part2-part1)] = 0; + + int32 accumLen = filename_to_tablename(temp, out, outlen); + + if (part2 && (accumLen + 4 < outlen)) + { + strcat(out, "#P#"); + accumLen += 4; + + memset(temp, 0, min(outlen, part2-part1)); + memcpy(temp, part3, min(outlen, part4-part3)); + temp[min(outlen-1, part4-part3)] = 0; + + accumLen += filename_to_tablename(temp, strend(out), outlen-accumLen); + + if (part4 && (accumLen + (strend(in) - part4 + 1) < outlen)) + { + strcat(out, part4); + } + } +} + +void db2i_table::getDB2LibNameFromPath(const char* path, char* lib, NameFormatFlags format) +{ + if (strstr(path, mysql_tmpdir) == path) + { + strcpy(lib, DB2I_TEMP_TABLE_SCHEMA); + } + else + { + const char* c = strend(path) - 1; + while (c > path && *c != '\\' && *c != '/') + --c; + + if (c != path) + { + const char* dbEnd = c; + do { + --c; + } while (c >= path && *c != '\\' && *c != '/'); + + if (c >= path) + { + const char* dbStart = c+1; + char fileName[FN_REFLEN]; + memcpy(fileName, dbStart, dbEnd - dbStart); + fileName[dbEnd-dbStart] = 0; + + char dbName[MAX_DB2_SCHEMANAME_LENGTH+1]; + filenameToTablename(fileName, dbName , sizeof(dbName)); + + convertMySQLNameToDB2Name(dbName, lib, sizeof(dbName), true, (format==ASCII_SQL) ); + } + else + DBUG_ASSERT(0); // This should never happen! + } + } +} + +void db2i_table::getDB2FileNameFromPath(const char* path, char* file, NameFormatFlags format) +{ + const char* fileEnd = strend(path); + const char* c = fileEnd; + while (c > path && *c != '\\' && *c != '/') + --c; + + if (c != path) + { + const char* fileStart = c+1; + char fileName[FN_REFLEN]; + memcpy(fileName, fileStart, fileEnd - fileStart); + fileName[fileEnd - fileStart] = 0; + char db2Name[MAX_DB2_FILENAME_LENGTH+1]; + filenameToTablename(fileName, db2Name, sizeof(db2Name)); + convertMySQLNameToDB2Name(db2Name, file, sizeof(db2Name), true, (format==ASCII_SQL) ); + } +} + +// Generates the DB2 index name when given the MySQL index and table names. +int32 db2i_table::appendQualifiedIndexFileName(const char* indexName, + const char* tableName, + String& to, + NameFormatFlags format, + enum_DB2I_INDEX_TYPE type) +{ + char generatedName[MAX_DB2_FILENAME_LENGTH+1]; + strncpy(generatedName, indexName, DB2I_INDEX_NAME_LENGTH_TO_PRESERVE); + generatedName[DB2I_INDEX_NAME_LENGTH_TO_PRESERVE] = 0; + char* endOfGeneratedName; + + if (type == typeDefault) + { + strcat(generatedName, DB2I_DEFAULT_INDEX_NAME_DELIMITER); + endOfGeneratedName = strend(generatedName); + } + else if (type != typeNone) + { + strcat(generatedName, DB2I_ADDL_INDEX_NAME_DELIMITER); + endOfGeneratedName = strend(generatedName); + *(endOfGeneratedName-2) = char(type); + } + + uint lenWithoutFile = endOfGeneratedName - generatedName; + + char strippedTableName[MAX_DB2_FILENAME_LENGTH+1]; + if (format == ASCII_SQL) + { + strcpy(strippedTableName, tableName); + stripExtraQuotes(strippedTableName+1, sizeof(strippedTableName)); + tableName = strippedTableName; + } + + if (strlen(tableName) > (MAX_DB2_FILENAME_LENGTH-lenWithoutFile)) + return -1; + + strncat(generatedName, + tableName+1, + min(strlen(tableName), (MAX_DB2_FILENAME_LENGTH-lenWithoutFile))-2 ); + + char finalName[MAX_DB2_FILENAME_LENGTH+1]; + convertMySQLNameToDB2Name(generatedName, finalName, sizeof(finalName), true, (format==ASCII_SQL)); + to.append(finalName); + + return 0; +} + + +void db2i_table::findConversionDefinition(enum_conversionDirection direction, uint16 fieldID) +{ + getConversion(direction, + mysqlTable->field[fieldID]->charset(), + db2Field(fieldID).getCCSID(), + conversionDefinitions[direction][fieldID]); +} + + +db2i_file::db2i_file(db2i_table* table) : db2Table(table) +{ + commonCtorInit(); + + DBUG_ASSERT(table->getMySQLTable()->table_name.length <= MAX_DB2_FILENAME_LENGTH-2); + + db2FileName = (char*)table->getDB2TableName(db2i_table::EBCDIC_NATIVE); +} + +db2i_file::db2i_file(db2i_table* table, int index) : db2Table(table) +{ + commonCtorInit(); + + if ((index == table->getMySQLTable()->primary_key) && !table->isTemporary()) + { + db2FileName = (char*)table->getDB2TableName(db2i_table::EBCDIC_NATIVE); + } + else + { + // Generate the index name (in index___table form); quote and EBCDICize it. + String qualifiedPath; + qualifiedPath.length(0); + + const char* asciiFileName = table->getDB2TableName(db2i_table::ASCII_NATIVE); + + db2i_table::appendQualifiedIndexFileName(table->getMySQLTable()->key_info[index].name, + asciiFileName, + qualifiedPath, + db2i_table::ASCII_NATIVE, + typeDefault); + + db2FileName = (char*)my_malloc(qualifiedPath.length()+1, MYF(MY_WME | MY_ZEROFILL)); + convToEbcdic(qualifiedPath.ptr(), db2FileName, qualifiedPath.length()); + } +} + +void db2i_file::commonCtorInit() +{ + masterDefn = 0; + memset(&formats, 0, maxRowFormats*sizeof(RowFormat)); +} + + +void db2i_file::fillILEDefn(ShrDef* defn, bool readInArrivalSeq) +{ + defn->ObjNamLen = strlen(db2FileName); + DBUG_ASSERT(defn->ObjNamLen <= sizeof(defn->ObjNam)); + memcpy(defn->ObjNam, db2FileName, defn->ObjNamLen); + defn->ArrSeq[0] = (readInArrivalSeq ? QMY_YES : QMY_NO); +} + |