blob: 621247b554d69e5f43e1ca2752fe9a19e87491ce [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "exec/hdfs-avro-scanner.h"
#include <algorithm>
#include <limits.h>
#include "exec/read-write-util.h"
#include "runtime/date-value.h"
#include "runtime/decimal-value.inline.h"
#include "runtime/runtime-state.h"
#include "runtime/string-value.inline.h"
#include "testutil/gtest-util.h"
#include "common/names.h"
// TODO: IMPALA-3658: complete CHAR unit tests.
// TODO: IMPALA-3658: complete VARCHAR unit tests.
namespace impala {
class HdfsAvroScannerTest : public testing::Test {
public:
void TestReadUnionType(int null_union_position, uint8_t* data, int64_t data_len,
bool expected_is_null, TErrorCode::type expected_error = TErrorCode::OK) {
// Reset parse_status_
scanner_.parse_status_ = Status::OK();
uint8_t* new_data = data;
bool is_null = -1;
bool expect_success = expected_error == TErrorCode::OK;
bool success = scanner_.ReadUnionType(null_union_position, &new_data, data + data_len,
&is_null);
EXPECT_EQ(success, expect_success);
if (success) {
EXPECT_TRUE(scanner_.parse_status_.ok());
EXPECT_EQ(is_null, expected_is_null);
EXPECT_EQ(new_data, data + 1);
} else {
EXPECT_EQ(scanner_.parse_status_.code(), expected_error);
}
}
template<typename T>
void CheckReadResult(T expected_val, int expected_encoded_len,
TErrorCode::type expected_error, T val, bool success, int actual_encoded_len) {
bool expect_success = expected_error == TErrorCode::OK;
EXPECT_EQ(success, expect_success);
if (success) {
EXPECT_TRUE(scanner_.parse_status_.ok());
EXPECT_EQ(val, expected_val);
EXPECT_EQ(expected_encoded_len, actual_encoded_len);
} else {
EXPECT_EQ(scanner_.parse_status_.code(), expected_error);
}
}
// Templated function for calling different ReadAvro* functions.
//
// PrimitiveType is a template parameter so we can pass in int 'slot_byte_size' to
// ReadAvroDecimal, but otherwise this argument is always the PrimitiveType 'type'
// argument.
template<typename T, typename ReadAvroTypeFn, typename PrimitiveType>
void TestReadAvroType(ReadAvroTypeFn read_fn, PrimitiveType type, uint8_t* data,
int64_t data_len, T expected_val, int expected_encoded_len,
TErrorCode::type expected_error = TErrorCode::OK) {
// Reset parse_status_
scanner_.parse_status_ = Status::OK();
uint8_t* new_data = data;
T slot;
bool success = (scanner_.*read_fn)(type, &new_data, data + data_len, true, &slot,
NULL);
CheckReadResult(expected_val, expected_encoded_len, expected_error, slot, success,
new_data - data);
}
void TestReadAvroBoolean(uint8_t* data, int64_t data_len, bool expected_val,
TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroBoolean, TYPE_BOOLEAN, data, data_len,
expected_val, 1, expected_error);
}
void TestReadAvroInt32(uint8_t* data, int64_t data_len, int32_t expected_val,
int expected_encoded_len, TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroInt32, TYPE_INT, data, data_len,
expected_val, expected_encoded_len, expected_error);
// Test type promotion to long, float, and double
int64_t expected_bigint = expected_val;
TestReadAvroType(&HdfsAvroScanner::ReadAvroInt32, TYPE_BIGINT, data, data_len,
expected_bigint, expected_encoded_len, expected_error);
float expected_float = expected_val;
TestReadAvroType(&HdfsAvroScanner::ReadAvroInt32, TYPE_FLOAT, data, data_len,
expected_float, expected_encoded_len, expected_error);
double expected_double = expected_val;
TestReadAvroType(&HdfsAvroScanner::ReadAvroInt32, TYPE_DOUBLE, data, data_len,
expected_double, expected_encoded_len, expected_error);
}
void TestReadAvroDate(uint8_t* data, int64_t data_len, const DateValue& expected_val,
int expected_encoded_len, TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroDate, TYPE_DATE, data, data_len,
expected_val, expected_encoded_len, expected_error);
}
void TestReadAvroInt64(uint8_t* data, int64_t data_len, int64_t expected_val,
int expected_encoded_len, TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroInt64, TYPE_BIGINT, data, data_len,
expected_val, expected_encoded_len, expected_error);
// Test type promotion to float and double
float expected_float = expected_val;
TestReadAvroType(&HdfsAvroScanner::ReadAvroInt64, TYPE_FLOAT, data, data_len,
expected_float, expected_encoded_len, expected_error);
double expected_double = expected_val;
TestReadAvroType(&HdfsAvroScanner::ReadAvroInt64, TYPE_DOUBLE, data, data_len,
expected_double, expected_encoded_len, expected_error);
}
void TestReadAvroFloat(uint8_t* data, int64_t data_len, float expected_val,
TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroFloat, TYPE_FLOAT, data, data_len,
expected_val, 4, expected_error);
// Test type promotion to double
double expected_double = expected_val;
TestReadAvroType(&HdfsAvroScanner::ReadAvroFloat, TYPE_DOUBLE, data, data_len,
expected_double, 4, expected_error);
}
void TestReadAvroDouble(uint8_t* data, int64_t data_len, double expected_val,
TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroDouble, TYPE_DOUBLE, data, data_len,
expected_val, 8, expected_error);
}
void TestReadAvroChar(int max_len, uint8_t* data, int64_t data_len,
StringValue expected_val, int expected_encoded_len,
TErrorCode::type expected_error = TErrorCode::OK) {
// Reset parse_status_
scanner_.parse_status_ = Status::OK();
uint8_t* new_data = data;
char slot[max<int>(sizeof(StringValue), max_len)];
bool success = scanner_.ReadAvroChar(TYPE_CHAR, max_len, &new_data, data + data_len,
true, slot, NULL);
// Convert to non-inlined string value for comparison.
StringValue value(slot, max_len);
CheckReadResult(expected_val, expected_encoded_len, expected_error, value, success,
new_data - data);
}
void TestReadAvroVarchar(int max_len, uint8_t* data, int64_t data_len,
StringValue expected_val, int expected_encoded_len,
TErrorCode::type expected_error = TErrorCode::OK) {
// Reset parse_status_
scanner_.parse_status_ = Status::OK();
uint8_t* new_data = data;
StringValue slot;
bool success = scanner_.ReadAvroVarchar(TYPE_VARCHAR, max_len, &new_data,
data + data_len, true, &slot, NULL);
CheckReadResult(expected_val, expected_encoded_len, expected_error, slot, success,
new_data - data);
}
void TestReadAvroString(uint8_t* data, int64_t data_len, StringValue expected_val,
int expected_encoded_len, TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroString, TYPE_STRING, data, data_len,
expected_val, expected_encoded_len, expected_error);
}
template<typename T>
void TestReadAvroDecimal(uint8_t* data, int64_t data_len, DecimalValue<T> expected_val,
int expected_encoded_len, TErrorCode::type expected_error = TErrorCode::OK) {
TestReadAvroType(&HdfsAvroScanner::ReadAvroDecimal, sizeof(expected_val), data,
data_len, expected_val, expected_encoded_len, expected_error);
}
void TestInt64Val(int64_t val) {
uint8_t data[100];
int len = ReadWriteUtil::PutZLong(val, data);
DCHECK_GT(len, 0);
TestReadAvroInt64(data, len, val, len);
TestReadAvroInt64(data, len + 1, val, len);
TestReadAvroInt64(data, len - 1, -1, -1, TErrorCode::SCANNER_INVALID_INT);
}
protected:
HdfsAvroScanner scanner_;
};
// Tests reading a [<some type>, "null"] union.
TEST_F(HdfsAvroScannerTest, NullUnionTest) {
uint8_t data[100];
data[0] = 0;
TestReadUnionType(0, data, 1, true);
TestReadUnionType(1, data, 1, false);
TestReadUnionType(0, data, 10, true);
TestReadUnionType(1, data, 10, false);
TestReadUnionType(0, data, 0, false, TErrorCode::AVRO_TRUNCATED_BLOCK);
data[0] = 2;
TestReadUnionType(0, data, 1, false);
TestReadUnionType(1, data, 1, true);
TestReadUnionType(0, data, 10, false);
TestReadUnionType(1, data, 10, true);
TestReadUnionType(0, data, 0, false, TErrorCode::AVRO_TRUNCATED_BLOCK);
data[0] = 1;
TestReadUnionType(0, data, 0, false, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadUnionType(0, data, 1, false, TErrorCode::AVRO_INVALID_UNION);
data[0] = -1;
TestReadUnionType(0, data, 1, false, TErrorCode::AVRO_INVALID_UNION);
}
TEST_F(HdfsAvroScannerTest, BooleanTest) {
uint8_t data[100];
data[0] = 0;
TestReadAvroBoolean(data, 1, false);
TestReadAvroBoolean(data, 10, false);
TestReadAvroBoolean(data, 0, false, TErrorCode::AVRO_TRUNCATED_BLOCK);
data[0] = 1;
TestReadAvroBoolean(data, 1, true);
TestReadAvroBoolean(data, 10, true);
TestReadAvroBoolean(data, 0, false, TErrorCode::AVRO_TRUNCATED_BLOCK);
data[0] = 2;
TestReadAvroBoolean(data, 1, false, TErrorCode::AVRO_INVALID_BOOLEAN);
}
TEST_F(HdfsAvroScannerTest, Int32Test) {
uint8_t data[100];
data[0] = 1; // decodes to -1
TestReadAvroInt32(data, 1, -1, 1);
TestReadAvroInt32(data, 10, -1, 1);
TestReadAvroInt32(data, 0, -1, -1, TErrorCode::SCANNER_INVALID_INT);
data[0] = 2; // decodes to 1
TestReadAvroInt32(data, 1, 1, 1);
TestReadAvroInt32(data, 10, 1, 1);
TestReadAvroInt32(data, 0, -1, -1, TErrorCode::SCANNER_INVALID_INT);
data[0] = 0x80; // decodes to 64
data[1] = 0x01;
TestReadAvroInt32(data, 2, 64, 2);
TestReadAvroInt32(data, 10, 64, 2);
TestReadAvroInt32(data, 0, -1, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroInt32(data, 1, -1, -1, TErrorCode::SCANNER_INVALID_INT);
int len = ReadWriteUtil::PutZInt(INT_MAX, data);
TestReadAvroInt32(data, len, INT_MAX, len);
TestReadAvroInt32(data, len + 1, INT_MAX, len);
TestReadAvroInt32(data, len - 1, -1, -1, TErrorCode::SCANNER_INVALID_INT);
len = ReadWriteUtil::PutZInt(INT_MIN, data);
TestReadAvroInt32(data, len, INT_MIN, len);
TestReadAvroInt32(data, len + 1, INT_MIN, len);
TestReadAvroInt32(data, len - 1, -1, -1, TErrorCode::SCANNER_INVALID_INT);
// TODO: we don't handle invalid values (e.g. overflow) (IMPALA-3659)
}
TEST_F(HdfsAvroScannerTest, DateTest) {
uint8_t data[100];
data[0] = 1; // decodes to -1 which corresponds to 1969-12-31.
TestReadAvroDate(data, 1, DateValue(1969, 12, 31), 1);
TestReadAvroDate(data, 10, DateValue(1969, 12, 31), 1);
// Empty data.
DateValue invalid_dv;
TestReadAvroDate(data, 0, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
data[0] = 2; // decodes to 1 which corresponds to 1970-01-02.
TestReadAvroDate(data, 1, DateValue(1970, 1, 2), 1);
TestReadAvroDate(data, 10, DateValue(1970, 1, 2), 1);
TestReadAvroDate(data, 0, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
data[0] = 0x80; // decodes to 64 which corresponds to 1970-03-06.
data[1] = 0x01;
TestReadAvroDate(data, 2, DateValue(1970, 3, 6), 2);
TestReadAvroDate(data, 10, DateValue(1970, 3, 6), 2);
TestReadAvroDate(data, 0, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroDate(data, 1, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
// Test upper limit: 9999-12-31.
const int32_t MAX_DATE_DAYS_SINCE_EPOCH = 2932896;
int len = ReadWriteUtil::PutZInt(MAX_DATE_DAYS_SINCE_EPOCH, data);
TestReadAvroDate(data, len, DateValue(9999, 12 ,31), len);
TestReadAvroDate(data, len + 1, DateValue(9999, 12, 31), len);
TestReadAvroDate(data, len - 1, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
len = ReadWriteUtil::PutZInt(MAX_DATE_DAYS_SINCE_EPOCH + 1, data);
TestReadAvroDate(data, len, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len + 1, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len - 1, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
len = ReadWriteUtil::PutZInt(INT_MAX, data);
TestReadAvroDate(data, len, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len + 1, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len - 1, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
// Test lower limit: 0001-01-01.
const int32_t MIN_DATE_DAYS_SINCE_EPOCH = -719162;
len = ReadWriteUtil::PutZInt(MIN_DATE_DAYS_SINCE_EPOCH, data);
TestReadAvroDate(data, len, DateValue(1, 1, 1), len);
TestReadAvroDate(data, len + 1, DateValue(1, 1, 1), len);
TestReadAvroDate(data, len - 1, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
len = ReadWriteUtil::PutZInt(MIN_DATE_DAYS_SINCE_EPOCH - 1, data);
TestReadAvroDate(data, len, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len + 1, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len - 1, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
len = ReadWriteUtil::PutZInt(INT_MIN, data);
TestReadAvroDate(data, len, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len + 1, invalid_dv, -1, TErrorCode::AVRO_INVALID_DATE);
TestReadAvroDate(data, len - 1, invalid_dv, -1, TErrorCode::SCANNER_INVALID_INT);
}
TEST_F(HdfsAvroScannerTest, Int64Test) {
uint8_t data[100];
data[0] = 1; // decodes to -1
TestReadAvroInt64(data, 1, -1, 1);
TestReadAvroInt64(data, 10, -1, 1);
TestReadAvroInt64(data, 0, -1, -1, TErrorCode::SCANNER_INVALID_INT);
data[0] = 2; // decodes to 1
TestReadAvroInt64(data, 1, 1, 1);
TestReadAvroInt64(data, 10, 1, 1);
TestReadAvroInt64(data, 0, -1, -1, TErrorCode::SCANNER_INVALID_INT);
data[0] = 0x80; // decodes to 64
data[1] = 0x01;
TestReadAvroInt64(data, 2, 64, 2);
TestReadAvroInt64(data, 10, 64, 2);
TestReadAvroInt64(data, 0, -1, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroInt64(data, 1, -1, -1, TErrorCode::SCANNER_INVALID_INT);
TestInt64Val(INT_MAX);
TestInt64Val(INT_MIN);
TestInt64Val(LLONG_MAX);
TestInt64Val(LLONG_MIN);
// TODO: we don't handle invalid values (e.g. overflow) (IMPALA-3659)
}
TEST_F(HdfsAvroScannerTest, FloatTest) {
uint8_t data[100];
float f = 1.23456789;
memcpy(data, &f, sizeof(float));
TestReadAvroFloat(data, 4, f);
TestReadAvroFloat(data, 10, f);
TestReadAvroFloat(data, 0, f, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroFloat(data, 1, f, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroFloat(data, 2, f, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroFloat(data, 3, f, TErrorCode::AVRO_TRUNCATED_BLOCK);
}
TEST_F(HdfsAvroScannerTest, DoubleTest) {
uint8_t data[100];
double d = 1.23456789012345;
memcpy(data, &d, sizeof(double));
TestReadAvroDouble(data, 8, d);
TestReadAvroDouble(data, 10, d);
TestReadAvroDouble(data, 0, d, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDouble(data, 1, d, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDouble(data, 2, d, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDouble(data, 3, d, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDouble(data, 7, d, TErrorCode::AVRO_TRUNCATED_BLOCK);
}
TEST_F(HdfsAvroScannerTest, StringLengthOverflowTest) {
const char* s = "hello world";
StringValue sv(s);
// Test handling of strings that would overflow the StringValue::len 32-bit integer.
// Test cases with 0 and 1 in the upper bit of the 32-bit integer.
vector<int64_t> large_string_lens({0x1FFFFFFFF, 0x0FFFFFFFF, 0x100000000});
for (int64_t large_string_len: large_string_lens) {
LOG(INFO) << "Testing large string of length " << large_string_len;
vector<uint8_t> large_buffer(large_string_len + ReadWriteUtil::MAX_ZLONG_LEN);
int64_t zlong_len = ReadWriteUtil::PutZLong(large_string_len, large_buffer.data());
memcpy(large_buffer.data() + zlong_len, s, strlen(s));
// CHAR and VARCHAR truncation should still work in this case.
TestReadAvroChar(sv.len, large_buffer.data(), large_buffer.size(), sv,
zlong_len + large_string_len);
TestReadAvroVarchar(sv.len, large_buffer.data(), large_buffer.size(), sv,
zlong_len + large_string_len);
// Interpreting as a string would overflow length field.
TestReadAvroString(large_buffer.data(), large_buffer.size(), sv, -1,
TErrorCode::SCANNER_STRING_LENGTH_OVERFLOW);
}
}
TEST_F(HdfsAvroScannerTest, StringTest) {
uint8_t data[100];
const char* s = "hello";
DCHECK_EQ(strlen(s), 5);
data[0] = 10; // decodes to 5
memcpy(&data[1], s, 5);
StringValue sv(s);
TestReadAvroString(data, 6, sv, 6);
TestReadAvroString(data, 10, sv, 6);
TestReadAvroString(data, 0, sv, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroString(data, 1, sv, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroString(data, 5, sv, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
data[0] = 1; // decodes to -1
TestReadAvroString(data, 10, sv, -1, TErrorCode::AVRO_INVALID_LENGTH);
data[0] = 0; // decodes to 0
sv.len = 0;
TestReadAvroString(data, 1, sv, 1);
TestReadAvroString(data, 10, sv, 1);
}
TEST_F(HdfsAvroScannerTest, DecimalTest) {
uint8_t data[100];
Decimal4Value d4v(123);
// Unscaled value (123) can be stored in 1 byte
data[0] = 2; // decodes to 1
data[1] = 123;
TestReadAvroDecimal(data, 2, d4v, 2);
TestReadAvroDecimal(data, 10, d4v, 2);
TestReadAvroDecimal(data, 0, d4v, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroDecimal(data, 1, d4v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
data[0] = 10; // decodes to 5
TestReadAvroDecimal(data, 10, d4v, -1, TErrorCode::AVRO_INVALID_LENGTH);
data[0] = 1; // decodes to -1
TestReadAvroDecimal(data, 10, d4v, -1, TErrorCode::AVRO_INVALID_LENGTH);
data[0] = 0; // decodes to 0
TestReadAvroDecimal(data, 10, Decimal4Value(0), 1);
data[0] = 0x80; // decodes to 64
data[1] = 0x01;
TestReadAvroDecimal(data, 100, d4v, -1, TErrorCode::AVRO_INVALID_LENGTH);
d4v = Decimal4Value(123456789);
// Unscaled value can be stored in 4 bytes
data[0] = 8; // decodes to 4
#if __BYTE_ORDER == __LITTLE_ENDIAN
BitUtil::ByteSwap(&data[1], &d4v.value(), 4);
#else
memcpy(&data[1], &d4v.value(), 4);
#endif
TestReadAvroDecimal(data, 5, d4v, 5);
TestReadAvroDecimal(data, 10, d4v, 5);
TestReadAvroDecimal(data, 0, d4v, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroDecimal(data, 1, d4v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDecimal(data, 4, d4v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
Decimal8Value d8v(1);
data[0] = 2; // decodes to 1
data[1] = 1;
TestReadAvroDecimal(data, 2, d8v, 2);
TestReadAvroDecimal(data, 10, d8v, 2);
TestReadAvroDecimal(data, 0, d8v, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroDecimal(data, 1, d8v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
d8v = Decimal8Value(123456789012345678);
data[0] = 16; // decodes to 8
#if __BYTE_ORDER == __LITTLE_ENDIAN
BitUtil::ByteSwap(&data[1], &d8v.value(), 8);
#else
memcpy(&data[1], &d8v.value(), 8);
#endif
TestReadAvroDecimal(data, 9, d8v, 9);
TestReadAvroDecimal(data, 10, d8v, 9);
TestReadAvroDecimal(data, 0, d8v, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroDecimal(data, 1, d8v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDecimal(data, 7, d8v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
Decimal16Value d16v(1234567890);
data[0] = 10; // decodes to 5
#if __BYTE_ORDER == __LITTLE_ENDIAN
BitUtil::ByteSwap(&data[1], &d16v.value(), 5);
#else
memcpy(&data[1], &d16v.value(), 5);
#endif
TestReadAvroDecimal(data, 6, d16v, 6);
TestReadAvroDecimal(data, 10, d16v, 6);
TestReadAvroDecimal(data, 0, d16v, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroDecimal(data, 1, d16v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDecimal(data, 4, d16v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
/// Produce a very large decimal value.
memset(&d16v.value(), 0xFF, sizeof(d16v.value()));
data[0] = 32; // decodes to 16
#if __BYTE_ORDER == __LITTLE_ENDIAN
BitUtil::ByteSwap(&data[1], &d16v.value(), 16);
#else
memcpy(&data[1], &d16v.value(), 16);
#endif
TestReadAvroDecimal(data, 17, d16v, 17);
TestReadAvroDecimal(data, 20, d16v, 17);
TestReadAvroDecimal(data, 0, d16v, -1, TErrorCode::SCANNER_INVALID_INT);
TestReadAvroDecimal(data, 1, d16v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
TestReadAvroDecimal(data, 16, d16v, -1, TErrorCode::AVRO_TRUNCATED_BLOCK);
}
}