This is an automated email from the ASF dual-hosted git repository.

alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new 0345190  KUDU-2671 allow a range to have empty hash schema
0345190 is described below

commit 03451904a20123ca27eaa4e9773b94c0532fd342
Author: Alexey Serbin <[email protected]>
AuthorDate: Mon Aug 30 22:03:23 2021 -0700

    KUDU-2671 allow a range to have empty hash schema
    
    With this patch, the semantics of an empty hash schema for a range
    changes.  Now an empty per-range hash schema means no hash bucketing for
    the range.  Prior to this patch, an empty hash schema for a range meant
    using the table-wide hash schema.
    
    The new semantics are better because:
      * they allow for having ranges with no hash bucketing even if there is
        a non-trivial hash bucketing at the table-wide level
      * they are less surprising to a user of the client API
    
    This patch updates several test cases to account for the change and
    adds a new test case to cover the new functionality.
    
    Change-Id: Ia43df69ecd7040e285e098fde49d84a7a00d1fbb
    Reviewed-on: http://gerrit.cloudera.org:8080/17825
    Tested-by: Kudu Jenkins
    Reviewed-by: Andrew Wong <[email protected]>
    Reviewed-by: Mahesh Reddy <[email protected]>
---
 src/kudu/client/client.cc                          |   8 +-
 src/kudu/client/client.h                           |  25 +-
 src/kudu/client/flex_partitioning_client-test.cc   |  61 +++-
 src/kudu/client/table_creator-internal.cc          |   3 +-
 src/kudu/client/table_creator-internal.h           |   1 +
 src/kudu/common/partition-test.cc                  |  67 ++---
 src/kudu/common/partition.cc                       |  50 ++--
 src/kudu/common/partition_pruner-test.cc           | 316 ++++++++++-----------
 src/kudu/common/partition_pruner.cc                |   3 +-
 .../integration-tests/table_locations-itest.cc     |   5 +-
 10 files changed, 271 insertions(+), 268 deletions(-)

