static RC RollBackUpdate(SM_DbHandle &db, Event &event, RID &rid) { RC rc; printf("QL: Undoing update.\n"); RM_FileHandle *pTableHandle; if ((rc = db.FindTableHandle(event.tableName.c_str(), pTableHandle))) return rc; RM_Record record; if ((rc = pTableHandle->GetRec(rid, record))) return rc; char *data; if ((rc = record.GetData(data))) return rc; SM_Attribute *pAttr; if ((rc = db.FindAttribute(event.tableName.c_str(), event.attrName.c_str(), pAttr))) return rc; // If indexed, remove the old entry. IX_IndexHandle *pIndexHandle; if (pAttr->hasIndex) { if ((rc = db.FindIndexHandle(event.tableName.c_str(), event.attrName.c_str(), pIndexHandle))) return rc; if ((rc = pIndexHandle->DeleteEntry(data + pAttr->attrOffset, rid))) return rc; } // Restore the record. int recordSize = pTableHandle->header.recordSize; memcpy(data, event.record, recordSize); // Update the record. if ((rc = pTableHandle->UpdateRec(record))) return rc; // If indexed, insert the new entry. if (pAttr->hasIndex) { if ((rc = pIndexHandle->InsertEntry(data + pAttr->attrOffset, rid))) return rc; } return 0; }
RC QL_Manager::Update() { RC rc; vector<RM_Record> chosenRecords; RM_FileHandle *pTableHandle; if ((rc = db.FindTableHandle(rmp.relName, pTableHandle))) return rc; SM_Attribute *pAttr; if ((rc = db.FindAttribute(rmp.relName, rmp.updAttr.attrName, pAttr))) return rc; if (rmp.rhsValue.type != pAttr->attrType && rmp.rhsValue.type != NOTYPE) { fprintf(stderr, "QL: Update attributes with different type!\n"); return QL_ERR_INVALID_COMMAND; } if (rmp.rhsValue.type == NOTYPE && pAttr->notNull) { fprintf(stderr, "QL: Update not-null attribute with NULL!\n"); return QL_ERR_INVALID_COMMAND; } if ((rc = FindRecords(rmp.relName, chosenRecords))) return rc; vector<RM_Record>::iterator pRecord; int recordSize = pTableHandle->header.recordSize; for (pRecord = chosenRecords.begin(); pRecord != chosenRecords.end(); pRecord++) { RID rid; if ((rc = pRecord->GetRid(rid))) return rc; char *data; if ((rc = pRecord->GetData(data))) return rc; int *pNullBitmap = (int *)(data + recordSize - sizeof(int)); // Check primary key uniqueness. SM_Attribute *attr = pAttr; if (attr->isPrimary && !attr->hasIndex) { RM_FileScan scan; if ((rc = scan.OpenScan(*pTableHandle, attr->attrType, attr->attrLength, attr->attrOffset, attr->number, EQ_OP, rmp.rhsValue.data))) return rc; RM_Record rec; if (scan.GetNextRec(rec) != RM_ERR_EOF) { fprintf(stderr, "QL: Primary key conflicts!\n"); scan.CloseScan(); return QL_PRIMARY_KEY; } if ((rc = scan.CloseScan())) return rc; } // Check foreign key existence. if (attr->isForeignKey) { RM_FileHandle *pForeign; if ((rc = db.FindTableHandle(attr->refTableName, pForeign))) return rc; SM_Attribute *foreignAttr; if ((rc = db.FindAttribute(attr->refTableName, attr->refAttrName, foreignAttr))) return rc; if (foreignAttr->attrType != attr->attrType) { fprintf(stderr, "QL: mismatch attribute type with foreign key.\n"); return rc; } RM_FileScan scan; if ((rc = scan.OpenScan(*pForeign, foreignAttr->attrType, foreignAttr->attrLength, foreignAttr->attrOffset, foreignAttr->number, EQ_OP, rmp.rhsValue.data))) return rc; RM_Record rec; if (scan.GetNextRec(rec) != 0) { fprintf(stderr, "QL: Foreign key does not exist!\n"); scan.CloseScan(); return QL_FOREIGN_KEY; } if ((rc = scan.CloseScan())) return rc; } Event event; event.type = UPDATE; event.record = new char[recordSize]; event.tableName = rmp.relName; event.attrName = rmp.updAttr.attrName; memcpy(event.record, data, recordSize); // If indexed, remove the old entry. IX_IndexHandle *pIndexHandle; if (pAttr->hasIndex) { if ((rc = db.FindIndexHandle(rmp.relName, pAttr->attrName, pIndexHandle))) { delete[] event.record; return rc; } if ((rc = pIndexHandle->DeleteEntry(data + pAttr->attrOffset, rid))) { delete[] event.record; return rc; } } map<RID, Event, RID_LessThan>::iterator pPrevEvent = transaction.find(rid); if (pPrevEvent == transaction.end()) { transaction.insert(pair<RID, Event>(rid, event)); } else { delete[] event.record; } // Modify the record. if (pAttr->attrType == INT || pAttr->attrType == FLOAT) { memcpy(data + pAttr->attrOffset, rmp.rhsValue.data, pAttr->attrLength); *pNullBitmap &= ~(1 << pAttr->number); } else if (pAttr->attrType == NOTYPE) { *pNullBitmap |= 1 << pAttr->number; } else { strncpy(data + pAttr->attrOffset, (const char *)rmp.rhsValue.data, pAttr->attrLength); *pNullBitmap &= ~(1 << pAttr->number); } // Update the record. if ((rc = pTableHandle->UpdateRec(*pRecord))) { delete[] event.record; return rc; } // If indexed, insert the new entry. if (pAttr->hasIndex) { if ((rc = pIndexHandle->InsertEntry(data + pAttr->attrOffset, rid))) { delete[] event.record; return rc; } } } return 0; }