You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by aw...@apache.org on 2019/08/20 04:32:55 UTC

[kudu] 02/02: [tools] Add table tools to delete column and alter column

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

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

commit dc3cbb795218b9b05da78f65249cbaf61395cc50
Author: zhangyifan27 <ch...@163.com>
AuthorDate: Thu Aug 1 12:04:30 2019 +0800

    [tools] Add table tools to delete column and alter column
    
    This patch supports to delete column and alter column for
    a table by command line tools.
    The 'delete_column' tool can be used as:
    - kudu table delete_column <master_addresses> <table_name> <column_name>
    The alter column tools can be used as:
    - kudu table column_set_default <master_addresses> <table_name> <column_name> <default_value>
      (<default_value> should be provided as a JSON array, e.g. [1] or ["foo"])
    - kudu table column_remove_default <master_addresses> <table_name> <column_name>
    - kudu table column_set_compression <master_addresses> <table_name> <column_name> <compression_type>
    - kudu table column_set_encoding <master_addresses> <table_name> <column_name> <encoding_type>
    - kudu table column_set_block_size <master_addresses> <table_name> <column_name> <block_size>
    
    Change-Id: I228340e46fe48ffc782c4c7346f890444b8c550f
    Reviewed-on: http://gerrit.cloudera.org:8080/13976
    Tested-by: Kudu Jenkins
    Reviewed-by: Adar Dembo <ad...@cloudera.com>
    Reviewed-by: Andrew Wong <aw...@cloudera.com>
    Reviewed-by: Yingchun Lai <40...@qq.com>
---
 src/kudu/client/schema.cc           |   9 ++
 src/kudu/client/schema.h            |   7 +
 src/kudu/tools/kudu-tool-test.cc    | 251 ++++++++++++++++++++++++++++++++-
 src/kudu/tools/tool_action_table.cc | 270 +++++++++++++++++++++++++++++++++++-
 4 files changed, 534 insertions(+), 3 deletions(-)

diff --git a/src/kudu/client/schema.cc b/src/kudu/client/schema.cc
index 78113fb..eaae666 100644
--- a/src/kudu/client/schema.cc
+++ b/src/kudu/client/schema.cc
@@ -718,6 +718,15 @@ KuduColumnSchema KuduSchema::Column(size_t idx) const {
                           attrs, type_attrs, col.comment());
 }
 
+bool KuduSchema::HasColumn(const std::string& col_name, KuduColumnSchema* col_schema) const {
+  int idx = schema_->find_column(col_name);
+  if (idx == Schema::kColumnNotFound) {
+    return false;
+  }
+  *col_schema = Column(idx);
+  return true;
+}
+
 KuduPartialRow* KuduSchema::NewRow() const {
   return new KuduPartialRow(schema_);
 }