diff --git a/src/kudu/client/client.cc b/src/kudu/client/client.cc
index a6c12d0..1ed91fa 100644
--- a/src/kudu/client/client.cc
+++ b/src/kudu/client/client.cc
@@ -879,8 +879,12 @@ KuduTableCreator& KuduTableCreator::add_range_partition(
     KuduPartialRow* upper_bound,
     RangePartitionBound lower_bound_type,
     RangePartitionBound upper_bound_type) {
-  data_->range_partitions_.emplace_back(new KuduRangePartition(
+  unique_ptr<KuduRangePartition> range_partition(new KuduRangePartition(
       lower_bound, upper_bound, lower_bound_type, upper_bound_type));
+  // Using KuduTableCreator::add_range_partition() assumes the range partition
+  // uses the table-wide schema.
+  range_partition->data_->is_table_wide_hash_schema_ = true;
+  data_->range_partitions_.emplace_back(std::move(range_partition));
   return *this;
 }
 
@@ -1006,7 +1010,7 @@ Status KuduTableCreator::Create() {
       RowOperationsPBEncoder encoder(range_pb->mutable_range_bounds());
       encoder.Add(lower_bound_type, *range->lower_bound_);
       encoder.Add(upper_bound_type, *range->upper_bound_);
-      if (range->hash_schema_.empty()) {
+      if (range->is_table_wide_hash_schema_) {
         // With the presence of a range with custom hash schema when the
         // table-wide hash schema is used for this particular range, also add 
an
         // element into PartitionSchemaPB::custom_hash_schema_ranges to satisfy
diff --git a/src/kudu/client/client.h b/src/kudu/client/client.h
index 4e51a9e..ea7638b 100644
--- a/src/kudu/client/client.h
+++ b/src/kudu/client/client.h
@@ -1216,7 +1216,7 @@ class KUDU_EXPORT KuduTableCreator {
   /// A helper class to represent a Kudu range partition with a custom hash
   /// bucket schema. The hash sub-partitioning for a range partition might be
   /// different from the default table-wide hash bucket schema specified during
-  /// a table's creation (see KuduTableCreator::add_hash_partitions()).
+  /// the creation of a table (see KuduTableCreator::add_hash_partitions()).
   /// Correspondingly, this class provides a means to specify a custom hash
   /// bucket structure for the data in a range partition.
   class KuduRangePartition {
@@ -1242,13 +1242,16 @@ class KUDU_EXPORT KuduTableCreator {
 
     ~KuduRangePartition();
 
-    /// Add an extra level of hash partitioning for this range partition.
+    /// Add a level of hash sub-partitioning for this range partition.
     ///
-    /// The newly added hash partitioning level is defined by its hash bucket
-    /// schema. The hash bucket schema is specified by the parameters of this
-    /// method. A range partition can have multiple levels of hash 
partitioning,
-    /// i.e. this method can be called multiple times to establish a
-    /// multi-dimensional hash bucket structure for the range partition.
+    /// The hash schema for the range partition is defined by the whole set of
+    /// its hash sub-partitioning levels. A range partition can have multiple
+    /// levels of hash sub-partitioning: this method can be called multiple
+    /// times to define a multi-dimensional hash bucketing structure for the
+    /// range. Alternatively, a range partition can have zero levels of hash
+    /// sub-partitioning: simply don't call this method on a newly created
+    /// @c KuduRangePartition object to have no hash sub-partitioning for the
+    /// range represented by the object.
     ///
     /// @param [in] columns
     ///   Names of columns to use for partitioning.
@@ -1306,7 +1309,13 @@ class KUDU_EXPORT KuduTableCreator {
   /// Add a range partition with a custom hash bucket schema.
   ///
   /// This method allows adding a range partition which has hash partitioning
-  /// schema different from the schema used for a range partition.
+  /// schema different from the table-wide one.
+  ///
+  /// @li When called with a @c KuduRangePartition for which
+  ///   @c KuduRangePartition::add_hash_partitions() hasn't been called,
+  ///   a range with no hash sub-partitioning is created.
+  /// @li To create a range with the table-wide hash schema, use
+  ///   @c KuduTableCreator::add_range_partition() instead.
   ///
   /// @warning This functionality isn't fully implemented yet.
   ///
diff --git a/src/kudu/client/flex_partitioning_client-test.cc 
b/src/kudu/client/flex_partitioning_client-test.cc
index a2ab310..cc00baa 100644
--- a/src/kudu/client/flex_partitioning_client-test.cc
+++ b/src/kudu/client/flex_partitioning_client-test.cc
@@ -270,7 +270,7 @@ class FlexPartitioningCreateTableTest : public 
FlexPartitioningTest {};
 // TODO(aserbin): add verification based on PartitionSchema provided by
 //                KuduTable::partition_schema() once PartitionPruner
 //                recognized custom hash bucket schema for ranges
-TEST_F(FlexPartitioningCreateTableTest, CustomHashBuckets) {
+TEST_F(FlexPartitioningCreateTableTest, CustomHashSchema) {
   // One-level hash bucket structure: { 3, "key" }.
   {
     constexpr const char* const kTableName = "3@key";
@@ -285,14 +285,14 @@ TEST_F(FlexPartitioningCreateTableTest, 
CustomHashBuckets) {
   }
 }
 
-TEST_F(FlexPartitioningCreateTableTest, TableWideHashBuckets) {
+TEST_F(FlexPartitioningCreateTableTest, TableWideHashSchema) {
   // Create a table with the following partitions:
   //
   //            hash bucket
   //   key    0           1
   //         -------------------------
   //  <111    x:{key}     x:{key}
-  constexpr const char* const kTableName = "TableWideHashBuckets";
+  constexpr const char* const kTableName = "TableWideHashSchema";
 
   unique_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
   table_creator->table_name(kTableName)
@@ -316,6 +316,38 @@ TEST_F(FlexPartitioningCreateTableTest, 
TableWideHashBuckets) {
   NO_FATALS(CheckTableRowsNum(kTableName, 222));
 }
 
+TEST_F(FlexPartitioningCreateTableTest, EmptyTableWideHashSchema) {
+  constexpr const char* const kTableName = "EmptyTableWideHashSchema";
+
+  unique_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
+  table_creator->table_name(kTableName)
+      .schema(&schema_)
+      .num_replicas(1)
+      .set_range_partition_columns({ kKeyColumn });
+
+  // Add a range partition with the table-wide hash partitioning rules: no hash
+  // bucketing at all.
+  {
+    unique_ptr<KuduPartialRow> lower(schema_.NewRow());
+    ASSERT_OK(lower->SetInt32(kKeyColumn, INT32_MIN));
+    unique_ptr<KuduPartialRow> upper(schema_.NewRow());
+    ASSERT_OK(upper->SetInt32(kKeyColumn, 111));
+    table_creator->add_range_partition(lower.release(), upper.release());
+  }
+
+  // Add a custom range: no hash bucketing as well.
+  {
+    auto p = CreateRangePartition(111, 222);
+    table_creator->add_custom_range_partition(p.release());
+  }
+
+  ASSERT_OK(table_creator->Create());
+  // There should be 2 tablets total: one per each range created.
+  NO_FATALS(CheckTabletCount(kTableName, 2));
+  ASSERT_OK(InsertTestRows(kTableName, -111, 222, KuduSession::MANUAL_FLUSH));
+  NO_FATALS(CheckTableRowsNum(kTableName, 333));
+}
+
 // Create a table with mixed set of range partitions, using both table-wide and
 // custom hash bucket schemas.
 //
@@ -323,7 +355,7 @@ TEST_F(FlexPartitioningCreateTableTest, 
TableWideHashBuckets) {
 //                KuduTable::partition_schema() once PartitionPruner
 //                recognized custom hash bucket schema for ranges
 // TODO(aserbin): add InsertTestRows() when proper key encoding is implemented
-TEST_F(FlexPartitioningCreateTableTest, DefaultAndCustomHashBuckets) {
+TEST_F(FlexPartitioningCreateTableTest, DefaultAndCustomHashSchemas) {
   // Create a table with the following partitions:
   //
   //            hash bucket
@@ -333,8 +365,8 @@ TEST_F(FlexPartitioningCreateTableTest, 
DefaultAndCustomHashBuckets) {
   // 111-222  x:{key}     x:{key}     x:{key}         -
   // 222-333  x:{key}     x:{key}     x:{key}     x:{key}
   // 333-444  x:{key}     x:{key}     -               -
-  // 444-555  x:{key}     x:{key}     -               -
-  constexpr const char* const kTableName = "DefaultAndCustomHashBuckets";
+  // 444-555  -           -           -               -
+  constexpr const char* const kTableName = "DefaultAndCustomHashSchemas";
 
   unique_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
   table_creator->table_name(kTableName)
@@ -376,18 +408,21 @@ TEST_F(FlexPartitioningCreateTableTest, 
DefaultAndCustomHashBuckets) {
     table_creator->add_custom_range_partition(p.release());
   }
 
-  // Add a range partition with table-wide hash schema: not calling
-  // KuduRangePartition::add_hash_partition() means the range is using the
-  // table-wide schema.
-  //
-  // TODO(aserbin): update this once empty range schema means no hash bucketing
+  // Add a range partition with no hash bucketing. The table-wide hash schema
+  // established by the KuduTableCreator::add_hash_partition() call in the
+  // beginning of the scenario defines hash bucketing for ranges added by the
+  // KuduTableCreator::add_range_partition() method, but here the newly created
+  // range is added via the KuduTableCreator::add_custom_range_partition() 
call,
+  // so the new range has custom hash schema. Not calling
+  // KuduRangePartition::add_hash_partitions() on the newly created range means
+  // the range doesn't have any hash bucketing.
   {
     auto p = CreateRangePartition(444, 555);
     table_creator->add_custom_range_partition(p.release());
   }
 
   ASSERT_OK(table_creator->Create());
-  NO_FATALS(CheckTabletCount(kTableName, 13));
+  NO_FATALS(CheckTabletCount(kTableName, 12));
 
   // Make sure it's possible to insert rows into the table for all the existing
   // the paritions: first check the range of table-wide schema, then check
@@ -395,10 +430,8 @@ TEST_F(FlexPartitioningCreateTableTest, 
DefaultAndCustomHashBuckets) {
   // TODO(aserbin): uncomment CheckTableRowsNum() once partition pruning works
   ASSERT_OK(InsertTestRows(kTableName, -111, 0));
   NO_FATALS(CheckLiveRowCount(kTableName, 111));
-  //NO_FATALS(CheckTableRowsNum(kTableName, 222));
   ASSERT_OK(InsertTestRows(kTableName, 111, 555));
   NO_FATALS(CheckLiveRowCount(kTableName, 555));
-  //NO_FATALS(CheckTableRowsNum(kTableName, 555));
 
   // Meanwhile, inserting into non-covered ranges should result in a proper
   // error status return to the client attempting such an operation.
diff --git a/src/kudu/client/table_creator-internal.cc 
b/src/kudu/client/table_creator-internal.cc
index 3d64b27..85757af 100644
--- a/src/kudu/client/table_creator-internal.cc
+++ b/src/kudu/client/table_creator-internal.cc
@@ -40,7 +40,8 @@ KuduTableCreator::KuduRangePartition::Data::Data(
     : lower_bound_type_(lower_bound_type),
       upper_bound_type_(upper_bound_type),
       lower_bound_(lower_bound),
-      upper_bound_(upper_bound) {
+      upper_bound_(upper_bound),
+      is_table_wide_hash_schema_(false) {
 }
 
 Status KuduTableCreator::KuduRangePartition::Data::add_hash_partitions(
diff --git a/src/kudu/client/table_creator-internal.h 
b/src/kudu/client/table_creator-internal.h
index 23a5c25..590e105 100644
--- a/src/kudu/client/table_creator-internal.h
+++ b/src/kudu/client/table_creator-internal.h
@@ -110,6 +110,7 @@ class KuduTableCreator::KuduRangePartition::Data {
   std::unique_ptr<KuduPartialRow> upper_bound_;
 
   HashSchema hash_schema_;
+  bool is_table_wide_hash_schema_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Data);
diff --git a/src/kudu/common/partition-test.cc 
b/src/kudu/common/partition-test.cc
index abe779e..41ddaa9 100644
--- a/src/kudu/common/partition-test.cc
+++ b/src/kudu/common/partition-test.cc
@@ -923,9 +923,10 @@ TEST_F(PartitionTest, TestVaryingHashSchemasPerRange) {
     ASSERT_OK(upper.SetStringCopy("a", "a4"));
     ASSERT_OK(upper.SetStringCopy("b", "b4"));
     bounds.emplace_back(lower, upper);
-    range_hash_schemas.emplace_back(PartitionSchema::HashSchema());
+    range_hash_schemas.emplace_back(partition_schema.hash_schema());
+    // Use the table-wide hash schema for this range.
     bounds_with_hash_schemas.emplace_back(make_pair(std::move(lower), 
std::move(upper)),
-                                          PartitionSchema::HashSchema());
+                                          partition_schema.hash_schema());
   }
 
   { // [(a5, b5, _), (a6, _, c6))
@@ -1283,7 +1284,7 @@ TEST_F(PartitionTest, 
TestVaryingHashSchemasPerUnboundedRanges) {
 
   vector<Partition> partitions;
   ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas, 
schema, &partitions));
-  ASSERT_EQ(12, partitions.size());
+  ASSERT_EQ(11, partitions.size());
   // Partitions below sorted by range, can verify that the partition keyspace 
is filled by checking
   // that the start key of the first partition and the end key of the last 
partition is cleared.
 
@@ -1315,67 +1316,55 @@ TEST_F(PartitionTest, 
TestVaryingHashSchemasPerUnboundedRanges) {
   EXPECT_EQ(string("\0\0\0\3", 4), partitions[3].partition_key_start());
   EXPECT_EQ(string("\0\0\0\3" "a1\0\0\0\0c1", 12), 
partitions[3].partition_key_end());
 
-  ASSERT_EQ(1, partitions[4].hash_buckets().size());
-  EXPECT_EQ(0, partitions[4].hash_buckets()[0]);
-  EXPECT_EQ(string("a2\0\0b2\0\0", 8), partitions[4].range_key_start());
-  EXPECT_EQ(string("a3\0\0b3\0\0", 8), partitions[4].range_key_end());
-  EXPECT_EQ(string("\0\0\0\0" "a2\0\0b2\0\0", 12), 
partitions[4].partition_key_start());
-  EXPECT_EQ(string("\0\0\0\0" "a3\0\0b3\0\0", 12), 
partitions[4].partition_key_end());
+  ASSERT_EQ(0, partitions[4].hash_buckets().size());
 
-  ASSERT_EQ(1, partitions[5].hash_buckets().size());
-  EXPECT_EQ(1, partitions[5].hash_buckets()[0]);
-  EXPECT_EQ(string("a2\0\0b2\0\0", 8), partitions[5].range_key_start());
-  EXPECT_EQ(string("a3\0\0b3\0\0", 8), partitions[5].range_key_end());
-  EXPECT_EQ(string("\0\0\0\1" "a2\0\0b2\0\0", 12), 
partitions[5].partition_key_start());
-  EXPECT_EQ(string("\0\0\0\1" "a3\0\0b3\0\0", 12), 
partitions[5].partition_key_end());
+  ASSERT_EQ(2, partitions[5].hash_buckets().size());
+  EXPECT_EQ(0, partitions[5].hash_buckets()[0]);
+  EXPECT_EQ(0, partitions[5].hash_buckets()[1]);
+  EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[5].range_key_start());
+  EXPECT_EQ("", partitions[5].range_key_end());
+  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a4\0\0b4\0\0", 16), 
partitions[5].partition_key_start());
+  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1", 8), 
partitions[5].partition_key_end());
 
   ASSERT_EQ(2, partitions[6].hash_buckets().size());
   EXPECT_EQ(0, partitions[6].hash_buckets()[0]);
-  EXPECT_EQ(0, partitions[6].hash_buckets()[1]);
+  EXPECT_EQ(1, partitions[6].hash_buckets()[1]);
   EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[6].range_key_start());
   EXPECT_EQ("", partitions[6].range_key_end());
-  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a4\0\0b4\0\0", 16), 
partitions[6].partition_key_start());
-  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1", 8), 
partitions[6].partition_key_end());
+  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1" "a4\0\0b4\0\0", 
16),partitions[6].partition_key_start());
+  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2", 8), 
partitions[6].partition_key_end());
 
   ASSERT_EQ(2, partitions[7].hash_buckets().size());
   EXPECT_EQ(0, partitions[7].hash_buckets()[0]);
-  EXPECT_EQ(1, partitions[7].hash_buckets()[1]);
+  EXPECT_EQ(2, partitions[7].hash_buckets()[1]);
   EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[7].range_key_start());
   EXPECT_EQ("", partitions[7].range_key_end());
-  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1" "a4\0\0b4\0\0", 
16),partitions[7].partition_key_start());
-  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2", 8), 
partitions[7].partition_key_end());
+  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2" "a4\0\0b4\0\0", 16), 
partitions[7].partition_key_start());
+  EXPECT_EQ(string("\0\0\0\1", 4), partitions[7].partition_key_end());
 
   ASSERT_EQ(2, partitions[8].hash_buckets().size());
-  EXPECT_EQ(0, partitions[8].hash_buckets()[0]);
-  EXPECT_EQ(2, partitions[8].hash_buckets()[1]);
+  EXPECT_EQ(1, partitions[8].hash_buckets()[0]);
+  EXPECT_EQ(0, partitions[8].hash_buckets()[1]);
   EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[8].range_key_start());
   EXPECT_EQ("", partitions[8].range_key_end());
-  EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2" "a4\0\0b4\0\0", 16), 
partitions[8].partition_key_start());
-  EXPECT_EQ(string("\0\0\0\1", 4), partitions[8].partition_key_end());
+  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a4\0\0b4\0\0", 16), 
partitions[8].partition_key_start());
+  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1", 8), 
partitions[8].partition_key_end());
 
   ASSERT_EQ(2, partitions[9].hash_buckets().size());
   EXPECT_EQ(1, partitions[9].hash_buckets()[0]);
-  EXPECT_EQ(0, partitions[9].hash_buckets()[1]);
+  EXPECT_EQ(1, partitions[9].hash_buckets()[1]);
   EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[9].range_key_start());
   EXPECT_EQ("", partitions[9].range_key_end());
-  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a4\0\0b4\0\0", 16), 
partitions[9].partition_key_start());
-  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1", 8), 
partitions[9].partition_key_end());
+  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a4\0\0b4\0\0", 
16),partitions[9].partition_key_start());
+  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2", 8), 
partitions[9].partition_key_end());
 
   ASSERT_EQ(2, partitions[10].hash_buckets().size());
   EXPECT_EQ(1, partitions[10].hash_buckets()[0]);
