| /*------------------------------------------------------------------------- |
| * |
| * datumstreamblock.c |
| * |
| * Portions Copyright (c) 2011, EMC, Inc. |
| * Portions Copyright (c) 2012-Present VMware, Inc. or its affiliates. |
| * |
| * |
| * IDENTIFICATION |
| * src/backend/utils/datumstream/datumstreamblock.c |
| * |
| *------------------------------------------------------------------------- |
| */ |
| |
| #include "postgres.h" |
| #include "access/detoast.h" |
| #include "access/heaptoast.h" |
| #include "access/tupmacs.h" |
| #include "access/xlog.h" |
| #include "crypto/bufenc.h" |
| #include "utils/datumstreamblock.h" |
| #include "utils/guc.h" |
| |
| /* Forwards. */ |
| static char *VarlenaInfoToBuffer(char *buffer, uint8 * p); |
| |
| static void DatumStreamBlock_IntegrityCheckOrig( |
| uint8 * buffer, |
| int32 bufferSize, |
| bool minimalIntegrityChecks, |
| int32 expectedRowCount, |
| DatumStreamTypeInfo * typeInfo, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg); |
| |
| static void DatumStreamBlock_IntegrityCheckDense( |
| uint8 * buffer, |
| int32 bufferSize, |
| bool minimalIntegrityChecks, |
| int32 expectedRowCount, |
| DatumStreamTypeInfo * typeInfo, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg); |
| |
| /* Proper align with zero padding */ |
| static inline char * |
| att_align_zero(char *data, char alignchar) |
| { |
| size_t misalignment = (size_t)att_align_nominal(1, alignchar) - 1; |
| |
| while ((size_t)data & misalignment) |
| *(data++) = 0; |
| |
| return data; |
| } |
| |
| /* |
| * DatumStreamBlockRead. |
| */ |
| /* PERFORMANCE EXPERIMENT: Only do integrity and trace checking for DEBUG builds... */ |
| #ifdef USE_ASSERT_CHECKING |
| void |
| DatumStreamBlockRead_PrintVarlenaInfo( |
| DatumStreamBlockRead * dsr, |
| uint8 * p) |
| { |
| elog(LOG, "Read varlena <%s>", |
| VarlenaInfoToString(p)); |
| } |
| #endif |
| |
| int |
| errdetail_datumstreamblockread( |
| DatumStreamBlockRead * dsr) |
| { |
| dsr->errdetailCallback(dsr->errcontextArg); |
| |
| return 0; |
| } |
| |
| static int |
| errdetail_datumstreamblockread_callback( |
| void *arg) |
| { |
| DatumStreamBlockRead *dsr = (DatumStreamBlockRead *) arg; |
| |
| if (strncmp(dsr->eyecatcher, DatumStreamBlockRead_Eyecatcher, DatumStreamBlockRead_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockRead data structure not valid (eyecatcher)"); |
| |
| return errdetail_datumstreamblockread(dsr); |
| } |
| |
| int |
| errcontext_datumstreamblockread( |
| DatumStreamBlockRead * dsr) |
| { |
| dsr->errcontextCallback(dsr->errcontextArg); |
| |
| return 0; |
| } |
| |
| static int |
| errcontext_datumstreamblockread_callback( |
| void *arg) |
| { |
| DatumStreamBlockRead *dsr = (DatumStreamBlockRead *) arg; |
| |
| if (strncmp(dsr->eyecatcher, DatumStreamBlockRead_Eyecatcher, DatumStreamBlockRead_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockRead data structure not valid (eyecatcher)"); |
| |
| return errcontext_datumstreamblockread(dsr); |
| } |
| |
| void |
| DatumStreamBlockRead_ResetOrig(DatumStreamBlockRead * dsr) |
| { |
| /* |
| * PERFORMANCE EXPERIMENT: Only do integrity and trace checking for DEBUG |
| * builds... |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| if (strncmp(dsr->eyecatcher, DatumStreamBlockRead_Eyecatcher, DatumStreamBlockRead_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockRead data structure not valid (eyecatcher)"); |
| #endif |
| |
| /* |
| * Put before first entry. Caller will advance. |
| */ |
| dsr->nth = -1; |
| dsr->physical_datum_index = -1; |
| |
| /* |
| * Reset everything else. |
| */ |
| dsr->physical_datum_count = 0; |
| dsr->physical_data_size = 0; |
| dsr->logical_row_count = 0; |
| dsr->has_null = false; |
| |
| dsr->null_bitmap_beginp = NULL; |
| dsr->datum_beginp = NULL; |
| dsr->datum_afterp = NULL; |
| |
| dsr->buffer_beginp = NULL; |
| dsr->datump = NULL; |
| } |
| |
| void |
| DatumStreamBlockRead_GetReadyOrig( |
| DatumStreamBlockRead * dsr, |
| uint8 * buffer, |
| int32 bufferSize, |
| int64 firstRowNum, |
| int32 rowCount, |
| bool *hadToAdjustRowCount, |
| int32 * adjustedRowCount, |
| RelFileLocator *node) |
| { |
| uint8 *p; |
| |
| int32 unalignedHeaderSize; |
| int32 alignedHeaderSize; |
| bool minimalIntegrityChecks; |
| |
| DatumStreamBlock_Orig *blockOrig; |
| int32 minHeaderSize = sizeof(DatumStreamBlock_Orig); |
| |
| /* |
| * PERFORMANCE EXPERIMENT: Only do integrity and trace checking for DEBUG |
| * builds... |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| if (strncmp(dsr->eyecatcher, DatumStreamBlockRead_Eyecatcher, DatumStreamBlockRead_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockRead data structure not valid (eyecatcher)"); |
| #endif |
| |
| *hadToAdjustRowCount = false; |
| *adjustedRowCount = 0; |
| |
| #ifdef USE_ASSERT_CHECKING |
| minimalIntegrityChecks = false; |
| #else |
| minimalIntegrityChecks = true; |
| #endif |
| if (Debug_datumstream_block_read_check_integrity) |
| { |
| minimalIntegrityChecks = false; |
| } |
| |
| dsr->buffer_beginp = buffer; |
| |
| /* |
| * Read header information and setup for reading the datum in the block. |
| */ |
| |
| /* |
| * Advance pointer 'p' as we discover the contents of this block. |
| */ |
| p = dsr->buffer_beginp; |
| |
| if (bufferSize < minHeaderSize) |
| { |
| ereport(ERROR, |
| (errmsg("bad datum stream Original block header size"), |
| errdetail_internal("Found %d and expected the size to be at least %d.", |
| bufferSize, minHeaderSize), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| |
| blockOrig = (DatumStreamBlock_Orig *) p; |
| if (blockOrig->version != DatumStreamVersion_Original) |
| { |
| ereport(ERROR, |
| (errmsg("bad datum stream Original block version"), |
| errdetail_internal("Found %d and expected %d.", |
| blockOrig->version, |
| DatumStreamVersion_Original), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| |
| dsr->logical_row_count = blockOrig->ndatum; |
| |
| dsr->physical_datum_count = 0; |
| /* Not used for Original */ |
| dsr->physical_data_size = blockOrig->sz; |
| |
| p += sizeof(DatumStreamBlock_Orig); |
| |
| /* Set up acc */ |
| Assert(dsr->nth == -1); |
| Assert(dsr->physical_datum_index == -1); |
| |
| dsr->has_null = ((blockOrig->flags & DSB_HAS_NULLBITMAP) != 0); |
| if (dsr->has_null) |
| { |
| dsr->null_bitmap_beginp = p; |
| |
| DatumStreamBitMapRead_Init( |
| &dsr->null_bitmap, |
| dsr->null_bitmap_beginp, |
| dsr->logical_row_count); |
| /* |
| * The field nullsz byte length is MAXALIGN. |
| */ |
| p += blockOrig->nullsz; |
| } |
| |
| /* |
| * Pre-4.0 code did not enforce the following assertion. |
| * We identify this exception through firstRow, which is -1 |
| * for pre-4.0 blocks (not stored inside the block). |
| */ |
| Assert(dsr->logical_row_count == rowCount || firstRowNum == -1); |
| |
| /* |
| * In pre-4.0 blocks, the maximum value of ndatum is |
| * 32000 while rowCnt cannot exceed 16384, so we set |
| * rowCnt to ndatum to build the block directory |
| * consistently. |
| */ |
| if (dsr->logical_row_count > rowCount && firstRowNum == -1) |
| { |
| /* Adjust !!!! */ |
| *adjustedRowCount = dsr->logical_row_count; |
| *hadToAdjustRowCount = true; |
| } |
| |
| unalignedHeaderSize = (int32) (p - dsr->buffer_beginp); |
| alignedHeaderSize = MAXALIGN(unalignedHeaderSize); |
| |
| dsr->datum_beginp = dsr->buffer_beginp + alignedHeaderSize; |
| dsr->datum_afterp = dsr->datum_beginp + dsr->physical_data_size; |
| |
| /* |
| * PERFORMANCE EXPERIMENT: Only do integrity and trace checking for DEBUG |
| * builds... |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| if (Debug_appendonly_print_scan) |
| { |
| if (!dsr->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block read unpack Original with NO NULLs " |
| "(logical row count %d, physical data size = %d, " |
| "adjustedRowCount %d, row count adjusted %s, " |
| "unaligned header size %d, aligned header size %d, " |
| "datum begin %p, datum after %p)", |
| dsr->logical_row_count, |
| dsr->physical_data_size, |
| *adjustedRowCount, |
| (*hadToAdjustRowCount ? "true" : "false"), |
| unalignedHeaderSize, |
| alignedHeaderSize, |
| dsr->datum_beginp, |
| dsr->datum_afterp), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block read unpack Original with NULLs " |
| "(logical row count %d, physical data size = %d, " |
| "NULL bit-map MAXALIGN size %d, " |
| "adjustedRowCount %d, row count adjusted %s, " |
| "unaligned header size %d, aligned header size %d, " |
| "null begin %p, datum begin %p, datum after %p)", |
| dsr->logical_row_count, |
| dsr->physical_data_size, |
| blockOrig->nullsz, |
| *adjustedRowCount, |
| (*hadToAdjustRowCount ? "true" : "false"), |
| unalignedHeaderSize, |
| alignedHeaderSize, |
| dsr->null_bitmap_beginp, |
| dsr->datum_beginp, |
| dsr->datum_afterp), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| #endif |
| |
| dsr->datump = dsr->datum_beginp; |
| |
| if (FileEncryptionEnabled && blockOrig->encrypted) |
| { |
| DecryptAOBlock(dsr->datump, |
| dsr->physical_data_size, |
| node); |
| blockOrig->encrypted = 0; |
| } |
| |
| if (!minimalIntegrityChecks) |
| { |
| DatumStreamBlock_IntegrityCheckOrig( |
| buffer, |
| bufferSize, |
| minimalIntegrityChecks, |
| rowCount, |
| &dsr->typeInfo, |
| /* errdetailCallback */ errdetail_datumstreamblockread_callback, |
| /* errdetailArg */ (void *) dsr, |
| /* errcontextCallback */ errcontext_datumstreamblockread_callback, |
| /* errcontextArg */ (void *) dsr); |
| } |
| } |
| |
| void |
| DatumStreamBlockRead_Init( |
| DatumStreamBlockRead * dsr, |
| DatumStreamTypeInfo * typeInfo, |
| DatumStreamVersion datumStreamVersion, |
| bool rle_can_have_compression, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg) |
| { |
| memcpy(dsr->eyecatcher, DatumStreamBlockRead_Eyecatcher, DatumStreamBlockRead_EyecatcherLen); |
| |
| memcpy(&dsr->typeInfo, typeInfo, sizeof(DatumStreamTypeInfo)); |
| |
| dsr->datumStreamVersion = datumStreamVersion; |
| |
| dsr->rle_can_have_compression = rle_can_have_compression; |
| |
| dsr->errdetailCallback = errdetailCallback; |
| dsr->errcontextArg = errcontextArg; |
| dsr->errcontextCallback = errcontextCallback; |
| dsr->errcontextArg = errcontextArg; |
| |
| dsr->memctxt = CurrentMemoryContext; |
| |
| Assert(dsr->physical_data_size == 0); |
| |
| Assert(dsr->null_bitmap_beginp == NULL); |
| Assert(dsr->datum_beginp == NULL); |
| Assert(dsr->rle_compress_beginp == NULL); |
| Assert(dsr->rle_repeatcountsp == NULL); |
| |
| Assert(dsr->nth == 0); |
| Assert(dsr->physical_datum_index == 0); |
| Assert(dsr->physical_datum_count == 0); |
| |
| Assert(!dsr->has_null); |
| |
| Assert(dsr->datump == NULL); |
| |
| Assert(!dsr->rle_block_was_compressed); |
| |
| Assert(dsr->rle_repeatcounts_index == 0); |
| Assert(!dsr->rle_in_repeated_item); |
| Assert(dsr->rle_repeated_item_count == 0); |
| |
| Assert(dsr->delta_beginp == NULL); |
| Assert(dsr->delta_deltasp == NULL); |
| Assert(*(Datum *) &dsr->delta_datum_p == 0); |
| Assert(dsr->delta_bitmap_count == 0); |
| Assert(dsr->deltas_count == 0); |
| Assert(dsr->deltas_size == 0); |
| Assert(dsr->delta_block_was_compressed == false); |
| Assert(dsr->delta_item == false); |
| |
| } |
| |
| void |
| DatumStreamBlockRead_Finish( |
| DatumStreamBlockRead * dsr) |
| { |
| /* Place holder. */ |
| } |
| |
| /* |
| * Dense routines. |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| void |
| DatumStreamBlockRead_CheckDenseGetInvariant( |
| DatumStreamBlockRead * dsr) |
| { |
| int32 total_datum_index; |
| int32 currentDeltaBitMapOnCount; |
| |
| total_datum_index = dsr->physical_datum_index; |
| if (dsr->delta_block_was_compressed) |
| { |
| currentDeltaBitMapOnCount = DatumStreamBitMapRead_OnSeenCount(&dsr->delta_bitmap); |
| total_datum_index += currentDeltaBitMapOnCount; |
| } |
| else |
| { |
| currentDeltaBitMapOnCount = 0; |
| } |
| |
| if (!dsr->rle_block_was_compressed) |
| { |
| if (!dsr->has_null) |
| { |
| if (dsr->nth != total_datum_index) |
| { |
| ereport(ERROR, |
| (errmsg("nth position %d expected to match physical datum index %d + delta ON count %d when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(logical row count %d, physical datum count %d)", |
| dsr->nth, |
| dsr->physical_datum_index, |
| currentDeltaBitMapOnCount, |
| dsr->logical_row_count, |
| dsr->physical_datum_count), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| else |
| { |
| int32 currentNullOnCount; |
| int32 expectedNullOnCount; |
| |
| currentNullOnCount = DatumStreamBitMapRead_OnSeenCount(&dsr->null_bitmap); |
| |
| expectedNullOnCount = dsr->nth - total_datum_index; |
| |
| if (currentNullOnCount != expectedNullOnCount) |
| { |
| ereport(ERROR, |
| (errmsg("NULL bit-map ON count does not match when Dense block does not have RLE_TYPE compression"), |
| errdetail_internal("Found %d, expected %d.", |
| currentNullOnCount, |
| expectedNullOnCount), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| } |
| else |
| { |
| int32 currentCompressBitMapPosition; |
| int32 currentCompressBitMapOffCount; |
| |
| currentCompressBitMapPosition = DatumStreamBitMapRead_Position(&dsr->rle_compress_bitmap); |
| |
| if (currentCompressBitMapPosition != total_datum_index) |
| { |
| ereport(ERROR, |
| (errmsg("COMPRESS bit-map position %d expected to match physical datum index %d + delta ON count %d when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(logical row count %d, physical datum count %d)", |
| currentCompressBitMapPosition, |
| dsr->physical_datum_index, |
| currentDeltaBitMapOnCount, |
| dsr->logical_row_count, |
| dsr->physical_datum_count), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| |
| |
| currentCompressBitMapOffCount = currentCompressBitMapPosition + 1 - |
| DatumStreamBitMapRead_OnSeenCount(&dsr->rle_compress_bitmap); |
| |
| if (!dsr->has_null) |
| { |
| if (dsr->nth != currentCompressBitMapOffCount + dsr->rle_total_repeat_items_read - 1) |
| { |
| ereport(ERROR, |
| (errmsg("Nth position %d expected to match " |
| "current COMPRESS bit-map OFF count %d + total repeat items read %d - 1 " |
| "when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(logical row count %d, physical datum count %d)", |
| dsr->nth, |
| currentCompressBitMapOffCount, |
| dsr->rle_total_repeat_items_read, |
| dsr->logical_row_count, |
| dsr->physical_datum_count), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| else |
| { |
| int32 currentNullBitMapOnCount; |
| |
| currentNullBitMapOnCount = DatumStreamBitMapRead_OnSeenCount(&dsr->null_bitmap); |
| |
| if (dsr->nth != currentNullBitMapOnCount + currentCompressBitMapOffCount + dsr->rle_total_repeat_items_read - 1) |
| { |
| ereport(ERROR, |
| (errmsg("Nth position %d expected to match current NULL bit-map ON count %d + " |
| "current COMPRESS bit-map OFF count %d + total repeat items read %d - 1 " |
| "when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(logical row count %d, physical datum count %d)", |
| dsr->nth, |
| currentNullBitMapOnCount, |
| currentCompressBitMapOffCount, |
| dsr->rle_total_repeat_items_read, |
| dsr->logical_row_count, |
| dsr->physical_datum_count), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| } |
| |
| if (dsr->delta_block_was_compressed) |
| { |
| int32 currentDeltaBitMapPosition; |
| |
| currentDeltaBitMapPosition = DatumStreamBitMapRead_Position(&dsr->delta_bitmap); |
| if (currentDeltaBitMapPosition != total_datum_index) |
| { |
| ereport(ERROR, |
| (errmsg("DELTA bit-map position %d expected to match physical datum index %d + delta ON count %d " |
| "(logical row count %d, physical datum count %d)", |
| currentDeltaBitMapPosition, |
| dsr->physical_datum_index, |
| currentDeltaBitMapOnCount, |
| dsr->logical_row_count, |
| dsr->physical_datum_count), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| } |
| #endif |
| |
| void |
| DatumStreamBlockRead_ResetDense(DatumStreamBlockRead * dsr) |
| { |
| /* |
| * PERFORMANCE EXPERIMENT: Only do integrity and trace checking for DEBUG |
| * builds... |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| if (strncmp(dsr->eyecatcher, DatumStreamBlockRead_Eyecatcher, DatumStreamBlockRead_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockRead data structure not valid (eyecatcher)"); |
| #endif |
| |
| /* |
| * Put before first entry. Caller will advance. |
| */ |
| dsr->nth = -1; |
| dsr->physical_datum_index = -1; |
| |
| /* |
| * Reset everything else. |
| */ |
| dsr->physical_datum_count = 0; |
| dsr->physical_data_size = 0; |
| dsr->logical_row_count = 0; |
| dsr->has_null = false; |
| |
| dsr->null_bitmap_beginp = NULL; |
| dsr->datum_beginp = NULL; |
| dsr->datum_afterp = NULL; |
| dsr->rle_compress_beginp = NULL; |
| dsr->rle_repeatcountsp = NULL; |
| dsr->delta_beginp = NULL; |
| dsr->delta_deltasp = NULL; |
| *(Datum *) &dsr->delta_datum_p = 0; |
| |
| dsr->buffer_beginp = NULL; |
| dsr->datump = NULL; |
| |
| dsr->rle_block_was_compressed = false; |
| |
| dsr->rle_repeatcounts_index = 0; |
| dsr->rle_in_repeated_item = false; |
| dsr->rle_repeated_item_count = 0; |
| |
| dsr->rle_total_repeat_items_read = 0; |
| |
| dsr->delta_bitmap_count = 0; |
| dsr->deltas_count = 0; |
| dsr->deltas_size = 0; |
| |
| dsr->delta_block_was_compressed = false; |
| dsr->delta_item = false; |
| } |
| |
| void |
| DatumStreamBlockRead_GetReadyDense( |
| DatumStreamBlockRead * dsr, |
| uint8 * buffer, |
| int32 bufferSize, |
| int64 firstRowNum, |
| int32 rowCount, |
| bool *hadToAdjustRowCount, |
| int32 * adjustedRowCount, |
| RelFileLocator *node) |
| { |
| uint8 *p; |
| |
| int32 unalignedHeaderSize; |
| int32 alignedHeaderSize; |
| bool minimalIntegrityChecks; |
| |
| DatumStreamBlock_Dense *blockDense; |
| DatumStreamBlock_Rle_Extension *rleExtension; |
| DatumStreamBlock_Delta_Extension *deltaExtension; |
| |
| /* |
| * PERFORMANCE EXPERIMENT: Only do integrity and trace checking for DEBUG |
| * builds... |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| if (strncmp(dsr->eyecatcher, DatumStreamBlockRead_Eyecatcher, DatumStreamBlockRead_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockRead data structure not valid (eyecatcher)"); |
| #endif |
| |
| *hadToAdjustRowCount = false; |
| *adjustedRowCount = 0; |
| |
| #ifdef USE_ASSERT_CHECKING |
| minimalIntegrityChecks = false; |
| #else |
| minimalIntegrityChecks = true; |
| #endif |
| if (Debug_datumstream_block_read_check_integrity) |
| { |
| minimalIntegrityChecks = false; |
| } |
| |
| dsr->buffer_beginp = buffer; |
| |
| /* |
| * Read header information and setup for reading the datum in the block. |
| */ |
| |
| /* |
| * Advance pointer 'p' as we discover the contents of this block. |
| */ |
| p = dsr->buffer_beginp; |
| |
| Assert(p == buffer); |
| |
| blockDense = (DatumStreamBlock_Dense *) p; |
| |
| dsr->logical_row_count = blockDense->logical_row_count; |
| Assert(dsr->logical_row_count == rowCount); |
| |
| dsr->physical_datum_count = blockDense->physical_datum_count; |
| dsr->physical_data_size = blockDense->physical_data_size; |
| |
| p += sizeof(DatumStreamBlock_Dense); |
| |
| dsr->rle_block_was_compressed = ((blockDense->orig_4_bytes.flags & DSB_HAS_RLE_COMPRESSION) != 0); |
| if (dsr->rle_block_was_compressed) |
| { |
| rleExtension = (DatumStreamBlock_Rle_Extension *) p; |
| p += sizeof(DatumStreamBlock_Rle_Extension); |
| |
| dsr->rle_norepeats_null_bitmap_count = rleExtension->norepeats_null_bitmap_count; |
| dsr->rle_compress_bitmap_count = rleExtension->compress_bitmap_count; |
| dsr->rle_repeatcounts_count = rleExtension->repeatcounts_count; |
| dsr->rle_repeatcounts_size = rleExtension->repeatcounts_size; |
| } |
| else |
| { |
| rleExtension = NULL; |
| } |
| |
| /* Delta */ |
| dsr->delta_block_was_compressed = ((blockDense->orig_4_bytes.flags & DSB_HAS_DELTA_COMPRESSION) != 0); |
| if (dsr->delta_block_was_compressed) |
| { |
| deltaExtension = (DatumStreamBlock_Delta_Extension *) p; |
| p += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| dsr->delta_bitmap_count = deltaExtension->delta_bitmap_count; |
| dsr->deltas_count = deltaExtension->deltas_count; |
| dsr->deltas_size = deltaExtension->deltas_size; |
| } |
| else |
| { |
| deltaExtension = NULL; |
| } |
| |
| /* Set up acc */ |
| dsr->nth = -1; /* put it before first entry. Caller will |
| * advance */ |
| dsr->physical_datum_index = -1; |
| dsr->has_null = ((blockDense->orig_4_bytes.flags & DSB_HAS_NULLBITMAP) != 0); |
| |
| if (dsr->has_null) |
| { |
| dsr->null_bitmap_beginp = p; |
| |
| DatumStreamBitMapRead_Init( |
| &dsr->null_bitmap, |
| dsr->null_bitmap_beginp, |
| (!dsr->rle_block_was_compressed ? |
| dsr->logical_row_count : |
| dsr->rle_norepeats_null_bitmap_count)); |
| |
| p += DatumStreamBitMapRead_Size(&dsr->null_bitmap); |
| } |
| |
| unalignedHeaderSize = (int32) (p - dsr->buffer_beginp); |
| alignedHeaderSize = MAXALIGN(unalignedHeaderSize); |
| |
| /* |
| * Skip over alignment padding. |
| */ |
| dsr->datum_beginp = dsr->buffer_beginp + alignedHeaderSize; |
| dsr->datum_afterp = dsr->datum_beginp + dsr->physical_data_size; |
| |
| if (!dsr->rle_block_was_compressed) |
| { |
| /* |
| * PERFORMANCE EXPERIMENT: Only do integrity and trace checking for |
| * DEBUG builds... |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| if (Debug_appendonly_print_scan) |
| { |
| if (!dsr->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block read unpack Dense with NO NULLs " |
| "(logical row count %d, physical data size = %d, " |
| "unaligned header size %d, aligned header size %d, " |
| "datum begin %p, datum after %p)", |
| dsr->logical_row_count, |
| dsr->physical_data_size, |
| unalignedHeaderSize, |
| alignedHeaderSize, |
| dsr->datum_beginp, |
| dsr->datum_afterp), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream read unpack Dense block header for table with NULLs " |
| "(logical row count %d, physical data size = %d, NULL bit-map size %d, " |
| "unaligned header size %d, aligned header size %d, " |
| "null begin %p, datum begin %p, datum after %p)", |
| dsr->logical_row_count, |
| dsr->physical_data_size, |
| DatumStreamBitMapRead_Size(&dsr->null_bitmap), |
| unalignedHeaderSize, |
| alignedHeaderSize, |
| dsr->null_bitmap_beginp, |
| dsr->datum_beginp, |
| dsr->datum_afterp), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| #endif |
| } |
| else |
| { |
| /* |
| * RLE_TYPE compression was used for this block. |
| */ |
| dsr->rle_compress_beginp = p; |
| |
| DatumStreamBitMapRead_Init( |
| &dsr->rle_compress_bitmap, |
| dsr->rle_compress_beginp, |
| dsr->rle_compress_bitmap_count); |
| |
| p += DatumStreamBitMapRead_Size(&dsr->rle_compress_bitmap); |
| |
| /* |
| * Start our decompression of repeat counts at beginning. |
| */ |
| dsr->rle_repeatcountsp = p; |
| |
| p += dsr->rle_repeatcounts_size; |
| |
| dsr->rle_repeatcounts_index = -1; |
| dsr->rle_repeated_item_count = 0; |
| dsr->rle_in_repeated_item = false; |
| |
| unalignedHeaderSize = p - dsr->buffer_beginp; |
| alignedHeaderSize = MAXALIGN(unalignedHeaderSize); |
| |
| /* |
| * Skip over alignment padding. |
| */ |
| dsr->datum_beginp = dsr->buffer_beginp + alignedHeaderSize; |
| dsr->datum_afterp = dsr->datum_beginp + dsr->physical_data_size; |
| |
| /* |
| * PERFORMANCE EXPERIMENT: Only do integrity and trace checking for |
| * DEBUG builds... |
| */ |
| #ifdef USE_ASSERT_CHECKING |
| if (Debug_appendonly_print_scan) |
| { |
| if (!dsr->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block read unpack Dense with NO NULLs and RLE_TYPE compression " |
| "(logical row count %d, physical data size = %d, " |
| "compress bit-map count %d, compress bit-map size %d, " |
| "repeat counts count %d, repeat counts size %d, " |
| "unaligned header size %d, aligned header size %d, " |
| "datum begin %p, datum after %p)", |
| dsr->logical_row_count, |
| dsr->physical_data_size, |
| DatumStreamBitMapRead_Count(&dsr->rle_compress_bitmap), |
| DatumStreamBitMapRead_Size(&dsr->rle_compress_bitmap), |
| dsr->rle_repeatcounts_count, |
| dsr->rle_repeatcounts_size, |
| unalignedHeaderSize, |
| alignedHeaderSize, |
| dsr->datum_beginp, |
| dsr->datum_afterp), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block read unpack Dense with NULLs and RLE_TYPE compression " |
| "(logical row count %d, physical data size = %d, " |
| "norepeats NULL bit-map count %d, norepeats NULL bit-map size %d, " |
| "compress bit-map count %d, compress bit-map size %d, " |
| "repeat counts count %d, repeat counts size %d, " |
| "unaligned header size %d, aligned header size %d, " |
| "null begin %p, datum begin %p, datum after %p)", |
| dsr->logical_row_count, |
| dsr->physical_data_size, |
| DatumStreamBitMapRead_Count(&dsr->null_bitmap), |
| DatumStreamBitMapRead_Size(&dsr->null_bitmap), |
| DatumStreamBitMapRead_Count(&dsr->rle_compress_bitmap), |
| DatumStreamBitMapRead_Size(&dsr->rle_compress_bitmap), |
| dsr->rle_repeatcounts_count, |
| dsr->rle_repeatcounts_size, |
| unalignedHeaderSize, |
| alignedHeaderSize, |
| dsr->null_bitmap_beginp, |
| dsr->datum_beginp, |
| dsr->datum_afterp), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| #endif |
| } |
| |
| if (dsr->delta_block_was_compressed) |
| { |
| /* |
| * Delta compression was used for this block. |
| */ |
| dsr->delta_beginp = p; |
| |
| DatumStreamBitMapRead_Init( |
| &dsr->delta_bitmap, |
| dsr->delta_beginp, |
| dsr->delta_bitmap_count); |
| |
| p += DatumStreamBitMapRead_Size(&dsr->delta_bitmap); |
| |
| /* |
| * Start our decompression of deltas at beginning. |
| */ |
| dsr->delta_deltasp = p; |
| p += dsr->deltas_size; |
| unalignedHeaderSize = p - dsr->buffer_beginp; |
| alignedHeaderSize = MAXALIGN(unalignedHeaderSize); |
| |
| /* |
| * Skip over alignment padding. |
| */ |
| dsr->datum_beginp = dsr->buffer_beginp + alignedHeaderSize; |
| dsr->datum_afterp = dsr->datum_beginp + dsr->physical_data_size; |
| |
| if (Debug_appendonly_print_scan) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block read unpack Dense with NULLs and DELTA compression " |
| "(logical row count %d, physical data size = %d, " |
| "has_nul %s, norepeats NULL bit-map count %d, norepeats NULL bit-map size %d, " |
| "delta bit-map count %d, delta bit-map size %d, " |
| "deltas count %d, deltas size %d, " |
| "unaligned header size %d, aligned header size %d, " |
| "null begin %p, datum begin %p, datum after %p)", |
| dsr->logical_row_count, |
| dsr->physical_data_size, |
| dsr->has_null ? "TRUE" : "FALSE", |
| dsr->has_null ? DatumStreamBitMapRead_Count(&dsr->null_bitmap) : 0, |
| dsr->has_null ? DatumStreamBitMapRead_Size(&dsr->null_bitmap) : 0, |
| DatumStreamBitMapRead_Count(&dsr->delta_bitmap), |
| DatumStreamBitMapRead_Size(&dsr->delta_bitmap), |
| dsr->deltas_count, |
| dsr->deltas_size, |
| unalignedHeaderSize, |
| alignedHeaderSize, |
| dsr->null_bitmap_beginp, |
| dsr->datum_beginp, |
| dsr->datum_afterp), |
| errdetail_datumstreamblockread(dsr), |
| errcontext_datumstreamblockread(dsr))); |
| } |
| } |
| dsr->datump = dsr->datum_beginp; |
| if (FileEncryptionEnabled && (blockDense->orig_4_bytes.flags & DSB_HAS_ENCRYPTION) != 0) |
| { |
| DecryptAOBlock(dsr->datump, |
| dsr->physical_data_size, |
| node); |
| |
| /* reset the flag, mark the block has been decrypted */ |
| blockDense->orig_4_bytes.flags = blockDense->orig_4_bytes.flags & ~ DSB_HAS_ENCRYPTION; |
| } |
| |
| DatumStreamBlock_IntegrityCheckDense( |
| buffer, |
| bufferSize, |
| minimalIntegrityChecks, |
| rowCount, |
| &dsr->typeInfo, |
| /* errdetailCallback */ errdetail_datumstreamblockread_callback, |
| /* errdetailArg */ (void *) dsr, |
| /* errcontextCallback */ errcontext_datumstreamblockread_callback, |
| /* errcontextArg */ (void *) dsr); |
| } |
| |
| static int |
| errdetail_datumstreamblockwrite( |
| DatumStreamBlockWrite * dsw) |
| { |
| dsw->errdetailCallback(dsw->errcontextArg); |
| |
| return 0; |
| } |
| |
| static int |
| errdetail_datumstreamblockwrite_callback( |
| void *arg) |
| { |
| DatumStreamBlockWrite *dsw = (DatumStreamBlockWrite *) arg; |
| |
| if (strncmp(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockWrite data structure not valid (eyecatcher)"); |
| |
| return errdetail_datumstreamblockwrite(dsw); |
| } |
| |
| static int |
| errcontext_datumstreamblockwrite( |
| DatumStreamBlockWrite * dsw) |
| { |
| dsw->errcontextCallback(dsw->errcontextArg); |
| |
| return 0; |
| } |
| |
| static int |
| errcontext_datumstreamblockwrite_callback( |
| void *arg) |
| { |
| DatumStreamBlockWrite *dsw = (DatumStreamBlockWrite *) arg; |
| |
| if (strncmp(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockWrite data structure not valid (eyecatcher)"); |
| |
| return errcontext_datumstreamblockwrite(dsw); |
| } |
| |
| #ifdef USE_ASSERT_CHECKING |
| /* |
| * DatumStreamBlockWrite routines. |
| */ |
| static void |
| DatumStreamBlockWrite_CheckDenseInvariant( |
| DatumStreamBlockWrite * dsw) |
| { |
| int32 total_datum_count = 0; |
| |
| int32 currentCompressBitMapPosition = 0; |
| int32 currentCompressBitMapCount = 0; |
| int32 currentCompressBitMapOffCount = 0; |
| |
| int32 currentDeltaBitMapPosition = 0; |
| int32 currentDeltaBitMapCount = 0; |
| int32 currentDeltaBitMapOffCount = 0; |
| int32 currentDeltaBitMapOnCount = 0; |
| |
| if (dsw->delta_has_compression) |
| { |
| currentDeltaBitMapPosition = DatumStreamBitMapWrite_Count(&dsw->delta_bitmap) - 1; |
| currentDeltaBitMapCount = DatumStreamBitMapWrite_Count(&dsw->delta_bitmap); |
| currentDeltaBitMapOffCount = |
| currentDeltaBitMapCount |
| - DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap); |
| currentDeltaBitMapOnCount = DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap); |
| } |
| |
| total_datum_count = dsw->physical_datum_count + currentDeltaBitMapOnCount; |
| |
| if (!dsw->rle_has_compression) |
| { |
| if (!dsw->has_null) |
| { |
| if (dsw->nth != total_datum_count) |
| { |
| ereport(ERROR, |
| (errmsg("Nth position %d expected to match physical datum count %d + DELTA On count %d when Dense block does not have RLE_TYPE compression and does not have NULLs", |
| dsw->nth, |
| dsw->physical_datum_count, |
| currentDeltaBitMapOnCount), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| else |
| { |
| int32 currentNullOnCount; |
| int32 expectedNullOnCount; |
| |
| currentNullOnCount = DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap); |
| |
| expectedNullOnCount = dsw->nth - total_datum_count; |
| |
| if (currentNullOnCount != expectedNullOnCount) |
| { |
| ereport(ERROR, |
| (errmsg("NULL bit-map ON count does not match when Dense block does not have RLE_TYPE compression. Found %d, expected %d", |
| currentNullOnCount, |
| expectedNullOnCount), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| |
| if (dsw->rle_has_compression) |
| { |
| currentCompressBitMapPosition = DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap) - 1; |
| currentCompressBitMapCount = DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap); |
| currentCompressBitMapOffCount = currentCompressBitMapCount - |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap); |
| |
| if (currentCompressBitMapPosition != (dsw->physical_datum_count - 1) + currentDeltaBitMapOnCount) |
| { |
| ereport(ERROR, |
| (errmsg("COMPRESS bit-map position %d expected to match physical datum count %d - 1 when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(Nth %d)", |
| currentCompressBitMapPosition, |
| dsw->physical_datum_count, |
| dsw->nth), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| if (!dsw->has_null) |
| { |
| if (dsw->nth != currentCompressBitMapOffCount + dsw->rle_total_repeat_items_written) |
| { |
| ereport(ERROR, |
| (errmsg("Nth position %d expected to match " |
| "current COMPRESS bit-map OFF count %d + total repeat items written %d " |
| "when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(physical datum count %d)", |
| dsw->nth, |
| currentCompressBitMapOffCount, |
| dsw->rle_total_repeat_items_written, |
| dsw->physical_datum_count), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| else |
| { |
| int32 currentNullBitMapOnCount; |
| |
| int32 currentNullBitMapCount; |
| |
| currentNullBitMapOnCount = DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap); |
| |
| if (dsw->nth != currentNullBitMapOnCount + currentCompressBitMapOffCount + dsw->rle_total_repeat_items_written) |
| { |
| ereport(ERROR, |
| (errmsg("Nth position %d expected to match current NULL bit-map ON count %d + " |
| "current COMPRESS bit-map OFF count %d + total repeat items written %d " |
| "when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(physical datum count %d)", |
| dsw->nth, |
| currentNullBitMapOnCount, |
| currentCompressBitMapOffCount, |
| dsw->rle_total_repeat_items_written, |
| dsw->physical_datum_count), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| currentNullBitMapCount = DatumStreamBitMapWrite_Count(&dsw->null_bitmap); |
| if (currentNullBitMapCount != currentNullBitMapOnCount + currentCompressBitMapCount) |
| { |
| ereport(ERROR, |
| (errmsg("Current NULL bit-map count %d expected to match current NULL bit-map ON count %d + " |
| "current COMPRESS bit-map count %d " |
| "when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(total repeat items written %d, physical datum count %d)", |
| currentNullBitMapCount, |
| currentNullBitMapOnCount, |
| currentCompressBitMapCount, |
| dsw->rle_total_repeat_items_written, |
| dsw->physical_datum_count), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| |
| if (dsw->delta_has_compression) |
| { |
| if (currentDeltaBitMapPosition != (dsw->physical_datum_count - 1) + currentDeltaBitMapOnCount) |
| { |
| ereport(ERROR, |
| (errmsg("DELTA bit-map position %d expected to match physical datum count %d - 1 + %d DELTA On " |
| "count, when Dense block does not have RLE_TYPE compression and does not have NULLs " |
| "(Nth %d)", |
| currentDeltaBitMapPosition, |
| dsw->physical_datum_count, |
| currentDeltaBitMapOnCount, |
| dsw->nth), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| if (dsw->rle_has_compression) |
| { |
| if (currentDeltaBitMapCount != currentCompressBitMapCount) |
| { |
| ereport(ERROR, |
| (errmsg("Current DELTA bit-map count %d expected to match current COMPRESS bit-map count %d " |
| "(total repeat items written %d, physical datum count %d)", |
| currentDeltaBitMapCount, |
| currentCompressBitMapCount, |
| dsw->rle_total_repeat_items_written, |
| dsw->physical_datum_count), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| } |
| #endif |
| |
| static void |
| DatumStreamBlockWrite_PrintInputVarlenaInfo( |
| DatumStreamBlockWrite * dsw, |
| Datum originalDatum, |
| bool wasExtended) |
| { |
| uint8 *p; |
| |
| p = (uint8 *) DatumGetPointer(originalDatum); |
| |
| ereport(LOG, |
| (errmsg("Write input varlena input <%s> (nth %d, was extended %s)", |
| VarlenaInfoToString(p), |
| dsw->nth, |
| (wasExtended ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| static void |
| DatumStreamBlockWrite_PrintStoredSmallVarlenaInfo( |
| DatumStreamBlockWrite * dsw, |
| uint8 * outputBuffer) |
| { |
| uint8 *p; |
| |
| p = outputBuffer; |
| |
| ereport(LOG, |
| (errmsg("Write stored small varlena: <%s> (nth %d)", |
| VarlenaInfoToString(p), |
| dsw->nth), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| static void |
| DatumStreamBlockWrite_PutFixedLengthTrace( |
| DatumStreamBlockWrite * dsw, |
| uint8 * item_beginp) |
| { |
| if (!dsw->typeInfo->byval) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write Original fixed-length non-byval item " |
| "(nth %d, physical item index #%d, item size %d, item begin %p, item offset " INT64_FORMAT ", next item begin %p)", |
| dsw->nth, |
| dsw->physical_datum_count - 1, |
| dsw->typeInfo->datumlen, |
| item_beginp, |
| (int64) (item_beginp - dsw->datum_buffer), |
| dsw->datump), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| Datum readDatum; |
| |
| switch (dsw->typeInfo->datumlen) |
| { |
| case 1: |
| readDatum = *(uint8 *) item_beginp; |
| break; |
| case 2: |
| readDatum = *(uint16 *) item_beginp; |
| break; |
| case 4: |
| readDatum = *(uint32 *) item_beginp; |
| break; |
| case 8: |
| readDatum = *(Datum *) item_beginp; |
| break; |
| default: |
| ereport(FATAL, |
| (errmsg("fixed length type has unexpected length %d", |
| dsw->typeInfo->datumlen), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| readDatum = 0; |
| break; |
| /* Never reaches here. */ |
| } |
| |
| ereport(LOG, |
| (errmsg("Datum stream block write Original fixed-length item " |
| "(nth %d, physical item index #%d, item size %d, item begin %p, item offset " INT64_FORMAT ", next item begin %p, integer " INT64_FORMAT ")", |
| dsw->nth, |
| dsw->physical_datum_count - 1, |
| dsw->typeInfo->datumlen, |
| item_beginp, |
| (int64) (item_beginp - dsw->datum_buffer), |
| dsw->datump, |
| (int64) readDatum), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| |
| static void |
| DatumStreamBlockWrite_PutFixedLength( |
| DatumStreamBlockWrite * dsw, |
| Datum d) |
| { |
| if (!dsw->typeInfo->byval) |
| { |
| memcpy(dsw->datump, DatumGetPointer(d), dsw->typeInfo->datumlen); |
| dsw->datump += dsw->typeInfo->datumlen; |
| } |
| else |
| { |
| switch (dsw->typeInfo->datumlen) |
| { |
| case 1: |
| *(dsw->datump) = DatumGetChar(d); |
| ++dsw->datump; |
| break; |
| case 2: |
| Assert(IsAligned(dsw->datump, 2)); |
| *(uint16 *) (dsw->datump) = DatumGetUInt16(d); |
| dsw->datump += 2; |
| break; |
| case 4: |
| Assert(IsAligned(dsw->datump, 4)); |
| *(uint32 *) (dsw->datump) = DatumGetUInt32(d); |
| dsw->datump += 4; |
| break; |
| case 8: |
| Assert(IsAligned(dsw->datump, 8) || IsAligned(dsw->datump, 4)); |
| *(Datum *) (dsw->datump) = d; |
| dsw->datump += 8; |
| break; |
| default: |
| ereport(FATAL, |
| (errmsg("fixed length type has unexpected length %d", |
| dsw->typeInfo->datumlen), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| break; |
| } |
| } |
| } |
| |
| static void |
| DatumStreamBlockWrite_MakeNullBitMapSpace( |
| DatumStreamBlockWrite * dsw) |
| { |
| int32 newNullBitMapSize; |
| |
| if (!dsw->has_null) |
| { |
| newNullBitMapSize = DatumStreamBitMap_Size(dsw->always_null_bitmap_count + 1); |
| } |
| else |
| { |
| #ifdef USE_ASSERT_CHECKING |
| if (DatumStreamBitMapWrite_Count(&dsw->null_bitmap) != dsw->always_null_bitmap_count) |
| { |
| pg_usleep(120 * 1000000L); |
| ereport(ERROR, |
| (errmsg("Datum stream write %s block problem growing NULL bit-map buffer " |
| "(current logical row count %d, physical datum count %d, " |
| "null bit-map count %d, old NULL bit-map count %d)", |
| DatumStreamVersion_String(dsw->datumStreamVersion), |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| dsw->always_null_bitmap_count), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| #endif |
| newNullBitMapSize = DatumStreamBitMapWrite_NextSize(&dsw->null_bitmap); |
| } |
| |
| /* |
| * Buffer big enough? |
| */ |
| if (newNullBitMapSize > dsw->null_bitmap_buffer_size) |
| { |
| int32 newBufferSize; |
| void *newBuffer; |
| MemoryContext oldCtxt; |
| |
| /* |
| * Grow the NULL bit-map. |
| */ |
| newBufferSize = dsw->null_bitmap_buffer_size * 2; |
| if (newBufferSize < newNullBitMapSize) |
| { |
| newBufferSize = newNullBitMapSize + dsw->initialMaxDatumPerBlock; |
| } |
| |
| oldCtxt = MemoryContextSwitchTo(dsw->memctxt); |
| newBuffer = palloc(newBufferSize); |
| |
| DatumStreamBitMapWrite_CopyToLargerBuffer( |
| &dsw->null_bitmap, |
| newBuffer, |
| newBufferSize); |
| pfree(dsw->null_bitmap_buffer); |
| MemoryContextSwitchTo(oldCtxt); |
| |
| dsw->null_bitmap_buffer = newBuffer; |
| dsw->null_bitmap_buffer_size = newBufferSize; |
| |
| /* |
| * Trace the growth of the NULL bit-map buffer. |
| */ |
| if (Debug_appendonly_print_insert) |
| { |
| if (!dsw->rle_has_compression) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write %s block grew NULL bit-map buffer " |
| "(current logical row count %d, physical datum count %d, " |
| "null bit-map count %d, null bit-map ON count %d, null bit-map size %d, null bit-map max size %d)", |
| DatumStreamVersion_String(dsw->datumStreamVersion), |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->null_bitmap)), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write %s block formatted RLE_TYPE block grew NULL bit-map buffer " |
| "(current logical row count %d, physical datum count %d, " |
| "null bit-map count %d, null bit-map ON count %d, null bit-map size %d, null bit-map max size %d, " |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, " |
| "repeat counts count %d, repeat count size %d)", |
| DatumStreamVersion_String(dsw->datumStreamVersion), |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| |
| if (!dsw->has_null) |
| { |
| /* |
| * First NULL. Zero fill the NULL bit-map out and set position. |
| */ |
| dsw->has_null = true; |
| DatumStreamBitMapWrite_ZeroFill(&dsw->null_bitmap, /* bitIndex */ dsw->always_null_bitmap_count); |
| |
| /* |
| * Trace the zero fill out of the NULL bit-map buffer. |
| */ |
| if (Debug_appendonly_print_insert) |
| { |
| if (!dsw->rle_has_compression) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write %s block zero fill out NULL bit-map " |
| "(current logical row count %d, old NULL bit-map count %d, physical datum count %d, " |
| "null bit-map count %d, null bit-map ON count %d, null bit-map size %d)", |
| DatumStreamVersion_String(dsw->datumStreamVersion), |
| dsw->nth + 1, |
| dsw->always_null_bitmap_count, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap)), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write %s block formatted RLE_TYPE block zero fill out NULL bit-map " |
| "(current logical row count %d, old NULL bit-map count %d, physical datum count %d, " |
| "null bit-map count %d, null bit-map size %d, " |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, " |
| "repeat counts count %d, repeat count size %d)", |
| DatumStreamVersion_String(dsw->datumStreamVersion), |
| dsw->nth + 1, |
| dsw->always_null_bitmap_count, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| else |
| { |
| Assert(dsw->nth > 0); |
| Assert(DatumStreamBitMapWrite_Count(&dsw->null_bitmap) == dsw->always_null_bitmap_count); |
| } |
| |
| } |
| |
| static bool |
| DatumStreamBlockWrite_OrigHasSpace( |
| DatumStreamBlockWrite * dsw, |
| bool null, |
| int32 sz) |
| { |
| int32 headerSize; |
| int32 nullSize; |
| int32 currentDataSize; |
| |
| int32 newTotalSize; |
| |
| bool result; |
| |
| if (dsw->nth + 1 >= dsw->maxDatumPerBlock) |
| return false; |
| |
| headerSize = sizeof(DatumStreamBlock_Orig); |
| if (null || dsw->has_null) |
| { |
| nullSize = MAXALIGN(DatumStreamBitMap_Size(dsw->always_null_bitmap_count + 1)); |
| } |
| else |
| { |
| nullSize = 0; |
| } |
| |
| currentDataSize = (dsw->datump - dsw->datum_buffer); |
| |
| newTotalSize = (headerSize + nullSize + currentDataSize + sz); |
| result = (newTotalSize < dsw->maxDataBlockSize); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write checking Original new item space for " |
| "(nth %d, item size %d, configured datum length %d, item begin %p, item offset " INT64_FORMAT ", physical datum count %d, " |
| "headerSize %d, nullSize %d, current dataSize %d, " |
| "new total size %d, " |
| "maxdatasz %d, " |
| "result %s)", |
| dsw->nth, |
| sz, |
| dsw->typeInfo->datumlen, |
| dsw->datump, |
| (int64) (dsw->datump - dsw->datum_buffer), |
| dsw->physical_datum_count, |
| headerSize, |
| nullSize, |
| currentDataSize, |
| newTotalSize, |
| dsw->maxDataBlockSize, |
| (result ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| return result; |
| } |
| |
| static int |
| DatumStreamBlockWrite_PutOrig( |
| DatumStreamBlockWrite * dsw, |
| Datum d, |
| bool null, |
| void **toFree) |
| { |
| uint8 *item_beginp; |
| |
| Assert(dsw); |
| Assert(dsw->maxDataBlockSize > 0); |
| *toFree = NULL; |
| |
| if (null) |
| { |
| if (!DatumStreamBlockWrite_OrigHasSpace(dsw, null, 0)) |
| { |
| /* |
| * Too many items, or not enough room to add a NULL bit-map data. |
| */ |
| return -1; |
| } |
| |
| DatumStreamBlockWrite_MakeNullBitMapSpace(dsw); |
| |
| DatumStreamBitMapWrite_AddBit(&dsw->null_bitmap, /* on */ true); |
| |
| dsw->always_null_bitmap_count++; |
| dsw->nth++; |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write Original NULL " |
| "(nth %d)", |
| dsw->nth), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| return 0; |
| } |
| |
| /* |
| * Not a NULL. We have an item to add. |
| */ |
| if (dsw->typeInfo->datumlen < 0) |
| { |
| /* Variable length. */ |
| uint8 *dataStart; |
| int32 dataLen; |
| |
| int32 sz = 0; |
| char *p = NULL; |
| char c1 = 0; |
| int32 wsz = 0; |
| Datum originalDatum; |
| bool wasExtended = false; |
| |
| originalDatum = d; |
| |
| /* |
| * If toFree comes back non-NULL, we have created a palloc'd de-toasted and/or |
| * de-compressed varlena copy. |
| */ |
| if (dsw->typeInfo->datumlen == -1) |
| { |
| varattrib_untoast_ptr_len(d, (char **) &dataStart, |
| &dataLen, |
| toFree); |
| if (*toFree != NULL) |
| { |
| d = PointerGetDatum(*toFree); |
| wasExtended = true; |
| } |
| else |
| { |
| wasExtended = false; |
| } |
| } |
| |
| if (Debug_datumstream_write_print_small_varlena_info) |
| { |
| DatumStreamBlockWrite_PrintInputVarlenaInfo( |
| dsw, |
| originalDatum, |
| wasExtended); |
| } |
| |
| if (dsw->typeInfo->datumlen == -2) |
| { |
| sz = strlen(DatumGetCString(d)) + 1; |
| p = DatumGetPointer(d); |
| wsz = sz; |
| } |
| else if (VARATT_IS_SHORT(DatumGetPointer(d))) |
| { |
| sz = VARSIZE_SHORT(DatumGetPointer(d)); |
| p = DatumGetPointer(d); |
| wsz = sz; |
| } |
| else if (dsw->typeInfo->typstorage != 'p' && |
| VARATT_CAN_MAKE_SHORT(DatumGetPointer(d))) |
| { |
| sz = VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(d)); |
| c1 = VARSIZE_TO_SHORT_D(d); |
| p = VARDATA(DatumGetPointer(d)); |
| wsz = sz - 1; |
| } |
| else |
| { |
| sz = VARSIZE(DatumGetPointer(d)); |
| dsw->datump = (uint8 *) att_align_zero((char *) dsw->datump, dsw->typeInfo->align); |
| p = DatumGetPointer(d); |
| wsz = sz; |
| } |
| |
| if (!DatumStreamBlockWrite_OrigHasSpace(dsw, /* null */ false, sz)) |
| return -sz; |
| |
| /* |
| * Set item begin pointer after we have done zero padding. |
| */ |
| item_beginp = dsw->datump; |
| |
| if (c1 != 0) |
| { |
| *(dsw->datump) = (uint8) c1; |
| dsw->datump += 1; |
| } |
| |
| memcpy(dsw->datump, p, wsz); |
| |
| if (Debug_datumstream_write_print_small_varlena_info) |
| { |
| DatumStreamBlockWrite_PrintStoredSmallVarlenaInfo( |
| dsw, |
| item_beginp); |
| } |
| |
| dsw->datump += wsz; |
| |
| if (dsw->has_null) |
| { |
| DatumStreamBlockWrite_MakeNullBitMapSpace(dsw); |
| DatumStreamBitMapWrite_AddBit(&dsw->null_bitmap, /* on */ false); |
| } |
| |
| dsw->always_null_bitmap_count++; |
| dsw->nth++; |
| Assert(dsw->nth <= dsw->maxDatumPerBlock); |
| |
| ++dsw->physical_datum_count; |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write Original variable-length item " |
| "(nth %d, physical item index #%d, item size %d, item begin %p, item offset " INT64_FORMAT ", next item begin %p, datum buffer after %p)", |
| dsw->nth, |
| dsw->physical_datum_count - 1, |
| sz, |
| item_beginp, |
| (int64) (item_beginp - dsw->datum_buffer), |
| dsw->datump, |
| dsw->datum_afterp), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| return sz; |
| } |
| |
| /* Fixed length. */ |
| |
| item_beginp = dsw->datump; |
| |
| if (!DatumStreamBlockWrite_OrigHasSpace(dsw, /* null */ false, dsw->typeInfo->datumlen)) |
| { |
| return -dsw->typeInfo->datumlen; |
| } |
| |
| DatumStreamBlockWrite_PutFixedLength(dsw, d); |
| |
| if (dsw->has_null) |
| { |
| DatumStreamBlockWrite_MakeNullBitMapSpace(dsw); |
| |
| DatumStreamBitMapWrite_AddBit(&dsw->null_bitmap, /* on */ false); |
| } |
| |
| dsw->always_null_bitmap_count++; |
| dsw->nth++; |
| Assert(dsw->nth <= dsw->maxDatumPerBlock); |
| |
| ++dsw->physical_datum_count; |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| DatumStreamBlockWrite_PutFixedLengthTrace(dsw, item_beginp); |
| } |
| |
| return dsw->typeInfo->datumlen; |
| } |
| |
| static void |
| DatumStreamBlockWrite_MakeCompressBitMapSpace( |
| DatumStreamBlockWrite * dsw) |
| { |
| int32 newCompressBitMapSize; |
| |
| Assert(dsw->physical_datum_count >= 1); |
| |
| int32 deltaBitMapOnCount = 0; |
| |
| if (dsw->delta_has_compression) |
| { |
| deltaBitMapOnCount = DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap); |
| } |
| |
| if (!dsw->rle_has_compression) |
| { |
| newCompressBitMapSize = DatumStreamBitMap_Size(dsw->physical_datum_count + deltaBitMapOnCount); |
| } |
| else |
| { |
| Assert(DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap) == |
| (dsw->physical_datum_count + deltaBitMapOnCount)); |
| newCompressBitMapSize = DatumStreamBitMapWrite_NextSize(&dsw->rle_compress_bitmap); |
| } |
| |
| /* |
| * Buffer big enough? |
| */ |
| if (newCompressBitMapSize > dsw->rle_compress_bitmap_buffer_size) |
| { |
| int32 newBufferSize; |
| void *newBuffer; |
| MemoryContext oldCtxt; |
| |
| /* |
| * Grow the NULL bit-map. |
| */ |
| newBufferSize = dsw->rle_compress_bitmap_buffer_size * 2; |
| if (newBufferSize < newCompressBitMapSize) |
| { |
| newBufferSize = newCompressBitMapSize + dsw->initialMaxDatumPerBlock; |
| } |
| |
| oldCtxt = MemoryContextSwitchTo(dsw->memctxt); |
| newBuffer = palloc(newBufferSize); |
| |
| DatumStreamBitMapWrite_CopyToLargerBuffer( |
| &dsw->rle_compress_bitmap, |
| newBuffer, |
| newBufferSize); |
| pfree(dsw->rle_compress_bitmap_buffer); |
| MemoryContextSwitchTo(oldCtxt); |
| |
| dsw->rle_compress_bitmap_buffer = newBuffer; |
| dsw->rle_compress_bitmap_buffer_size = newBufferSize; |
| |
| /* |
| * Trace the growth of the NULL bit-map buffer. |
| */ |
| if (Debug_appendonly_print_insert) |
| { |
| if (!dsw->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE block grew COMPRESS bit-map buffer " |
| "(current logical row count %d, physical datum count %d, " |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, compression bit-map max size %d, " |
| "repeat counts count %d, repeat count size %d)", |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE block with NULLs grew COMPRESS bit-map buffer " |
| "(current logical row count %d, physical datum count %d, " |
| "null bit-map count %d, null bit-map ON count %d, null bit-map size %d, " |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, compression bit-map max size %d, " |
| "repeat counts count %d, repeat count size %d)", |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| |
| if (!dsw->rle_has_compression) |
| { |
| /* |
| * First COMPRESS bit-map entry. Zero fill the COMPRESS bit-map out and set the position. |
| */ |
| DatumStreamBitMapWrite_ZeroFill(&dsw->rle_compress_bitmap, |
| /* bitIndex */ dsw->physical_datum_count - 1 + deltaBitMapOnCount); |
| |
| /* |
| * Trace the zero fill out of the NULL bit-map buffer. |
| */ |
| if (Debug_appendonly_print_insert) |
| { |
| if (!dsw->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE block zero fill out COMPRESS bit-map " |
| "(current logical row count %d, physical datum count %d, delta bit-map ON count %d," |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, compression bit-map max size %d, " |
| "repeat counts count %d, repeat count size %d)", |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| deltaBitMapOnCount, |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE block with NULLs zero fill out COMPRESS bit-map " |
| "(current logical row count %d, physical datum count %d, delta bit-map ON count %d," |
| "null bit-map count %d, null bit-map size %d, " |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, compression bit-map max size %d, " |
| "repeat counts count %d, repeat count size %d)", |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| deltaBitMapOnCount, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| else |
| { |
| Assert(dsw->nth > 0); |
| } |
| |
| } |
| |
| /* |
| * Function calculates the space required for storing the |
| * RLE meta-data for current block. |
| * Increments headerSize and rleSize to reflect the additional |
| * size needed for RLE in block, if any. |
| */ |
| static inline void |
| DatumStreamBlockWrite_DenseRleSpace( |
| DatumStreamBlockWrite *dsw, bool null, |
| int32 *headerSize, int32 *rleSize) |
| { |
| if (!dsw->rle_has_compression) |
| { |
| return; |
| } |
| |
| *headerSize += sizeof(DatumStreamBlock_Rle_Extension); |
| |
| if (null) |
| { |
| /* CURRENT compressbitmap byte size since we don't add bits when NULL. */ |
| *rleSize += DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap); |
| } |
| else |
| { |
| /* NEXT compressbitmap byte size. */ |
| *rleSize += DatumStreamBitMapWrite_NextSize(&dsw->rle_compress_bitmap); |
| } |
| |
| /* |
| * CURRENT repeat counts size. |
| */ |
| *rleSize += dsw->rle_repeatcounts_current_size; |
| |
| /* |
| * If last item repeated is true, then to finalize the repeatcounts |
| * anytime later we will need space equivalent to its size in block. |
| * Hence account for its size now else during block write may go |
| * beyond block boundary. |
| */ |
| if (dsw->rle_last_item_is_repeated) |
| { |
| *rleSize += DatumStreamInt32Compress_Size( |
| dsw->rle_repeatcounts[dsw->rle_repeatcounts_count - 1]); |
| } |
| } |
| |
| /* |
| * Can we add an optional NULL bitmap entry or optionally the compress bit-map and |
| * repeat count array for RLE_TYPE? |
| */ |
| static bool |
| DatumStreamBlockWrite_DenseHasSpaceNull( |
| DatumStreamBlockWrite * dsw) |
| { |
| int32 headerSize = 0; |
| int32 nullSize = 0; |
| int32 rleSize = 0; |
| int32 deltaSize = 0; |
| int32 alignedHeaderSize = 0; |
| int32 currentDataSize = 0; |
| int32 newTotalSize = 0; |
| bool result = false; |
| |
| if (dsw->nth + 1 >= dsw->maxDatumPerBlock) |
| { |
| return false; |
| } |
| |
| headerSize = sizeof(DatumStreamBlock_Dense); |
| |
| /* |
| * Add in NULL bit-map, extra DatumStreamBlock_Rle struct, compress bit-map, repeated counts... |
| */ |
| nullSize = DatumStreamBitMap_Size(dsw->always_null_bitmap_count + 1); |
| |
| DatumStreamBlockWrite_DenseRleSpace(dsw, true, &headerSize, &rleSize); |
| |
| /* Add in Delta Compression structures */ |
| if (dsw->delta_has_compression) |
| { |
| /* |
| * Add in Delta bitmap but CURRENT deltas array byte lengths. |
| */ |
| headerSize += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| /* |
| * NEW delta bitmap byte size since we don't add bits when NULL; |
| */ |
| deltaSize = DatumStreamBitMapWrite_NextSize(&dsw->delta_bitmap); |
| |
| /* |
| * CURRENT deltas size. |
| */ |
| deltaSize += dsw->deltas_current_size; |
| } |
| |
| /* |
| * Align headers and meta-data (e.g. NULL bit-maps, etc). |
| */ |
| alignedHeaderSize = MAXALIGN(headerSize + nullSize + rleSize + deltaSize); |
| |
| /* |
| * Data. |
| */ |
| currentDataSize = (dsw->datump - dsw->datum_buffer); |
| |
| /* |
| * Total. |
| */ |
| newTotalSize = (alignedHeaderSize + currentDataSize); |
| result = (newTotalSize <= dsw->maxDataBlockSize); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write checking Dense new NULL space " |
| "(nth %d, configured datum length %d, item begin %p, item offset " INT64_FORMAT ", physical datum count %d, " |
| "has RLE_TYPE compression %s, " |
| "has DELTA compression %s, " |
| "headerSize %d, nullSize %d, rleSize %d, deltaSize %d, dataSize %d, " |
| "aligned header size %d, new total size %d, " |
| "maxdatasz %d, " |
| "result %s)", |
| dsw->nth, |
| dsw->typeInfo->datumlen, |
| dsw->datump, |
| (int64) (dsw->datump - dsw->datum_buffer), |
| dsw->physical_datum_count, |
| (dsw->rle_has_compression ? "true" : "false"), |
| (dsw->delta_has_compression ? "true" : "false"), |
| headerSize, |
| nullSize, |
| rleSize, |
| deltaSize, |
| currentDataSize, |
| alignedHeaderSize, |
| newTotalSize, |
| dsw->maxDataBlockSize, |
| (result ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Can we add an optional NULL bitmap entry or optionally the compress bit-map and |
| * repeat count array for RLE_TYPE? |
| */ |
| static bool |
| DatumStreamBlockWrite_DenseHasSpaceRepeat( |
| DatumStreamBlockWrite * dsw, |
| bool newRepeat) |
| { |
| int32 headerSize = 0; |
| int32 nullSize = 0; |
| int32 rleSize = 0; |
| int32 deltaSize = 0; |
| int32 alignedHeaderSize = 0; |
| int32 currentDataSize = 0; |
| int32 newTotalSize = 0; |
| bool result = false; |
| int32 total_datum_count = 0; |
| |
| if (dsw->nth + 1 >= dsw->maxDatumPerBlock) |
| { |
| return false; |
| } |
| |
| headerSize = sizeof(DatumStreamBlock_Dense); |
| |
| /* |
| * Add in NULL bit-map, extra DatumStreamBlock_Rle struct, compress bit-map, repeated counts... |
| */ |
| if (dsw->has_null) |
| { |
| /* |
| * The first item already incremented always_null_bitmap_count. |
| */ |
| nullSize = DatumStreamBitMap_Size(dsw->always_null_bitmap_count); |
| } |
| |
| total_datum_count = dsw->physical_datum_count; |
| |
| /* |
| * Add in Delta Compression structures |
| */ |
| if (dsw->delta_has_compression) |
| { |
| /* |
| * Add in Delta bitmap but CURRENT deltas array byte lengths. |
| */ |
| headerSize += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| /* |
| * NEW delta bitmap byte size since we don't add bits when NULL; |
| */ |
| deltaSize = DatumStreamBitMapWrite_NextSize(&dsw->delta_bitmap); |
| |
| /* |
| * CURRENT deltas size. |
| */ |
| deltaSize += dsw->deltas_current_size; |
| |
| total_datum_count += DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap); |
| } |
| |
| headerSize += sizeof(DatumStreamBlock_Rle_Extension); |
| if (newRepeat) |
| { |
| /* |
| * NEW compressbitmap byte size. |
| */ |
| rleSize = DatumStreamBitMap_Size(total_datum_count + 1); |
| } |
| else |
| { |
| /* |
| * CURRENT compressbitmap byte size. |
| */ |
| rleSize = DatumStreamBitMap_Size(total_datum_count); |
| } |
| |
| /* |
| * NEW repeat counts size. For simplicity, assume it will be the largest repeated count integer possible. |
| */ |
| rleSize += dsw->rle_repeatcounts_current_size + Int32Compress_MaxByteLen; |
| |
| /* |
| * Align headers and meta-data (e.g. NULL bit-maps, etc). |
| */ |
| alignedHeaderSize = MAXALIGN(headerSize + nullSize + rleSize + deltaSize); |
| |
| /* |
| * Data. |
| */ |
| currentDataSize = (dsw->datump - dsw->datum_buffer); |
| |
| /* |
| * Total. |
| */ |
| newTotalSize = (alignedHeaderSize + currentDataSize); |
| result = (newTotalSize <= dsw->maxDataBlockSize); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write checking Dense %s Repeat space " |
| "(nth %d, configured datum length %d, item begin %p, item offset " INT64_FORMAT ", physical datum count %d, " |
| "has RLE_TYPE compression %s, " |
| "has DELTA compression %s, " |
| "headerSize %d, nullSize %d, rleSize %d, deltaSize %d, dataSize %d, " |
| "aligned header size %d, new total size %d, " |
| "maxdatasz %d, " |
| "result %s)", |
| (newRepeat ? "NEW" : "OLD"), |
| dsw->nth, |
| dsw->typeInfo->datumlen, |
| dsw->datump, |
| (int64) (dsw->datump - dsw->datum_buffer), |
| dsw->physical_datum_count, |
| (dsw->rle_has_compression ? "true" : "false"), |
| (dsw->delta_has_compression ? "true" : "false"), |
| headerSize, |
| nullSize, |
| rleSize, |
| deltaSize, |
| currentDataSize, |
| alignedHeaderSize, |
| newTotalSize, |
| dsw->maxDataBlockSize, |
| (result ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Can we add the delta bit-map and deltas array for RLE_TYPE with Delta? |
| */ |
| static bool |
| DatumStreamBlockWrite_DenseHasSpaceDelta( |
| DatumStreamBlockWrite * dsw) |
| { |
| int32 headerSize = 0; |
| int32 nullSize = 0; |
| int32 rleSize = 0; |
| int32 deltaSize = 0; |
| int32 alignedHeaderSize = 0; |
| int32 currentDataSize = 0; |
| int32 newTotalSize = 0; |
| bool result = false; |
| int32 total_datum_count = 0; |
| |
| if (dsw->nth + 1 >= dsw->maxDatumPerBlock) |
| { |
| return false; |
| } |
| |
| headerSize = sizeof(DatumStreamBlock_Dense); |
| |
| /* |
| * Add in NULL bit-map, extra DatumStreamBlock_Rle struct, compress bit-map, repeated counts... |
| */ |
| if (dsw->has_null) |
| { |
| /* |
| * Adding delta value will add a false bit to null_bitmap. |
| * So, must account for it. |
| */ |
| nullSize = DatumStreamBitMap_Size(dsw->always_null_bitmap_count + 1); |
| } |
| |
| DatumStreamBlockWrite_DenseRleSpace(dsw, false, &headerSize, &rleSize); |
| |
| total_datum_count = dsw->physical_datum_count; |
| if (dsw->delta_has_compression) |
| { |
| total_datum_count += DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap); |
| } |
| |
| /* |
| * Add in Delta bitmap but CURRENT deltas array byte lengths. |
| */ |
| headerSize += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| /* |
| * NEW delta bitmap byte size; |
| */ |
| deltaSize = DatumStreamBitMap_Size(total_datum_count + 1); |
| |
| /* |
| * NEW deltas size. For simplicity, assume it will be the largest delta integer possible. |
| */ |
| deltaSize += dsw->deltas_current_size + Int32CompressReserved3_MaxByteLen; |
| |
| /* |
| * Align headers and meta-data (e.g. NULL bit-maps, etc). |
| */ |
| alignedHeaderSize = MAXALIGN(headerSize + nullSize + rleSize + deltaSize); |
| |
| /* |
| * Data. |
| */ |
| currentDataSize = (dsw->datump - dsw->datum_buffer); |
| |
| /* |
| * Total. |
| */ |
| newTotalSize = (alignedHeaderSize + currentDataSize); |
| result = (newTotalSize <= dsw->maxDataBlockSize); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write checking Dense DELTA space " |
| "(nth %d, configured datum length %d, item begin %p, item offset " INT64_FORMAT ", physical datum count %d, " |
| "has RLE_TYPE compression %s, " |
| "has DELTA compression %s, " |
| "headerSize %d, nullSize %d, rleSize %d, deltaSize %d, dataSize %d, " |
| "aligned header size %d, new total size %d, " |
| "maxdatasz %d, " |
| "result %s)", |
| dsw->nth, |
| dsw->typeInfo->datumlen, |
| dsw->datump, |
| (int64) (dsw->datump - dsw->datum_buffer), |
| dsw->physical_datum_count, |
| (dsw->rle_has_compression ? "true" : "false"), |
| (dsw->delta_has_compression ? "true" : "false"), |
| headerSize, |
| nullSize, |
| rleSize, |
| deltaSize, |
| currentDataSize, |
| alignedHeaderSize, |
| newTotalSize, |
| dsw->maxDataBlockSize, |
| (result ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Can we add a compressed bitmap array and repeat count array for RLE_TYPE? |
| */ |
| static bool |
| DatumStreamBlockWrite_DenseHasSpaceItem( |
| DatumStreamBlockWrite * dsw, |
| int32 sz) |
| { |
| int32 headerSize = 0; |
| int32 nullSize = 0; |
| int32 rleSize = 0; |
| int32 deltaSize = 0; |
| int32 alignedHeaderSize = 0; |
| int32 currentDataSize = 0; |
| int32 newTotalSize = 0; |
| bool result = false; |
| |
| if (dsw->nth + 1 >= dsw->maxDatumPerBlock) |
| { |
| return false; |
| } |
| |
| headerSize = sizeof(DatumStreamBlock_Dense); |
| |
| /* |
| * Add in NULL bit-map, extra DatumStreamBlock_Rle_Extension struct, compress bit-map, repeated counts... |
| */ |
| |
| if (dsw->has_null) |
| { |
| nullSize = DatumStreamBitMap_Size(dsw->always_null_bitmap_count + 1); |
| } |
| |
| DatumStreamBlockWrite_DenseRleSpace(dsw, false, &headerSize, &rleSize); |
| |
| if (dsw->delta_has_compression) |
| { |
| /* |
| * Add in Delta bitmap but CURRENT deltas array byte lengths. |
| */ |
| headerSize += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| /* |
| * NEW delta bitmap byte size since we don't add bits when NULL; |
| */ |
| deltaSize = DatumStreamBitMapWrite_NextSize(&dsw->delta_bitmap); |
| |
| /* |
| * CURRENT deltas size. |
| */ |
| deltaSize += dsw->deltas_current_size; |
| } |
| |
| /* |
| * Align headers and meta-data (e.g. NULL bit-maps, etc). |
| */ |
| alignedHeaderSize = MAXALIGN(headerSize + nullSize + rleSize + deltaSize); |
| |
| /* |
| * Data. |
| */ |
| currentDataSize = (dsw->datump - dsw->datum_buffer); |
| |
| /* |
| * Total. |
| */ |
| newTotalSize = (alignedHeaderSize + currentDataSize + sz); |
| result = (newTotalSize <= dsw->maxDataBlockSize); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write checking Dense new item space for " |
| "(nth %d, item size %d, configured datum length %d, item begin %p, item offset " INT64_FORMAT ", physical datum count %d, " |
| "has RLE_TYPE compression %s, " |
| "has DELTA compression %s, " |
| "headerSize %d, nullSize %d, rleSize %d, deltaSize %d, current dataSize %d, " |
| "aligned header size %d, new total size %d, " |
| "maxdatasz %d, " |
| "result %s)", |
| dsw->nth, |
| sz, |
| dsw->typeInfo->datumlen, |
| dsw->datump, |
| (int64) (dsw->datump - dsw->datum_buffer), |
| dsw->physical_datum_count, |
| (dsw->rle_has_compression ? "true" : "false"), |
| (dsw->delta_has_compression ? "true" : "false"), |
| headerSize, |
| nullSize, |
| rleSize, |
| deltaSize, |
| currentDataSize, |
| alignedHeaderSize, |
| newTotalSize, |
| dsw->maxDataBlockSize, |
| (result ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| return result; |
| } |
| |
| static void |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize( |
| DatumStreamBlockWrite * dsw) |
| { |
| Assert(dsw->rle_has_compression); |
| Assert(dsw->rle_last_item_is_repeated); |
| |
| dsw->rle_last_item_is_repeated = false; |
| dsw->rle_last_item = NULL; |
| dsw->rle_last_item_size = 0; |
| |
| /* |
| * Look at how large the current repeat count is and add in its size. |
| */ |
| dsw->rle_repeatcounts_current_size += |
| DatumStreamInt32Compress_Size( |
| dsw->rle_repeatcounts[dsw->rle_repeatcounts_count - 1]); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write Dense finalized repeated item for " |
| "(nth %d, item size %d, item begin %p, item offset " INT64_FORMAT ", " |
| "repeat index %d, repeat count %d, repeat counts size %d)", |
| dsw->nth, |
| dsw->typeInfo->datumlen, |
| dsw->datump, |
| (int64) (dsw->datump - dsw->datum_buffer), |
| dsw->rle_repeatcounts_count - 1, |
| dsw->rle_repeatcounts[dsw->rle_repeatcounts_count - 1], |
| dsw->rle_repeatcounts_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| } |
| |
| static void |
| DatumStreamBlockWrite_DenseIncrNull( |
| DatumStreamBlockWrite * dsw) |
| { |
| Assert(dsw->has_null); |
| |
| DatumStreamBitMapWrite_AddBit(&dsw->null_bitmap, /* on */ true); |
| |
| /* |
| * Always maintain this NULL bit-map counter even if we don't have RLE_TYPE compression yet. |
| */ |
| dsw->always_null_bitmap_count++; |
| |
| /* |
| * Maintain compression data structures. |
| */ |
| if (dsw->rle_want_compression) |
| { |
| if (dsw->rle_last_item_is_repeated) |
| { |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| |
| dsw->rle_last_item = NULL; |
| dsw->rle_last_item_size = 0; |
| } |
| |
| /* |
| * Total number of items represented in this block. |
| */ |
| ++dsw->nth; |
| Assert(dsw->nth <= dsw->maxDatumPerBlock); |
| } |
| |
| static void |
| DatumStreamBlockWrite_DenseIncrItem( |
| DatumStreamBlockWrite * dsw, |
| uint8 * rle_last_item, |
| int32 rle_last_item_size) |
| { |
| if (dsw->has_null) |
| { |
| DatumStreamBlockWrite_MakeNullBitMapSpace(dsw); |
| |
| DatumStreamBitMapWrite_AddBit(&dsw->null_bitmap, /* on */ false); |
| } |
| |
| /* |
| * Always maintain this NULL bit-map counter even if we don't have NULLs yet and/or RLE_TYPE compression yet. |
| */ |
| dsw->always_null_bitmap_count++; |
| |
| /* |
| * Maintain RLE compression data structures. |
| */ |
| if (dsw->rle_want_compression) |
| { |
| if (dsw->rle_last_item_is_repeated) |
| { |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| |
| dsw->rle_last_item = rle_last_item; |
| dsw->rle_last_item_size = rle_last_item_size; |
| |
| if (dsw->rle_has_compression) |
| { |
| DatumStreamBlockWrite_MakeCompressBitMapSpace(dsw); |
| |
| /* |
| * New items start off with their bit as OFF. |
| */ |
| DatumStreamBitMapWrite_AddBit(&dsw->rle_compress_bitmap, /* on */ false); |
| } |
| } |
| |
| /* |
| * Total number of items represented in this block. |
| */ |
| ++dsw->nth; |
| Assert(dsw->nth <= dsw->maxDatumPerBlock); |
| |
| ++dsw->physical_datum_count; |
| } |
| |
| static void |
| DatumStreamBlockWrite_RleIncrRepeated( |
| DatumStreamBlockWrite * dsw) |
| { |
| /* |
| * DO NOT advance the null bit-map since it was advanced on the first item. |
| */ |
| |
| if (!dsw->rle_last_item_is_repeated) |
| { |
| /* |
| * First time this item has repeated. |
| */ |
| dsw->rle_last_item_is_repeated = true; |
| |
| dsw->rle_total_repeat_items_written++; |
| /* Bump here to count the first item. */ |
| |
| if (!dsw->rle_has_compression) |
| { |
| /* |
| * Zero fill out, if necessary. |
| */ |
| DatumStreamBlockWrite_MakeCompressBitMapSpace(dsw); |
| |
| DatumStreamBitMapWrite_AddBit(&dsw->rle_compress_bitmap, /* on */ true); |
| |
| /* |
| * Set rle_has_compression after calling |
| * ~_MakeBitMapSpaceForCompress above. |
| */ |
| dsw->rle_has_compression = true; |
| } |
| else |
| { |
| /* |
| * Set the repeated item bit (that was initialized as OFF in ~_DenseIncrItem) in |
| * the COMPRESS bit-map. |
| */ |
| DatumStreamBitMapWrite_Set(&dsw->rle_compress_bitmap); |
| } |
| |
| if (dsw->rle_repeatcounts_count + 1 >= dsw->rle_repeatcounts_maxcount) |
| { |
| int32 oldBufferSize; |
| int32 newBufferSize; |
| void *newBuffer; |
| MemoryContext oldCtxt; |
| |
| /* |
| * Grow the repeat counts array. |
| */ |
| oldBufferSize = dsw->rle_repeatcounts_maxcount * Int32Compress_MaxByteLen; |
| newBufferSize = oldBufferSize * 2; |
| |
| oldCtxt = MemoryContextSwitchTo(dsw->memctxt); |
| newBuffer = palloc(newBufferSize); |
| |
| memcpy(newBuffer, dsw->rle_repeatcounts, oldBufferSize); |
| |
| pfree(dsw->rle_repeatcounts); |
| MemoryContextSwitchTo(oldCtxt); |
| |
| dsw->rle_repeatcounts = newBuffer; |
| dsw->rle_repeatcounts_maxcount *= 2; |
| } |
| |
| /* |
| * Initialize the repeat count. |
| */ |
| dsw->rle_repeatcounts[dsw->rle_repeatcounts_count] = 1; |
| dsw->rle_repeatcounts_count++; |
| } |
| else |
| { |
| dsw->rle_repeatcounts[dsw->rle_repeatcounts_count - 1]++; |
| } |
| |
| /* |
| * In the end, we use rle_savings to estimate the eofUncompress. |
| */ |
| dsw->savings += dsw->rle_last_item_size; |
| |
| /* |
| * Advance our overall count of items. |
| * |
| * DO NOT increment always_null_bitmap_count here. |
| */ |
| ++dsw->nth; |
| dsw->rle_total_repeat_items_written++; |
| /* Count new repeated item. */ |
| |
| Assert(dsw->nth <= dsw->maxDatumPerBlock); |
| } |
| |
| /* |
| * If we have space, mark the previous RLE_TYPE entry as repeated. |
| */ |
| static bool |
| DatumStreamBlockWrite_RleMarkRepeat( |
| DatumStreamBlockWrite * dsw) |
| { |
| /* |
| * Allocate the compress bit-map and repeat count array if necessary. And, |
| * see if there is room for both and room including a new compress bit and |
| * new count. |
| */ |
| if (!DatumStreamBlockWrite_DenseHasSpaceRepeat( |
| dsw, |
| /* newRepeat */ !dsw->rle_last_item_is_repeated)) |
| { |
| return false; |
| } |
| |
| DatumStreamBlockWrite_RleIncrRepeated(dsw); |
| return true; |
| } |
| |
| static void |
| DatumStreamBlockWrite_MakeDeltaCompressBitMapSpace( |
| DatumStreamBlockWrite * dsw) |
| { |
| int32 newCompressBitMapSize; |
| |
| Assert(dsw->physical_datum_count >= 1); |
| |
| if (!dsw->delta_has_compression) |
| { |
| newCompressBitMapSize = DatumStreamBitMap_Size(dsw->physical_datum_count); |
| } |
| else |
| { |
| newCompressBitMapSize = DatumStreamBitMapWrite_NextSize(&dsw->delta_bitmap); |
| } |
| |
| /* |
| * Buffer big enough? |
| */ |
| if (newCompressBitMapSize > dsw->delta_bitmap_buffer_size) |
| { |
| int32 newBufferSize; |
| void *newBuffer; |
| MemoryContext oldCtxt; |
| |
| /* |
| * Grow the Delta bit-map. |
| */ |
| newBufferSize = dsw->delta_bitmap_buffer_size * 2; |
| if (newBufferSize < newCompressBitMapSize) |
| { |
| newBufferSize = newCompressBitMapSize + dsw->initialMaxDatumPerBlock; |
| } |
| |
| oldCtxt = MemoryContextSwitchTo(dsw->memctxt); |
| newBuffer = palloc(newBufferSize); |
| |
| DatumStreamBitMapWrite_CopyToLargerBuffer( |
| &dsw->delta_bitmap, |
| newBuffer, |
| newBufferSize); |
| pfree(dsw->delta_bitmap_buffer); |
| MemoryContextSwitchTo(oldCtxt); |
| |
| dsw->delta_bitmap_buffer = newBuffer; |
| dsw->delta_bitmap_buffer_size = newBufferSize; |
| |
| /* |
| * Trace the growth of the Delta bit-map buffer. |
| */ |
| if (Debug_appendonly_print_insert) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE block grew DELTA COMPRESS bit-map buffer " |
| "(current logical row count %d, physical datum count %d, " |
| "delta bit-map count %d, delta bit-map ON count %d, delta bit-map size %d, delta bit-map max size %d, " |
| "repeat counts count %d, repeat count size %d)", |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->delta_bitmap), |
| dsw->deltas_count, |
| dsw->deltas_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| |
| if (!dsw->delta_has_compression) |
| { |
| /* |
| * First delta bit-map entry. Zero fill the delta COMPRESS bit-map out and set the position. |
| */ |
| DatumStreamBitMapWrite_ZeroFill(&dsw->delta_bitmap, /* bitIndex */ dsw->physical_datum_count); |
| |
| /* |
| * Trace the zero fill out of the NULL bit-map buffer. |
| */ |
| if (Debug_appendonly_print_insert) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE DELTA block zero fill out DELTA bit-map " |
| "(current logical row count %d, physical datum count %d, " |
| "delta bit-map count %d, delta bit-map ON count %d, delta bit-map size %d, delta bit-map max size %d, " |
| "deltas count %d, deltas size %d)", |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->delta_bitmap), |
| dsw->deltas_count, |
| dsw->deltas_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| else |
| { |
| Assert(dsw->nth > 0); |
| if (Debug_appendonly_print_insert) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE DELTA block DELTA bit-map " |
| "(current logical row count %d, physical datum count %d, " |
| "delta bit-map count %d, delta bit-map ON count %d, delta bit-map size %d, delta bit-map max size %d, " |
| "deltas count %d, deltas size %d)", |
| dsw->nth + 1, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_MaxSize(&dsw->delta_bitmap), |
| dsw->deltas_count, |
| dsw->deltas_current_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| } |
| |
| static inline void |
| DatumStreamBlockWrite_DeltaMaintain( |
| DatumStreamBlockWrite * dsw, |
| Datum d) |
| { |
| if (!dsw->delta_want_compression) |
| return; |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream insert DELTA Maintain = " INT64_FORMAT, d), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| /* |
| * Maintain Delta compression data structures. |
| */ |
| switch (dsw->typeInfo->datumlen) |
| { |
| case 4: |
| *(uint32 *) (&dsw->compare_item) = DatumGetUInt32(d); |
| break; |
| case 8: |
| dsw->compare_item = d; |
| break; |
| default: |
| ereport(FATAL, |
| (errmsg("DELTA Compression maintain, fixed length type has unexpected length %d", |
| dsw->typeInfo->datumlen), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| break; |
| } |
| |
| /* |
| * Add a 0 bit in Delta Bitmap |
| * Zero fill out, if necessary. |
| */ |
| if (dsw->delta_has_compression) |
| { |
| DatumStreamBlockWrite_MakeDeltaCompressBitMapSpace(dsw); |
| DatumStreamBitMapWrite_AddBit(&dsw->delta_bitmap, /* on */ false); |
| } |
| } |
| |
| static inline void |
| DatumStreamBlockWrite_DeltaAdd( |
| DatumStreamBlockWrite * dsw, |
| int64 delta, |
| bool sign) |
| { |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream insert DELTA Add = " INT64_FORMAT " sign = %d", |
| delta, sign), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| /* |
| * Zero fill out, if necessary. |
| */ |
| DatumStreamBlockWrite_MakeDeltaCompressBitMapSpace(dsw); |
| /* Set delta_has_compression after calling ~_MakeDeltaBitMapSpace above. */ |
| dsw->delta_has_compression = true; |
| |
| /* |
| * Maintain NULL data structures. |
| */ |
| if (dsw->has_null) |
| { |
| DatumStreamBlockWrite_MakeNullBitMapSpace(dsw); |
| |
| DatumStreamBitMapWrite_AddBit(&dsw->null_bitmap, /* on */ false); |
| } |
| |
| /* |
| * Always maintain this NULL bit-map counter even if we don't have NULLs yet and/or RLE_TYPE compression yet. |
| */ |
| dsw->always_null_bitmap_count++; |
| |
| /* |
| * Maintain RLE compression data structures. |
| */ |
| Assert(dsw->rle_want_compression == true); |
| if (dsw->rle_last_item_is_repeated) |
| { |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| |
| /* RLE last item now should be the current datum */ |
| dsw->rle_last_item = (uint8 *) & dsw->compare_item; |
| dsw->rle_last_item_size = dsw->typeInfo->datumlen; |
| |
| if (dsw->rle_has_compression) |
| { |
| DatumStreamBlockWrite_MakeCompressBitMapSpace(dsw); |
| |
| /* |
| * New items start off with their bit as OFF. |
| */ |
| DatumStreamBitMapWrite_AddBit(&dsw->rle_compress_bitmap, /* on */ false); |
| } |
| |
| /* |
| * Add a set bit to delta bitmap... This needs to happen after |
| * MakeCompressBitMapSpace |
| */ |
| DatumStreamBitMapWrite_AddBit(&dsw->delta_bitmap, /* on */ true); |
| |
| if (dsw->deltas_count + 1 >= dsw->deltas_maxcount) |
| { |
| int32 oldBufferSize; |
| int32 newBufferSize; |
| void *newBuffer; |
| MemoryContext oldCtxt; |
| |
| /* |
| * Grow the delta and delta_sign array. |
| */ |
| oldBufferSize = dsw->deltas_maxcount * Int32Compress_MaxByteLen; |
| newBufferSize = oldBufferSize * 2; |
| |
| oldCtxt = MemoryContextSwitchTo(dsw->memctxt); |
| newBuffer = palloc(newBufferSize); |
| |
| memcpy(newBuffer, dsw->deltas, oldBufferSize); |
| |
| pfree(dsw->deltas); |
| MemoryContextSwitchTo(oldCtxt); |
| |
| dsw->deltas = newBuffer; |
| |
| /* Grow the delta_sign buffer as well */ |
| oldBufferSize = dsw->deltas_maxcount * sizeof(bool); |
| newBufferSize = oldBufferSize * 2; |
| |
| oldCtxt = MemoryContextSwitchTo(dsw->memctxt); |
| newBuffer = palloc(newBufferSize); |
| |
| memcpy(newBuffer, dsw->delta_sign, oldBufferSize); |
| |
| pfree(dsw->delta_sign); |
| MemoryContextSwitchTo(oldCtxt); |
| |
| dsw->delta_sign = newBuffer; |
| |
| |
| dsw->deltas_maxcount *= 2; |
| } |
| |
| /* |
| * Store the delta and sign. |
| */ |
| dsw->deltas[dsw->deltas_count] = delta; |
| dsw->delta_sign[dsw->deltas_count] = sign; |
| |
| dsw->deltas_current_size += |
| DatumStreamInt32CompressReserved3_Size(dsw->deltas[dsw->deltas_count]); |
| dsw->deltas_count++; |
| |
| /* |
| * In the end, we use delta_savings to estimate the eofUncompress. |
| */ |
| dsw->savings += dsw->typeInfo->datumlen;; |
| |
| /* |
| * Advance our overall count of items. |
| * |
| */ |
| ++dsw->nth; |
| |
| Assert(dsw->nth <= dsw->maxDatumPerBlock); |
| } |
| |
| /* |
| * Delta compression is applied only if delta between the adjacent tuples can |
| * be stored max by 4 bytes. Since upper 3 bits are reserved, leaves room of |
| * 29 bits max value for delta to be stored. If delta turns out to be larger |
| * than this value, delta compression is not applied for this tuple instead |
| * actual value is directly stored. |
| */ |
| #define MAX_DELTA_SUPPORTED_DELTA_COMPRESSION 0x1FFFFFFF |
| |
| static Delta_Compression_status |
| DatumStreamBlockWrite_PerformDeltaCompression( |
| DatumStreamBlockWrite * dsw, |
| Datum d) |
| { |
| int64 delta = 0; |
| bool positive_delta = true; |
| |
| if (!dsw->delta_want_compression) |
| { |
| return DELTA_COMPRESSION_NOT_APPLIED; |
| } |
| |
| /* |
| * Check if its first non-NULL datum of the block then |
| * just need to add a starting 0 bit in deltaBit map and return |
| * as first value will always be stored as physical datum |
| */ |
| if (dsw->not_first_datum == false) |
| { |
| dsw->not_first_datum = true; |
| return DELTA_COMPRESSION_NOT_APPLIED; |
| } |
| |
| /* Here means, we have compare value stored to calculate the Delta */ |
| switch (dsw->typeInfo->datumlen) |
| { |
| case 4: |
| if (DatumGetUInt32(dsw->compare_item) <= DatumGetUInt32(d)) |
| { |
| /* Positive delta */ |
| delta = DatumGetUInt32(d) - DatumGetUInt32(dsw->compare_item); |
| positive_delta = true; |
| } |
| else |
| { |
| /* Negative Delta */ |
| delta = DatumGetUInt32(dsw->compare_item) - DatumGetUInt32(d); |
| positive_delta = false; |
| } |
| break; |
| |
| case 8: |
| if (dsw->compare_item <= d) |
| { |
| /* Positive delta */ |
| delta = d - dsw->compare_item; |
| positive_delta = true; |
| } |
| else |
| { |
| /* Negative Delta */ |
| delta = dsw->compare_item - d; |
| positive_delta = false; |
| } |
| |
| break; |
| default: |
| ereport(FATAL, |
| (errmsg("DELTA compression fixed length type has unexpected length %d", |
| dsw->typeInfo->datumlen), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| break; |
| } |
| |
| /* |
| * Check if delta value fits the storage reserved for it. Important is to |
| * also check for overflow case, where delta goes negative. As logic above |
| * always subtracts smaller number from larger, delta must be positive |
| * except overflow case. |
| */ |
| if (delta < 0 || delta > MAX_DELTA_SUPPORTED_DELTA_COMPRESSION) |
| { |
| return DELTA_COMPRESSION_NOT_APPLIED; |
| } |
| |
| if (!DatumStreamBlockWrite_DenseHasSpaceDelta(dsw)) |
| { |
| return DELTA_COMPRESSION_ERROR; |
| } |
| |
| /* Update the compare_item now to be new value */ |
| switch (dsw->typeInfo->datumlen) |
| { |
| case 4: |
| *(uint32 *) (&dsw->compare_item) = DatumGetUInt32(d); |
| break; |
| case 8: |
| dsw->compare_item = d; |
| break; |
| default: |
| ereport(FATAL, |
| (errmsg("DELTA Compression fixed length type has unexpected length %d", |
| dsw->typeInfo->datumlen), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| break; |
| } |
| |
| DatumStreamBlockWrite_DeltaAdd(dsw, delta, positive_delta); |
| |
| return DELTA_COMPRESSION_OK; |
| } |
| |
| /* |
| * The Dense and optially RLE_TYPE version of datumstream_put. |
| */ |
| static int |
| DatumStreamBlockWrite_PutDense( |
| DatumStreamBlockWrite * dsw, |
| Datum d, |
| bool null, |
| void **toFree) |
| { |
| uint8 *item_beginp; |
| |
| bool havePreviousValueToLookAt; |
| bool isEqual; |
| uint8 *rle_last_item; |
| |
| Assert(dsw); |
| *toFree = NULL; |
| |
| Delta_Compression_status delta_status; |
| |
| #ifdef USE_ASSERT_CHECKING |
| DatumStreamBlockWrite_CheckDenseInvariant(dsw); |
| #endif |
| |
| if (null) |
| { |
| if (!DatumStreamBlockWrite_DenseHasSpaceNull(dsw)) |
| { |
| /* |
| * Too many items, or not enough room to add a NULL bit-map data. |
| */ |
| return -1; |
| } |
| |
| DatumStreamBlockWrite_MakeNullBitMapSpace(dsw); |
| |
| DatumStreamBlockWrite_DenseIncrNull(dsw); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream insert Dense NULL for " |
| "(nth %d, new NULL bit-map count %d)", |
| dsw->nth, |
| dsw->always_null_bitmap_count), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| return 0; |
| } |
| |
| /* |
| * Not a NULL. We have an item to add. |
| */ |
| /* |
| * But first, do we have a previous value to look at? |
| */ |
| havePreviousValueToLookAt = |
| (dsw->rle_want_compression && |
| dsw->rle_last_item != NULL); |
| |
| /* |
| * All the DeltaRange datatypes supported have FIXED length and |
| * hence don't need to check for the same in the below Variable length for DeltaRange |
| */ |
| |
| if (dsw->typeInfo->datumlen < 0) |
| { |
| /* Variable length. */ |
| uint8 *dataStart; |
| int32 dataLen; |
| |
| int32 sz = 0; |
| char *p = NULL; |
| char c1 = 0; |
| int32 wsz = 0; |
| Datum originalDatum; |
| bool wasExtended = false; |
| |
| Datum storedDatum; |
| uint8 *storedDataStart; |
| int32 storedDataLen; |
| void *storedToFree; |
| |
| /* Variable length */ |
| originalDatum = d; |
| |
| /* |
| * If toFree comes back non-NULL, we have created a palloc'd de-toasted and/or |
| * de-compressed varlena copy. |
| */ |
| if (dsw->typeInfo->datumlen == -1) |
| { |
| varattrib_untoast_ptr_len( |
| d, |
| (char **) &dataStart, |
| &dataLen, |
| toFree); |
| if (*toFree != NULL) |
| { |
| d = PointerGetDatum(*toFree); |
| wasExtended = true; |
| } |
| else |
| { |
| wasExtended = false; |
| } |
| } |
| else |
| { |
| dataLen = 0; |
| dataStart = NULL; |
| } |
| |
| if (Debug_datumstream_write_print_small_varlena_info) |
| { |
| DatumStreamBlockWrite_PrintInputVarlenaInfo( |
| dsw, |
| originalDatum, |
| wasExtended); |
| } |
| |
| if (dsw->rle_last_item_is_repeated && |
| dsw->rle_repeatcounts[dsw->rle_repeatcounts_count - 1] >= MAXREPEAT_COUNT) |
| { |
| /* |
| * Reguardless of whether new is equal, we need to finalized the repeated item. |
| */ |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| else if (havePreviousValueToLookAt) |
| { |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream insert has previous Dense variable-length item to look at " |
| "(control block %p, nth %d, new item size %d, new item %p, last item size %d, last item %p, data buffer %p, (next item) datum pointer %p, data buffer after %p)", |
| dsw, |
| dsw->nth, |
| dataLen, |
| dataStart, |
| dsw->rle_last_item_size, |
| dsw->rle_last_item, |
| dsw->datum_buffer, |
| dsw->datump, |
| dsw->datum_afterp), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| if (dataLen != dsw->rle_last_item_size || !dataStart) |
| { |
| isEqual = false; |
| } |
| else |
| { |
| isEqual = |
| (memcmp(dsw->rle_last_item, dataStart, dsw->rle_last_item_size) == 0); |
| } |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream insert Dense variable-length possible repeated item %s " |
| "(control block %p, nth %d)", |
| (isEqual ? "EQUAL" : "NOT EQUAL"), |
| dsw, |
| dsw->nth), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| if (isEqual) |
| { |
| if (!DatumStreamBlockWrite_RleMarkRepeat(dsw)) |
| { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * NOT EQUAL. |
| */ |
| if (dsw->rle_last_item_is_repeated) |
| { |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| } |
| |
| if (dsw->typeInfo->datumlen == -2) |
| { |
| sz = strlen(DatumGetCString(d)) + 1; |
| p = DatumGetPointer(d); |
| wsz = sz; |
| } |
| else if (VARATT_IS_SHORT(DatumGetPointer(d))) |
| { |
| sz = VARSIZE_SHORT(DatumGetPointer(d)); |
| p = DatumGetPointer(d); |
| wsz = sz; |
| } |
| else if (dsw->typeInfo->typstorage != 'p' && |
| VARATT_CAN_MAKE_SHORT(DatumGetPointer(d))) |
| { |
| sz = VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(d)); |
| c1 = VARSIZE_TO_SHORT_D(d); |
| p = VARDATA(DatumGetPointer(d)); |
| wsz = sz - 1; |
| } |
| else |
| { |
| sz = VARSIZE(DatumGetPointer(d)); |
| dsw->datump = (uint8 *) att_align_zero((char *) dsw->datump, dsw->typeInfo->align); |
| p = DatumGetPointer(d); |
| wsz = sz; |
| } |
| |
| if (!DatumStreamBlockWrite_DenseHasSpaceItem(dsw, sz)) |
| { |
| return -sz; |
| } |
| |
| /* |
| * Set item begin pointer after we have done zero padding. |
| */ |
| item_beginp = dsw->datump; |
| |
| if (c1 != 0) |
| { |
| *(dsw->datump) = c1; |
| dsw->datump += 1; |
| } |
| |
| memcpy(dsw->datump, p, wsz); |
| |
| if (Debug_datumstream_write_print_small_varlena_info) |
| { |
| DatumStreamBlockWrite_PrintStoredSmallVarlenaInfo( |
| dsw, |
| item_beginp); |
| } |
| |
| dsw->datump += wsz; |
| |
| storedDatum = PointerGetDatum(item_beginp); |
| |
| if (dsw->typeInfo->datumlen == -1) |
| { |
| varattrib_untoast_ptr_len( |
| storedDatum, |
| (char **) &storedDataStart, |
| &storedDataLen, |
| &storedToFree); |
| Assert(storedToFree == NULL); |
| } |
| else |
| { |
| Assert(dsw->typeInfo->datumlen == -2); |
| storedDataStart = (uint8 *) DatumGetCString(storedDatum); |
| storedDataLen = strlen(DatumGetCString(storedDatum)) + 1; |
| } |
| DatumStreamBlockWrite_DenseIncrItem( |
| dsw, |
| storedDataStart, |
| storedDataLen); |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write Dense variable-length item " |
| "(nth %d, item size %d, item begin %p, item offset " INT64_FORMAT ", next item begin %p, datum buffer after %p)", |
| dsw->nth, |
| sz, |
| item_beginp, |
| (int64) (item_beginp - dsw->datum_buffer), |
| dsw->datump, |
| dsw->datum_afterp), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| return sz; |
| } |
| |
| /* Fixed length */ |
| |
| item_beginp = dsw->datump; |
| |
| if (dsw->rle_last_item_is_repeated && |
| dsw->rle_repeatcounts[dsw->rle_repeatcounts_count - 1] >= MAXREPEAT_COUNT) |
| { |
| /* |
| * Reguardless of whether new is equal, we need to finalized the repeated item. |
| */ |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| else if (havePreviousValueToLookAt) |
| { |
| /* |
| * Do we have a fixed length REPEATED value? |
| */ |
| if (dsw->rle_last_item_size != dsw->typeInfo->datumlen) |
| { |
| elog(ERROR, "Last data item size %d doesn't match type datum length %d", |
| dsw->rle_last_item_size, |
| dsw->typeInfo->datumlen); |
| } |
| |
| Assert(dsw->rle_last_item_size == dsw->typeInfo->datumlen); |
| |
| if (!dsw->typeInfo->byval) |
| { |
| isEqual = |
| (memcmp(dsw->rle_last_item, DatumGetPointer(d), |
| dsw->typeInfo->datumlen) == 0); |
| } |
| else |
| { |
| switch (dsw->typeInfo->datumlen) |
| { |
| case 1: |
| isEqual = (*(dsw->rle_last_item) == DatumGetChar(d)); |
| break; |
| case 2: |
| Assert(IsAligned(dsw->datump, 2)); |
| isEqual = (*(uint16 *) (dsw->rle_last_item) == DatumGetUInt16(d)); |
| break; |
| case 4: |
| Assert(IsAligned(dsw->datump, 4)); |
| isEqual = (*(uint32 *) (dsw->rle_last_item) == DatumGetUInt32(d)); |
| break; |
| case 8: |
| Assert(IsAligned(dsw->datump, 8) || IsAligned(dsw->datump, 4)); |
| isEqual = (*(Datum *) (dsw->rle_last_item) == d); |
| break; |
| default: |
| ereport(FATAL, |
| (errmsg("fixed length type has strange length %d", |
| dsw->typeInfo->datumlen), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| isEqual = false; |
| break; |
| } |
| } |
| |
| if (isEqual) |
| { |
| if (!DatumStreamBlockWrite_RleMarkRepeat(dsw)) |
| { |
| /* |
| * Not enough space to add meta data to record a repeat. |
| */ |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * NOT EQUAL. |
| */ |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream insert Dense fixed-length possible repeated item NOT EQUAL " |
| "(nth %d, item size %d, item begin %p, next item begin %p, datum buffer after %p)", |
| dsw->nth, |
| dsw->typeInfo->datumlen, |
| item_beginp, |
| dsw->datump, |
| dsw->datum_afterp), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| if (dsw->rle_last_item_is_repeated) |
| { |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| |
| /* |
| * Fall through and see if there is enough space for new item. |
| */ |
| } |
| |
| if (dsw->delta_want_compression) |
| { |
| /* |
| * RLE done with its checks and if we are here means not repeated/exceding the MAX_REPEAT_COUNT |
| * in either case, now should check for Delta if supported and if it falls within range, |
| * should store Delta instead of storing the pysical datum |
| */ |
| delta_status = DatumStreamBlockWrite_PerformDeltaCompression(dsw, d); |
| /* Should return from here if we have performed DeltaCompression */ |
| switch (delta_status) |
| { |
| case DELTA_COMPRESSION_OK: |
| return 0; |
| case DELTA_COMPRESSION_ERROR: |
| return -1; |
| case DELTA_COMPRESSION_NOT_APPLIED: |
| break; |
| /* FALL through */ |
| } |
| } |
| |
| if (!DatumStreamBlockWrite_DenseHasSpaceItem(dsw, dsw->typeInfo->datumlen)) |
| { |
| /* |
| * Not enough space for the new item. |
| */ |
| return -dsw->typeInfo->datumlen; |
| } |
| |
| /* |
| * Remember the beginning of the new item for DatumStreamBlockWrite_DenseIncrItem below. |
| */ |
| rle_last_item = dsw->datump; |
| |
| DatumStreamBlockWrite_PutFixedLength(dsw, d); |
| |
| DatumStreamBlockWrite_DenseIncrItem(dsw, rle_last_item, dsw->typeInfo->datumlen); |
| |
| if (dsw->delta_want_compression) |
| { |
| DatumStreamBlockWrite_DeltaMaintain(dsw, d); |
| } |
| |
| if (Debug_appendonly_print_insert_tuple) |
| { |
| DatumStreamBlockWrite_PutFixedLengthTrace(dsw, item_beginp); |
| } |
| |
| return dsw->typeInfo->datumlen; |
| } |
| |
| int |
| DatumStreamBlockWrite_Put( |
| DatumStreamBlockWrite * dsw, |
| Datum datum, |
| bool null, |
| void **toFree) |
| { |
| if (strncmp(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockWrite data structure not valid (eyecatcher)"); |
| |
| switch (dsw->datumStreamVersion) |
| { |
| case DatumStreamVersion_Original: |
| return DatumStreamBlockWrite_PutOrig(dsw, datum, null, toFree); |
| |
| case DatumStreamVersion_Dense: |
| case DatumStreamVersion_Dense_Enhanced: |
| { |
| int result; |
| |
| result = DatumStreamBlockWrite_PutDense(dsw, datum, null, toFree); |
| |
| #ifdef USE_ASSERT_CHECKING |
| /* |
| * Check afterwards to verify invariants of latest write. |
| */ |
| DatumStreamBlockWrite_CheckDenseInvariant(dsw); |
| #endif |
| return result; |
| } |
| |
| default: |
| ereport(FATAL, |
| (errmsg("Unexpected datum stream version %d", |
| dsw->datumStreamVersion), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| return 0; |
| /* Never reaches here. */ |
| } |
| } |
| |
| int |
| DatumStreamBlockWrite_Nth(DatumStreamBlockWrite * dsw) |
| { |
| if (strncmp(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockWrite data structure not valid (eyecatcher)"); |
| |
| return dsw->nth; |
| } |
| |
| void |
| DatumStreamBlockWrite_GetReady( |
| DatumStreamBlockWrite * dsw) |
| { |
| if (strncmp(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockWrite data structure not valid (eyecatcher)"); |
| |
| dsw->nth = 0; |
| dsw->physical_datum_count = 0; |
| |
| dsw->always_null_bitmap_count = 0; |
| |
| dsw->remember_savings = dsw->savings; |
| |
| dsw->has_null = false; |
| DatumStreamBitMapWrite_Init( |
| &dsw->null_bitmap, |
| dsw->null_bitmap_buffer, |
| dsw->null_bitmap_buffer_size); |
| |
| |
| switch (dsw->datumStreamVersion) |
| { |
| case DatumStreamVersion_Original: |
| dsw->datump = dsw->datum_buffer; |
| break; |
| |
| case DatumStreamVersion_Dense: |
| case DatumStreamVersion_Dense_Enhanced: |
| dsw->datump = dsw->datum_buffer; |
| |
| if (dsw->rle_want_compression) |
| { |
| /* Set up for RLETYPE compression */ |
| dsw->rle_has_compression = false; |
| |
| dsw->rle_last_item = NULL; |
| dsw->rle_last_item_size = 0; |
| dsw->rle_last_item_is_repeated = false; |
| |
| dsw->rle_total_repeat_items_written = 0; |
| |
| DatumStreamBitMapWrite_Init( |
| &dsw->rle_compress_bitmap, |
| dsw->rle_compress_bitmap_buffer, |
| dsw->rle_compress_bitmap_buffer_size); |
| |
| dsw->rle_repeatcounts_count = 0; |
| dsw->rle_repeatcounts_current_size = 0; |
| } |
| |
| if (dsw->delta_want_compression) |
| { |
| /* Set up for RLETYPE with delta compression */ |
| dsw->delta_has_compression = false; |
| |
| DatumStreamBitMapWrite_Init( |
| &dsw->delta_bitmap, |
| dsw->delta_bitmap_buffer, |
| dsw->delta_bitmap_buffer_size); |
| |
| dsw->deltas_count = 0; |
| dsw->deltas_current_size = 0; |
| |
| dsw->not_first_datum = false; |
| dsw->compare_item = 0; |
| } |
| |
| break; |
| |
| default: |
| ereport(FATAL, |
| (errmsg("Unexpected datum stream version %d", |
| dsw->datumStreamVersion), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| break; |
| /* Never reached. */ |
| } |
| } |
| |
| static int64 |
| DatumStreamBlockWrite_BlockOrig( |
| DatumStreamBlockWrite * dsw, |
| uint8 * buffer, |
| RelFileLocator *node) |
| { |
| uint8 *p; |
| DatumStreamBlock_Orig block; |
| int32 unalignedNullSize; |
| int32 rowCount; |
| int64 writesz; |
| bool minimalIntegrityChecks; |
| |
| p = buffer; |
| |
| /* First write header */ |
| block.version = DatumStreamVersion_Original; |
| block.flags = dsw->has_null ? DSB_HAS_NULLBITMAP : 0; |
| block.ndatum = dsw->nth; |
| block.encrypted = 0; |
| |
| if (FileEncryptionEnabled) |
| block.encrypted = 1; |
| /* NOTE:Unfortunately, this was not zeroed in the earlier releases of the code. */ |
| |
| /* compress null bitmaps */ |
| if (!dsw->has_null) |
| { |
| unalignedNullSize = 0; |
| block.nullsz = 0; |
| } |
| else |
| { |
| Assert( |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap) == dsw->nth); |
| |
| unalignedNullSize = DatumStreamBitMapWrite_Size(&dsw->null_bitmap); |
| block.nullsz = MAXALIGN(unalignedNullSize); |
| } |
| |
| block.sz = dsw->datump - dsw->datum_buffer; |
| |
| /* |
| * Serialize the different data in to the write buffer. |
| */ |
| memcpy(p, &block, sizeof(DatumStreamBlock_Orig)); |
| p += sizeof(DatumStreamBlock_Orig); |
| |
| /* Next write the null bitmap */ |
| if (dsw->has_null) |
| { |
| int32 nullPadSize; |
| int32 pad; |
| |
| memcpy(p, dsw->null_bitmap_buffer, unalignedNullSize); |
| p += unalignedNullSize; |
| |
| /* |
| * Zero pad after the NULL bit-map to just before the aligned datum data. |
| */ |
| nullPadSize = block.nullsz - unalignedNullSize; |
| for (pad = 0; pad < nullPadSize; pad++) |
| { |
| *(p++) = 0; |
| } |
| } |
| |
| /* Next write data */ |
| memcpy(p, dsw->datum_buffer, block.sz); |
| p += block.sz; |
| |
| /* Calculate write size. */ |
| writesz = p - buffer; |
| rowCount = dsw->nth; |
| |
| if (Debug_appendonly_print_insert) |
| { |
| if (!dsw->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Original block formatted with NO NULLs " |
| "(total length = %d, logical row count %d, data length %d)", |
| (int32) writesz, |
| rowCount, |
| block.sz), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Original block formatted with NULLs for " |
| "(total length = %d, logical row count %d, null bit-map ON count %d, null bit-map aligned length %d, data length %d)", |
| (int32) writesz, |
| rowCount, |
| DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap), |
| block.nullsz, |
| block.sz), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| |
| |
| #ifdef USE_ASSERT_CHECKING |
| minimalIntegrityChecks = false; |
| #else |
| minimalIntegrityChecks = true; |
| #endif |
| if (Debug_datumstream_block_write_check_integrity) |
| { |
| minimalIntegrityChecks = false; |
| } |
| DatumStreamBlock_IntegrityCheckOrig( |
| buffer, |
| (int32) writesz, |
| minimalIntegrityChecks, |
| rowCount, |
| dsw->typeInfo, |
| /* errdetailCallback */ errdetail_datumstreamblockwrite_callback, |
| /* errdetailArg */ (void *) dsw, |
| /* errcontextCallback */ errcontext_datumstreamblockwrite_callback, |
| /* errcontextArg */ (void *) dsw); |
| |
| if (FileEncryptionEnabled) |
| { |
| EncryptAOBLock(p - block.sz, |
| block.sz, |
| node); |
| } |
| |
| return writesz; |
| } |
| |
| static int64 |
| DatumStreamBlockWrite_BlockDense( |
| DatumStreamBlockWrite * dsw, |
| uint8 * buffer, |
| RelFileLocator *node) |
| { |
| int64 writesz = 0; |
| uint8 *p = NULL; |
| DatumStreamBlock_Dense dense; |
| DatumStreamBlock_Rle_Extension rle_extension; |
| DatumStreamBlock_Delta_Extension delta_extension; |
| int32 headerSize; |
| int32 nullSize; |
| int32 rleSize; |
| int32 deltaSize; |
| int32 metadataSize; |
| int32 metadataMaxAlignSize; |
| int32 nullPadSize; |
| int32 pad; |
| int32 rowCount; |
| int32 totalRepeatCountsSize; |
| int32 totalDeltasSize; |
| int64 formattedMetadataSize; |
| bool minimalIntegrityChecks; |
| |
| totalRepeatCountsSize = 0; |
| totalDeltasSize = 0; |
| |
| /* |
| * Maintain compression data structures. |
| */ |
| if (dsw->rle_last_item_is_repeated) |
| { |
| Assert(dsw->rle_has_compression); |
| DatumStreamBlockWrite_RleFinalizeRepeatCountSize(dsw); |
| } |
| |
| p = buffer; |
| |
| /* First fill in orig header portion */ |
| dense.orig_4_bytes.version = dsw->datumStreamVersion; |
| dense.orig_4_bytes.flags = dsw->has_null ? DSB_HAS_NULLBITMAP : 0; |
| if (dsw->rle_has_compression) |
| { |
| dense.orig_4_bytes.flags |= DSB_HAS_RLE_COMPRESSION; |
| } |
| |
| if (dsw->delta_has_compression) |
| { |
| dense.orig_4_bytes.flags |= DSB_HAS_DELTA_COMPRESSION; |
| } |
| |
| if (FileEncryptionEnabled) |
| { |
| dense.orig_4_bytes.flags |= DSB_HAS_ENCRYPTION; |
| } |
| |
| dense.logical_row_count = dsw->nth; |
| dense.physical_datum_count = dsw->physical_datum_count; |
| dense.physical_data_size = dsw->datump - dsw->datum_buffer; |
| |
| headerSize = sizeof(DatumStreamBlock_Dense); |
| |
| /* |
| * Add in NULL bit-map, extra DatumStreamBlock_Rle struct, compress bit-map, repeated counts... |
| */ |
| |
| if (dsw->has_null) |
| { |
| nullSize = DatumStreamBitMapWrite_Size(&dsw->null_bitmap); |
| } |
| else |
| { |
| nullSize = 0; |
| } |
| |
| if (dsw->rle_has_compression) |
| { |
| /* |
| * Add in compress bitmap and repeat counts byte lengths, |
| * if we have done compression in this block. |
| */ |
| headerSize += sizeof(DatumStreamBlock_Rle_Extension); |
| |
| if (dsw->has_null) |
| { |
| rle_extension.norepeats_null_bitmap_count = |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap); |
| } |
| else |
| { |
| rle_extension.norepeats_null_bitmap_count = 0; |
| } |
| |
| /* |
| * Compress bit-map byte size since we don't add bits when NULL; |
| */ |
| rleSize = DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap); |
| |
| rle_extension.compress_bitmap_count = |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap); |
| |
| /* |
| * Repeat counts count and size. |
| */ |
| rleSize += dsw->rle_repeatcounts_current_size; |
| |
| rle_extension.repeatcounts_count = dsw->rle_repeatcounts_count; |
| rle_extension.repeatcounts_size = dsw->rle_repeatcounts_current_size; |
| |
| /* |
| * We charge the compression metadata size against the RLE_TYPE savings. |
| */ |
| dsw->savings -= (sizeof(DatumStreamBlock_Rle_Extension) + rleSize); |
| } |
| else |
| { |
| rleSize = 0; |
| } |
| |
| /* |
| * Add in extra DatumStreamBlock_Delta struct, Delta bit-map, deltas... |
| */ |
| |
| if (dsw->delta_has_compression) |
| { |
| /* |
| * Add in Delta bitmap and deltas byte lengths, |
| * if we have done compression in this block. |
| */ |
| headerSize += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| /* |
| * Delta bit-map byte size since we don't add bits when NULL; |
| */ |
| deltaSize = DatumStreamBitMapWrite_Size(&dsw->delta_bitmap); |
| |
| delta_extension.delta_bitmap_count = |
| DatumStreamBitMapWrite_Count(&dsw->delta_bitmap); |
| |
| /* |
| * Repeat counts count and size. |
| */ |
| deltaSize += dsw->deltas_current_size; |
| |
| delta_extension.deltas_count = dsw->deltas_count; |
| delta_extension.deltas_size = dsw->deltas_current_size; |
| |
| /* |
| * We charge the compression metadata size against the RLE_TYPE with Delta savings. |
| */ |
| dsw->savings -= (sizeof(DatumStreamBlock_Delta_Extension) + deltaSize); |
| } |
| else |
| { |
| deltaSize = 0; |
| } |
| |
| /* |
| * Align headers and meta-data (e.g. NULL bit-maps, etc). |
| */ |
| metadataSize = headerSize + nullSize + rleSize + deltaSize; |
| metadataMaxAlignSize = MAXALIGN(metadataSize); |
| |
| memcpy(p, &dense, sizeof(DatumStreamBlock_Dense)); |
| p += sizeof(DatumStreamBlock_Dense); |
| |
| if (dsw->rle_has_compression) |
| { |
| memcpy(p, &rle_extension, sizeof(DatumStreamBlock_Rle_Extension)); |
| p += sizeof(DatumStreamBlock_Rle_Extension); |
| } |
| |
| if (dsw->delta_has_compression) |
| { |
| memcpy(p, &delta_extension, sizeof(DatumStreamBlock_Delta_Extension)); |
| p += sizeof(DatumStreamBlock_Delta_Extension); |
| } |
| |
| if (dsw->has_null) |
| { |
| memcpy(p, dsw->null_bitmap_buffer, DatumStreamBitMapWrite_Size(&dsw->null_bitmap)); |
| p += DatumStreamBitMapWrite_Size(&dsw->null_bitmap); |
| } |
| |
| if (dsw->rle_has_compression) |
| { |
| int i; |
| |
| /* |
| * Compress bit-map. |
| */ |
| memcpy(p, dsw->rle_compress_bitmap_buffer, DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap)); |
| p += DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap); |
| |
| /* |
| * Write out optimal Repeat Count integer sizes. |
| */ |
| Assert(totalRepeatCountsSize == 0); |
| for (i = 0; i < dsw->rle_repeatcounts_count; i++) |
| { |
| int byteLen; |
| |
| Assert(totalRepeatCountsSize + |
| DatumStreamInt32Compress_Size(dsw->rle_repeatcounts[i]) |
| <= dsw->rle_repeatcounts_current_size); |
| |
| byteLen = DatumStreamInt32Compress_Encode(p, dsw->rle_repeatcounts[i]); |
| p += byteLen; |
| totalRepeatCountsSize += byteLen; |
| } |
| } |
| |
| /* Add Delta compress bitmap and Deltas */ |
| if (dsw->delta_has_compression) |
| { |
| int i; |
| |
| /* |
| * Compress bit-map. |
| */ |
| memcpy(p, dsw->delta_bitmap_buffer, DatumStreamBitMapWrite_Size(&dsw->delta_bitmap)); |
| p += DatumStreamBitMapWrite_Size(&dsw->delta_bitmap); |
| |
| /* |
| * Write out optimal Deltas integer sizes. |
| */ |
| Assert(totalDeltasSize == 0); |
| for (i = 0; i < dsw->deltas_count; i++) |
| { |
| int byteLen; |
| |
| Assert(totalDeltasSize + |
| DatumStreamInt32CompressReserved3_Size(dsw->deltas[i]) |
| <= dsw->deltas_current_size); |
| |
| byteLen = DatumStreamInt32CompressReserved3_Encode(p, dsw->deltas[i], dsw->delta_sign[i]); |
| p += byteLen; |
| totalDeltasSize += byteLen; |
| } |
| } |
| |
| /* |
| * Were our meta-data size calculations correct? |
| */ |
| formattedMetadataSize = (p - buffer); |
| if (formattedMetadataSize != metadataSize) |
| { |
| ereport(ERROR, |
| (errmsg("Formatted datum stream write metasize size different (expected %d, found " INT64_FORMAT ")", |
| metadataSize, |
| formattedMetadataSize), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| /* |
| * Zero pad after metadata to just before the aligned datum data. |
| */ |
| nullPadSize = metadataMaxAlignSize - metadataSize; |
| for (pad = 0; pad < nullPadSize; pad++) |
| { |
| *(p++) = 0; |
| } |
| |
| /* Next write data */ |
| if (metadataMaxAlignSize + dense.physical_data_size > dsw->maxDataBlockSize) |
| { |
| ereport(ERROR, |
| (errmsg("Formatted datum stream MAXALIGN metadata size %d + physical datum size %d " |
| "(total %d, metadata size %d, header size %d, null size %d, RLE_TYPE size %d) would exceed maximum data blocksize %d)", |
| metadataMaxAlignSize, |
| dense.physical_data_size, |
| metadataMaxAlignSize + dense.physical_data_size, |
| metadataSize, |
| headerSize, |
| nullSize, |
| rleSize, |
| dsw->maxDataBlockSize), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| |
| memcpy(p, dsw->datum_buffer, dense.physical_data_size); |
| p += dense.physical_data_size; |
| |
| /* Calculate write size. */ |
| writesz = p - buffer; |
| rowCount = dsw->nth; |
| |
| if (Debug_appendonly_print_insert) |
| { |
| if (!dsw->rle_has_compression) |
| { |
| if (!dsw->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted with NO NULLs " |
| "(maximum length %d, total length = %d, logical row count and physical datum count %d, " |
| "metadata size %d, metadata size MAXALIGN %d, header size %d, null size %d, RLE_TYPE size %d, " |
| "physical data size %d)", |
| dsw->maxDataBlockSize, |
| (int32) writesz, |
| rowCount, |
| metadataSize, |
| metadataMaxAlignSize, |
| headerSize, |
| nullSize, |
| rleSize, |
| dense.physical_data_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted with NULLs " |
| "(maximum length %d, total length = %d, logical row count %d, physical datum count %d, " |
| "null bit-map count %d, null bit-map ON count %d, null bit-map size %d, " |
| "metadata size %d, metadata size MAXALIGN %d, header size %d, null size %d, RLE_TYPE size %d, " |
| "physical data size %d)", |
| dsw->maxDataBlockSize, |
| (int32) writesz, |
| rowCount, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap), |
| metadataSize, |
| metadataMaxAlignSize, |
| headerSize, |
| nullSize, |
| rleSize, |
| dense.physical_data_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| else |
| { |
| if (!dsw->has_null) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE block with NO NULLs " |
| "(maximum length %d, total length = %d, logical row count %d, physical datum count %d, " |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, " |
| "repeat counts count %d, repeat counts size %d, output repeat counts size %d, " |
| "metadata size %d, metadata size MAXALIGN %d, " |
| "additional savings " INT64_FORMAT ", total savings " INT64_FORMAT ", " |
| "physical data size %d)", |
| dsw->maxDataBlockSize, |
| (int32) writesz, |
| rowCount, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size, |
| totalRepeatCountsSize, |
| metadataSize, |
| metadataMaxAlignSize, |
| dsw->savings - dsw->remember_savings, |
| dsw->savings, |
| dense.physical_data_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| else |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE block with NULLs " |
| "(maximum length %d, total length = %d, logical row count %d, physical datum count %d, " |
| "null bit-map count %d, null bit-map ON count %d, null bit-map size %d, " |
| "compression bit-map count %d, compression bit-map ON count %d, compression bit-map size %d, " |
| "repeat counts count %d, repeat count size %d, output repeat counts size %d, " |
| "metadata size %d, metadata size MAXALIGN %d, " |
| "additional savings " INT64_FORMAT ", total savings " INT64_FORMAT ", " |
| "physical data size %d)", |
| dsw->maxDataBlockSize, |
| (int32) writesz, |
| rowCount, |
| dsw->physical_datum_count, |
| DatumStreamBitMapWrite_Count(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->null_bitmap), |
| DatumStreamBitMapWrite_Count(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->rle_compress_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->rle_compress_bitmap), |
| dsw->rle_repeatcounts_count, |
| dsw->rle_repeatcounts_current_size, |
| totalRepeatCountsSize, |
| metadataSize, |
| metadataMaxAlignSize, |
| dsw->savings - dsw->remember_savings, |
| dsw->savings, |
| dense.physical_data_size), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| |
| if (dsw->delta_has_compression) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream write Dense block formatted RLE_TYPE with DELTA compression " |
| "delta bit-map count %d, delta bit-map ON count %d, delta bit-map size %d, " |
| "deltas count %d, deltas size %d, output deltas size %d)", |
| DatumStreamBitMapWrite_Count(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_OnCount(&dsw->delta_bitmap), |
| DatumStreamBitMapWrite_Size(&dsw->delta_bitmap), |
| dsw->deltas_count, |
| dsw->deltas_current_size, |
| totalDeltasSize), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| } |
| |
| #ifdef USE_ASSERT_CHECKING |
| minimalIntegrityChecks = false; |
| #else |
| minimalIntegrityChecks = true; |
| #endif |
| if (Debug_datumstream_block_write_check_integrity) |
| { |
| minimalIntegrityChecks = false; |
| } |
| DatumStreamBlock_IntegrityCheckDense( |
| buffer, |
| (int32) writesz, |
| minimalIntegrityChecks, |
| rowCount, |
| dsw->typeInfo, |
| /* errdetailCallback */ errdetail_datumstreamblockwrite_callback, |
| /* errdetailArg */ (void *) dsw, |
| /* errcontextCallback */ errcontext_datumstreamblockwrite_callback, |
| /* errcontextArg */ (void *) dsw); |
| |
| if (FileEncryptionEnabled) |
| EncryptAOBLock(buffer + metadataMaxAlignSize, |
| dense.physical_data_size, |
| node); |
| return writesz; |
| } |
| |
| int64 |
| DatumStreamBlockWrite_Block( |
| DatumStreamBlockWrite * dsw, |
| uint8 * buffer, |
| RelFileLocator *node) |
| { |
| if (strncmp(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockWrite data structure not valid (eyecatcher)"); |
| |
| switch (dsw->datumStreamVersion) |
| { |
| case DatumStreamVersion_Original: |
| return DatumStreamBlockWrite_BlockOrig(dsw, buffer, node); |
| |
| case DatumStreamVersion_Dense: |
| case DatumStreamVersion_Dense_Enhanced: |
| return DatumStreamBlockWrite_BlockDense(dsw, buffer, node); |
| |
| default: |
| ereport(FATAL, |
| (errmsg("Unexpected datum stream version %d", |
| dsw->datumStreamVersion), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| return 0; |
| /* Never reaches here. */ |
| } |
| } |
| |
| void |
| DatumStreamBlockWrite_Init( |
| DatumStreamBlockWrite * dsw, |
| DatumStreamTypeInfo * typeInfo, |
| DatumStreamVersion datumStreamVersion, |
| bool rle_want_compression, |
| bool delta_want_compression, |
| int32 initialMaxDatumPerBlock, |
| int32 maxDatumPerBlock, |
| int32 maxDataBlockSize, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg, |
| RelFileLocator *relFileNode) |
| { |
| memcpy(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen); |
| |
| dsw->typeInfo = typeInfo; |
| |
| dsw->datumStreamVersion = datumStreamVersion; |
| |
| dsw->rle_want_compression = rle_want_compression; |
| dsw->delta_want_compression = delta_want_compression; |
| |
| dsw->initialMaxDatumPerBlock = initialMaxDatumPerBlock; |
| dsw->maxDatumPerBlock = maxDatumPerBlock; |
| |
| dsw->maxDataBlockSize = maxDataBlockSize; |
| |
| dsw->errdetailCallback = errdetailCallback; |
| dsw->errcontextArg = errcontextArg; |
| dsw->errcontextCallback = errcontextCallback; |
| dsw->errcontextArg = errcontextArg; |
| |
| dsw->memctxt = CurrentMemoryContext; |
| |
| /* |
| * Now start setting up our write buffers, etc. |
| */ |
| dsw->datum_buffer_size = dsw->maxDataBlockSize; |
| dsw->datum_buffer = palloc(dsw->datum_buffer_size); |
| dsw->datum_afterp = dsw->datum_buffer + dsw->datum_buffer_size; |
| |
| switch (dsw->datumStreamVersion) |
| { |
| case DatumStreamVersion_Original: |
| /* |
| * The maximum number of NULLs is regulated by the maximum number of rows that |
| * can be put in the Append-Only Small Content block header. |
| */ |
| if (Debug_datumstream_write_use_small_initial_buffers) |
| { |
| dsw->null_bitmap_buffer_size = 64; |
| } |
| else |
| { |
| dsw->null_bitmap_buffer_size = (dsw->initialMaxDatumPerBlock + 1) / 8; |
| } |
| dsw->null_bitmap_buffer = palloc(dsw->null_bitmap_buffer_size); |
| |
| if (Debug_appendonly_print_insert) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write created " |
| "(maximum usable block space = %d, datum_buffer %p, " |
| "datumlen = %d, typid = %u, align '%c', by value = %s)", |
| dsw->maxDataBlockSize, |
| dsw->datum_buffer, |
| dsw->typeInfo->datumlen, |
| (uint32) dsw->typeInfo->typid, |
| dsw->typeInfo->align, |
| (dsw->typeInfo->byval ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| break; |
| |
| case DatumStreamVersion_Dense: |
| case DatumStreamVersion_Dense_Enhanced: |
| if (Debug_datumstream_write_use_small_initial_buffers) |
| { |
| dsw->null_bitmap_buffer_size = 64; |
| } |
| else |
| { |
| dsw->null_bitmap_buffer_size = (dsw->initialMaxDatumPerBlock + 1) / 8; |
| } |
| dsw->null_bitmap_buffer = palloc(dsw->null_bitmap_buffer_size); |
| |
| if (dsw->rle_want_compression) |
| { |
| /* |
| * Start with lower than MAX, since MAX is huge. |
| */ |
| if (Debug_datumstream_write_use_small_initial_buffers) |
| { |
| dsw->rle_compress_bitmap_buffer_size = 8; |
| } |
| else |
| { |
| dsw->rle_compress_bitmap_buffer_size = (dsw->initialMaxDatumPerBlock + 1) / 8; |
| } |
| dsw->rle_compress_bitmap_buffer = palloc(dsw->rle_compress_bitmap_buffer_size); |
| |
| /* |
| * Worst case repeat is 2 different repeated values for whole block. |
| */ |
| dsw->rle_repeatcounts_count = 0; |
| if (Debug_datumstream_write_use_small_initial_buffers) |
| { |
| dsw->rle_repeatcounts_maxcount = 16; |
| } |
| else |
| { |
| dsw->rle_repeatcounts_maxcount = dsw->initialMaxDatumPerBlock / 2; |
| } |
| dsw->rle_repeatcounts = |
| palloc(dsw->rle_repeatcounts_maxcount * Int32Compress_MaxByteLen); |
| } |
| else |
| { |
| Assert(dsw->rle_compress_bitmap_buffer_size == 0); |
| Assert(dsw->rle_compress_bitmap_buffer == NULL); |
| Assert(dsw->rle_repeatcounts_count == 0); |
| Assert(dsw->rle_repeatcounts_maxcount == 0); |
| Assert(dsw->rle_repeatcounts == NULL); |
| } |
| |
| if (dsw->delta_want_compression) |
| { |
| /* |
| * Start with lower than MAX, since MAX is huge. |
| */ |
| if (Debug_datumstream_write_use_small_initial_buffers) |
| { |
| dsw->delta_bitmap_buffer_size = 8; |
| } |
| else |
| { |
| dsw->delta_bitmap_buffer_size = (dsw->initialMaxDatumPerBlock + 1) / 8; |
| } |
| dsw->delta_bitmap_buffer = palloc(dsw->delta_bitmap_buffer_size); |
| |
| /* |
| * Worst case delta encoding is all datums in block having small |
| * Start with lower than MAX, since MAX is huge. |
| */ |
| dsw->deltas_count = 0; |
| if (Debug_datumstream_write_use_small_initial_buffers) |
| { |
| dsw->deltas_maxcount = 16; |
| } |
| else |
| { |
| dsw->deltas_maxcount = dsw->initialMaxDatumPerBlock; |
| } |
| dsw->deltas = |
| palloc(dsw->deltas_maxcount * Int32Compress_MaxByteLen); |
| dsw->delta_sign = |
| palloc(dsw->deltas_maxcount * sizeof(bool)); |
| } |
| else |
| { |
| Assert(dsw->delta_bitmap_buffer_size == 0); |
| Assert(dsw->delta_bitmap_buffer == NULL); |
| Assert(dsw->deltas_count == 0); |
| Assert(dsw->deltas_maxcount == 0); |
| Assert(dsw->deltas == NULL); |
| Assert(dsw->delta_sign == NULL); |
| } |
| |
| if (Debug_appendonly_print_insert) |
| { |
| ereport(LOG, |
| (errmsg("Datum stream block write created " |
| "(maximum usable block space = %d, datum_buffer %p, " |
| "datumlen = %d, typid = %u, align '%c', by value = %s)", |
| dsw->maxDataBlockSize, |
| dsw->datum_buffer, |
| dsw->typeInfo->datumlen, |
| (uint32) dsw->typeInfo->typid, |
| dsw->typeInfo->align, |
| (dsw->typeInfo->byval ? "true" : "false")), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| } |
| break; |
| |
| default: |
| ereport(FATAL, |
| (errmsg("Unexpected datum stream version %d", |
| dsw->datumStreamVersion), |
| errdetail_datumstreamblockwrite(dsw), |
| errcontext_datumstreamblockwrite(dsw))); |
| return; |
| /* Never reached. */ |
| } |
| |
| /* Set up our write block information */ |
| DatumStreamBlockWrite_GetReady(dsw); |
| } |
| |
| void |
| DatumStreamBlockWrite_Finish( |
| DatumStreamBlockWrite * dsw) |
| { |
| MemoryContext oldCtxt; |
| |
| if (strncmp(dsw->eyecatcher, DatumStreamBlockWrite_Eyecatcher, DatumStreamBlockWrite_EyecatcherLen) != 0) |
| elog(FATAL, "DatumStreamBlockWrite data structure not valid (eyecatcher)"); |
| |
| oldCtxt = MemoryContextSwitchTo(dsw->memctxt); |
| if (dsw->null_bitmap_buffer != NULL) |
| { |
| pfree(dsw->null_bitmap_buffer); |
| dsw->null_bitmap_buffer = NULL; |
| } |
| |
| if (dsw->datum_buffer != NULL) |
| { |
| pfree(dsw->datum_buffer); |
| dsw->datum_buffer = NULL; |
| } |
| |
| if (dsw->rle_compress_bitmap_buffer != NULL) |
| { |
| pfree(dsw->rle_compress_bitmap_buffer); |
| dsw->rle_compress_bitmap_buffer = NULL; |
| } |
| |
| if (dsw->rle_repeatcounts != NULL) |
| { |
| pfree(dsw->rle_repeatcounts); |
| dsw->rle_repeatcounts = NULL; |
| } |
| |
| if (dsw->delta_bitmap_buffer != NULL) |
| { |
| pfree(dsw->delta_bitmap_buffer); |
| dsw->delta_bitmap_buffer = NULL; |
| } |
| |
| if (dsw->deltas != NULL) |
| { |
| pfree(dsw->deltas); |
| dsw->deltas = NULL; |
| } |
| |
| if (dsw->delta_sign != NULL) |
| { |
| pfree(dsw->delta_sign); |
| dsw->delta_sign = NULL; |
| } |
| |
| MemoryContextSwitchTo(oldCtxt); |
| } |
| |
| /* |
| * DatumStreamBlock. |
| */ |
| static int32 |
| DatumStreamBlock_IntegrityCheckVarlena( |
| uint8 * physicalData, |
| int32 physicalDataSize, |
| DatumStreamVersion datumStreamVersion, |
| DatumStreamTypeInfo * typeInfo, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg) |
| { |
| int32 count; |
| int32 currentOffset; |
| uint8 *p; |
| |
| Assert(typeInfo->datumlen == -1); |
| Assert(physicalDataSize >= 0); |
| if (physicalDataSize == 0) |
| { |
| return 0; |
| } |
| |
| count = 0; |
| |
| p = physicalData; |
| currentOffset = 0; |
| while (true) |
| { |
| int32 remainingSize; |
| int32 varLen; |
| |
| remainingSize = physicalDataSize - currentOffset; |
| Assert(remainingSize > 0); |
| |
| /* |
| * Verify and move past any possible zero paddings AFTER PREVIOUS varlena data. |
| */ |
| if (currentOffset > 0 && *p == 0) |
| { |
| uint8 *afterPadding; |
| int32 saveBeginOffset; |
| |
| /* |
| * Note that SHORT varlena has the high bit of the first byte as 1, so |
| * we will not go here if item begins with SHORT header. |
| */ |
| |
| afterPadding = (uint8 *) att_align_nominal(p, typeInfo->align); |
| saveBeginOffset = currentOffset; |
| while (p < afterPadding) |
| { |
| if (*p != 0) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item zero padding byte at offset %d is not zero (begin offset %d, physical item index #%d)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| saveBeginOffset, |
| count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| p++; |
| currentOffset++; |
| remainingSize--; |
| if (remainingSize <= 0) |
| { |
| break; |
| } |
| } |
| } |
| |
| if (currentOffset >= physicalDataSize) |
| { |
| break; |
| } |
| |
| /* |
| * Enough room for minimum varlena? |
| */ |
| if (VARATT_IS_EXTERNAL(p)) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item at physical offset %d is corrupt (varlena is EXTERNAL, physical item index #%d)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| varLen = 0; |
| /* Never reaches here. */ |
| } |
| else if (VARATT_IS_SHORT(p)) |
| { |
| Assert(remainingSize >= 1); |
| |
| varLen = VARSIZE_SHORT(p); |
| |
| /* |
| * Check SHORT varlena length. |
| */ |
| if (varLen < VARHDRSZ_SHORT) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item at physical offset %d. SHORT varlena VARSIZE too short (size %d, remaining size %d, physical size %d, physical item index #%d, varlena: %s)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| varLen, |
| remainingSize, |
| physicalDataSize, |
| count, |
| VarlenaInfoToString(p)), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| if (varLen > remainingSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item at physical offset %d. SHORT varlena size bad (size %d, remaining size %d, physical size %d, physical item index #%d, varlena: %s)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| varLen, |
| remainingSize, |
| physicalDataSize, |
| count, |
| VarlenaInfoToString(p)), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| else |
| { |
| if (remainingSize < VARHDRSZ) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item at physical offset %d. Remaining length %d too short for regular varlena 4 byte header (physical item index #%d)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| remainingSize, |
| count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (currentOffset % 1 != 0) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item at physical offset %d. Not aligned on at least a 2 byte boundary for regular varlena header (physical item index #%d)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| varLen = VARSIZE_ANY(p); |
| |
| if (varLen < VARHDRSZ) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item at physical offset %d. Regular varlena VARSIZE too short (length %d, remaining size %d, physical size %d, physical item index #%d, varlena: %s)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| varLen, |
| remainingSize, |
| physicalDataSize, |
| count, |
| VarlenaInfoToString(p)), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| if (varLen > remainingSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream %s variable-length item at physical offset %d. Regular varlena length bad (length %d, remaining size %d, physical size %d, physical item index #%d, varlena: %s)", |
| DatumStreamVersion_String(datumStreamVersion), |
| currentOffset, |
| varLen, |
| remainingSize, |
| physicalDataSize, |
| count, |
| VarlenaInfoToString(p)), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| |
| p += varLen; |
| currentOffset += varLen; |
| |
| if (currentOffset >= physicalDataSize) |
| { |
| Assert(currentOffset == physicalDataSize); |
| break; |
| } |
| |
| count++; |
| } |
| |
| return count; |
| } |
| |
| static void |
| DatumStreamBlock_IntegrityCheckOrig( |
| uint8 * buffer, |
| int32 bufferSize, |
| bool minimalIntegrityChecks, |
| int32 expectedRowCount, |
| DatumStreamTypeInfo * typeInfo, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg) |
| { |
| int32 minHeaderSize = sizeof(DatumStreamBlock_Orig); |
| |
| DatumStreamBlock_Orig *blockOrig; |
| |
| int32 headerSize; |
| uint8 *p; |
| |
| bool hasNull; |
| |
| if (bufferSize < minHeaderSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream Original block header size. Found %d and expected the size to be at least %d", |
| bufferSize, |
| minHeaderSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| blockOrig = (DatumStreamBlock_Orig *) buffer; |
| headerSize = minHeaderSize; |
| p = buffer + headerSize; |
| |
| if (blockOrig->version != DatumStreamVersion_Original) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream Original block version. Found %d and expected %d", |
| blockOrig->version, |
| DatumStreamVersion_Original), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (minimalIntegrityChecks) |
| { |
| return; |
| } |
| |
| /* CONSIDER: Verify reserved flags are Zero */ |
| |
| hasNull = ((blockOrig->flags & DSB_HAS_NULLBITMAP) != 0); |
| |
| /* UNDONE: Add a whole bunch of other checking... */ |
| |
| if (hasNull) |
| { |
| /* |
| * The field nullsz byte length is MAXALIGN. |
| */ |
| p += blockOrig->nullsz; |
| } |
| |
| if (typeInfo->datumlen == -1) |
| { |
| /* |
| * Variable length items (i.e. varlena). |
| */ |
| DatumStreamBlock_IntegrityCheckVarlena( |
| p, |
| blockOrig->sz, |
| DatumStreamVersion_Original, |
| typeInfo, |
| errdetailCallback, |
| errdetailArg, |
| errcontextCallback, |
| errcontextArg); |
| } |
| } |
| |
| static void |
| DatumStreamBlock_IntegrityCheckDenseDelta( |
| DatumStreamBlock_Delta_Extension * deltaExtension, |
| uint8 * p, |
| int32 bufferSize, |
| int32 headerSize, |
| DatumStreamBlock_Rle_Extension * rleExtension, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg) |
| { |
| int32 deltaBitMapSize; |
| int32 actualDeltasOnCount; |
| int32 totalDeltasSize; |
| int32 alignedHeaderSize; |
| int i; |
| |
| Assert(deltaExtension != NULL); |
| Assert(p != NULL); |
| |
| if (deltaExtension->delta_bitmap_count <= 0) |
| { |
| ereport(ERROR, |
| (errmsg("DELTA bit-map count is negative or 0 and is expected to be greater than 0. (%d)", |
| deltaExtension->delta_bitmap_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (deltaExtension->deltas_count <= 0) |
| { |
| ereport(ERROR, |
| (errmsg("DELTA deltas count is negative or 0 and is expected to be greater than 0. (%d)", |
| deltaExtension->deltas_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (deltaExtension->deltas_size <= 0) |
| { |
| ereport(ERROR, |
| (errmsg("DELTA deltas size is negative or 0 and is expected to be greater than 0. (%d)", |
| deltaExtension->deltas_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (rleExtension != NULL) |
| { |
| if (deltaExtension->delta_bitmap_count != rleExtension->compress_bitmap_count) |
| { |
| ereport(ERROR, |
| (errmsg("DELTA delta_bitmap count (%d) is expected to equal to RLE_TYPE compress bitmap count (%d)", |
| deltaExtension->delta_bitmap_count, |
| rleExtension->compress_bitmap_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| |
| deltaBitMapSize = DatumStreamBitMap_Size(deltaExtension->delta_bitmap_count); |
| headerSize += deltaBitMapSize; |
| |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Expected RLE_TYPE header with DELTA size %d including NULL bit-map is larger than buffer size %d", |
| headerSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| actualDeltasOnCount = DatumStreamBitMap_CountOn(p, deltaExtension->delta_bitmap_count); |
| |
| if (actualDeltasOnCount != deltaExtension->deltas_count) |
| { |
| ereport(ERROR, |
| (errmsg("DELTA extension header bit-map ON count does not match DELTA bit-map ON count. Found %d, expected %d", |
| actualDeltasOnCount, |
| deltaExtension->deltas_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| p += deltaBitMapSize; |
| |
| headerSize += deltaExtension->deltas_size; |
| |
| alignedHeaderSize = MAXALIGN(headerSize); |
| |
| if (bufferSize < alignedHeaderSize) |
| { |
| ereport(ERROR, |
| (errmsg("Expected RLE_TYPE DELTA header size %d including deltas size is larger than buffer size %d", |
| alignedHeaderSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| totalDeltasSize = 0; |
| for (i = 0; i < deltaExtension->deltas_count; i++) |
| { |
| int32 deltasCount; |
| int byteLen; |
| bool sign; |
| |
| deltasCount = DatumStreamInt32CompressReserved3_Decode(p, &byteLen, &sign); |
| /* UNDONE: Range check repeatCount */ |
| |
| totalDeltasSize += byteLen; |
| p += byteLen; |
| } |
| |
| if (totalDeltasSize != deltaExtension->deltas_size) |
| { |
| ereport(ERROR, |
| (errmsg("Bad DELTA type deltas size. Found %d, expected %d", |
| totalDeltasSize, |
| deltaExtension->deltas_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| |
| static void |
| DatumStreamBlock_IntegrityCheckDense( |
| uint8 * buffer, |
| int32 bufferSize, |
| bool minimalIntegrityChecks, |
| int32 expectedRowCount, |
| DatumStreamTypeInfo * typeInfo, |
| int (*errdetailCallback) (void *errdetailArg), |
| void *errdetailArg, |
| int (*errcontextCallback) (void *errcontextArg), |
| void *errcontextArg) |
| { |
| int32 minHeaderSize = sizeof(DatumStreamBlock_Dense); |
| |
| DatumStreamBlock_Dense *blockDense; |
| |
| int32 headerSize; |
| uint8 *p; |
| |
| bool hasNull; |
| bool hasRleCompression; |
| bool hasDeltaCompression; |
| |
| int32 alignedHeaderSize; |
| int32 deltaOnCount; |
| DatumStreamBlock_Delta_Extension *deltaExtension; |
| DatumStreamBlock_Rle_Extension *rleExtension; |
| |
| deltaExtension = NULL; |
| rleExtension = NULL; |
| |
| alignedHeaderSize = 0; |
| |
| if (bufferSize < minHeaderSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream Dense block header size. Found %d and expected the size to be at least %d", |
| bufferSize, |
| minHeaderSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| blockDense = (DatumStreamBlock_Dense *) buffer; |
| headerSize = minHeaderSize; |
| p = buffer + headerSize; |
| |
| if ((blockDense->orig_4_bytes.version != DatumStreamVersion_Dense) && |
| (blockDense->orig_4_bytes.version != DatumStreamVersion_Dense_Enhanced)) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream Dense block version. Found %d and expected %d", |
| blockDense->orig_4_bytes.version, |
| DatumStreamVersion_Dense_Enhanced), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (minimalIntegrityChecks) |
| { |
| return; |
| } |
| |
| /* CONSIDER: Verify reserved flags are Zero */ |
| |
| hasNull = ((blockDense->orig_4_bytes.flags & DSB_HAS_NULLBITMAP) != 0); |
| hasRleCompression = ((blockDense->orig_4_bytes.flags & DSB_HAS_RLE_COMPRESSION) != 0); |
| hasDeltaCompression = ((blockDense->orig_4_bytes.flags & DSB_HAS_DELTA_COMPRESSION) != 0); |
| |
| /* |
| * Verify logical row count. |
| */ |
| if (blockDense->logical_row_count < 0) |
| { |
| ereport(ERROR, |
| (errmsg("Logical row count is negative and is expected to be greater than 0. (%d)", |
| blockDense->logical_row_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| if (blockDense->logical_row_count == 0) |
| { |
| ereport(ERROR, |
| (errmsg("Logical row count is zero and is expected to be at greater than 0"), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| if (blockDense->logical_row_count != expectedRowCount) |
| { |
| ereport(ERROR, |
| (errmsg("Logical row count does not match expected value (found %d, expected %d)", |
| blockDense->logical_row_count, |
| expectedRowCount), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| /* |
| * Verify physical datum count. |
| */ |
| if (blockDense->physical_datum_count < 0) |
| { |
| ereport(ERROR, |
| (errmsg("Physical datum count is negative and is expected to be at least greater than or equal to 0. (%d)", |
| blockDense->physical_datum_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| /* |
| * Verify physical data size. |
| */ |
| if (blockDense->physical_data_size < 0) |
| { |
| ereport(ERROR, |
| (errmsg("Physical data size is negative and is expected to be at least greater than or equal to 0. (%d)", |
| blockDense->physical_data_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (blockDense->physical_datum_count > 0) |
| { |
| if (blockDense->physical_data_size == 0) |
| { |
| ereport(ERROR, |
| (errmsg("Physical data size is zero and is expected to be at least greater than 0 since physical datum count is %d", |
| blockDense->physical_datum_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (blockDense->physical_data_size > bufferSize) |
| { |
| ereport(ERROR, |
| (errmsg("Physical data size %d is greater than buffer size %d", |
| blockDense->physical_data_size, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| /* |
| * This check will make it safer to do multiplication of datum count and datum length. |
| */ |
| if (blockDense->physical_datum_count > blockDense->physical_data_size) |
| { |
| ereport(ERROR, |
| (errmsg("More physical items %d than physical bytes %d", |
| blockDense->physical_datum_count, |
| blockDense->physical_data_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (typeInfo->datumlen >= 0) |
| { |
| int64 calculatedDataSize; |
| |
| /* |
| * Fixed-length items. |
| */ |
| calculatedDataSize = ((int64) blockDense->physical_datum_count) * typeInfo->datumlen; |
| |
| if (calculatedDataSize > blockDense->physical_data_size) |
| { |
| ereport(ERROR, |
| (errmsg("Physical size doesn't match calculations for %d count of fixed-size %d items " |
| "(found " INT64_FORMAT ", expected %d)", |
| blockDense->physical_datum_count, |
| typeInfo->datumlen, |
| calculatedDataSize, |
| blockDense->physical_data_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| } |
| else |
| { |
| Assert(blockDense->physical_datum_count == 0); |
| if (blockDense->physical_data_size != 0) |
| { |
| ereport(ERROR, |
| (errmsg("Physical data size %d is expected to be at 0 since physical datum count is 0", |
| blockDense->physical_data_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| |
| if (!hasRleCompression) |
| { |
| int32 total_datum_count; |
| |
| if (hasDeltaCompression) |
| { |
| headerSize += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream DELTA block header extension size. Found %d and expected the size to be at least %d", |
| bufferSize, |
| headerSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| deltaExtension = (DatumStreamBlock_Delta_Extension *) p; |
| p += sizeof(DatumStreamBlock_Delta_Extension); |
| deltaOnCount = deltaExtension->deltas_count; |
| } |
| else |
| { |
| deltaOnCount = 0; |
| } |
| total_datum_count = blockDense->physical_datum_count + deltaOnCount; |
| |
| if (!hasNull) |
| { |
| alignedHeaderSize = MAXALIGN(headerSize); |
| |
| if (blockDense->logical_row_count != total_datum_count) |
| { |
| ereport(ERROR, |
| (errmsg("Logical row count expected to match physical datum count when block does not have NULLs " |
| "(logical row count %d, physical datum count %d + deltaOnCount %d)", |
| blockDense->logical_row_count, |
| blockDense->physical_datum_count, |
| deltaOnCount), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| else |
| { |
| int32 nullBitMapSize; |
| |
| int32 actualNullOnCount; |
| int32 expectedNullOnCount; |
| |
| nullBitMapSize = DatumStreamBitMap_Size(blockDense->logical_row_count); |
| headerSize += nullBitMapSize; |
| |
| if (!hasDeltaCompression) |
| { |
| alignedHeaderSize = MAXALIGN(headerSize); |
| |
| if (bufferSize < alignedHeaderSize) |
| { |
| ereport(ERROR, |
| (errmsg("Expected header size %d including NULL bit-map is larger than buffer size %d", |
| alignedHeaderSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| else |
| { |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Expected header size %d including NULL bit-map is larger than buffer size %d", |
| headerSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| |
| actualNullOnCount = DatumStreamBitMap_CountOn(p, blockDense->logical_row_count); |
| |
| expectedNullOnCount = blockDense->logical_row_count - total_datum_count; |
| |
| if (actualNullOnCount != expectedNullOnCount) |
| { |
| ereport(ERROR, |
| (errmsg("NULL bit-map ON count does not match. Found %d, expected %d", |
| actualNullOnCount, |
| expectedNullOnCount), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| p += nullBitMapSize; |
| } |
| |
| /* CONSIDER: Verify zero padding */ |
| } |
| else |
| { |
| int32 actualNullOnCount; |
| |
| int32 compressBitMapSize; |
| |
| int32 actualCompressOnCount; |
| |
| int32 totalRepeatCount; |
| int32 totalRepeatCountsSize; |
| |
| int i; |
| |
| int32 expectedNullOnCount; |
| |
| headerSize += sizeof(DatumStreamBlock_Rle_Extension); |
| |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream RLE_TYPE block header extension size. Found %d and expected the size to be at least %d", |
| bufferSize, |
| headerSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| rleExtension = (DatumStreamBlock_Rle_Extension *) p; |
| |
| if (!hasNull) |
| { |
| if (rleExtension->norepeats_null_bitmap_count != 0) |
| { |
| ereport(ERROR, |
| (errmsg("RLE_TYPE NULL bit-map count is expected to be 0 when there are no NULLs. (%d)", |
| rleExtension->norepeats_null_bitmap_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| else |
| { |
| if (rleExtension->norepeats_null_bitmap_count <= 0) |
| { |
| ereport(ERROR, |
| (errmsg("RLE_TYPE NULL bit-map count is negative or 0 and is expected to be greater than 0 when there are NULLs. (%d)", |
| rleExtension->norepeats_null_bitmap_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| |
| if (rleExtension->compress_bitmap_count <= 0) |
| { |
| ereport(ERROR, |
| (errmsg("RLE_TYPE COMPRESS bit-map count is negative or 0 and is expected to be greater than 0. (%d)", |
| rleExtension->compress_bitmap_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (rleExtension->repeatcounts_count <= 0) |
| { |
| ereport(ERROR, |
| (errmsg("RLE_TYPE repeats count is negative or 0 and is expected to be greater than 0. (%d)", |
| rleExtension->repeatcounts_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| if (rleExtension->repeatcounts_size <= 0) |
| { |
| ereport(ERROR, |
| (errmsg("RLE_TYPE repeats size is negative or 0 and is expected to be greater than 0. (%d)", |
| rleExtension->repeatcounts_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| p += sizeof(DatumStreamBlock_Rle_Extension); |
| |
| if (hasDeltaCompression) |
| { |
| headerSize += sizeof(DatumStreamBlock_Delta_Extension); |
| |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad datum stream RLE_TYPE DELTA block header extension size. Found %d and expected the size to be at least %d", |
| bufferSize, |
| headerSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| deltaExtension = (DatumStreamBlock_Delta_Extension *) p; |
| p += sizeof(DatumStreamBlock_Delta_Extension); |
| } |
| |
| if (!hasNull) |
| { |
| actualNullOnCount = 0; |
| } |
| else |
| { |
| int32 nullBitMapSize; |
| |
| nullBitMapSize = DatumStreamBitMap_Size(rleExtension->norepeats_null_bitmap_count); |
| headerSize += nullBitMapSize; |
| |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Bad NULL bit-map size %d with RLE_TYPE compression extension header is larger than buffer size %d", |
| headerSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| actualNullOnCount = DatumStreamBitMap_CountOn(p, rleExtension->norepeats_null_bitmap_count); |
| |
| p += nullBitMapSize; |
| } |
| |
| compressBitMapSize = DatumStreamBitMap_Size(rleExtension->compress_bitmap_count); |
| headerSize += compressBitMapSize; |
| |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Expected RLE_TYPE header size %d including NULL bit-map is larger than buffer size %d", |
| headerSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| actualCompressOnCount = DatumStreamBitMap_CountOn(p, rleExtension->compress_bitmap_count); |
| |
| if (actualCompressOnCount != rleExtension->repeatcounts_count) |
| { |
| ereport(ERROR, |
| (errmsg("RLE_TYPE COMPRESS bit-map ON count does not match COMPRESS bit-map ON count. Found %d, expected %d", |
| actualCompressOnCount, |
| rleExtension->repeatcounts_count), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| p += compressBitMapSize; |
| |
| headerSize += rleExtension->repeatcounts_size; |
| |
| if (!hasDeltaCompression) |
| { |
| alignedHeaderSize = MAXALIGN(headerSize); |
| |
| if (bufferSize < alignedHeaderSize) |
| { |
| ereport(ERROR, |
| (errmsg("Expected RLE_TYPE header size %d including repeat counts is larger than buffer size %d", |
| alignedHeaderSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| else |
| { |
| if (bufferSize < headerSize) |
| { |
| ereport(ERROR, |
| (errmsg("Expected RLE_TYPE header size %d including repeat counts is larger than buffer size %d", |
| headerSize, |
| bufferSize), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| } |
| |
| totalRepeatCount = 0; |
| totalRepeatCountsSize = 0; |
| for (i = 0; i < rleExtension->repeatcounts_count; i++) |
| { |
| int32 repeatCount; |
| int byteLen; |
| |
| repeatCount = DatumStreamInt32Compress_Decode(p, &byteLen); |
| /* UNDONE: Range check repeatCount */ |
| |
| totalRepeatCount += repeatCount; |
| totalRepeatCountsSize += byteLen; |
| p += byteLen; |
| } |
| |
| if (totalRepeatCountsSize != rleExtension->repeatcounts_size) |
| { |
| ereport(ERROR, |
| (errmsg("Bad RLE_TYPE repeats count size. Found %d, expected %d", |
| totalRepeatCountsSize, |
| rleExtension->repeatcounts_size), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| |
| expectedNullOnCount = |
| blockDense->logical_row_count - |
| rleExtension->compress_bitmap_count - |
| totalRepeatCount; |
| |
| if (!hasNull) |
| { |
| Assert(actualNullOnCount == 0); |
| if (expectedNullOnCount != 0) |
| { |
| ereport(ERROR, |
| (errmsg("Logical row count, COMPRESS bit-map count, and total repeat count for RLE_TYPE compression do not add up properly. Found %d, expected %d. " |
| "(logical row count %d, COMPRESS bit-map count %d, total repeat count %d)", |
| actualNullOnCount, |
| expectedNullOnCount, |
| blockDense->logical_row_count, |
| rleExtension->compress_bitmap_count, |
| totalRepeatCount), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| else |
| { |
| if (actualNullOnCount != expectedNullOnCount) |
| { |
| ereport(ERROR, |
| (errmsg("NULL bit-map ON count for RLE_TYPE compression does not match. Found %d, expected %d. " |
| "(logical row count %d, COMPRESS bit-map count %d, total repeat count %d)", |
| actualNullOnCount, |
| expectedNullOnCount, |
| blockDense->logical_row_count, |
| rleExtension->compress_bitmap_count, |
| totalRepeatCount), |
| errdetailCallback(errdetailArg), |
| errcontextCallback(errcontextArg))); |
| } |
| } |
| |
| /* UNDONE: Verify zero padding */ |
| } |
| |
| if (hasDeltaCompression) |
| { |
| DatumStreamBlock_IntegrityCheckDenseDelta( |
| deltaExtension, |
| p, |
| bufferSize, |
| headerSize, |
| rleExtension, |
| errdetailCallback, |
| errdetailArg, |
| errcontextCallback, |
| errcontextArg); |
| } |
| |
| if (typeInfo->datumlen == -1) |
| { |
| /* |
| * Variable-length items. |
| */ |
| |
| DatumStreamBlock_IntegrityCheckVarlena( |
| buffer + alignedHeaderSize, |
| blockDense->physical_data_size, |
| blockDense->orig_4_bytes.version, |
| typeInfo, |
| errdetailCallback, |
| errdetailArg, |
| errcontextCallback, |
| errcontextArg); |
| } |
| } |
| |
| char * |
| DatumStreamVersion_String(DatumStreamVersion datumStreamVersion) |
| { |
| switch (datumStreamVersion) |
| { |
| case DatumStreamVersion_Original: |
| return "Original"; |
| case DatumStreamVersion_Dense: |
| return "Dense"; |
| case DatumStreamVersion_Dense_Enhanced: |
| return "Dense_Enhanced"; |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| /* |
| * varlena header info to string. |
| */ |
| static char * |
| VarlenaInfoToBuffer(char *buffer, uint8 * p) |
| { |
| uint32 alignment = (uint32) ((uint8 *) INTALIGN(p) - p); |
| |
| if (VARATT_IS_EXTERNAL(p)) |
| { |
| struct varatt_external *ext = (struct varatt_external *) p; |
| bool externalIsCompressed = VARATT_EXTERNAL_IS_COMPRESSED(*ext); |
| |
| sprintf(buffer, |
| "external (header ptr %p, header alignment %u, header 0x%.8x): " |
| "va_rawsize: %d, va_extinfo %u, valueid %u, toastrelid %u (compressed %s)", |
| p, |
| alignment, |
| *((uint32 *) p), |
| ext->va_rawsize, |
| ext->va_extinfo, |
| ext->va_valueid, |
| ext->va_toastrelid, |
| (externalIsCompressed ? "true" : "false")); |
| } |
| else if (VARATT_IS_SHORT(p)) |
| { |
| sprintf(buffer, |
| "short (header ptr %p, header alignment %u, header 0x%.2x): " |
| "VARSIZE_SHORT %d, VARDATA_SHORT %p", |
| p, |
| alignment, |
| (uint32) * ((uint8 *) p), |
| (int32) VARSIZE_SHORT(p), |
| VARDATA_SHORT(p)); |
| } |
| else if (VARATT_IS_COMPRESSED(p)) |
| { |
| varattrib_4b *comp = (varattrib_4b *) p; |
| |
| sprintf(buffer, |
| "compressed (header ptr %p, header alignment %u, header 0x%.8x): " |
| "va_tcinfo: %u, " |
| "VARSIZE_ANY %d, VARDATA_ANY %p", |
| p, |
| alignment, |
| *((uint32 *) p), |
| (uint32) comp->va_compressed.va_tcinfo, |
| (int32) VARSIZE_ANY(p), |
| VARDATA_ANY(p)); |
| } |
| else |
| { |
| sprintf(buffer, |
| "regular (header ptr %p, header alignment %u, header 0x%.8x): " |
| "VARSIZE_ANY %d, VARDATA_ANY %p", |
| p, |
| alignment, |
| *((uint32 *) p), |
| (int32) VARSIZE_ANY(p), |
| VARDATA_ANY(p)); |
| } |
| |
| return buffer; |
| } |
| |
| static char varlenaInfoBuffer[100]; |
| |
| char * |
| VarlenaInfoToString(uint8 * p) |
| { |
| return VarlenaInfoToBuffer(varlenaInfoBuffer, p); |
| } |