| // 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 <string> |
| |
| #include <gtest/gtest.h> |
| |
| #include "kudu/common/columnblock-test-util.h" |
| #include "kudu/common/common.pb.h" |
| #include "kudu/common/rowblock.h" |
| #include "kudu/common/types.h" |
| #include "kudu/gutil/strings/substitute.h" |
| #include "kudu/util/memory/arena.h" |
| #include "kudu/util/test_macros.h" |
| |
| namespace kudu { |
| class Slice; |
| } // namespace kudu |
| |
| using std::string; |
| using strings::Substitute; |
| |
| namespace kudu { |
| |
| TEST(TestColumnBlock, TestEquals) { |
| ScopedColumnBlock<UINT32> scb1(1); |
| ScopedColumnBlock<UINT32> scb2(1); |
| ASSERT_EQ(scb1, scb2); |
| |
| // Even though this updates a value, scb2 is still entirely null. |
| scb2[0] = 5; |
| ASSERT_EQ(scb1, scb2); |
| |
| // If we un-null that cell in scb2, the two column blocks are no longer equal. |
| scb2.SetCellIsNull(0, false); |
| ASSERT_NE(scb1, scb2); |
| |
| // Now let's also un-null that cell in scb1. The null bitmaps match again, but |
| // the data itself does not. |
| scb1.SetCellIsNull(0, false); |
| ASSERT_NE(scb1, scb2); |
| |
| // These two column blocks aren't the same length. |
| ScopedColumnBlock<UINT32> scb3(1); |
| ScopedColumnBlock<UINT32> scb4(2); |
| ASSERT_NE(scb3, scb4); |
| |
| // Let's make sure they're equal even when the data is indirected. |
| ScopedColumnBlock<STRING> scb5(1); |
| ScopedColumnBlock<STRING> scb6(1); |
| scb5.SetCellIsNull(0, false); |
| scb5[0] = "foo"; |
| scb6.SetCellIsNull(0, false); |
| scb6[0] = "foo"; |
| ASSERT_EQ(scb5, scb6); |
| } |
| |
| TEST(TestColumnBlock, TestCopyTo) { |
| ScopedColumnBlock<UINT32> src(8, /*allow_nulls=*/false); |
| ScopedColumnBlock<UINT32> dst(8, /*allow_nulls=*/false); |
| |
| for (int i = 0; i < src.nrows(); i++) { |
| src[i] = i; |
| } |
| for (int i = 0; i < dst.nrows(); i++) { |
| dst[i] = 100; |
| } |
| |
| SelectionVector sv(src.nrows()); |
| sv.SetAllTrue(); |
| |
| // src: 0 1 2 3 4 5 6 7 |
| // dst: 100 100 100 100 100 100 100 100 |
| // ------------------------------------ |
| // dst: 100 100 100 100 100 3 4 5 |
| ASSERT_OK(src.CopyTo(sv, &dst, 3, 5, 3)); |
| |
| for (int i = 0; i < dst.nrows(); i++) { |
| int expected_val = i < 5 ? 100 : i - 2; |
| ASSERT_EQ(expected_val, dst[i]); |
| } |
| } |
| |
| TEST(TestColumnBlock, TestCopyToIndirectData) { |
| ScopedColumnBlock<STRING> src(8, /*allow_nulls=*/false); |
| ScopedColumnBlock<STRING> dst(8, /*allow_nulls=*/false); |
| |
| // Ignore idx 3, and poke a corresponding hole in the selection vector. |
| Slice* next_cell = reinterpret_cast<Slice*>(src.data()); |
| for (int i = 0; i < src.nrows(); i++, next_cell++) { |
| if (i == 3) continue; |
| ASSERT_TRUE(src.arena()->RelocateSlice(Substitute("h$0", i), next_cell)); |
| } |
| next_cell = reinterpret_cast<Slice*>(dst.data()); |
| for (int i = 0; i < dst.nrows(); i++, next_cell++) { |
| ASSERT_TRUE(dst.arena()->RelocateSlice("", next_cell)); |
| } |
| |
| SelectionVector sv(src.nrows()); |
| sv.SetAllTrue(); |
| sv.SetRowUnselected(3); |
| |
| // src: h0 h1 h2 ?? h4 h5 h6 h7 |
| // dst: "" "" "" "" "" "" "" "" |
| // ---------------------------- |
| // dst: "" "" "" "" "" "" h4 h5 |
| ASSERT_OK(src.CopyTo(sv, &dst, 3, 5, 3)); |
| |
| for (int i = 0; i < dst.nrows(); i++) { |
| string expected_val = i < 6 ? "" : Substitute("h$0", i - 2); |
| ASSERT_EQ(expected_val, dst[i].ToString()); |
| } |
| } |
| |
| TEST(TestColumnBlock, TestCopyToNulls) { |
| ScopedColumnBlock<UINT32> src(8); |
| ScopedColumnBlock<UINT32> dst(8); |
| |
| // Initialize idx 3 to null in both 'src' and 'dst'. |
| for (int i = 0; i < src.nrows(); i++) { |
| src.SetCellIsNull(i, i == 3); |
| if (i != 3) { |
| src[i] = i; |
| } |
| } |
| for (int i = 0; i < dst.nrows(); i++) { |
| dst.SetCellIsNull(i, i == 3); |
| if (i != 3) { |
| dst[i] = 100; |
| } |
| } |
| |
| SelectionVector sv(src.nrows()); |
| sv.SetAllTrue(); |
| |
| // src: 0 1 2 null 4 5 6 7 |
| // dst: 100 100 100 null 100 100 100 100 |
| // -------------------------------------- |
| // dst: 100 100 100 null 100 null 4 5 |
| ASSERT_OK(src.CopyTo(sv, &dst, 3, 5, 3)); |
| |
| for (int i = 0; i < dst.nrows(); i++) { |
| SCOPED_TRACE(i); |
| if (i == 3 || i == 5) { |
| ASSERT_TRUE(dst.is_null(i)); |
| } else { |
| ASSERT_FALSE(dst.is_null(i)); |
| int expected_val = i < 6 ? 100 : i - 2; |
| ASSERT_EQ(expected_val, dst[i]); |
| } |
| } |
| } |
| |
| } // namespace kudu |