-  EXPECT_EQ(1, partitions[10].hash_buckets()[1]);
+  EXPECT_EQ(2, partitions[10].hash_buckets()[1]);
   EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[10].range_key_start());
   EXPECT_EQ("", partitions[10].range_key_end());
-  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a4\0\0b4\0\0", 
16),partitions[10].partition_key_start());
-  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2", 8), 
partitions[10].partition_key_end());
-
-  ASSERT_EQ(2, partitions[10].hash_buckets().size());
-  EXPECT_EQ(1, partitions[11].hash_buckets()[0]);
-  EXPECT_EQ(2, partitions[11].hash_buckets()[1]);
-  EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[11].range_key_start());
-  EXPECT_EQ("", partitions[11].range_key_end());
-  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2" "a4\0\0b4\0\0", 16), 
partitions[11].partition_key_start());
-  EXPECT_EQ("", partitions[11].partition_key_end());
+  EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2" "a4\0\0b4\0\0", 16), 
partitions[10].partition_key_start());
+  EXPECT_EQ("", partitions[10].partition_key_end());
 }
 
 TEST_F(PartitionTest, TestPartitionSchemaPB) {
diff --git a/src/kudu/common/partition.cc b/src/kudu/common/partition.cc
index c01fbcf..1925b87 100644
--- a/src/kudu/common/partition.cc
+++ b/src/kudu/common/partition.cc
@@ -555,11 +555,6 @@ Status PartitionSchema::CreatePartitions(
   RETURN_NOT_OK(EncodeRangeSplits(split_rows, schema, &splits));
   RETURN_NOT_OK(SplitRangeBounds(schema, splits, &bounds_with_hash_schemas));
 
-  // Maps each partition to its respective hash schemas within 
'bounds_with_hash_schemas',
-  // needed for logic later in function for filling in holes in partition key 
space. Will be
-  // empty if no per range hash schemas are used.
-  vector<int> partition_idx_to_hash_schema_idx;
-
   // Even if no hash partitioning for a table is specified, there must be at
   // least one element in 'base_hash_partitions': it's used to build the result
   // set of range partitions.
@@ -568,6 +563,12 @@ Status PartitionSchema::CreatePartitions(
   DCHECK(base_hash_partitions.size() > 1 ||
          base_hash_partitions.front().hash_buckets().empty());
 
+  // Maps each partition to its respective hash schema within
+  // 'bounds_with_hash_schemas', needed for the logic later in this method
+  // for filling in holes in partition key space. The container is empty if no
+  // per-range hash schemas are present.
+  vector<size_t> partition_idx_to_hash_schema_idx;
+
   if (range_hash_schemas.empty()) {
     // Create a partition per range bound and hash bucket combination.
     vector<Partition> new_partitions;
@@ -587,23 +588,15 @@ Status PartitionSchema::CreatePartitions(
     DCHECK(split_rows.empty());
     vector<Partition> result_partitions;
     // Iterate through each bound and its hash schemas to generate hash 
partitions.
-    for (int i = 0; i < bounds_with_hash_schemas.size(); ++i) {
+    for (size_t i = 0; i < bounds_with_hash_schemas.size(); ++i) {
       const auto& bound = bounds_with_hash_schemas[i];
-      const auto& current_range_hash_schema = bound.hash_schema;
-      // If current bound's HashSchema is empty, implies use of default
-      // table-wide schema. If not empty, generate hash partitions for all the
-      // provided hash schemas in this range.
-      vector<Partition> current_bound_hash_partitions =
-          current_range_hash_schema.empty() ? base_hash_partitions
-                                            : GenerateHashPartitions(
-                                                   current_range_hash_schema,
-                                                   hash_encoder);
+      vector<Partition> current_bound_hash_partitions = GenerateHashPartitions(
+          bound.hash_schema, hash_encoder);
       // Add range information to the partition key.
       for (Partition& partition : current_bound_hash_partitions) {
         partition.partition_key_start_.append(bound.lower);
         partition.partition_key_end_.append(bound.upper);
-        int index = current_range_hash_schema.empty() ? -1 : i;
-        partition_idx_to_hash_schema_idx.emplace_back(index);
+        partition_idx_to_hash_schema_idx.emplace_back(i);
       }
       result_partitions.insert(result_partitions.end(),
                                
std::make_move_iterator(current_bound_hash_partitions.begin()),
@@ -630,13 +623,13 @@ Status PartitionSchema::CreatePartitions(
   // the absolute start and end case, these holes are filled by clearing the
   // partition key beginning at the hash component. For a concrete example,
   // see PartitionTest::TestCreatePartitions.
-  const HashDimension* hash_dimension;
-  for (int j = 0; j < partitions->size(); j++) {
-    Partition& partition = (*partitions)[j];
+  for (size_t partition_idx = 0; partition_idx < partitions->size(); 
++partition_idx) {
+    Partition& partition = (*partitions)[partition_idx];
+    const int hash_buckets_num = 
static_cast<int>(partition.hash_buckets().size());
     // Find the first zero-valued bucket from the end and truncate the 
partition key
     // starting from that bucket onwards for zero-valued buckets.
     if (partition.range_key_start().empty()) {
-      for (int i = static_cast<int>(partition.hash_buckets().size()) - 1; i >= 
0; i--) {
+      for (int i = hash_buckets_num - 1; i >= 0; --i) {
         if (partition.hash_buckets()[i] != 0) {
           break;
         }
@@ -653,16 +646,13 @@ Status PartitionSchema::CreatePartitions(
     // [ (1, 0, "a2b2") -> (1, 1, "a2b2") ]
     // [ (1, 1, "a2b2") -> (_, _, "a2b2") ]
     if (partition.range_key_end().empty()) {
-      for (int i = static_cast<int>(partition.hash_buckets().size()) - 1; i >= 
0; i--) {
+      const auto& hash_schema = range_hash_schemas.empty()
+          ? hash_schema_
+          : 
bounds_with_hash_schemas[partition_idx_to_hash_schema_idx[partition_idx]].hash_schema;
+      for (int i = hash_buckets_num - 1; i >= 0; --i) {
         partition.partition_key_end_.erase(kEncodedBucketSize * i);
-        int32_t hash_bucket = partition.hash_buckets()[i] + 1;
-        if (range_hash_schemas.empty() || partition_idx_to_hash_schema_idx[j] 
== -1) {
-          hash_dimension = &hash_schema_[i];
-        } else {
-          const auto& hash_schemas_idx = partition_idx_to_hash_schema_idx[j];
-          hash_dimension = 
&bounds_with_hash_schemas[hash_schemas_idx].hash_schema[i];
-        }
-        if (hash_bucket != hash_dimension->num_buckets) {
+        const int32_t hash_bucket = partition.hash_buckets()[i] + 1;
+        if (hash_bucket != hash_schema[i].num_buckets) {
           hash_encoder.Encode(&hash_bucket, &partition.partition_key_end_);
           break;
         }
diff --git a/src/kudu/common/partition_pruner-test.cc 
b/src/kudu/common/partition_pruner-test.cc
index 95bb56a..3d7a9e7 100644
--- a/src/kudu/common/partition_pruner-test.cc
+++ b/src/kudu/common/partition_pruner-test.cc
@@ -1111,172 +1111,161 @@ TEST_F(PartitionPrunerTest, 
TestHashSchemasPerRangePruning) {
                 { ColumnId(0), ColumnId(1), ColumnId(2) },
                 3);
 
-  PartitionSchema partition_schema;
-  auto pb = PartitionSchemaPB();
+  PartitionSchemaPB pb;
   CreatePartitionSchemaPB({"C"}, { {{"A"}, 2, 0}, {{"B"}, 2, 0} }, &pb);
 
   vector<pair<KuduPartialRow, KuduPartialRow>> bounds;
   vector<PartitionSchema::HashSchema> range_hash_schemas;
 
-  // Need to add per range hash schema components to the field 
'range_with_hash_schemas_'
-  // of PartitionSchema because PartitionPruner will use them to construct 
partition key ranges.
-  // Currently, PartitionSchema::CreatePartitions() does not leverage this 
field
-  // so these components will have to be passed separately to the function as 
well.
+  // Need to add per range hash schema components to the field
+  // 'ranges_with_hash_schemas_' of PartitionSchema because PartitionPruner 
will
+  // use them to construct partition key ranges. Currently,
+  // PartitionSchema::CreatePartitions() does not leverage this field, so these
+  // components will have to be passed separately to the function as well.
 
-  // [(_, _, a), (_, _, c))
-  {
-    AddRangePartitionWithSchema(schema, {{"C", "a"}}, {{"C", "c"}}, {}, {},
-                                { {{"A"}, 3, 0} }, &bounds, 
&range_hash_schemas, &pb);
-  }
+  // None of the ranges below uses the table-wide hash schema.
 
+  // [(_, _, a), (_, _, c))
+  AddRangePartitionWithSchema(schema, {{"C", "a"}}, {{"C", "c"}}, {}, {},
+                              { {{"A"}, 3, 0} }, &bounds, &range_hash_schemas, 
&pb);
   // [(_, _, d), (_, _, f))
-  {
-    AddRangePartitionWithSchema(schema, {{"C", "d"}}, {{"C", "f"}}, {}, {},
-                                { {{"A"}, 2, 0}, {{"B"}, 3, 0} },
-                                &bounds, &range_hash_schemas, &pb);
-  }
-
+  AddRangePartitionWithSchema(schema, {{"C", "d"}}, {{"C", "f"}}, {}, {},
+                              { {{"A"}, 2, 0}, {{"B"}, 3, 0} },
+                              &bounds, &range_hash_schemas, &pb);
   // [(_, _, h), (_, _, j))
-  {
-    AddRangePartitionWithSchema(schema, {{"C", "h"}}, {{"C", "j"}}, {}, {},
-                                {}, &bounds, &range_hash_schemas, &pb);
-  }
-
+  AddRangePartitionWithSchema(schema, {{"C", "h"}}, {{"C", "j"}}, {}, {},
+                              {}, &bounds, &range_hash_schemas, &pb);
   // [(_, _, k), (_, _, m))
-  {
-    AddRangePartitionWithSchema(schema, {{"C", "k"}}, {{"C", "m"}}, {}, {},
-                                { {{"B"}, 2, 0} }, &bounds, 
&range_hash_schemas, &pb);
-
-  }
+  AddRangePartitionWithSchema(schema, {{"C", "k"}}, {{"C", "m"}}, {}, {},
+                              { {{"B"}, 2, 0} }, &bounds, &range_hash_schemas, 
&pb);
 
+  PartitionSchema partition_schema;
   ASSERT_OK(PartitionSchema::FromPB(pb, schema, &partition_schema));
 
   vector<Partition> partitions;
   ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas, 
schema, &partitions));
-
-  ASSERT_EQ(15, partitions.size());
+  ASSERT_EQ(12, partitions.size());
 
   // Applies the specified predicates to a scan and checks that the expected
   // number of partitions are pruned.
   const auto check = [&] (const vector<ColumnPredicate>& predicates,
-                    const string& lower_bound_partition_key,
-                    const string& upper_bound_partition_key,
-                    size_t remaining_tablets,
-                    size_t pruner_ranges) {
+                          const string& lower_bound_partition_key,
+                          const string& upper_bound_partition_key,
+                          size_t remaining_tablets,
+                          size_t pruner_ranges) {
     ScanSpec spec;
-
     spec.SetLowerBoundPartitionKey(lower_bound_partition_key);
     spec.SetExclusiveUpperBoundPartitionKey(upper_bound_partition_key);
     for (const auto& pred : predicates) {
       spec.AddPredicate(pred);
     }
-
-    NO_FATALS(CheckPrunedPartitions(schema, partition_schema, partitions, spec,
-                                    remaining_tablets, pruner_ranges));
+    CheckPrunedPartitions(schema, partition_schema, partitions, spec,
+                          remaining_tablets, pruner_ranges);
   };
 
   constexpr int8_t zero = 0;
   constexpr int8_t one = 1;
 
-  Slice a = "a";
-  Slice b = "b";
-  Slice e = "e";
-  Slice f = "f";
-  Slice i = "i";
-  Slice l = "l";
-  Slice m = "m";
+  const Slice a = "a";
+  const Slice b = "b";
+  const Slice e = "e";
+  const Slice f = "f";
+  const Slice i = "i";
+  const Slice l = "l";
+  const Slice m = "m";
 
   // No Bounds
-  check({}, "", "", 15, 15);
+  NO_FATALS(check({}, "", "", 12, 12));
 
   // A = 1
-  check({ ColumnPredicate::Equality(schema.column(0), &one)}, "", "", 8, 8);
-
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(0), &one) },
+                  "", "", 7, 7));
   // B = 1
-  check({ ColumnPredicate::Equality(schema.column(1), &one)}, "", "", 8, 8);
-
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &one) },
+                  "", "", 7, 7));
   // A = 0
   // B = 1
   // C >= "e"
-  check({ ColumnPredicate::Equality(schema.column(0), &zero),
-          ColumnPredicate::Equality(schema.column(1), &one),
-          ColumnPredicate::Range(schema.column(2), &e, nullptr)}, "", "", 3, 
3);
-
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(0), &zero),
+                    ColumnPredicate::Equality(schema.column(1), &one),
+                    ColumnPredicate::Range(schema.column(2), &e, nullptr) },
+                  "", "", 3, 3));
   // A = 0
   // B = 1
   // C = "e"
-  check({ ColumnPredicate::Equality(schema.column(0), &zero),
-          ColumnPredicate::Equality(schema.column(1), &one),
-          ColumnPredicate::Equality(schema.column(2), &e)}, "", "", 1, 1);
-
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(0), &zero),
+                    ColumnPredicate::Equality(schema.column(1), &one),
+                    ColumnPredicate::Equality(schema.column(2), &e) },
+                  "", "", 1, 1));
   // B = 1
   // C >= "b"
   // C < "j"
-  check({ ColumnPredicate::Equality(schema.column(1), &one),
-          ColumnPredicate::Range(schema.column(2), &b, nullptr),
-          ColumnPredicate::Range(schema.column(2), nullptr, &i)}, "", "", 7, 
7);
-
-
-  // A = 0
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &one),
+                    ColumnPredicate::Range(schema.column(2), &b, nullptr),
+                    ColumnPredicate::Range(schema.column(2), nullptr, &i) },
+                  "", "", 6, 6));
+  // B = 0
   // C >= "e"
   // C < "l"