diff --git a/src/kudu/client/schema.h b/src/kudu/client/schema.h
index 10c7578..c5c3c52 100644
--- a/src/kudu/client/schema.h
+++ b/src/kudu/client/schema.h
@@ -575,6 +575,13 @@ class KUDU_EXPORT KuduSchema {
   /// @return Schema for the specified column.
   KuduColumnSchema Column(size_t idx) const;
 
+  /// @param [in] col_name
+  ///   Column name.
+  /// @param [out] col_schema.
+  ///   Schema for the specified column.
+  /// @return @c true iff the specified column exists.
+  bool HasColumn(const std::string& col_name, KuduColumnSchema* col_schema) const;
+
   /// @return The number of columns in the schema.
   size_t num_columns() const;
 
diff --git a/src/kudu/tools/kudu-tool-test.cc b/src/kudu/tools/kudu-tool-test.cc
index 13efcd0..17ccf4c 100644
--- a/src/kudu/tools/kudu-tool-test.cc
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -134,6 +134,7 @@
 
 DECLARE_bool(hive_metastore_sasl_enabled);
 DECLARE_bool(show_values);
+DECLARE_bool(show_attributes);
 DECLARE_string(block_manager);
 DECLARE_string(hive_metastore_uris);
 
@@ -2922,6 +2923,8 @@ TEST_F(ToolTest, TestMasterList) {
 // (4)list tables
 // (5)scan a table
 // (6)copy a table
+// (7)alter a column
+// (8)delete a column
 TEST_F(ToolTest, TestDeleteTable) {
   NO_FATALS(StartExternalMiniCluster());
   shared_ptr<KuduClient> client;
@@ -3003,7 +3006,6 @@ TEST_F(ToolTest, TestRenameColumn) {
   workload.Setup();
 
   string master_addr = cluster_->master()->bound_rpc_addr().ToString();
-  string out;
   NO_FATALS(RunActionStdoutNone(Substitute("table rename_column $0 $1 $2 $3",
                                            master_addr, kTableName,
                                            kColumnName, kNewColumnName)));
@@ -3252,6 +3254,253 @@ TEST_P(ToolTestCopyTableParameterized, TestCopyTable) {
   }
 }
 
+TEST_F(ToolTest, TestAlterColumn) {
+  NO_FATALS(StartExternalMiniCluster());
+  const string& kTableName = "kudu.table.alter.column";
+  const string& kColumnName = "col.0";
+
+  KuduSchemaBuilder schema_builder;
+  schema_builder.AddColumn("key")
+      ->Type(client::KuduColumnSchema::INT32)
+      ->NotNull()
+      ->PrimaryKey();
+  schema_builder.AddColumn(kColumnName)
+      ->Type(client::KuduColumnSchema::INT32)
+      ->NotNull()
+      ->Compression(KuduColumnStorageAttributes::CompressionType::LZ4)
+      ->Encoding(KuduColumnStorageAttributes::EncodingType::BIT_SHUFFLE)
+      ->BlockSize(40960);
+  KuduSchema schema;
+  ASSERT_OK(schema_builder.Build(&schema));
+
+  // Create the table.
+  TestWorkload workload(cluster_.get());
+  workload.set_table_name(kTableName);
+  workload.set_schema(schema);
+  workload.set_num_replicas(1);
+  workload.Setup();
+
+  string master_addr = cluster_->master()->bound_rpc_addr().ToString();
+  shared_ptr<KuduClient> client;
+  ASSERT_OK(KuduClientBuilder()
+                .add_master_server_addr(master_addr)
+                .Build(&client));
+  shared_ptr<KuduTable> table;
+  FLAGS_show_attributes = true;
+
+  // Test a few error cases.
+  const auto check_bad_input = [&](const string& alter_type,
+                                   const string& alter_value,
+                                   const string& err) {
+    string stderr;
+    Status s = RunActionStderrString(
+      Substitute("table $0 $1 $2 $3 $4",
+                 alter_type, master_addr, kTableName, kColumnName, alter_value), &stderr);
+    ASSERT_TRUE(s.IsRuntimeError());
+    ASSERT_STR_CONTAINS(stderr, err);
+  };
+
+  // Set write_default value for a column.
+  NO_FATALS(RunActionStdoutNone(Substitute("table column_set_default $0 $1 $2 $3",
+                                           master_addr, kTableName, kColumnName, "[1024]")));
+  ASSERT_OK(client->OpenTable(kTableName, &table));
+  ASSERT_STR_CONTAINS(table->schema().ToString(), "1024");
+
+  // Remove write_default value for a column.
+  NO_FATALS(RunActionStdoutNone(Substitute("table column_remove_default $0 $1 $2",
+                                           master_addr, kTableName, kColumnName)));
+  ASSERT_OK(client->OpenTable(kTableName, &table));
+  ASSERT_STR_NOT_CONTAINS(table->schema().ToString(), "1024");
+
+  // Alter compression type for a column.
+  NO_FATALS(RunActionStdoutNone(Substitute("table column_set_compression $0 $1 $2 $3",
+                                           master_addr, kTableName, kColumnName,
+                                           "DEFAULT_COMPRESSION")));
+  ASSERT_OK(client->OpenTable(kTableName, &table));
+  ASSERT_STR_CONTAINS(table->schema().ToString(), "DEFAULT_COMPRESSION");
+  ASSERT_STR_NOT_CONTAINS(table->schema().ToString(), "LZ4");
+
+  // Test invalid compression type.
+  NO_FATALS(check_bad_input("column_set_compression",
+                            "UNKNOWN_COMPRESSION_TYPE",
+                            "Failed to parse compression type"));
+
+  // Alter encoding type for a column.
+  NO_FATALS(RunActionStdoutNone(Substitute("table column_set_encoding $0 $1 $2 $3",
+                                           master_addr, kTableName, kColumnName,
+                                           "PLAIN_ENCODING")));
+  ASSERT_OK(client->OpenTable(kTableName, &table));
+  ASSERT_STR_CONTAINS(table->schema().ToString(), "PLAIN_ENCODING");
+  ASSERT_STR_NOT_CONTAINS(table->schema().ToString(), "BIT_SHUFFLE");
+
+  // Test invalid encoding type.
+  NO_FATALS(check_bad_input("column_set_encoding",
+                            "UNKNOWN_ENCODING_TYPE",
+                            "Failed to parse encoding type"));
+
+  // Alter block_size for a column.
+  NO_FATALS(RunActionStdoutNone(Substitute("table column_set_block_size $0 $1 $2 $3",
+                                           master_addr, kTableName, kColumnName, "10240")));
+  ASSERT_OK(client->OpenTable(kTableName, &table));
+  ASSERT_STR_CONTAINS(table->schema().ToString(), "10240");
+  ASSERT_STR_NOT_CONTAINS(table->schema().ToString(), "40960");
+
+  // Test invalid block_size.
+  NO_FATALS(check_bad_input("column_set_block_size", "0", "Invalid block size:"));
+}
+
+TEST_F(ToolTest, TestColumnSetDefault) {
+  NO_FATALS(StartExternalMiniCluster());
+  const string& kTableName = "kudu.table.set.default";
+  const string& kIntColumn = "col.int";
+  const string& kStringColumn = "col.string";
+  const string& kBoolColumn = "col.bool";
+  const string& kFloatColumn = "col.float";
+  const string& kDoubleColumn = "col.double";
+  const string& kBinaryColumn = "col.binary";
+  const string& kUnixtimeMicrosColumn = "col.unixtime_micros";
+  const string& kDecimalColumn = "col.decimal";
+
+  KuduSchemaBuilder schema_builder;
+  schema_builder.AddColumn("key")
+      ->Type(client::KuduColumnSchema::INT32)
+      ->NotNull()
+      ->PrimaryKey();
+  schema_builder.AddColumn(kIntColumn)
+      ->Type(client::KuduColumnSchema::INT64);
+  schema_builder.AddColumn(kStringColumn)
+      ->Type(client::KuduColumnSchema::STRING);
+  schema_builder.AddColumn(kBoolColumn)
+      ->Type(client::KuduColumnSchema::BOOL);
+  schema_builder.AddColumn(kFloatColumn)
+      ->Type(client::KuduColumnSchema::FLOAT);
+  schema_builder.AddColumn(kDoubleColumn)
+      ->Type(client::KuduColumnSchema::DOUBLE);
+  schema_builder.AddColumn(kBinaryColumn)
+      ->Type(client::KuduColumnSchema::BINARY);
+  schema_builder.AddColumn(kUnixtimeMicrosColumn)
+      ->Type(client::KuduColumnSchema::UNIXTIME_MICROS);
+  schema_builder.AddColumn(kDecimalColumn)
+      ->Type(client::KuduColumnSchema::DECIMAL)
+      ->Precision(30)
+      ->Scale(4);
+  KuduSchema schema;
+  ASSERT_OK(schema_builder.Build(&schema));
+
+  // Create the table.
+  TestWorkload workload(cluster_.get());
+  workload.set_table_name(kTableName);
+  workload.set_schema(schema);
+  workload.set_num_replicas(1);
+  workload.Setup();
+
+  string master_addr = cluster_->master()->bound_rpc_addr().ToString();
+  shared_ptr<KuduClient> client;
+  ASSERT_OK(KuduClientBuilder()
+                .add_master_server_addr(master_addr)
+                .Build(&client));
+  shared_ptr<KuduTable> table;
+  FLAGS_show_attributes = true;
+
+  // Test setting write_default value for a column.
+  const auto check_set_defult = [&](const string& col_name,
+                                    const string& value,
+                                    const string& target_value) {
+    RunActionStdoutNone(Substitute("table column_set_default $0 $1 $2 $3",
+                                   master_addr, kTableName, col_name, value));
+    ASSERT_OK(client->OpenTable(kTableName, &table));
+    ASSERT_STR_CONTAINS(table->schema().ToString(), target_value);
+  };
+
+  // Test a few error cases.
+  const auto check_bad_input = [&](const string& col_name,
+                                   const string& value,
+                                   const string& err) {
+    string stderr;
+    Status s = RunActionStderrString(
+      Substitute("table column_set_default $0 $1 $2 $3",
+                 master_addr, kTableName, col_name, value), &stderr);
+    ASSERT_TRUE(s.IsRuntimeError());
+    ASSERT_STR_CONTAINS(stderr, err);
+  };
+
+  // Set write_default value for a int column.
+  NO_FATALS(check_set_defult(kIntColumn, "[-2]", "-2"));
+  NO_FATALS(check_bad_input(kIntColumn, "[\"string\"]", "unable to parse"));
+  NO_FATALS(check_bad_input(kIntColumn, "[123.4]", "unable to parse"));
+
+  // Set write_default value for a string column.
+  NO_FATALS(check_set_defult(kStringColumn, "[\"string_value\"]", "string_value"));
+  NO_FATALS(check_bad_input(kStringColumn, "[123]", "unable to parse"));
+  // Test empty string is a valid default value for a string column.
+  NO_FATALS(check_set_defult(kStringColumn, "[\"\"]", "\"\""));
+  NO_FATALS(check_set_defult(kStringColumn, "[null]", "\"\""));
+  // Test invalid input of an empty string.
+  NO_FATALS(check_bad_input(kStringColumn, "\"\"", "expected object array but got string"));
+  NO_FATALS(check_bad_input(kStringColumn, "[]", "you should provide one default value"));
+
+  // Set write_default value for a bool column.
+  NO_FATALS(check_set_defult(kBoolColumn, "[true]", "true"));
+  NO_FATALS(check_set_defult(kBoolColumn, "[false]", "false"));
+  NO_FATALS(check_bad_input(kBoolColumn, "[TRUE]", "JSON text is corrupt: Invalid value."));
+
+  // Set write_default value for a float column.
+  NO_FATALS(check_set_defult(kFloatColumn, "[1.23]", "1.23"));
+
+  // Set write_default value for a double column.
+  NO_FATALS(check_set_defult(kDoubleColumn, "[-1.2345]", "-1.2345"));
+
+  // Set write_default value for a binary column.
+  // Empty string tests is the same with string column.
+  NO_FATALS(check_set_defult(kBinaryColumn, "[\"binary_value\"]", "binary_value"));
+
+  // Set write_default value for a unixtime_micro column.
+  NO_FATALS(check_set_defult(kUnixtimeMicrosColumn, "[12345]", "12345"));
+
+  // Test setting write_default value for a decimal column.
+  NO_FATALS(check_bad_input(
+    kDecimalColumn,
+    "[123]",
+    "DECIMAL columns are not supported for setting default value by this tool"));
+}
+
+TEST_F(ToolTest, TestDeleteColumn) {
+  NO_FATALS(StartExternalMiniCluster());
+  const string& kTableName = "kudu.table.delete.column";
+  const string& kColumnName = "col.0";
+
+  KuduSchemaBuilder schema_builder;
+  schema_builder.AddColumn("key")
+      ->Type(client::KuduColumnSchema::INT32)
+      ->NotNull()
+      ->PrimaryKey();
+  schema_builder.AddColumn(kColumnName)
+      ->Type(client::KuduColumnSchema::INT32)
+      ->NotNull();
+  KuduSchema schema;
+  ASSERT_OK(schema_builder.Build(&schema));
+
+  // Create the table.
+  TestWorkload workload(cluster_.get());
+  workload.set_table_name(kTableName);
+  workload.set_schema(schema);
+  workload.set_num_replicas(1);
+  workload.Setup();
+
+  string master_addr = cluster_->master()->bound_rpc_addr().ToString();
+  shared_ptr<KuduClient> client;
+  ASSERT_OK(KuduClientBuilder()
+                .add_master_server_addr(master_addr)
+                .Build(&client));
+  shared_ptr<KuduTable> table;
+  ASSERT_OK(client->OpenTable(kTableName, &table));
+  ASSERT_STR_CONTAINS(table->schema().ToString(), kColumnName);
+  NO_FATALS(RunActionStdoutNone(Substitute("table delete_column $0 $1 $2",
+                                           master_addr, kTableName, kColumnName)));
+  ASSERT_OK(client->OpenTable(kTableName, &table));
+  ASSERT_STR_NOT_CONTAINS(table->schema().ToString(), kColumnName);
+}
+
 Status CreateLegacyHmsTable(HmsClient* client,
                             const string& hms_database_name,
                             const string& hms_table_name,
diff --git a/src/kudu/tools/tool_action_table.cc b/src/kudu/tools/tool_action_table.cc
index f5cbed2..5739186 100644
--- a/src/kudu/tools/tool_action_table.cc
+++ b/src/kudu/tools/tool_action_table.cc
@@ -46,6 +46,7 @@
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/stl_util.h"
 #include "kudu/gutil/strings/join.h"
+#include "kudu/gutil/strings/numbers.h"
 #include "kudu/gutil/strings/split.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/tools/table_scanner.h"
@@ -53,10 +54,12 @@
 #include "kudu/tools/tool_action_common.h"
 #include "kudu/util/jsonreader.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 
 using kudu::client::KuduClient;
 using kudu::client::KuduClientBuilder;
 using kudu::client::KuduColumnSchema;
+using kudu::client::KuduColumnStorageAttributes;
 using kudu::client::KuduPredicate;
 using kudu::client::KuduScanToken;
 using kudu::client::KuduScanTokenBuilder;
@@ -65,6 +68,7 @@ using kudu::client::KuduSchema;
 using kudu::client::KuduTable;
 using kudu::client::KuduTableAlterer;
 using kudu::client::KuduTableCreator;
+using kudu::client::KuduValue;
 using kudu::client::internal::ReplicaController;
 using std::cerr;
 using std::cout;
@@ -72,6 +76,7 @@ using std::endl;
 using std::set;
 using std::string;
 using std::unique_ptr;
+using std::unordered_map;
 using std::vector;
 using strings::Split;
 using strings::Substitute;
@@ -160,10 +165,14 @@ const char* const kConfigValueArg = "config_value";
 const char* const kErrorMsgArg = "unable to parse value $0 for column $1 of type $2";
 const char* const kTableRangeLowerBoundArg = "table_range_lower_bound";
 const char* const kTableRangeUpperBoundArg = "table_range_upper_bound";
+const char* const kDefaultValueArg = "default_value";
+const char* const kCompressionTypeArg = "compression_type";
+const char* const kEncodingTypeArg = "encoding_type";
+const char* const kBlockSizeArg = "block_size";
 
 enum PartitionAction {
-    ADD,
-    DROP,
+  ADD,
+  DROP,
 };
 
 Status DeleteTable(const RunnerContext& context) {
@@ -654,6 +663,203 @@ Status AddRangePartition(const RunnerContext& context) {
   return ModifyRangePartition(context, PartitionAction::ADD);
 }
 
+Status ParseValueOfType(const string& default_value,
+                        KuduColumnSchema::DataType type,
+                        KuduValue** value) {
+  JsonReader reader(default_value);
+  RETURN_NOT_OK(reader.Init());
+  vector<const rapidjson::Value*> values;
+  RETURN_NOT_OK(reader.ExtractObjectArray(reader.root(),
+                                          /*field=*/nullptr,
+                                          &values));
+  if (values.size() != 1) {
+    return Status::InvalidArgument(Substitute(
+      "We got $0 value(s), you should provide one default value.",
+      std::to_string(values.size())));
+  }
+
+  string msg = Substitute("unable to parse value for column type $0",
+                          KuduColumnSchema::DataTypeToString(type));
+  switch (type) {
+    case KuduColumnSchema::DataType::INT8:
+    case KuduColumnSchema::DataType::INT16:
+    case KuduColumnSchema::DataType::INT32:
+    case KuduColumnSchema::DataType::INT64:
+    case KuduColumnSchema::DataType::UNIXTIME_MICROS: {
+      int64_t int_value;
+      RETURN_NOT_OK_PREPEND(
+          reader.ExtractInt64(values[0], /*field=*/nullptr, &int_value), msg);
+      *value = KuduValue::FromInt(int_value);
+      break;
+    }
+    case KuduColumnSchema::DataType::BINARY:
+    case KuduColumnSchema::DataType::STRING: {
+      string str_value;
+      RETURN_NOT_OK_PREPEND(
+        reader.ExtractString(values[0], /*field=*/nullptr, &str_value), msg);
+      *value = KuduValue::CopyString(str_value);
+      break;
+    }
+    case KuduColumnSchema::DataType::BOOL: {
+      bool bool_value;
+      RETURN_NOT_OK_PREPEND(
+        reader.ExtractBool(values[0], /*field=*/nullptr, &bool_value), msg);
+      *value = KuduValue::FromBool(bool_value);
+      break;
+    }
+    case KuduColumnSchema::DataType::FLOAT: {
+      double double_value;
+      RETURN_NOT_OK_PREPEND(
+        reader.ExtractDouble(values[0], /*field=*/nullptr, &double_value), msg);
+      *value = KuduValue::FromFloat(double_value);
+      break;
+    }
+    case KuduColumnSchema::DataType::DOUBLE: {
+      double double_value;
+      RETURN_NOT_OK_PREPEND(
+        reader.ExtractDouble(values[0], /*field=*/nullptr, &double_value), msg);
+      *value = KuduValue::FromDouble(double_value);
+      break;
+    }
+    case KuduColumnSchema::DataType::DECIMAL:
+    default:
+      return Status::NotSupported(Substitute(
+        "$0 columns are not supported for setting default value by this tool,"
+        "is this tool out of date?",
+        KuduColumnSchema::DataTypeToString(type)));
+  }
+  return Status::OK();
+}
+
+Status ColumnSetDefault(const RunnerContext& context) {
+  const string& table_name = FindOrDie(context.required_args, kTableNameArg);
+  const string& column_name = FindOrDie(context.required_args, kColumnNameArg);
+  const string& default_value = FindOrDie(context.required_args, kDefaultValueArg);
+
+  client::sp::shared_ptr<KuduClient> client;
+  RETURN_NOT_OK(CreateKuduClient(context, &client));
+  KuduSchema schema;
+  RETURN_NOT_OK(client->GetTableSchema(table_name, &schema));
+
+  // Here we use the first column to initialize an object of KuduColumnSchema
+  // for there is no default constructor for it.
+  KuduColumnSchema col_schema = schema.Column(0);
+  if (!schema.HasColumn(column_name, &col_schema)) {
+    return Status::NotFound(Substitute("Couldn't find column $0", column_name));
+  }
+
+  KuduValue* value = nullptr;
+  RETURN_NOT_OK(ParseValueOfType(default_value, col_schema.type(), &value));
+  unique_ptr<KuduTableAlterer> alterer(client->NewTableAlterer(table_name));
+  alterer->AlterColumn(column_name)->Default(value);
+  return alterer->Alter();
+}
+
+Status ColumnRemoveDefault(const RunnerContext& context) {
+  const string& table_name = FindOrDie(context.required_args, kTableNameArg);
+  const string& column_name = FindOrDie(context.required_args, kColumnNameArg);
+
+  client::sp::shared_ptr<KuduClient> client;
+  RETURN_NOT_OK(CreateKuduClient(context, &client));
+  unique_ptr<KuduTableAlterer> alterer(client->NewTableAlterer(table_name));
+  alterer->AlterColumn(column_name)->RemoveDefault();
+  return alterer->Alter();
+}
+
+Status ColumnSetCompression(const RunnerContext& context) {
+  const string& table_name = FindOrDie(context.required_args, kTableNameArg);
+  const string& column_name = FindOrDie(context.required_args, kColumnNameArg);
+  const string& compression_type_arg = FindOrDie(context.required_args, kCompressionTypeArg);
+  std::string compression_type_uc;
+  ToUpperCase(compression_type_arg, &compression_type_uc);
+
+  static unordered_map<string, KuduColumnStorageAttributes::CompressionType> compression_type_map =
+     {{"DEFAULT_COMPRESSION", KuduColumnStorageAttributes::CompressionType::DEFAULT_COMPRESSION},
+      {"NO_COMPRESSION", KuduColumnStorageAttributes::CompressionType::NO_COMPRESSION},
+      {"SNAPPY", KuduColumnStorageAttributes::CompressionType::SNAPPY},
+      {"LZ4", KuduColumnStorageAttributes::CompressionType::LZ4},
+      {"ZLIB", KuduColumnStorageAttributes::CompressionType::ZLIB}};
+
+  const KuduColumnStorageAttributes::CompressionType* compression_type =
+    FindOrNull(compression_type_map, compression_type_uc);
+  if (!compression_type) {
+    return Status::InvalidArgument(Substitute(
+      "Failed to parse compression type from $0, supported compression types are: $1.",
+      compression_type_arg,
+      JoinKeysIterator(compression_type_map.begin(), compression_type_map.end(), ", ")));
+  }
+
+  client::sp::shared_ptr<KuduClient> client;
+  RETURN_NOT_OK(CreateKuduClient(context, &client));
+  unique_ptr<KuduTableAlterer> alterer(client->NewTableAlterer(table_name));
+  alterer->AlterColumn(column_name)->Compression(*compression_type);
+  return alterer->Alter();
+}
+
+Status ColumnSetEncoding(const RunnerContext& context) {
+  const string& table_name = FindOrDie(context.required_args, kTableNameArg);
+  const string& column_name = FindOrDie(context.required_args, kColumnNameArg);
+  const string& encoding_type_arg = FindOrDie(context.required_args, kEncodingTypeArg);
+  std::string encoding_type_uc;
+  ToUpperCase(encoding_type_arg, &encoding_type_uc);
+
+  static unordered_map<string, KuduColumnStorageAttributes::EncodingType> encoding_type_map =
+     {{"AUTO_ENCODING", KuduColumnStorageAttributes::EncodingType::AUTO_ENCODING},
+      {"PLAIN_ENCODING", KuduColumnStorageAttributes::EncodingType::PLAIN_ENCODING},
+      {"PREFIX_ENCODING", KuduColumnStorageAttributes::EncodingType::PREFIX_ENCODING},
+      {"RLE", KuduColumnStorageAttributes::EncodingType::RLE},
+      {"DICT_ENCODING", KuduColumnStorageAttributes::EncodingType::DICT_ENCODING},
+      {"BIT_SHUFFLE", KuduColumnStorageAttributes::EncodingType::BIT_SHUFFLE}};
+
+  const KuduColumnStorageAttributes::EncodingType* encoding_type =
+    FindOrNull(encoding_type_map, encoding_type_uc);
+  if (!encoding_type) {
+    return Status::InvalidArgument(Substitute(
+      "Failed to parse encoding type from $0, supported encoding types are: $1.",
+      encoding_type_arg,
+      JoinKeysIterator(encoding_type_map.begin(), encoding_type_map.end(), ", ")));
+  }
+
+  client::sp::shared_ptr<KuduClient> client;
+  RETURN_NOT_OK(CreateKuduClient(context, &client));
+  unique_ptr<KuduTableAlterer> alterer(client->NewTableAlterer(table_name));
+  alterer->AlterColumn(column_name)->Encoding(*encoding_type);
+  return alterer->Alter();
+}
+
+Status ColumnSetBlockSize(const RunnerContext& context) {
+  const string& table_name = FindOrDie(context.required_args, kTableNameArg);
+  const string& column_name = FindOrDie(context.required_args, kColumnNameArg);
+  const string& str_block_size = FindOrDie(context.required_args, kBlockSizeArg);
+
+  int32_t block_size;
+  if (!safe_strto32(str_block_size, &block_size)) {
+    return Status::InvalidArgument(Substitute(
+      "Unable to parse block_size value: $0.", str_block_size));
+  }
+  if (block_size <= 0) {
+    return Status::InvalidArgument(Substitute(
+      "Invalid block size: $0, it should be set higher than 0.", str_block_size));
+  }
+
+  client::sp::shared_ptr<KuduClient> client;
+  RETURN_NOT_OK(CreateKuduClient(context, &client));
+  unique_ptr<KuduTableAlterer> alterer(client->NewTableAlterer(table_name));
+  alterer->AlterColumn(column_name)->BlockSize(block_size);
+  return alterer->Alter();
+}
+
+Status DeleteColumn(const RunnerContext& context) {
+  const string& table_name = FindOrDie(context.required_args, kTableNameArg);
+  const string& column_name = FindOrDie(context.required_args, kColumnNameArg);
+
+  client::sp::shared_ptr<KuduClient> client;
+  RETURN_NOT_OK(CreateKuduClient(context, &client));
+  unique_ptr<KuduTableAlterer> alterer(client->NewTableAlterer(table_name));
+  alterer->DropColumn(column_name);
+  return alterer->Alter();
+}
+
 } // anonymous namespace
 
 unique_ptr<Mode> BuildTableMode() {
@@ -800,9 +1006,69 @@ unique_ptr<Mode> BuildTableMode() {
       .AddOptionalParameter("upper_bound_type")
       .Build();
 
+  unique_ptr<Action> column_set_default =
+      ActionBuilder("column_set_default", &ColumnSetDefault)
+      .Description("Set write_default value for a column")
+      .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+      .AddRequiredParameter({ kTableNameArg, "Name of the table to alter" })
+      .AddRequiredParameter({ kColumnNameArg, "Name of the table column to alter" })
+      .AddRequiredParameter({ kDefaultValueArg,
+                              "Write default value of the column, should be provided as a "
+                              "JSON array, e.g. [1] or [\"foo\"]" })
+      .Build();
+
+  unique_ptr<Action> column_remove_default =
+      ActionBuilder("column_remove_default", &ColumnRemoveDefault)
+      .Description("Remove write_default value for a column")
+      .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+      .AddRequiredParameter({ kTableNameArg, "Name of the table to alter" })
+      .AddRequiredParameter({ kColumnNameArg, "Name of the table column to alter" })
+      .Build();
+
+  unique_ptr<Action> column_set_compression =
+      ActionBuilder("column_set_compression", &ColumnSetCompression)
+      .Description("Set compression type for a column")
+      .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+      .AddRequiredParameter({ kTableNameArg, "Name of the table to alter" })
+      .AddRequiredParameter({ kColumnNameArg, "Name of the table column to alter" })
+      .AddRequiredParameter({ kCompressionTypeArg, "Compression type of the column" })
+      .Build();
+
+  unique_ptr<Action> column_set_encoding =
+      ActionBuilder("column_set_encoding", &ColumnSetEncoding)
+      .Description("Set encoding type for a column")
+      .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+      .AddRequiredParameter({ kTableNameArg, "Name of the table to alter" })
+      .AddRequiredParameter({ kColumnNameArg, "Name of the table column to alter" })
+      .AddRequiredParameter({ kEncodingTypeArg, "Encoding type of the column" })
+      .Build();
+
+  unique_ptr<Action> column_set_block_size =
+      ActionBuilder("column_set_block_size", &ColumnSetBlockSize)
+      .Description("Set block size for a column")
+      .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+      .AddRequiredParameter({ kTableNameArg, "Name of the table to alter" })
+      .AddRequiredParameter({ kColumnNameArg, "Name of the table column to alter" })
+      .AddRequiredParameter({ kBlockSizeArg, "Block size of the column" })
+      .Build();
+
+  unique_ptr<Action> delete_column =
+      ActionBuilder("delete_column", &DeleteColumn)
+      .Description("Delete a column")
+      .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+      .AddRequiredParameter({ kTableNameArg, "Name of the table to alter" })
+      .AddRequiredParameter({ kColumnNameArg, "Name of the table column to delete" })
+      .Build();
+
   return ModeBuilder("table")
       .Description("Operate on Kudu tables")
       .AddAction(std::move(add_range_partition))
+      .AddAction(std::move(column_set_default))
+      .AddAction(std::move(column_remove_default))
+      .AddAction(std::move(column_set_compression))
+      .AddAction(std::move(column_set_encoding))
+      .AddAction(std::move(column_set_block_size))
+      .AddAction(std::move(delete_column))
       .AddAction(std::move(delete_table))
       .AddAction(std::move(describe_table))
       .AddAction(std::move(drop_range_partition))