8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 18:03:04 +01:00

Merge pull request #287 from red-soft-ru/B3_0_big_records_fix

Use rhd header for the last record fragment to fix wrong determination of the header size in get_header() function
This commit is contained in:
Vlad Khorsun 2021-10-21 16:28:33 +03:00 committed by GitHub
commit dd349828e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3647,11 +3647,15 @@ static void store_big_record(thread_db* tdbb,
RelationPages* relPages = rpb->rpb_relation->getPages(tdbb); RelationPages* relPages = rpb->rpb_relation->getPages(tdbb);
PageNumber prior(relPages->rel_pg_space_id, 0); PageNumber prior(relPages->rel_pg_space_id, 0);
signed char count = 0; signed char count = 0;
const USHORT max_data = dbb->dbb_page_size - (static_cast<USHORT>(sizeof(data_page)) + RHDF_SIZE);
// The last fragment should have rhd header because rhd_incomplete flag won't be set for it.
// It's important for get_header() function which relies on rhd_incomplete flag to determine header size.
FB_SIZE_T header_size = RHD_SIZE;
USHORT max_data = dbb->dbb_page_size - (static_cast<USHORT>(sizeof(data_page)) + header_size);
// Fill up data pages tail first until what's left fits on a single page. // Fill up data pages tail first until what's left fits on a single page.
while (size > max_data) do
{ {
// Allocate and format data page and fragment header // Allocate and format data page and fragment header
@ -3660,14 +3664,23 @@ static void store_big_record(thread_db* tdbb,
page->dpg_header.pag_flags = dpg_orphan | dpg_full; page->dpg_header.pag_flags = dpg_orphan | dpg_full;
page->dpg_relation = rpb->rpb_relation->rel_id; page->dpg_relation = rpb->rpb_relation->rel_id;
page->dpg_count = 1; page->dpg_count = 1;
// Cast to (rhdf*) but use only rhd fields for the last fragment
rhdf* header = (rhdf*) & page->dpg_rpt[1]; rhdf* header = (rhdf*) & page->dpg_rpt[1];
page->dpg_rpt[0].dpg_offset = (UCHAR *) header - (UCHAR *) page; page->dpg_rpt[0].dpg_offset = (UCHAR *) header - (UCHAR *) page;
page->dpg_rpt[0].dpg_length = max_data + RHDF_SIZE; page->dpg_rpt[0].dpg_length = max_data + header_size;
header->rhdf_flags = (prior.getPageNum()) ? rhd_fragment | rhd_incomplete : rhd_fragment; header->rhdf_flags = rhd_fragment;
header->rhdf_f_page = prior.getPageNum();
if (prior.getPageNum())
{
// This is not the last fragment
header->rhdf_flags |= rhd_incomplete;
header->rhdf_f_page = prior.getPageNum();
}
USHORT length = max_data; USHORT length = max_data;
size -= length; size -= length;
UCHAR* out = header->rhdf_data + length; UCHAR* out = (UCHAR *) header + page->dpg_rpt[0].dpg_length;
// Move compressed data onto page // Move compressed data onto page
@ -3722,7 +3735,11 @@ static void store_big_record(thread_db* tdbb,
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
prior = rpb->getWindow(tdbb).win_page; prior = rpb->getWindow(tdbb).win_page;
}
// Other fragments except the last one should have rhdf header
header_size = RHDF_SIZE;
max_data = dbb->dbb_page_size - (static_cast<USHORT>(sizeof(data_page)) + header_size);
} while (size > max_data);
// What's left fits on a page. Luckily, we don't have to store it ourselves. // What's left fits on a page. Luckily, we don't have to store it ourselves.