-  check({ ColumnPredicate::Equality(schema.column(1), &zero),
-          ColumnPredicate::Range(schema.column(2), &e, nullptr),
-          ColumnPredicate::Range(schema.column(2), nullptr, &l)}, "", "", 5, 
5);
-
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &zero),
+                    ColumnPredicate::Range(schema.column(2), &e, nullptr),
+                    ColumnPredicate::Range(schema.column(2), nullptr, &l) },
+                  "", "", 4, 4));
   // C >= "a"
   // C < "b"
-  check({ ColumnPredicate::Range(schema.column(2), &a, &b)}, "", "", 3, 3);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &a, &b) },
+                  "", "", 3, 3));
   // C >= "a"
   // C < "e"
-  check({ ColumnPredicate::Range(schema.column(2), &a, &e)}, "", "", 9, 9);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &a, &e) },
+                  "", "", 9, 9));
   // C >= "e"
   // C < "i"
-  check({ ColumnPredicate::Range(schema.column(2), &e, &i)}, "", "", 10, 10);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &e, &i) },
+                  "", "", 7, 7));
   // C >= "a"
   // C < "l"
-  check({ ColumnPredicate::Range(schema.column(2), &a, &l)}, "", "", 15, 15);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &a, &l) },
+                  "", "", 12, 12));
   // C >= "i"
   // C < "l"
