//-< CLASS.CPP >-----------------------------------------------------*--------* // FastDB Version 1.0 (c) 1999 GARRET * ? * // (Main Memory Database Management System) * /\| * // * / \ * // Created: 20-Nov-98 K.A. Knizhnik * / [] \ * // Last update: 1-Jan-99 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // Metaclass information //-------------------------------------------------------------------*--------* #define INSIDE_FASTDB #include "fastdb.h" #include "compiler.h" #include "symtab.h" #ifndef CHECK_RECORD_SIZE #define CHECK_RECORD_SIZE 1 #endif dbTableDescriptor* dbTableDescriptor::chain; void* dbFieldDescriptor::operator new(size_t size EXTRA_DEBUG_NEW_PARAMS) { return dbMalloc(size); } void dbFieldDescriptor::operator delete(void* p EXTRA_DEBUG_NEW_PARAMS) { dbFree(p); } dbFieldDescriptor::dbFieldDescriptor(const char* name) { next = prev = this; this->name = name; longName = NULL; dbSymbolTable::add((char*&) (this->name), tkn_ident, FASTDB_CLONE_ANY_IDENTIFIER); appOffs = dbsOffs = 0; defTable = refTable = NULL; refTableName = NULL; components = NULL; inverseRefName = NULL; indexType = 0; method = NULL; attr = OneToOneMapping; tTree = 0; hashTable = 0; comparator = (dbUDTComparator)&memcmp; } dbFieldDescriptor::dbFieldDescriptor(const char* fieldName, int offs, int size, int index, char* inverse, dbFieldDescriptor* fieldComponents) { next = prev = this; name = fieldName; longName = NULL; dbSymbolTable::add((char*&) name, tkn_ident, FASTDB_CLONE_ANY_IDENTIFIER); appOffs = offs; dbsOffs = 0; alignment = appSize = dbsSize = size; defTable = refTable = NULL; indexType = index; type = appType = dbField::tpStructure; inverseRefName = inverse; if (inverseRefName != NULL) { dbSymbolTable::add(inverseRefName, tkn_ident, FASTDB_CLONE_ANY_IDENTIFIER); } inverseRef = NULL; components = fieldComponents; method = NULL; attr = 0; tTree = 0; hashTable = 0; comparator = (dbUDTComparator)&memcmp; } dbFieldDescriptor::~dbFieldDescriptor() { if (type == dbField::tpString) { delete components; } delete[] longName; } dbFieldDescriptor* dbFieldDescriptor::find(const char* name) { dbFieldDescriptor* field = components; do { if (field->name == name) { return field; } } while ((field = field->next) != components); return NULL; } void dbFieldDescriptor::adjustReferences(byte* record, size_t base, size_t size, long shift) { dbFieldDescriptor* fd = this; do { if (fd->type == dbField::tpArray) { byte** ptr = (byte**)((dbAnyArray*)(record + fd->appOffs) + 1); if ((unsigned long)*ptr - base <= size) { *ptr += shift; } else { if (fd->attr & HasArrayComponents) { int nElems = ((dbAnyArray*)(record+fd->appOffs))->length(); byte* arrBase = *ptr; while (--nElems >= 0) { fd->components->adjustReferences(arrBase, base, size, shift); arrBase += fd->components->appSize; } } } } else if (fd->type == dbField::tpString) { char** str = (char**)(record + fd->appOffs); if ((unsigned long)*str - base <= size) { *str += shift; } } else if (fd->attr & HasArrayComponents) { fd->components->adjustReferences(record + fd->appOffs, base, size, shift); } } while ((fd = fd->next) != this); } size_t dbFieldDescriptor::calculateRecordSize(byte* base, size_t offs) { dbFieldDescriptor* fd = this; do { switch (fd->appType) { case dbField::tpArray: { int nElems = ((dbAnyArray*)(base + fd->appOffs))->length(); offs = DOALIGN(offs, fd->components->alignment) + nElems*fd->components->dbsSize; if (fd->attr & HasArrayComponents) { byte* elem = (byte*)((dbAnyArray*)(base+fd->appOffs))->base(); dbFieldDescriptor* component = fd->components; size_t elemSize = component->appSize; while (--nElems >= 0) { offs = component->calculateRecordSize(elem, offs); elem += elemSize; } } continue; } case dbField::tpString: { char* str = *(char**)(base + fd->appOffs); if (str != NULL) { offs += strlen(str) + 1; } else { offs += 1; } continue; } #ifdef USE_STD_STRING case dbField::tpStdString: offs += ((std::string*)(base + fd->appOffs))->length() + 1; continue; #endif default: if (fd->attr & HasArrayComponents) { offs = fd->components->calculateRecordSize(base+fd->appOffs, offs); } } } while ((fd = fd->next) != this); return offs; } size_t dbFieldDescriptor::calculateNewRecordSize(byte* base, size_t offs) { dbFieldDescriptor* fd = this; do { if (fd->type == dbField::tpArray) { if (fd->oldDbsType == dbField::tpUnknown) { continue; } int nElems = ((dbVarying*)(base + fd->oldDbsOffs))->size; offs = DOALIGN(offs, fd->components->alignment) + nElems*fd->components->dbsSize; if (fd->attr & HasArrayComponents) { byte* elem = base + ((dbVarying*)(base+fd->oldDbsOffs))->offs; while (--nElems >= 0) { offs = fd->components->calculateNewRecordSize(elem, offs); elem += fd->components->oldDbsSize; } } } else if (fd->type == dbField::tpString) { if (fd->oldDbsType == dbField::tpUnknown) { offs += 1; } else { offs += ((dbVarying*)(base + fd->oldDbsOffs))->size; } } else if (fd->attr & HasArrayComponents) { offs = fd->components->calculateNewRecordSize(base, offs); } } while ((fd = fd->next) != this); return offs; } void dbFieldDescriptor::fetchRecordFields(byte* dst, byte* src) { dbFieldDescriptor* fd = this; do { switch (fd->appType) { case dbField::tpBool: *(bool*)(dst+fd->appOffs) = *(bool*)(src+fd->dbsOffs); break; case dbField::tpInt1: *(int1*)(dst+fd->appOffs) = *(int1*)(src+fd->dbsOffs); break; case dbField::tpInt2: *(int2*)(dst+fd->appOffs) = *(int2*)(src+fd->dbsOffs); break; case dbField::tpInt4: *(int4*)(dst+fd->appOffs) = *(int4*)(src+fd->dbsOffs); break; case dbField::tpInt8: *(db_int8*)(dst+fd->appOffs) = *(db_int8*)(src+fd->dbsOffs); break; case dbField::tpReal4: *(real4*)(dst+fd->appOffs) = *(real4*)(src+fd->dbsOffs); break; case dbField::tpReal8: *(real8*)(dst+fd->appOffs) = *(real8*)(src+fd->dbsOffs); break; case dbField::tpRawBinary: memcpy(dst+fd->appOffs, src+fd->dbsOffs, fd->dbsSize); break; case dbField::tpString: *(char**)(dst+fd->appOffs) = (char*)(src + ((dbVarying*)(src+fd->dbsOffs))->offs); break; #ifdef USE_STD_STRING case dbField::tpStdString: ((std::string*)(dst + fd->appOffs))->assign((char*)(src + ((dbVarying*)(src+fd->dbsOffs))->offs), ((dbVarying*)(src+fd->dbsOffs))->size - 1); break; #endif case dbField::tpArray: { int nElems = ((dbVarying*)(src+fd->dbsOffs))->size; byte* srcElem = src + ((dbVarying*)(src+fd->dbsOffs))->offs; dbAnyArray* array = (dbAnyArray*)(dst+fd->appOffs); if (fd->attr & dbFieldDescriptor::OneToOneMapping) { fd->arrayAllocator(array, srcElem, nElems); } else { fd->arrayAllocator(array, NULL, nElems); byte* dstElem = (byte*)array->base(); dbFieldDescriptor* component = fd->components; while (--nElems >= 0) { component->fetchRecordFields(dstElem, srcElem); dstElem += component->appSize; srcElem += component->dbsSize; } } } break; case dbField::tpReference: ((dbAnyReference*)(dst+fd->appOffs))->oid = *(oid_t*)(src+fd->dbsOffs); break; case dbField::tpStructure: fd->components->fetchRecordFields(dst + fd->appOffs, src); break; default: return; } } while ((fd = fd->next) != this); } size_t dbFieldDescriptor::storeRecordFields(byte* dst, byte* src, size_t offs, bool insert) { dbFieldDescriptor* fd = this; do { #ifdef AUTOINCREMENT_SUPPORT if (insert && (fd->indexType & AUTOINCREMENT) != 0) { assert (fd->appType == dbField::tpInt4); *(int4*)(dst+fd->dbsOffs) = *(int4*)(src+fd->appOffs) = fd->defTable->autoincrementCount; continue; } #endif switch (fd->appType) { case dbField::tpBool: *(bool*)(dst+fd->dbsOffs) = *(bool*)(src+fd->appOffs); break; case dbField::tpInt1: *(int1*)(dst+fd->dbsOffs) = *(int1*)(src+fd->appOffs); break; case dbField::tpInt2: *(int2*)(dst+fd->dbsOffs) = *(int2*)(src+fd->appOffs); break; case dbField::tpInt4: *(int4*)(dst+fd->dbsOffs) = *(int4*)(src+fd->appOffs); break; case dbField::tpInt8: *(db_int8*)(dst+fd->dbsOffs) = *(db_int8*)(src+fd->appOffs); break; case dbField::tpReal4: *(real4*)(dst+fd->dbsOffs) = *(real4*)(src+fd->appOffs); break; case dbField::tpReal8: *(real8*)(dst+fd->dbsOffs) = *(real8*)(src+fd->appOffs); break; case dbField::tpRawBinary: memcpy(dst+fd->dbsOffs, src+fd->appOffs, fd->dbsSize); break; #ifdef USE_STD_STRING case dbField::tpStdString: { ((dbVarying*)(dst+fd->dbsOffs))->offs = offs; std::string* str = (std::string*)(src + fd->appOffs); int len = str->length(); str->copy((char*)dst + offs, len); dst[offs + len] = '\0'; ((dbVarying*)(dst+fd->dbsOffs))->size = len+1; offs += (len+1); } break; #endif case dbField::tpString: { ((dbVarying*)(dst+fd->dbsOffs))->offs = offs; char* str = *(char**)(src + fd->appOffs); if (str != NULL) { strcpy((char*)dst + offs, str); offs += ((dbVarying*)(dst+fd->dbsOffs))->size = strlen(*(char**)(src + fd->appOffs)) + 1; } else { *((char*)dst + offs) = '\0'; offs += 1; } } break; case dbField::tpArray: { int nElems = ((dbAnyArray*)(src + fd->appOffs))->length(); byte* srcElem=(byte*)((dbAnyArray*)(src+fd->appOffs))->base(); byte* dstElem = (byte*)DOALIGN(long(dst)+offs, fd->components->alignment); offs = dstElem - dst; ((dbVarying*)(dst+fd->dbsOffs))->size = nElems; ((dbVarying*)(dst+fd->dbsOffs))->offs = offs; size_t sizeElem = fd->components->dbsSize; size_t offsElem = nElems*sizeElem; offs += offsElem; if (srcElem != NULL) { if (fd->attr & dbFieldDescriptor::OneToOneMapping) { memcpy(dstElem, srcElem, offsElem); } else { dbFieldDescriptor* component = fd->components; while (--nElems >= 0) { offsElem = component->storeRecordFields(dstElem, srcElem, offsElem, insert); offsElem -= sizeElem; dstElem += sizeElem; srcElem += component->appSize; } offs += offsElem; } } } break; case dbField::tpReference: *(oid_t*)(dst+fd->dbsOffs) = ((dbAnyReference*)(src+fd->appOffs))->oid; break; case dbField::tpStructure: offs = fd->components->storeRecordFields(dst, src+fd->appOffs, offs, insert); break; default: return offs; } } while ((fd = fd->next) != this); return offs; } void dbFieldDescriptor::markUpdatedFields(byte* dst, byte* src) { dbFieldDescriptor* fd = this; do { if (fd->indexType & (HASHED|INDEXED)) { switch (fd->appType) { case dbField::tpBool: if (*(bool*)(dst+fd->dbsOffs) != *(bool*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpInt1: if (*(int1*)(dst+fd->dbsOffs) != *(int1*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpInt2: if (*(int2*)(dst+fd->dbsOffs) != *(int2*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpInt4: if (*(int4*)(dst+fd->dbsOffs) != *(int4*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpInt8: if (*(db_int8*)(dst+fd->dbsOffs) != *(db_int8*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpReference: if (*(oid_t*)(dst+fd->dbsOffs) != *(oid_t*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpReal4: if (*(real4*)(dst+fd->dbsOffs) != *(real4*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpReal8: if (*(real8*)(dst+fd->dbsOffs) != *(real8*)(src+fd->appOffs)) { fd->attr |= Updated; } break; case dbField::tpRawBinary: if (memcmp(dst+fd->dbsOffs, src+fd->appOffs, fd->dbsSize) != 0) { fd->attr |= Updated; } break; case dbField::tpString: if (strcmp((char*)dst + ((dbVarying*)(dst+fd->dbsOffs))->offs, *(char**)(src + fd->appOffs)) != 0) { fd->attr |= Updated; } break; #ifdef USE_STD_STRING case dbField::tpStdString: if (*(std::string*)(src + fd->appOffs) != (char*)(dst + ((dbVarying*)(dst+fd->dbsOffs))->offs)) { fd->attr |= Updated; } break; #endif case dbField::tpStructure: fd->components->markUpdatedFields(dst, src+fd->appOffs); break; case dbField::tpArray: break; default: return; } } } while ((fd = fd->next) != this); } size_t dbFieldDescriptor::convertRecord(byte* dst, byte* src, size_t offs) { dbFieldDescriptor* fd = this; int1 i1; int2 i2; int4 i4; db_int8 i8; real4 f4; real8 f8; bool b; do { switch (fd->type) { case dbField::tpBool: switch (fd->oldDbsType) { case dbField::tpBool: b = *(bool*)(src + fd->oldDbsOffs); break; case dbField::tpInt1: b = *(int1*)(src + fd->oldDbsOffs) != 0; break; case dbField::tpInt2: b = *(int2*)(src + fd->oldDbsOffs) != 0; break; case dbField::tpInt4: b = *(int4*)(src + fd->oldDbsOffs) != 0; break; case dbField::tpInt8: b = *(db_int8*)(src + fd->oldDbsOffs) != 0; break; case dbField::tpReal4: b = *(real4*)(src + fd->oldDbsOffs) != 0; break; case dbField::tpReal8: b = *(real8*)(src + fd->oldDbsOffs) != 0; break; default: b = false; } *(bool*)(dst + fd->dbsOffs) = b; break; case dbField::tpInt1: switch (fd->oldDbsType) { case dbField::tpBool: i1 = *(bool*)(src + fd->oldDbsOffs); break; case dbField::tpInt1: i1 = *(int1*)(src + fd->oldDbsOffs); break; case dbField::tpInt2: i1 = (int1)*(int2*)(src + fd->oldDbsOffs); break; case dbField::tpInt4: i1 = (int1)*(int4*)(src + fd->oldDbsOffs); break; case dbField::tpInt8: i1 = (int1)*(db_int8*)(src + fd->oldDbsOffs); break; case dbField::tpReal4: i1 = (int1)*(real4*)(src + fd->oldDbsOffs); break; case dbField::tpReal8: i1 = (int1)*(real8*)(src + fd->oldDbsOffs); break; default: i1 = 0; } *(int1*)(dst + fd->dbsOffs) = i1; break; case dbField::tpInt2: switch (fd->oldDbsType) { case dbField::tpBool: i2 = *(bool*)(src + fd->oldDbsOffs); break; case dbField::tpInt1: i2 = *(int1*)(src + fd->oldDbsOffs); break; case dbField::tpInt2: i2 = *(int2*)(src + fd->oldDbsOffs); break; case dbField::tpInt4: i2 = (int2)*(int4*)(src + fd->oldDbsOffs); break; case dbField::tpInt8: i2 = (int2)*(db_int8*)(src + fd->oldDbsOffs); break; case dbField::tpReal4: i2 = (int2)*(real4*)(src + fd->oldDbsOffs); break; case dbField::tpReal8: i2 = (int2)*(real8*)(src + fd->oldDbsOffs); break; default: i2 = 0; } *(int2*)(dst + fd->dbsOffs) = i2; break; case dbField::tpInt4: switch (fd->oldDbsType) { case dbField::tpBool: i4 = *(bool*)(src + fd->oldDbsOffs); break; case dbField::tpInt1: i4 = *(int1*)(src + fd->oldDbsOffs); break; case dbField::tpInt2: i4 = *(int2*)(src + fd->oldDbsOffs); break; case dbField::tpInt4: i4 = *(int4*)(src + fd->oldDbsOffs); break; case dbField::tpInt8: i4 = (int4)*(db_int8*)(src + fd->oldDbsOffs); break; case dbField::tpReal4: i4 = (int4)*(real4*)(src + fd->oldDbsOffs); break; case dbField::tpReal8: i4 = (int4)*(real8*)(src + fd->oldDbsOffs); break; default: i4 = 0; } *(int4*)(dst + fd->dbsOffs) = i4; break; case dbField::tpInt8: switch (fd->oldDbsType) { case dbField::tpBool: i8 = *(bool*)(src + fd->oldDbsOffs); break; case dbField::tpInt1: i8 = *(int1*)(src + fd->oldDbsOffs); break; case dbField::tpInt2: i8 = *(int2*)(src + fd->oldDbsOffs); break; case dbField::tpInt4: i8 = *(int4*)(src + fd->oldDbsOffs); break; case dbField::tpInt8: i8 = *(db_int8*)(src + fd->oldDbsOffs); break; case dbField::tpReal4: i8 = (db_int8)*(real4*)(src + fd->oldDbsOffs); break; case dbField::tpReal8: i8 = (db_int8)*(real8*)(src + fd->oldDbsOffs); break; default: i8 = 0; } *(db_int8*)(dst + fd->dbsOffs) = i8; break; case dbField::tpReal4: switch (fd->oldDbsType) { case dbField::tpBool: f4 = (real4)*(bool*)(src + fd->oldDbsOffs); break; case dbField::tpInt1: f4 = (real4)*(int1*)(src + fd->oldDbsOffs); break; case dbField::tpInt2: f4 = (real4)*(int2*)(src + fd->oldDbsOffs); break; case dbField::tpInt4: f4 = (real4)*(int4*)(src + fd->oldDbsOffs); break; case dbField::tpInt8: f4 = (real4)*(db_int8*)(src + fd->oldDbsOffs); break; case dbField::tpReal4: f4 = *(real4*)(src + fd->oldDbsOffs); break; case dbField::tpReal8: f4 = (real4)*(real8*)(src + fd->oldDbsOffs); break; default: f4 = 0; } *(real4*)(dst + fd->dbsOffs) = f4; break; case dbField::tpReal8: switch (fd->oldDbsType) { case dbField::tpBool: f8 = (real8)*(bool*)(src + fd->oldDbsOffs); break; case dbField::tpInt1: f8 = (real8)*(int1*)(src + fd->oldDbsOffs); break; case dbField::tpInt2: f8 = (real8)*(int2*)(src + fd->oldDbsOffs); break; case dbField::tpInt4: f8 = (real8)*(int4*)(src + fd->oldDbsOffs); break; case dbField::tpInt8: f8 = (real8)*(db_int8*)(src + fd->oldDbsOffs); break; case dbField::tpReal4: f8 = *(real4*)(src + fd->oldDbsOffs); break; case dbField::tpReal8: f8 = *(real8*)(src + fd->oldDbsOffs); break; default: f8 = 0; } *(real8*)(dst + fd->dbsOffs) = f8; break; case dbField::tpRawBinary: if (fd->oldDbsType == dbField::tpRawBinary) { memcpy(dst + fd->dbsOffs, src + fd->oldDbsOffs, size_t(fd->oldDbsSize) < fd->dbsSize ? size_t(fd->oldDbsSize) : fd->dbsSize); } break; case dbField::tpString: if (fd->oldDbsType == dbField::tpUnknown) { ((dbVarying*)(dst + fd->dbsOffs))->size = 1; ((dbVarying*)(dst + fd->dbsOffs))->offs = offs; *(char*)(dst + offs++) = '\0'; } else { size_t len = ((dbVarying*)(src + fd->oldDbsOffs))->size; ((dbVarying*)(dst + fd->dbsOffs))->size = len; ((dbVarying*)(dst + fd->dbsOffs))->offs = offs; memcpy(dst + offs, src + ((dbVarying*)(src+fd->oldDbsOffs))->offs, len); offs += len; } break; case dbField::tpArray: if (fd->oldDbsType == dbField::tpUnknown) { ((dbVarying*)(dst + fd->dbsOffs))->size = 0; ((dbVarying*)(dst + fd->dbsOffs))->offs = 0; } else { int len = ((dbVarying*)(src+fd->oldDbsOffs))->size; byte* srcElem = src + ((dbVarying*)(src+fd->oldDbsOffs))->offs; ((dbVarying*)(dst + fd->dbsOffs))->size = len; byte* dstElem = (byte*)DOALIGN(long(dst)+offs, fd->components->alignment); offs = dstElem - dst; ((dbVarying*)(dst+fd->dbsOffs))->offs = offs; size_t offsElem = len*fd->components->dbsSize; offs += offsElem; while (--len >= 0) { offsElem = fd->components->convertRecord(dstElem, srcElem, offsElem); offsElem -= fd->components->dbsSize; dstElem += fd->components->dbsSize; srcElem += fd->components->oldDbsSize; } offs += offsElem; } break; case dbField::tpStructure: offs = fd->components->convertRecord(dst, src, offs); break; case dbField::tpReference: if (fd->oldDbsType == dbField::tpUnknown) { *(oid_t*)(dst + fd->dbsOffs) = 0; } else { *(oid_t*)(dst + fd->dbsOffs) = *(oid_t*)(src + fd->oldDbsOffs); } break; default: return offs; } } while ((fd = fd->next) != this); return offs; } int dbTableDescriptor::initialAutoincrementCount; dbTableDescriptor::dbTableDescriptor(char* tableName, dbDatabase* database, size_t objSize, describeFunc func, dbTableDescriptor* original) { cloneOf = original; isStatic = true; if (original == NULL) { next = chain; chain = this; } name = tableName; dbSymbolTable::add(name, tkn_ident, FASTDB_CLONE_ANY_IDENTIFIER); describeComponentsFunc = func; columns = (*func)(); nextFieldLink = &firstField; hashedFields = NULL; indexedFields = NULL; inverseFields = NULL; tableId = 0; nFields = 0; nColumns = 0; db = database; fixedDatabase = database != NULL; fixedSize = sizeof(dbRecord); int attr = dbFieldDescriptor::OneToOneMapping; appSize = 0; autoincrementCount = initialAutoincrementCount; size_t maxAlignment = calculateFieldsAttributes(columns, "", sizeof(dbRecord), HASHED|INDEXED, attr); #if CHECK_RECORD_SIZE appSize = DOALIGN(appSize, maxAlignment); if (appSize < objSize) { fprintf(stderr, "Warning: may be not all fields of the class '%s' " "were described\n", name); } #endif *nextFieldLink = NULL; } int dbTableDescriptor::calculateFieldsAttributes(dbFieldDescriptor* first, char const* prefix, int offs, int indexMask, int& attr) { dbFieldDescriptor *field = first; size_t alignment = 1; do { if (field->method) { assert(((void)"Not empty record", field != first)); do { assert(((void)"Methods should be specified after variables", field->method != NULL)); field->dbsOffs = first->dbsOffs; field->components = first; if (attr & dbFieldDescriptor::OneToOneMapping) { field->method = field->method->optimize(); } } while ((field = field->next) != first); break; } if (*prefix != '\0') { char* p = new char[strlen(prefix)+strlen(field->name)+1]; sprintf(p, "%s%s", prefix, field->name); field->longName = p; } else { nColumns += 1; field->longName = new char[strlen(field->name)+1]; strcpy(field->longName, field->name); } field->defTable = this; field->indexType &= indexMask|DB_FIELD_INHERITED_MASK; field->attr = (attr & dbFieldDescriptor::ComponentOfArray) | dbFieldDescriptor::OneToOneMapping; if (field->inverseRefName) { assert(!(attr & dbFieldDescriptor::ComponentOfArray) && (field->type == dbField::tpReference || (field->type == dbField::tpArray && field->components->type==dbField::tpReference))); field->nextInverseField = inverseFields; inverseFields = field; } *nextFieldLink = field; nextFieldLink = &field->nextField; field->fieldNo = nFields++; switch (field->type) { case dbField::tpArray: { size_t saveOffs = fixedSize; size_t saveAppSize = appSize; fixedSize = 0; attr = (attr | dbFieldDescriptor::HasArrayComponents) & ~dbFieldDescriptor::OneToOneMapping; field->attr |= dbFieldDescriptor::ComponentOfArray; calculateFieldsAttributes(field->components, field->longName, 0, 0, field->attr); if (field->components->dbsSize != field->components->appSize) { field->attr &= ~dbFieldDescriptor::OneToOneMapping; } fixedSize = saveOffs; appSize = DOALIGN(saveAppSize, sizeof(void*)) + sizeof(void*)*3; break; } case dbField::tpStructure: { char* aggregateName = new char[strlen(field->longName) + 2]; sprintf(aggregateName, "%s.", field->longName); size_t saveOffs = fixedSize; size_t saveAppSize = appSize; appSize = 0; size_t struct_alignment = calculateFieldsAttributes(field->components, aggregateName, offs + field->appOffs, field->indexType, field->attr); field->alignment = struct_alignment; field->dbsOffs = field->components->dbsOffs; attr |= field->attr & dbFieldDescriptor::HasArrayComponents; attr &= field->attr | ~dbFieldDescriptor::OneToOneMapping; field->dbsSize = DOALIGN(fixedSize-saveOffs, struct_alignment); if ((field->attr & dbFieldDescriptor::HasArrayComponents) && struct_alignment < sizeof(void*)) { struct_alignment = sizeof(void*); } appSize = DOALIGN(appSize, struct_alignment) + DOALIGN(saveAppSize, struct_alignment); delete[] aggregateName; break; } case dbField::tpString: attr = (attr | dbFieldDescriptor::HasArrayComponents) & ~dbFieldDescriptor::OneToOneMapping; // no break default: appSize = DOALIGN(appSize, field->appSize) + field->appSize; } if (alignment < field->alignment) { alignment = field->alignment; } if (field->type != dbField::tpStructure) { field->dbsOffs = fixedSize = DOALIGN(fixedSize, field->alignment); fixedSize += field->dbsSize; if (field->dbsOffs != offs + field->appOffs) { attr &= ~dbFieldDescriptor::OneToOneMapping; } if (field->indexType & (HASHED|INDEXED)) { assert(!(field->attr & dbFieldDescriptor::ComponentOfArray)); if (field->indexType & HASHED) { field->nextHashedField = hashedFields; hashedFields = field; } if (field->indexType & INDEXED) { field->nextIndexedField = indexedFields; indexedFields = field; } } } } while ((field = field->next) != first); return alignment; } int dbFieldDescriptor::sizeWithoutOneField(dbFieldDescriptor* field, byte* base, size_t& size) { dbFieldDescriptor* fd = this; int offs, last = 0; do { if (fd != field) { if (fd->type == dbField::tpArray || fd->type == dbField::tpString){ dbVarying* arr = (dbVarying*)(base + fd->dbsOffs); if (arr->offs > last) { last = arr->offs; } int n = arr->size; size = DOALIGN(size, fd->components->alignment) + fd->components->dbsSize * n; if (fd->attr & HasArrayComponents) { byte* elem = base + arr->offs; while (--n >= 0) { offs = fd->components->sizeWithoutOneField(field, elem, size); if (arr->offs + offs > last) { last = arr->offs + offs; } elem += fd->components->dbsSize; } } } else if (fd->attr & HasArrayComponents) { offs = fd->components->sizeWithoutOneField(field, base, size); if (offs > last) { last = offs; } } } } while ((fd = fd->next) != this); return last; } size_t dbFieldDescriptor::copyRecordExceptOneField(dbFieldDescriptor* field, byte* dst, byte* src, size_t offs) { dbFieldDescriptor* fd = this; do { if (fd != field) { if (fd->type == dbField::tpArray || fd->type == dbField::tpString){ dbVarying* srcArr = (dbVarying*)(src + fd->dbsOffs); dbVarying* dstArr = (dbVarying*)(dst + fd->dbsOffs); int n = srcArr->size; byte* srcElem = src + srcArr->offs; byte* dstElem = (byte*)DOALIGN(long(dst) + offs, fd->components->alignment); dstArr->offs = offs = dstElem - dst; dstArr->size = n; size_t sizeElem = fd->components->dbsSize; size_t offsElem = sizeElem * n; offs += offsElem; if (fd->attr & HasArrayComponents) { while (--n >= 0) { offsElem = fd->components-> copyRecordExceptOneField(field, dstElem, srcElem, offsElem); offsElem -= sizeElem; dstElem += sizeElem; srcElem += sizeElem; } offs += offsElem; } else { memcpy(dstElem, srcElem, offsElem); } } else if (fd->attr & HasArrayComponents) { offs = fd->components->copyRecordExceptOneField(field, dst, src, offs); } else if (fd->method == NULL) { memcpy(dst+fd->dbsOffs, src+fd->dbsOffs, fd->dbsSize); } } } while ((fd = fd->next) != this); return offs; } void dbTableDescriptor::checkRelationship() { dbFieldDescriptor* fd; for (fd = inverseFields; fd != NULL; fd = fd->nextInverseField) { dbTableDescriptor* refTable = fd->refTable ? fd->refTable : fd->components->refTable; fd->inverseRef = refTable->findSymbol(fd->inverseRefName); if (fd->inverseRef == NULL || fd->inverseRef->inverseRefName != fd->name) { char msg[256]; if (fd->inverseRef == NULL) { sprintf(msg, "Failed to locate inverse reference field %s.%s for field %s.%s", refTable->name, fd->inverseRefName, fd->defTable->name, fd->longName); } else { sprintf(msg, "Inverse references for field %s.%s is %s.%s, but its inverse reference is %s", fd->defTable->name, fd->longName, refTable->name, fd->inverseRefName, fd->inverseRef->inverseRefName); } db->handleError(dbDatabase::InconsistentInverseReference, msg); } } } dbFieldDescriptor* dbTableDescriptor::find(char const* name) { char* symnam = (char*)name; dbSymbolTable::add(symnam, tkn_ident); return findSymbol(symnam); } dbFieldDescriptor* dbTableDescriptor::findSymbol(const char* name) { dbFieldDescriptor* first = columns; dbFieldDescriptor* field = first; do { if (field->name == name) { return field; } } while ((field = field->next) != first); return NULL; } dbFieldDescriptor& dbFieldDescriptor::adjustOffsets(long offs) { if (offs != 0) { dbFieldDescriptor* fd = this; do { fd->appOffs += offs; } while ((fd = fd->next) != this); } return *this; } bool dbTableDescriptor::match(dbTable* table, bool confirmDeleteColumns) { unsigned nFields = table->fields.size; unsigned nMatches = 0; bool formatNotChanged = (nFields == this->nFields); for (dbFieldDescriptor* fd = firstField; fd != NULL; fd = fd->nextField) { dbField* field = (dbField*)((char*)table + table->fields.offs); fd->oldDbsType = dbField::tpUnknown; for (int n = nFields; --n >= 0; field++) { if (strcmp(fd->longName, (char*)field + field->name.offs) == 0) { assert(((void)"field can be converted to new format", (fd->type == dbField::tpReference && field->type == dbField::tpReference && strcmp((char*)field + field->tableName.offs, fd->refTable->name) == 0) || (fd->type <= dbField::tpReal8 && field->type <= dbField::tpReal8) || (fd->type == dbField::tpString && field->type == dbField::tpString) || (fd->type >= dbField::tpArray && fd->type == field->type))); fd->oldDbsType = field->type; fd->oldDbsOffs = field->offset; fd->oldDbsSize = field->size; if (field->type != fd->type || field->offset != fd->dbsOffs) { formatNotChanged = false; } nMatches += 1; // // Try to reuse indices // fd->hashTable = 0; fd->tTree = 0; if (field->type == fd->type) { if ((fd->indexType & HASHED) != 0 && field->hashTable != 0) { fd->hashTable = field->hashTable; // reuse index field->hashTable = 0; // prevent index from destruction } if ((fd->indexType & INDEXED) != 0 && field->tTree != 0) { fd->tTree = field->tTree; // reuse index field->tTree = 0; // prevent index from destruction } } break; } } } if (!confirmDeleteColumns) { assert(((void)"field can be removed only from empty table", nFields==nMatches)); } return formatNotChanged; } void dbTableDescriptor::setFlags() { for (dbFieldDescriptor* fd = firstField; fd != NULL; fd = fd->nextField) { if (fd->tTree != 0) { fd->indexType |= INDEXED; } else if (fd->hashTable != 0) { fd->indexType |= HASHED; } } } bool dbTableDescriptor::equal(dbTable* table) { #ifdef AUTOINCREMENT_SUPPORT autoincrementCount = table->count; #endif if (nColumns != table->nColumns || nFields != table->fields.size || fixedSize != table->fixedSize) { return false; } dbField* field = (dbField*)((char*)table + table->fields.offs); for (dbFieldDescriptor* fd = firstField; fd != NULL; fd = fd->nextField) { if (strcmp(fd->longName, (char*)field + field->name.offs) != 0 || (!fd->refTable && *((char*)field+field->tableName.offs) != '\0') || (fd->refTable && strcmp((char*)field + field->tableName.offs, fd->refTable->name) != 0) || (fd->inverseRefName == NULL && *((char*)field + field->inverse.offs) != '\0') || (fd->inverseRefName != NULL && strcmp((char*)field + field->inverse.offs, fd->inverseRefName) != 0) || fd->dbsOffs != field->offset || fd->type != field->type) { return false; } fd->tTree = field->tTree; fd->hashTable = field->hashTable; field += 1; } return true; } dbTableDescriptor::dbTableDescriptor(dbTable* table) { next = chain; chain = this; cloneOf = NULL; isStatic = false; name = (char*)table + table->name.offs; dbSymbolTable::add(name, tkn_ident, true); nextFieldLink = &firstField; hashedFields = NULL; indexedFields = NULL; inverseFields = NULL; nFields = 0; nColumns = 0; fixedSize = table->fixedSize; int attr = 0; appSize = 0; columns = buildFieldsList(table, "", 0, attr); *nextFieldLink = NULL; db = NULL; tableId = 0; #ifdef AUTOINCREMENT_SUPPORT autoincrementCount = table->count; #endif } class _AlignArray : public dbAnyArray { protected: void* data; size_t allocated; }; class _AlignReference { protected: oid_t oid; }; union _aligns { struct { char n; bool v; } _abool; struct { char n; int1 v; } _aint1; struct { char n; int2 v; } _aint2; struct { char n; int4 v; } _aint4; struct { char n; db_int8 v; } _aint8; struct { char n; real4 v; } _areal4; struct { char n; real8 v; } _areal8; struct { char n; char *v; } _astring; struct { char n; char v[1]; } _arawbinary; struct { char n; _AlignReference v; } _areference; struct { char n; _AlignArray v; } _aarray; } __aligns; #define COMPUTE_ALIGNED_SIZE(type) \ (((char *)&(((union _aligns *)0)->_a##type.v)) - ((char *)&(((union _aligns *)0)->_a##type.n))) dbFieldDescriptor* dbTableDescriptor::buildFieldsList(dbTable* table, char const* prefix, int prefixLen, int& attr) { dbFieldDescriptor* components = NULL; dbField* field = (dbField*)((char*)table+table->fields.offs) + nFields; while (nFields < table->fields.size && strncmp((char*)field + field->name.offs, prefix, prefixLen) == 0) { char* longName = (char*)field + field->name.offs; char* name = longName + prefixLen; if (*name == '.') { name += 1; } else if (prefixLen != 0 && *name != '[') { break; } dbSymbolTable::add(name, tkn_ident, true); dbFieldDescriptor* fd = new dbFieldDescriptor(name); fd->dbsOffs = field->offset; fd->alignment = fd->dbsSize = field->size; fd->longName = new char[strlen(longName)+1]; strcpy(fd->longName, longName); fd->type = fd->appType = field->type; int appFieldSize, appAlignedFieldSize; switch (field->type) { case dbField::tpBool: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(bool); appFieldSize = sizeof(bool); break; case dbField::tpInt1: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(int1); appFieldSize = sizeof(int1); break; case dbField::tpInt2: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(int2); appFieldSize = sizeof(int2); break; case dbField::tpInt4: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(int4); appFieldSize = sizeof(int4); break; case dbField::tpInt8: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(int8); appFieldSize = sizeof(db_int8); break; case dbField::tpReal4: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(real4); appFieldSize = sizeof(real4); break; case dbField::tpReal8: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(real8); appFieldSize = sizeof(real8); break; case dbField::tpString: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(string); appFieldSize = sizeof(char *); break; case dbField::tpRawBinary: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(rawbinary); appFieldSize = field->size; break; case dbField::tpReference: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(reference); appFieldSize = sizeof(dbAnyReference); break; case dbField::tpArray: appAlignedFieldSize = COMPUTE_ALIGNED_SIZE(array); appFieldSize = sizeof(_AlignArray); break; default: appAlignedFieldSize = 1; appFieldSize = 0; } fd->appOffs = appSize = DOALIGN(appSize, appAlignedFieldSize); appSize += fd->appSize = appFieldSize; if ((fd->hashTable = field->hashTable) != 0) { fd->nextHashedField = hashedFields; hashedFields = fd; } if ((fd->tTree = field->tTree) != 0) { fd->nextIndexedField = indexedFields; indexedFields = fd; } fd->fieldNo = nFields++; fd->defTable = this; fd->refTable = NULL; fd->refTableName = NULL; if (field->hashTable != 0) { fd->indexType |= HASHED; } if (field->tTree != 0) { fd->indexType |= INDEXED; } if (field->tableName.size > 1) { fd->refTableName = (char*)field + field->tableName.offs; dbSymbolTable::add(fd->refTableName, tkn_ident, true); } fd->inverseRefName = NULL; if (field->inverse.size > 1) { fd->nextInverseField = inverseFields; inverseFields = fd; fd->inverseRefName = (char*)field + field->inverse.offs; dbSymbolTable::add(fd->inverseRefName, tkn_ident, true); } fd->attr = (attr & dbFieldDescriptor::ComponentOfArray) | dbFieldDescriptor::OneToOneMapping; *nextFieldLink = fd; nextFieldLink = &fd->nextField; if (prefixLen == 0) { nColumns += 1; } if (components == NULL) { components = fd; } else { fd->next = components; fd->prev = components->prev; components->prev->next = fd; components->prev = fd; } if (fd->type == dbField::tpArray || fd->type == dbField::tpString) { attr |= dbFieldDescriptor::HasArrayComponents; fd->attr |= dbFieldDescriptor::ComponentOfArray; fd->alignment = 4; } if (fd->type == dbField::tpArray || fd->type == dbField::tpStructure) { int saveAppSize = appSize; if (fd->type == dbField::tpArray) { appSize = 0; } fd->components = buildFieldsList(table, longName, strlen(longName), fd->attr); if (fd->type == dbField::tpArray) { appSize = saveAppSize; } attr |= fd->attr & dbFieldDescriptor::HasArrayComponents; field = (dbField*)((char*)table + table->fields.offs) + nFields; if (fd->type == dbField::tpStructure) { size_t alignment = 1; dbFieldDescriptor* component = fd->components; do { if (component->alignment > alignment) { alignment = component->alignment; } } while ((component = component->next) != fd->components); fd->alignment = alignment; } else { if (fd->components->type == dbField::tpString) { fd->arrayAllocator = &dbArray::arrayAllocator; fd->attr &= ~dbFieldDescriptor::OneToOneMapping; } else { fd->arrayAllocator = &dbAnyArray::arrayAllocator; } } } else { if (fd->type == dbField::tpString) { fd->components = new dbFieldDescriptor("[]"); fd->components->type = fd->components->appType = dbField::tpInt1; fd->components->dbsSize = fd->components->appSize = 1; fd->components->alignment = 1; } field += 1; } } return components; } size_t dbTableDescriptor::totalNamesLength() { dbFieldDescriptor* fd; size_t len = strlen(name) + 1; for (fd = firstField; fd != NULL; fd = fd->nextField) { if (fd->name != NULL) { len += strlen(fd->longName) + 3; if (fd->inverseRefName != NULL) { len += strlen(fd->inverseRefName); } if (fd->refTable != NULL) { len += strlen(fd->refTable->name); } } } return len; } dbTableDescriptor* dbTableDescriptor::clone() { return new dbTableDescriptor(name, DETACHED_TABLE, appSize, describeComponentsFunc, this); } dbTableDescriptor::~dbTableDescriptor() { if (cloneOf == NULL) { dbTableDescriptor **tpp; for (tpp = &chain; *tpp != this; tpp = &(*tpp)->next); *tpp = next; } dbFieldDescriptor *field, *nextField; for (field = firstField; field != NULL; field = nextField) { nextField = field->nextField; delete field; } } void dbTableDescriptor::cleanup() { dbTableDescriptor* next, *desc; for (desc = chain; desc != NULL; desc = next) { next = desc->next; if (!desc->isStatic) { delete desc; } } } void dbTableDescriptor::storeInDatabase(dbTable* table) { int offs = sizeof(dbTable) + sizeof(dbField)*nFields; table->name.offs = offs; table->name.size = strlen(name)+1; strcpy((char*)table + offs, name); offs += table->name.size; table->fields.offs = sizeof(dbTable); table->fields.size = nFields; table->nRows = 0; table->nColumns = nColumns; table->fixedSize = fixedSize; table->firstRow = 0; table->lastRow = 0; #ifdef AUTOINCREMENT_SUPPORT table->count = autoincrementCount; #endif dbFieldDescriptor* fd; dbField* field = (dbField*)((char*)table + table->fields.offs); offs -= sizeof(dbTable); for (fd = firstField; fd != NULL; fd = fd->nextField) { field->name.offs = offs; field->name.size = strlen(fd->longName) + 1; strcpy((char*)field + offs, fd->longName); offs += field->name.size; field->tableName.offs = offs; if (fd->refTable != NULL) { field->tableName.size = strlen(fd->refTable->name) + 1; strcpy((char*)field + offs, fd->refTable->name); } else { field->tableName.size = 1; *((char*)field + offs) = '\0'; } offs += field->tableName.size; field->inverse.offs = offs; if (fd->inverseRefName != NULL) { field->inverse.size = strlen(fd->inverseRefName) + 1; strcpy((char*)field + offs, fd->inverseRefName); } else { field->inverse.size = 1; *((char*)field + offs) = '\0'; } offs += field->inverse.size; field->tTree = fd->tTree; field->hashTable = fd->hashTable; field->type = fd->type; field->size = fd->dbsSize; field->offset = fd->dbsOffs; field += 1; offs -= sizeof(dbField); } } dbAnyMethodTrampoline::~dbAnyMethodTrampoline() {}