| 246 | } |
| 247 | |
| 248 | void VerbAction::undo(thread_db* tdbb, jrd_tra* transaction, bool preserveLocks, VerbAction* preserveAction) |
| 249 | { |
| 250 | // Undo changes recorded for this verb action. |
| 251 | // After that, clear the verb action and prepare it for later reuse. |
| 252 | |
| 253 | record_param rpb; |
| 254 | rpb.rpb_relation = vct_relation; |
| 255 | rpb.rpb_number.setValue(BOF_NUMBER); |
| 256 | rpb.rpb_record = NULL; |
| 257 | rpb.getWindow(tdbb).win_flags = 0; |
| 258 | rpb.rpb_transaction_nr = transaction->tra_number; |
| 259 | |
| 260 | RecordBitmap::Accessor accessor(vct_records); |
| 261 | if (accessor.getFirst()) |
| 262 | { |
| 263 | do |
| 264 | { |
| 265 | rpb.rpb_number.setValue(accessor.current()); |
| 266 | |
| 267 | const bool have_undo = vct_undo && vct_undo->locate(rpb.rpb_number.getValue()); |
| 268 | |
| 269 | if (!DPM_get(tdbb, &rpb, LCK_read)) |
| 270 | BUGCHECK(186); // msg 186 record disappeared |
| 271 | |
| 272 | if ((have_undo || preserveLocks) && !(rpb.rpb_flags & rpb_deleted)) |
| 273 | VIO_data(tdbb, &rpb, transaction->tra_pool); |
| 274 | else |
| 275 | CCH_RELEASE(tdbb, &rpb.getWindow(tdbb)); |
| 276 | |
| 277 | if (rpb.rpb_transaction_nr != transaction->tra_number) |
| 278 | BUGCHECK(185); // msg 185 wrong record version |
| 279 | |
| 280 | if (!have_undo) |
| 281 | { |
| 282 | if (preserveLocks && rpb.rpb_b_page) |
| 283 | { |
| 284 | // Fetch previous record version and update in place current version with it |
| 285 | record_param temp = rpb; |
| 286 | temp.rpb_page = rpb.rpb_b_page; |
| 287 | temp.rpb_line = rpb.rpb_b_line; |
| 288 | temp.rpb_record = NULL; |
| 289 | |
| 290 | if (temp.rpb_flags & rpb_delta) |
| 291 | fb_assert(temp.rpb_prior != NULL); |
| 292 | else |
| 293 | fb_assert(temp.rpb_prior == NULL); |
| 294 | |
| 295 | if (!DPM_fetch(tdbb, &temp, LCK_read)) |
| 296 | BUGCHECK(291); // msg 291 cannot find record back version |
| 297 | |
| 298 | if (!(temp.rpb_flags & rpb_chained) || (temp.rpb_flags & (rpb_blob | rpb_fragment))) |
| 299 | ERR_bugcheck_msg("invalid back version"); |
| 300 | |
| 301 | VIO_data(tdbb, &temp, tdbb->getDefaultPool()); |
| 302 | |
| 303 | Record* const save_record = rpb.rpb_record; |
| 304 | if (rpb.rpb_flags & rpb_deleted) |
| 305 | rpb.rpb_record = NULL; |
no test coverage detected