-  check({ ColumnPredicate::Range(schema.column(2), &i, &l)}, "", "", 6, 6);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &i, &l) },
+                  "", "", 3, 3));
   // C >= "e"
-  check({ ColumnPredicate::Range(schema.column(2), &e, nullptr)}, "", "", 12, 
12);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &e, nullptr) },
+                  "", "", 9, 9));
   // C < "f"
-  check({ ColumnPredicate::Range(schema.column(2), nullptr, &f)}, "", "", 9, 
9);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), nullptr, &f) },
+                  "", "", 9, 9));
   // C >= "f"
-  check({ ColumnPredicate::Range(schema.column(2), &f, nullptr)}, "", "", 6, 
6);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &f, nullptr) },
+                  "", "", 3, 3));
   // C < "a"
-  check({ ColumnPredicate::Range(schema.column(2), nullptr, &a)}, "", "", 0, 
0);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), nullptr, &a) },
+                  "", "", 0, 0));
   // C >= "m"
-  check({ ColumnPredicate::Range(schema.column(2), &m, nullptr)}, "", "", 0, 
0);
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &m, nullptr) },
+                  "", "", 0, 0));
 
   // Uses None predicate to short circuit scan
-  check({ ColumnPredicate::None(schema.column(2))}, "", "", 0, 0);
+  NO_FATALS(check({ ColumnPredicate::None(schema.column(2))}, "", "", 0, 0));
 
   // partition key >= (hash=1, hash=0)
