blob: 5ee2abd5f0ac49741bd7ebc453268f809d3bfec5 [file]
// 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 <gtest/gtest.h>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "core/block/block.h"
#include "core/data_type/data_type_number.h"
#include "core/data_type/data_type_struct.h"
#include "storage/binlog.h"
#include "storage/schema.h"
namespace doris {
namespace {
TabletColumnPtr create_int_column(int32_t unique_id, std::string name, bool is_key = false) {
auto column = std::make_shared<TabletColumn>(
FieldAggregationMethod::OLAP_FIELD_AGGREGATION_NONE, FieldType::OLAP_FIELD_TYPE_INT,
false, unique_id, sizeof(int32_t));
column->set_name(std::move(name));
column->set_is_key(is_key);
return column;
}
TabletColumnPtr create_struct_column(int32_t unique_id) {
auto column = std::make_shared<TabletColumn>();
column->set_unique_id(unique_id);
column->set_name("s");
column->set_type(FieldType::OLAP_FIELD_TYPE_STRUCT);
column->set_is_nullable(false);
auto first_child = create_int_column(unique_id + 100, "a");
auto second_child = create_int_column(unique_id + 101, "b");
column->add_sub_column(*first_child);
column->add_sub_column(*second_child);
return column;
}
TabletSchemaSPtr create_row_binlog_schema_with_colliding_names() {
auto schema = std::make_shared<TabletSchema>();
schema->append_column(*create_int_column(10, "key", true));
schema->append_column(*create_int_column(11, "v"));
schema->append_column(*create_int_column(12, "__BEFORE__v__"));
schema->append_column(*create_int_column(13, binlog::build_before_column_name("v")));
schema->append_column(
*create_int_column(14, binlog::build_before_column_name("__BEFORE__v__")));
schema->append_column(*create_int_column(15, BINLOG_TSO_COL));
schema->append_column(*create_int_column(16, BINLOG_LSN_COL));
schema->append_column(*create_int_column(17, BINLOG_OP_COL));
return schema;
}
TEST(ReadSchemaTest, DefaultColumnsAreVisible) {
std::vector<TabletColumnPtr> storage_columns {create_int_column(10, "k", true),
create_int_column(11, "dropped"),
create_struct_column(12)};
ReadSchema read_schema(storage_columns);
ASSERT_EQ(3, read_schema.num_block_columns());
ASSERT_EQ(3, read_schema.num_read_columns());
for (size_t ordinal = 0; ordinal < storage_columns.size(); ++ordinal) {
EXPECT_EQ(storage_columns[ordinal].get(), read_schema.column(ordinal));
EXPECT_TRUE(
read_schema.data_type(ordinal)->equals(*storage_columns[ordinal]->get_vec_type()));
EXPECT_EQ(static_cast<int32_t>(ordinal),
read_schema.ordinal_by_uid(storage_columns[ordinal]->unique_id()));
}
}
TEST(ReadSchemaTest, ProjectionPreservesRequestedOrder) {
std::vector<TabletColumnPtr> storage_columns {create_int_column(10, "k", true),
create_int_column(11, "dropped"),
create_struct_column(12)};
ReadSchema read_schema(
project_columns_by_ordinal(storage_columns, std::vector<ColumnId> {2, 0, 2}));
ASSERT_EQ(3, read_schema.num_block_columns());
ASSERT_EQ(3, read_schema.num_read_columns());
EXPECT_EQ("s", read_schema.column(0)->name());
EXPECT_EQ("k", read_schema.column(1)->name());
EXPECT_EQ("s", read_schema.column(2)->name());
EXPECT_EQ(0, read_schema.ordinal_by_uid(12));
EXPECT_EQ(1, read_schema.ordinal_by_uid(10));
EXPECT_EQ(-1, read_schema.ordinal_by_uid(11));
}
TEST(ReadSchemaTest, ExpectedTypesDefineReadBlock) {
std::vector<TabletColumnPtr> read_columns {create_struct_column(12),
create_int_column(10, "k", true)};
auto pruned_struct_type = std::make_shared<DataTypeStruct>(
DataTypes {std::make_shared<DataTypeInt32>()}, Strings {"a"});
auto int_type = std::make_shared<DataTypeInt32>();
ReadSchema read_schema(std::move(read_columns),
std::vector<DataTypePtr> {pruned_struct_type, int_type});
EXPECT_FALSE(read_schema.column(0)->get_vec_type()->equals(*pruned_struct_type));
Block block = read_schema.create_read_block();
ASSERT_EQ(2, block.columns());
EXPECT_EQ("s", block.get_by_position(0).name);
EXPECT_EQ("k", block.get_by_position(1).name);
EXPECT_TRUE(block.get_by_position(0).type->equals(*pruned_struct_type));
EXPECT_TRUE(block.get_by_position(1).type->equals(*int_type));
}
TEST(ReadSchemaTest, AppendedDroppedColumnDoesNotExtendReadBlock) {
std::vector<TabletColumnPtr> read_columns {create_int_column(10, "k", true),
create_struct_column(12)};
auto dropped_column = create_int_column(11, "dropped", true);
ReadSchema read_schema(std::move(read_columns));
EXPECT_EQ(1, read_schema.num_key_columns());
read_schema.append_dropped_columns({*dropped_column});
ColumnId suffix_ordinal = read_schema.ordinal_by_uid(11);
EXPECT_EQ(2, suffix_ordinal);
EXPECT_EQ(2, read_schema.num_block_columns());
EXPECT_EQ(3, read_schema.num_read_columns());
EXPECT_EQ(1, read_schema.num_key_columns());
EXPECT_EQ(suffix_ordinal, read_schema.ordinal_by_uid(11));
EXPECT_TRUE(read_schema.data_type(suffix_ordinal)->equals(*dropped_column->get_vec_type()));
EXPECT_EQ(2, read_schema.create_read_block().columns());
}
TEST(ReadSchemaTest, RowBinlogMappingsUsePhysicalSchemaOrdinals) {
auto tablet_schema = create_row_binlog_schema_with_colliding_names();
// Reorder the two AFTER values and their BEFORE companions to verify that ReadSchema stores
// dense read ordinals resolved by unique id, rather than physical tablet column ids or names.
ReadSchema read_schema(project_columns_by_ordinal(
tablet_schema->columns(), std::vector<ColumnId> {0, 2, 1, 4, 3, 5, 6, 7}));
read_schema.init_row_binlog_column_mappings(*tablet_schema);
EXPECT_TRUE(read_schema.row_binlog_value_pairs_complete());
EXPECT_EQ(read_schema.row_binlog_value_column_pairs(),
(ReadSchema::RowBinlogValueColumnPairs {{2, 4}, {1, 3}}));
EXPECT_EQ(4, read_schema.before_column_ordinal(2));
EXPECT_EQ(3, read_schema.before_column_ordinal(1));
for (ColumnId ordinal : {0, 3, 4, 5, 6, 7}) {
EXPECT_EQ(ordinal, read_schema.before_column_ordinal(ordinal));
}
}
TEST(ReadSchemaTest, MalformedRowBinlogLayoutKeepsConservativeNameMapping) {
TabletSchema tablet_schema;
tablet_schema.append_column(*create_int_column(10, "key", true));
tablet_schema.append_column(*create_int_column(11, "v"));
tablet_schema.append_column(*create_int_column(12, binlog::build_before_column_name("v")));
tablet_schema.append_column(*create_int_column(13, "orphan"));
tablet_schema.append_column(*create_int_column(14, BINLOG_TSO_COL));
tablet_schema.append_column(*create_int_column(15, BINLOG_LSN_COL));
tablet_schema.append_column(*create_int_column(16, BINLOG_OP_COL));
ReadSchema read_schema(tablet_schema.columns());
read_schema.init_row_binlog_column_mappings(tablet_schema);
EXPECT_FALSE(read_schema.row_binlog_value_pairs_complete());
EXPECT_TRUE(read_schema.row_binlog_value_column_pairs().empty());
EXPECT_EQ(2, read_schema.before_column_ordinal(1));
}
} // namespace
} // namespace doris