-  check({}, string("\0\0\0\1\0\0\0\0", 8), "", 8, 8);
+  NO_FATALS(check({}, string("\0\0\0\1\0\0\0\0", 8), "", 7, 7));
 
   // partition key < (hash=1, hash=0)
-  check({}, "", string("\0\0\0\1\0\0\0\0", 8), 7, 7);
+  NO_FATALS(check({}, "", string("\0\0\0\1\0\0\0\0", 8), 5, 5));
 
   // C >= "e"
   // C < "m"
   // partition key >= (hash=1)
-  check({ColumnPredicate::Range(schema.column(2), &e, &m)}, string("\0\0\0\1", 
4), "", 6, 6);
-
+  NO_FATALS(check({ColumnPredicate::Range(schema.column(2), &e, &m)},
+                  string("\0\0\0\1", 4), "", 5, 5));
   // C >= "e"
   // C < "m"
   // partition key < (hash=1)
-  check({ColumnPredicate::Range(schema.column(2), &e, &m)}, "", 
string("\0\0\0\1", 4), 6, 6);
+  NO_FATALS(check({ColumnPredicate::Range(schema.column(2), &e, &m)}, "",
+                  string("\0\0\0\1", 4), 4, 4));
 }
 
 TEST_F(PartitionPrunerTest, 
TestHashSchemasPerRangeWithPartialPrimaryKeyRangePruning) {
@@ -1407,37 +1396,32 @@ TEST_F(PartitionPrunerTest, 
TestInListHashPruningPerRange) {
                 { ColumnId(0), ColumnId(1), ColumnId(2) },
                 3);
 
-  PartitionSchema partition_schema;
-  auto pb = PartitionSchemaPB();
+  PartitionSchemaPB pb;
   CreatePartitionSchemaPB({"A"}, { {{"B", "C"}, 3, 0} }, &pb);
 
   vector<pair<KuduPartialRow, KuduPartialRow>> bounds;
   vector<PartitionSchema::HashSchema> range_hash_schemas;
 
-  // [(a, _, _), (c, _, _))
-  {
-    AddRangePartitionWithSchema(schema, {{"A", "a"}}, {{"A", "c"}}, {}, {},
-                                { {{"B"}, 3, 0} }, &bounds, 
&range_hash_schemas, &pb);
-  }
+  // None of the ranges below uses the table-wide hash schema.
 
+  // [(a, _, _), (c, _, _))
+  AddRangePartitionWithSchema(schema, {{"A", "a"}}, {{"A", "c"}}, {}, {},
+                              { {{"B"}, 3, 0} }, &bounds, &range_hash_schemas, 
&pb);
   // [(c, _, _), (e, _, _))
-  {
-    AddRangePartitionWithSchema(schema, {{"A", "c"}}, {{"A", "e"}}, {}, {},
-                                {}, &bounds, &range_hash_schemas, &pb);
-  }
-
+  AddRangePartitionWithSchema(schema, {{"A", "c"}}, {{"A", "e"}}, {}, {},
+                              {}, &bounds, &range_hash_schemas, &pb);
   // [(e, _, _), (g, _, _))
-  {
-    AddRangePartitionWithSchema(schema, {{"A", "e"}}, {{"A", "g"}}, {}, {},
-                                { {{"C"}, 3, 0} }, &bounds, 
&range_hash_schemas, &pb);
-  }
+  AddRangePartitionWithSchema(schema, {{"A", "e"}}, {{"A", "g"}}, {}, {},
+                              { {{"C"}, 3, 0} }, &bounds, &range_hash_schemas, 
&pb);
 
+  PartitionSchema partition_schema;
   ASSERT_OK(PartitionSchema::FromPB(pb, schema, &partition_schema));
 
   vector<Partition> partitions;
-  ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas, 
schema, &partitions));
+  ASSERT_OK(partition_schema.CreatePartitions(
+      {}, bounds, range_hash_schemas, schema, &partitions));
 
-  ASSERT_EQ(9, partitions.size());
+  ASSERT_EQ(7, partitions.size());
 
   // Applies the specified predicates to a scan and checks that the expected
   // number of partitions are pruned.
@@ -1445,13 +1429,11 @@ TEST_F(PartitionPrunerTest, 
TestInListHashPruningPerRange) {
                     size_t remaining_tablets,
                     size_t pruner_ranges) {
     ScanSpec spec;
-
     for (const auto& pred : predicates) {
       spec.AddPredicate(pred);
     }
-
-    NO_FATALS(CheckPrunedPartitions(schema, partition_schema, partitions, spec,
-                                    remaining_tablets, pruner_ranges));
+    CheckPrunedPartitions(schema, partition_schema, partitions, spec,
+                          remaining_tablets, pruner_ranges);
   };
 
   // zero, one, eight are in different buckets when bucket number is 3 and 
seed is 0.
@@ -1464,15 +1446,18 @@ TEST_F(PartitionPrunerTest, 
TestInListHashPruningPerRange) {
 
   // B in [0, 1, 8];
   B_values = { &zero, &one, &eight };
-  check({ ColumnPredicate::InList(schema.column(1), &B_values) }, 9, 9);
+  NO_FATALS(check({ ColumnPredicate::InList(schema.column(1), &B_values) },
+                  7, 7));
 
   // B in [0, 1];
   B_values = { &zero, &one };
-  check({ ColumnPredicate::InList(schema.column(1), &B_values) }, 8, 8);
+  NO_FATALS(check({ ColumnPredicate::InList(schema.column(1), &B_values) },
+                  6, 6));
 
   // C in [0, 1];
   C_values = { &zero, &one };
-  check({ ColumnPredicate::InList(schema.column(2), &C_values) }, 8, 8);
+  NO_FATALS(check({ ColumnPredicate::InList(schema.column(2), &C_values) },
+                  6, 6));
 
   // B in [0, 1], C in [0, 1]
   // (0, 0) in bucket 2
@@ -1481,65 +1466,56 @@ TEST_F(PartitionPrunerTest, 
TestInListHashPruningPerRange) {
   // (1, 1) in bucket 0
   B_values = { &zero, &one };
   C_values = { &zero, &one };
-  check({ ColumnPredicate::InList(schema.column(1), &B_values),
-          ColumnPredicate::InList(schema.column(2), &C_values) },
-        7,  7);
+  NO_FATALS(check({ ColumnPredicate::InList(schema.column(1), &B_values),
+                    ColumnPredicate::InList(schema.column(2), &C_values) },
+                  5,  5));
 
   // B = 0, C in [0, 1]
   C_values = { &zero, &one };
-  check({ ColumnPredicate::Equality(schema.column(1), &zero),
-          ColumnPredicate::InList(schema.column(2), &C_values) },
-        4, 4);
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &zero),
+                    ColumnPredicate::InList(schema.column(2), &C_values) },
+                  4, 4));
 
   // B = 1, C in [0, 1]
   C_values = { &zero, &one };
-  check({ ColumnPredicate::Equality(schema.column(1), &one),
-          ColumnPredicate::InList(schema.column(2), &C_values) },
-        5, 5);
+  NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &one),
+                    ColumnPredicate::InList(schema.column(2), &C_values) },
+                  4, 4));
 }
 
 TEST_F(PartitionPrunerTest, TestSingleRangeElementAndBoundaryCase) {
   // CREATE TABLE t
   // (A INT8, B STRING)
   // PRIMARY KEY (A, B)
-  // PARTITION BY RANGE (A)
-  // DISTRIBUTE BY HASH(B) INTO 2 BUCKETS;
+  // PARTITION BY RANGE (A);
   Schema schema({ ColumnSchema("A", INT8),
                   ColumnSchema("B", STRING) },
                 { ColumnId(0), ColumnId(1) },
                 2);
 
-  PartitionSchema partition_schema;
-  auto pb = PartitionSchemaPB();
-  CreatePartitionSchemaPB({"A"}, { {{"B"}, 2, 0} }, &pb);
+  PartitionSchemaPB pb;
+  CreatePartitionSchemaPB({"A"}, {}, &pb);
 
   vector<pair<KuduPartialRow, KuduPartialRow>> bounds;
   vector<PartitionSchema::HashSchema> range_hash_schemas;
 
   // [(0, _), (1, _))
-  {
-    AddRangePartitionWithSchema(schema, {}, {}, {{"A", 0}}, {{"A", 1}},
-                                {{{"B"}, 4, 0}}, &bounds, &range_hash_schemas, 
&pb);
-  }
-
+  AddRangePartitionWithSchema(schema, {}, {}, {{"A", 0}}, {{"A", 1}},
+                              {{{"B"}, 4, 0}}, &bounds, &range_hash_schemas, 
&pb);
   // [(1, _), (2, _))
-  {
-    AddRangePartitionWithSchema(schema, {}, {}, {{"A", 1}}, {{"A", 2}},
-                                {}, &bounds, &range_hash_schemas, &pb);
-  }
-
+  AddRangePartitionWithSchema(schema, {}, {}, {{"A", 1}}, {{"A", 2}},
+                              {}, &bounds, &range_hash_schemas, &pb);
   // [(2, _), (3, _))
-  {
-    AddRangePartitionWithSchema(schema, {}, {}, {{"A", 2}}, {{"A", 3}},
-                                { {{"B"}, 3, 0} }, &bounds, 
&range_hash_schemas, &pb);
-  }
+  AddRangePartitionWithSchema(schema, {}, {}, {{"A", 2}}, {{"A", 3}},
+                              { {{"B"}, 3, 0} }, &bounds, &range_hash_schemas, 
&pb);
 
+  PartitionSchema partition_schema;
   ASSERT_OK(PartitionSchema::FromPB(pb, schema, &partition_schema));
 
   vector<Partition> partitions;
   ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas, 
schema, &partitions));
 
-  ASSERT_EQ(9, partitions.size());
+  ASSERT_EQ(8, partitions.size());
 
   // Applies the specified predicates to a scan and checks that the expected
   // number of partitions are pruned.
@@ -1547,13 +1523,11 @@ TEST_F(PartitionPrunerTest, 
TestSingleRangeElementAndBoundaryCase) {
       size_t remaining_tablets,
       size_t pruner_ranges) {
     ScanSpec spec;
-
     for (const auto& pred : predicates) {
       spec.AddPredicate(pred);
     }
-
-    NO_FATALS(CheckPrunedPartitions(schema, partition_schema, partitions, spec,
-                                    remaining_tablets, pruner_ranges));
+    CheckPrunedPartitions(schema, partition_schema, partitions, spec,
+                          remaining_tablets, pruner_ranges);
   };
 
   constexpr int8_t zero = 0;
@@ -1562,39 +1536,41 @@ TEST_F(PartitionPrunerTest, 
TestSingleRangeElementAndBoundaryCase) {
   constexpr int8_t three = 3;
 
   // No Bounds
-  check({}, 9, 9);
+  NO_FATALS(check({}, 8, 8));
 
   // A >= 0
-  check({ ColumnPredicate::Range(schema.column(0), &zero, nullptr)}, 9, 9);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &zero, nullptr) },
+                  8, 8));
   // A >= 1
-  check({ ColumnPredicate::Range(schema.column(0), &one, nullptr)}, 5, 5);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &one, nullptr) },
+                  4, 4));
   // A < 1
-  check({ ColumnPredicate::Range(schema.column(0), nullptr, &one)}, 4, 4);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), nullptr, &one) },
+                  4, 4));
   // A >= 2
-  check({ ColumnPredicate::Range(schema.column(0), &two, nullptr)}, 3, 3);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &two, nullptr) },
+                  3, 3));
   // A < 2
-  check({ ColumnPredicate::Range(schema.column(0), nullptr, &two)}, 6, 6);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), nullptr, &two) },
+                  5, 5));
   // A < 3
-  check({ ColumnPredicate::Range(schema.column(0), nullptr, &three)}, 9, 9);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), nullptr, &three) 
},
+                  8, 8));
   // A >= 0
   // A < 2
-  check({ ColumnPredicate::Range(schema.column(0), &zero, &two)}, 6, 6);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &zero, &two) },
+                  5, 5));
   // A >= 1
   // A < 2
-  check({ ColumnPredicate::Range(schema.column(0), &one, &two)}, 2, 2);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &one, &two) },
+                  1, 1));
   // A >= 1
   // A < 3
-  check({ ColumnPredicate::Range(schema.column(0), &one, &three)}, 5, 5);
-
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &one, &three) },
+                  4, 4));
   // A >= 3
-  check({ ColumnPredicate::Range(schema.column(0), &three, nullptr)}, 0, 0);
+  NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &three, nullptr) 
},
+                  0, 0));
 }
+
 } // namespace kudu
diff --git a/src/kudu/common/partition_pruner.cc 
b/src/kudu/common/partition_pruner.cc
index 6549001..7a7e82f 100644
--- a/src/kudu/common/partition_pruner.cc
+++ b/src/kudu/common/partition_pruner.cc
@@ -440,8 +440,7 @@ void PartitionPruner::Init(const Schema& schema,
     vector<RangeBounds> range_bounds;
     vector<PartitionSchema::HashSchema> hash_schemas_per_range;
     for (const auto& range : partition_schema.ranges_with_hash_schemas_) {
-      const auto& hash_schema = range.hash_schema.empty() ?
-          partition_schema.hash_schema_ : range.hash_schema;
+      const auto& hash_schema = range.hash_schema;
       // Both lower and upper bounds are unbounded.
       if (scan_range_lower_bound.empty() && scan_range_upper_bound.empty()) {
         range_bounds.emplace_back(RangeBounds{range.lower, range.upper});
diff --git a/src/kudu/integration-tests/table_locations-itest.cc 
b/src/kudu/integration-tests/table_locations-itest.cc
index f1cafb9..5fe8ecd 100644
--- a/src/kudu/integration-tests/table_locations-itest.cc
+++ b/src/kudu/integration-tests/table_locations-itest.cc
@@ -487,9 +487,10 @@ TEST_F(TableLocationsTest, TestRangeSpecificHashing) {
   HashSchema hash_schema_6 = { { { "key" }, 6, 2 } };
   range_hash_schemas.emplace_back(hash_schema_6);
 
-  // Table-wide hash schema, applied to range by default if no per-range 
schema is specified.
+  // Use 5 bucket hash schema as the table-wide one.
   HashSchema table_hash_schema_5 = { { { "val" }, 5, 4 } };
-  range_hash_schemas.emplace_back();
+  // Apply table-wide hash schema applied to this range.
+  range_hash_schemas.emplace_back(table_hash_schema_5);
 
   ASSERT_OK(CreateTable(
       table_name, schema, {}, bounds, range_hash_schemas, 
table_hash_schema_5));

Reply via email to