You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2017/02/08 15:35:43 UTC

ambari git commit: AMBARI-19898. Hive View 2.0: Ability to edit table through UI. (dipayanb)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.5 90d1ff1ad -> 151d2f167


AMBARI-19898. Hive View 2.0: Ability to edit table through UI. (dipayanb)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/151d2f16
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/151d2f16
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/151d2f16

Branch: refs/heads/branch-2.5
Commit: 151d2f1671c42db3e77c0305b29f6b1a5672f7a9
Parents: 90d1ff1
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Wed Feb 8 21:05:23 2017 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Wed Feb 8 21:05:23 2017 +0530

----------------------------------------------------------------------
 .../view/hive20/internal/dto/ColumnInfo.java    |  28 +-
 .../view/hive20/internal/dto/TableStats.java    |  11 +
 .../internal/parsers/TableMetaParserImpl.java   |   8 +
 .../generators/AlterTableQueryGenerator.java    |  82 +++---
 .../query/generators/QueryGenerationUtils.java  |   5 +-
 .../view/hive20/resources/browser/DDLProxy.java |   2 +-
 .../src/main/resources/ui/app/adapters/table.js |   6 +
 .../resources/ui/app/components/column-item.js  |   1 +
 .../resources/ui/app/components/edit-table.js   | 220 ++++++++++++++
 .../ui/app/components/property-item.js          |   1 +
 .../app/components/table-advanced-settings.js   |   5 +
 .../ui/app/components/table-columns.js          |   3 +-
 .../ui/app/components/table-properties.js       |   3 +-
 .../resources/ui/app/configs/edit-table-tabs.js |  48 +++
 .../hive20/src/main/resources/ui/app/router.js  |   1 +
 .../databases/database/tables/table/edit.js     |  86 ++++++
 .../ui/app/services/table-operations.js         |  24 ++
 .../src/main/resources/ui/app/styles/app.scss   |   3 +
 .../ui/app/templates/components/column-item.hbs |  13 +-
 .../ui/app/templates/components/edit-table.hbs  |  65 ++++
 .../app/templates/components/property-item.hbs  |  10 +-
 .../components/table-advanced-settings.hbs      | 295 ++++++++++---------
 .../app/templates/components/table-columns.hbs  |   1 +
 .../templates/components/table-properties.hbs   |   1 +
 .../templates/components/table-statistics.hbs   |   4 +
 .../databases/database/tables/table.hbs         |   2 +-
 .../databases/database/tables/table/edit.hbs    |  45 +++
 .../AlterTableQueryGenerationSpecTest.groovy    |  59 ----
 .../AlterTableQueryGeneratorTest.java           | 161 +++++++++-
 29 files changed, 911 insertions(+), 282 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
index 5daab91..9f179d1 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
@@ -20,6 +20,8 @@ package org.apache.ambari.view.hive20.internal.dto;
 
 import org.apache.commons.lang3.builder.EqualsBuilder;
 
+import java.util.Objects;
+
 /**
  *
  */
@@ -82,28 +84,20 @@ public class ColumnInfo {
   }
 
   @Override
-  public int hashCode() {
-    int result = name.hashCode();
-    result = 31 * result + type.hashCode();
-    result = 31 * result + (precision != null ? precision.hashCode() : 0);
-    result = 31 * result + (scale != null ? scale.hashCode() : 0);
-    result = 31 * result + (comment != null ? comment.hashCode() : 0);
-    return result;
-  }
-
-  @Override
   public boolean equals(Object o) {
     if (this == o) return true;
-
     if (o == null || getClass() != o.getClass()) return false;
-
     ColumnInfo that = (ColumnInfo) o;
+    return ((name == that.name) || (name != null && name.equalsIgnoreCase(that.name))) &&
+        ((type == that.type) || (type != null && type.equalsIgnoreCase(that.type))) &&
+        Objects.equals(precision, that.precision) &&
+        Objects.equals(scale, that.scale) &&
+        Objects.equals(comment, that.comment);
+  }
 
-    return new EqualsBuilder()
-        .append(getName(), that.getName())
-        .append(getType(), that.getType())
-        .append(getComment(), that.getComment())
-        .isEquals();
+  @Override
+  public int hashCode() {
+    return Objects.hash(name);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
index b8b4f07..3048d22 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
@@ -24,12 +24,14 @@ package org.apache.ambari.view.hive20.internal.dto;
  */
 public class TableStats {
   public static final String NUM_FILES = "numFiles";
+  public static final String NUM_ROWS = "numRows";
   public static final String COLUMN_STATS_ACCURATE = "COLUMN_STATS_ACCURATE";
   public static final String RAW_DATA_SIZE = "rawDataSize";
   public static final String TOTAL_SIZE = "totalSize";
 
   private Boolean isTableStatsEnabled;
   private Integer numFiles;
+  private Integer numRows;
   private String columnStatsAccurate;
   private Integer rawDataSize;
   private Integer totalSize;
@@ -74,11 +76,20 @@ public class TableStats {
     this.totalSize = totalSize;
   }
 
+  public Integer getNumRows() {
+    return numRows;
+  }
+
+  public void setNumRows(Integer numRows) {
+    this.numRows = numRows;
+  }
+
   @Override
   public String toString() {
     final StringBuilder sb = new StringBuilder("TableStats{");
     sb.append("isStatsEnabled='").append(isTableStatsEnabled).append('\'');
     sb.append(", numFiles='").append(numFiles).append('\'');
+    sb.append(", numRows='").append(numRows).append('\'');
     sb.append(", columnStatsAccurate='").append(columnStatsAccurate).append('\'');
     sb.append(", rawDataSize='").append(rawDataSize).append('\'');
     sb.append(", totalSize='").append(totalSize).append('\'');

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
index b0c9fe4..f2a1933 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
@@ -86,6 +86,9 @@ public class TableMetaParserImpl implements TableMetaParser<TableMeta> {
     String numFiles = tableInfo.getParameters().get(TableStats.NUM_FILES);
     tableInfo.getParameters().remove(TableStats.NUM_FILES);
 
+    String numRows = tableInfo.getParameters().get(TableStats.NUM_ROWS);
+    tableInfo.getParameters().remove(TableStats.NUM_ROWS);
+
     String columnStatsAccurate = tableInfo.getParameters().get(TableStats.COLUMN_STATS_ACCURATE);
     tableInfo.getParameters().remove(TableStats.COLUMN_STATS_ACCURATE);
 
@@ -100,6 +103,11 @@ public class TableMetaParserImpl implements TableMetaParser<TableMeta> {
       tableStats.setNumFiles(Integer.valueOf(numFiles.trim()));
     }
 
+    if(!Strings.isNullOrEmpty(numRows) && !Strings.isNullOrEmpty(numRows.trim())){
+      tableStats.setTableStatsEnabled(true);
+      tableStats.setNumRows(Integer.valueOf(numRows.trim()));
+    }
+
     if(!Strings.isNullOrEmpty(rawDataSize) && !Strings.isNullOrEmpty(rawDataSize.trim())){
       tableStats.setTableStatsEnabled(true);
       tableStats.setRawDataSize(Integer.valueOf(rawDataSize.trim()));

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
index 73f8266..b119f6a 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
@@ -31,16 +31,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.annotation.Nullable;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import static org.apache.ambari.view.hive20.internal.query.generators.QueryGenerationUtils.isNullOrEmpty;
 
 public class AlterTableQueryGenerator implements QueryGenerator {
   private static final Logger LOG = LoggerFactory.getLogger(AlterTableQueryGenerator.class);
 
+  public static List<String> SYSTEM_PROPERTY_LIST = Arrays.asList("last_modified_time", "transient_lastDdlTime", "last_modified_by", "numRows", "numFiles", "rawDataSize", "totalSize", "COLUMN_STATS_ACCURATE");
+
   private final TableMeta oldMeta;
   private final TableMeta newMeta;
 
@@ -65,11 +64,6 @@ public class AlterTableQueryGenerator implements QueryGenerator {
   public Optional<String> getQuery() {
     List<Optional<String>> queries = new LinkedList<>();
 
-    // TODO: rename of table name has to be handled separately as other queries depend on new name.
-//    Optional<String> tableRenameQuery = this.generateTableRenameQuery(this.getOldMeta().getDatabase(),
-//      this.getOldMeta().getTable(), this.getNewMeta().getDatabase(), this.getNewMeta().getTable());
-//    queries.add(tableRenameQuery);
-
     Optional<List<Optional<String>>> columnQuery = this.generateColumnQuery();
     if (columnQuery.isPresent()) {
       queries.addAll(columnQuery.get());
@@ -81,28 +75,30 @@ public class AlterTableQueryGenerator implements QueryGenerator {
       queries.add(tablePropertiesQuery);
     }
 
-    if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
-      String oldSerde = this.getOldMeta().getStorageInfo().getSerdeLibrary();
-      String newSerde = this.getNewMeta().getStorageInfo().getSerdeLibrary();
-      Map<String, String> oldParameters = this.getOldMeta().getStorageInfo().getParameters();
-      Map<String, String> newParameters = this.getNewMeta().getStorageInfo().getParameters();
-
-      Optional<String> serdeProperties = this.generateSerdeQuery(oldSerde, oldParameters, newSerde, newParameters);
-      queries.add(serdeProperties);
-    }
-
-    if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
-      List<String> oldBucketCols = this.getOldMeta().getStorageInfo().getBucketCols();
-      List<ColumnOrder> oldSortCols = this.getOldMeta().getStorageInfo().getSortCols();
-      String oldNumBuckets = this.getOldMeta().getStorageInfo().getNumBuckets();
-
-      List<String> newBucketCols = this.getNewMeta().getStorageInfo().getBucketCols();
-      List<ColumnOrder> newSortCols = this.getNewMeta().getStorageInfo().getSortCols();
-      String newNumBuckets = this.getNewMeta().getStorageInfo().getNumBuckets();
-
-      Optional<String> storagePropertyQuery = this.generateStoragePropertyQuery(oldBucketCols, oldSortCols, oldNumBuckets, newBucketCols, newSortCols, newNumBuckets);
-      queries.add(storagePropertyQuery);
-    }
+    // storage change is not required to be handled.
+//    if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
+//      String oldSerde = this.getOldMeta().getStorageInfo().getSerdeLibrary();
+//      String newSerde = this.getNewMeta().getStorageInfo().getSerdeLibrary();
+//      Map<String, String> oldParameters = this.getOldMeta().getStorageInfo().getParameters();
+//      Map<String, String> newParameters = this.getNewMeta().getStorageInfo().getParameters();
+//
+//      Optional<String> serdeProperties = this.generateSerdeQuery(oldSerde, oldParameters, newSerde, newParameters);
+//      queries.add(serdeProperties);
+//    }
+
+    // change of bucketed columns is not required right now
+//    if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
+//      List<String> oldBucketCols = this.getOldMeta().getStorageInfo().getBucketCols();
+//      List<ColumnOrder> oldSortCols = this.getOldMeta().getStorageInfo().getSortCols();
+//      String oldNumBuckets = this.getOldMeta().getStorageInfo().getNumBuckets();
+//
+//      List<String> newBucketCols = this.getNewMeta().getStorageInfo().getBucketCols();
+//      List<ColumnOrder> newSortCols = this.getNewMeta().getStorageInfo().getSortCols();
+//      String newNumBuckets = this.getNewMeta().getStorageInfo().getNumBuckets();
+//
+//      Optional<String> storagePropertyQuery = this.generateStoragePropertyQuery(oldBucketCols, oldSortCols, oldNumBuckets, newBucketCols, newSortCols, newNumBuckets);
+//      queries.add(storagePropertyQuery);
+//    }
 
 
     List<String> queryList = FluentIterable.from(queries).filter(new Predicate<Optional<String>>() {
@@ -322,19 +318,33 @@ public class AlterTableQueryGenerator implements QueryGenerator {
     return Optional.absent();
   }
 
-  Optional<String> generateTablePropertiesQuery(Map oldProps, Map newProps) {
+  Optional<String> generateTablePropertiesQuery(Map<String, String> oldProps, Map<String, String> newProps) {
     Optional<String> query = createTablePropertiesQuery(oldProps, newProps);
     if (query.isPresent()) return Optional.of(getQueryPerfix() + query.get());
     else return Optional.absent();
   }
 
 
-  static Optional<String> createTablePropertiesQuery(Map oldProps, Map newProps) {
+  static Optional<String> createTablePropertiesQuery(Map<String, String> oldProps, Map<String, String> newProps) {
+    if( null == newProps && null == oldProps){
+      return Optional.absent();
+    }
+
     if (null == newProps) {
-      newProps = new HashMap();
+      newProps = new HashMap<>();
     }
-// TODO ignore system generated table properties during comparison
-    if (!QueryGenerationUtils.isEqual(oldProps, newProps)) {
+
+    if(null == oldProps){
+      oldProps = new HashMap<>();
+    }
+    // ignore system generated table properties during comparison
+
+   for(String prop : SYSTEM_PROPERTY_LIST){
+      newProps.remove(prop);
+      oldProps.remove(prop);
+   }
+
+    if (!QueryGenerationUtils.isEqual(oldProps, newProps) && !newProps.isEmpty()) {
       return Optional.of(" SET TBLPROPERTIES (" + QueryGenerationUtils.getPropertiesAsKeyValues(newProps) + ")");
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
index d9dc6e1..db219c4 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
@@ -81,8 +81,11 @@ public class QueryGenerationUtils {
     Map<Object, Object> modified = new HashMap<>();
     Map<Object, Object> deleted = new HashMap<>();
 
-    if(oldProps == null && newProps == null) return Optional.of(ret);
+    if(oldProps == null && newProps == null) return Optional.absent();
 
+    if(oldProps == null && newProps != null){
+      oldProps = new HashMap();
+    }
     if(oldProps != null && newProps != null){
       Set<Map.Entry> entrySet = oldProps.entrySet();
       for(Map.Entry e : entrySet){

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
index f75b008..f5ecdee 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
@@ -279,7 +279,7 @@ public class DDLProxy {
     if(alterQuery.isPresent()){
       return alterQuery.get();
     }else{
-      throw new ServiceException("Failed to generate alter table query for table " + oldTableMeta.getDatabase() + "." + oldTableMeta.getTable());
+      throw new ServiceException("Failed to generate alter table query for table " + oldTableMeta.getDatabase() + "." + oldTableMeta.getTable() + ". No difference was found.");
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
index 47174e4..e133419 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
@@ -44,6 +44,12 @@ export default DDLAdapter.extend({
     return this.ajax(postURL, 'POST', { data: { tableInfo: tableMetaInfo } });
   },
 
+  editTable(tableMetaInfo) {
+    let postURL = this.buildURL('table', null, null, 'query',
+      { databaseId: tableMetaInfo.database, tableName: tableMetaInfo.table });
+    return this.ajax(postURL, 'PUT', { data: { tableInfo: tableMetaInfo } });
+  },
+
   deleteTable(database, tableName) {
     let deletURL = this.buildURL('table', null, null, 'query', { databaseId: database, tableName: tableName });
     return this.ajax(deletURL, 'DELETE');

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js b/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
index d4e43f3..f2e45bd 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
@@ -23,6 +23,7 @@ export default Ember.Component.extend({
   tagName: 'tr',
   advancedOption: false,
   datatypes: Ember.copy(datatypes),
+  editMode: false,
 
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js b/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js
new file mode 100644
index 0000000..439dbcf
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js
@@ -0,0 +1,220 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import datatypes from '../configs/datatypes';
+import Column from '../models/column';
+import Helper from '../configs/helpers';
+import TableProperty from '../models/table-property';
+
+export default Ember.Component.extend({
+
+  init() {
+    this._super(...arguments);
+    this.set('columns', Ember.A());
+    this.set('properties', []);
+    this.set('settings', {});
+    this.set('shouldAddBuckets', null);
+    this.set('settingErrors', []);
+  },
+
+  didReceiveAttrs() {
+    this.get('tabs').setEach('active', false);
+    let firstTab = this.get('tabs.firstObject');
+    firstTab.set('active', true);
+    this.set('columns', this._transformColumns());
+    this.set('properties', this._extractParameters());
+    this.set('settings', this._extractSettings());
+  },
+
+  actions: {
+    cancel() {
+      this.sendAction('cancel');
+    },
+
+    edit() {
+      if (this.validate()) {
+        this.sendAction('edit', {
+          database: this.get('table.database'),
+          table: this.get('table.table'),
+          columns: this.get('columns'),
+          settings: this.get('settings'),
+          properties: this.get('properties')
+        });
+      }
+    }
+  },
+
+  _transformColumns() {
+    let columns = [];
+    columns.pushObjects(this.get('table.columns').map((item) => {
+      return this._getColumnEntry(item, false, this._isClustered(this.get('table'), item.name))
+    }));
+
+    if (!Ember.isEmpty(this.get('table.partitionInfo'))) {
+      columns.pushObjects(this.get('table.partitionInfo.columns').map((item) => {
+        return this._getColumnEntry(item, true, false);
+      }));
+    }
+
+    return columns;
+  },
+
+  _getColumnEntry(column, isPartitioned, isClustered) {
+    return Column.create({
+      name: column.name,
+      type: this._getType(column.type),
+      comment: column.comment,
+      precision: column.precision,
+      scale: column.scale,
+      isPartitioned: isPartitioned,
+      isClustered: isClustered,
+      editing: !(isPartitioned || isClustered),
+      newColumn: false
+    });
+  },
+
+  _getType(typeString) {
+    return datatypes.find((item) => item.label.toLowerCase() === typeString.toLowerCase());
+  },
+
+  _isClustered(tableInfo, columnName) {
+    if (!Ember.isEmpty(tableInfo.get('storageInfo.bucketCols'))) {
+      return tableInfo.get('storageInfo.bucketCols').contains(columnName);
+    } else {
+      return false;
+    }
+  },
+
+  _extractParameters() {
+    if (!Ember.isEmpty(this.get('table.detailedInfo.parameters'))) {
+      let tableProperties = this.get('table.detailedInfo.parameters');
+      return Object.keys(tableProperties)
+        .filter((item) => item !== 'transactional')
+        .map((item) => {
+          return TableProperty.create({
+            key: item,
+            value: tableProperties[item],
+            editing: false,
+            newProperty: false
+          });
+        })
+    } else {
+      return [];
+    }
+  },
+
+  _extractSettings() {
+    let settings = {};
+    let tableInfo = this.get('table');
+
+    // filter out transaction parameter to set if transactional
+    if (!Ember.isEmpty(this.get('table.detailedInfo.parameters'))) {
+      let tableProperties = this.get('table.detailedInfo.parameters');
+      let transactional = Object.keys(tableProperties)
+        .filter((item) => item === 'transactional');
+      if (!Ember.isEmpty(transactional)) {
+        settings.transactional = true;
+      }
+    }
+
+    // Find if already clustered, then set number of buckets
+    if (!Ember.isEmpty(tableInfo.get('storageInfo.bucketCols'))) {
+      settings.numBuckets = parseInt(tableInfo.get('storageInfo.numBuckets'))
+      this.set('shouldAddBuckets', true);
+    }
+
+    return settings;
+  },
+
+  validate() {
+    if (!(this.checkColumnUniqueness() &&
+      this.validateColumns())) {
+      this.selectTab("edit.table.columns");
+      return false;
+    }
+
+    if(!(this.validateNumBuckets())) {
+      this.selectTab("edit.table.advanced");
+      return false;
+    }
+
+    if (!(this.validateTableProperties())) {
+      this.selectTab("edit.table.properties");
+      return false;
+    }
+    return true;
+  },
+
+  checkColumnUniqueness() {
+    let columnNames = [];
+    for (let i = 0; i < this.get('columns.length'); i++) {
+      let column = this.get('columns').objectAt(i);
+      column.clearError();
+      if (columnNames.indexOf(column.get('name')) === -1) {
+        columnNames.pushObject(column.get('name'));
+      } else {
+        column.get('errors').push({type: 'name', error: 'Name should be unique'});
+        return false;
+      }
+    }
+
+    return true;
+  },
+
+  validateColumns() {
+    for (let i = 0; i < this.get('columns.length'); i++) {
+      let column = this.get('columns').objectAt(i);
+      if (!column.validate()) {
+        return false;
+      }
+    }
+    return true;
+  },
+
+  validateTableProperties() {
+    for (let i = 0; i < this.get('properties.length'); i++) {
+      let property = this.get('properties').objectAt(i);
+      if (!property.validate()) {
+        return false;
+      }
+    }
+    return true;
+  },
+
+  validateNumBuckets() {
+    let clusteredColumns = this.get('columns').filterBy('isClustered', true);
+    if(clusteredColumns.get('length') > 0 &&
+      (Ember.isEmpty(this.get('settings.numBuckets')) ||
+      !Helper.isInteger(this.get('settings.numBuckets')))) {
+      this.get('settingErrors').pushObject({type: 'numBuckets', error: "Some columns are clustered, Number of buckets are required."});
+      return false;
+    }
+
+    return true;
+  },
+
+  selectTab(link) {
+    this.get('tabs').setEach('active', false);
+    let selectedTab = this.get('tabs').findBy('link', link);
+    if (!Ember.isEmpty(selectedTab)) {
+      selectedTab.set('active', true);
+    }
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js b/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
index 96ef473..edc2c44 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
@@ -20,6 +20,7 @@ import Ember from 'ember';
 
 export default Ember.Component.extend({
   tagName: 'tr',
+  editMode: false,
 
   didInsertElement() {
     Ember.run.later( () => {

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js b/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
index 5e50a5c..99a9bb6 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
@@ -29,6 +29,8 @@ export default Ember.Component.extend({
   showRowFormatInput: false,
   shouldAddBuckets: false,
   errors: [],
+  editMode: false,
+  disableTransactionInput: false,
 
   settings: {},
 
@@ -67,6 +69,9 @@ export default Ember.Component.extend({
       this.set('selectedNullDefinition', this.get('settings.rowFormat.nullDefinedAs'));
       this.set('selectedEscapeDefinition', this.get('settings.rowFormat.escapeDefinedAs'));
     }
+    if(!Ember.isEmpty(this.get('settings.transactional')) && this.get('settings.transactional') && this.get('editMode')) {
+      this.set('disableTransactionInput', true);
+    }
   },
 
   locationInputObserver: Ember.observer('showLocationInput', function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js b/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
index 5479496..7d83353 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
@@ -21,6 +21,7 @@ import Column from '../models/column';
 
 export default Ember.Component.extend({
   columns: [],
+  editMode: false,
   shouldAddBuckets: null,
 
   clusteredColumnObserver: Ember.observer('columns.@each.isClustered', function(sender, key, value, rev) {
@@ -37,7 +38,7 @@ export default Ember.Component.extend({
 
   actions: {
     addNewColumn() {
-      let newEmptyColumn = Column.create({editing: true});
+      let newEmptyColumn = Column.create({editing: true, newColumn: true});
       this.get('columns').pushObject(newEmptyColumn);
     },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js b/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
index 1ba15cc..f1ee645 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
@@ -21,10 +21,11 @@ import TableProperty from '../models/table-property';
 
 export default Ember.Component.extend({
   properties: [],
+  editMode: false,
 
   actions: {
     addNewRow() {
-      let emptyProperty = TableProperty.create({editing: true});
+      let emptyProperty = TableProperty.create({editing: true, newProperty: true});
       this.get('properties').pushObject(emptyProperty);
     },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js b/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js
new file mode 100644
index 0000000..49e702f
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+let editTableTabs = [
+  Ember.Object.create({
+    name: 'columns',
+    label: 'COLUMNS',
+    transition: false,
+    link: 'edit.table.columns',
+    faIcon: 'list'
+  }),
+
+  Ember.Object.create({
+    name: 'advanced',
+    label: 'ADVANCED',
+    transition: false,
+    link: 'edit.table.advanced',
+    faIcon: 'file-text-o'
+  }),
+
+  Ember.Object.create({
+    name: 'properties',
+    label: 'TABLE PROPERTIES',
+    transition: false,
+    link: 'edit.table.properties',
+    faIcon: 'file-text-o'
+  })
+
+];
+
+export default editTableTabs;

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/router.js b/contrib/views/hive20/src/main/resources/ui/app/router.js
index c781a34..ffb0f83 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/router.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/router.js
@@ -45,6 +45,7 @@ Router.map(function() {
         this.route('new');
         this.route('upload-table');
         this.route('table', {path: '/:name'}, function() {
+          this.route('edit');
           this.route('rename');
           this.route('columns');
           this.route('partitions');

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js
new file mode 100644
index 0000000..47340ba
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js
@@ -0,0 +1,86 @@
+/**
+ * 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.
+ */
+
+import TableMetaRouter from './table-meta-router';
+import tabs from '../../../../../configs/edit-table-tabs';
+
+export default TableMetaRouter.extend({
+
+  tableOperations: Ember.inject.service(),
+
+  activate() {
+    let tableController = this.controllerFor('databases.database.tables.table');
+    this.set('existingTabs', tableController.get('tabs'));
+    tableController.set('tabs', []);
+  },
+
+  deactivate() {
+    let tableController = this.controllerFor('databases.database.tables.table');
+    tableController.set('tabs', this.get('existingTabs'));
+  },
+
+  setupController(controller, model) {
+    this._super(controller, model);
+    controller.set('tabs', Ember.copy(tabs));
+  },
+
+  actions: {
+
+    cancel() {
+      this.transitionTo('databases.database.tables');
+    },
+
+    edit(settings) {
+      this._modalStatus(true, 'Submitting request to edit table');
+      this.get('tableOperations').editTable(settings).then((job) => {
+        this._modalStatus(true, 'Waiting for the table edit job to complete');
+        return this.get('tableOperations').waitForJobToComplete(job.get('id'), 5 * 1000);
+      }).then((status) => {
+        this._modalStatus(true, 'Successfully edited the table');
+        this._transitionToTables();
+      }).catch((err) => {
+        this._modalStatus(true, 'Failed to edit table');
+        this._alertMessage('Failed to edit table', err);
+        this._transitionToTables();
+      });
+    }
+
+  },
+
+  _modalStatus(status, message) {
+    this.controller.set('showModal', status);
+    if(status) {
+      this.controller.set('modalMessage', message);
+    }
+  },
+
+  _transitionToTables() {
+    Ember.run.later(() => {
+      this._modalStatus(false);
+      this.send('refreshTableInfo');
+      this.transitionTo('databases.database.tables.table');
+    }, 2000);
+  },
+
+  _alertMessage(message, err) {
+    console.log(message, err);
+    // TODO: user alert message here
+  }
+
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
index d11816c..a5be574 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
@@ -45,6 +45,30 @@ export default Ember.Service.extend({
     });
   },
 
+  editTable(settings) {
+    let detailedInfo = this._getDetailedInfo(settings);
+    let storageInfo = this._getStorageInfo(settings);
+    let columns = this._getColumns(settings);
+    let partitionColumns = this._getPartitionColumns(settings);
+
+    let tableInfo = Ember.Object.create({
+      database: settings.database,
+      table: settings.table,
+      columns: columns,
+      partitionInfo: { columns: partitionColumns },
+      detailedInfo: detailedInfo,
+      storageInfo: storageInfo
+    });
+    return new Promise((resolve, reject) => {
+      this.get('store').adapterFor('table').editTable(tableInfo).then((data) => {
+        this.get('store').pushPayload(data);
+        resolve(this.get('store').peekRecord('job', data.job.id));
+      }, (err) => {
+        reject(err);
+      });
+    });
+  },
+
   deleteTable(database, table) {
     return new Ember.RSVP.Promise((resolve, reject) => {
       this.get('store').adapterFor('table').deleteTable(database, table).then((data) => {

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
index bce9f69..968d3b3 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
+++ b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
@@ -270,6 +270,9 @@ pre {
 .create-table-controls {
   padding-top: 15px;
   padding-bottom: 15px;
+  .warning {
+    margin-top: 15px;
+  }
 }
 
 .column-precision {

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
index 73fac89..b649d5b 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
@@ -27,7 +27,7 @@
 </td>
 <td>
   {{#power-select
-    disabled=notEditing
+    disabled=(not column.editing)
     selected=column.type
     options=datatypes
     searchField="label"
@@ -114,10 +114,13 @@
 </td>
 <td>
   <div class="text-center">
-    {{#unless column.editing}}
-      <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
-    {{/unless}}
-    <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+    {{#if (or column.newColumn (not editMode)) }}
+      {{#unless column.editing}}
+        <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
+      {{/unless}}
+      <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+    {{/if}}
+
   </div>
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs
new file mode 100644
index 0000000..70e7824
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs
@@ -0,0 +1,65 @@
+{{!
+* 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.
+}}
+
+<div class="col-md-12">
+  {{#tabs-pane tabs=tabs inverse=true as |tab|}}
+    {{tabs-item tab=tab tabs=tabs}}
+  {{/tabs-pane}}
+
+  <div class="create-table-inner">
+    <div class="row">
+      {{#each tabs as |tab|}}
+        {{#if tab.active}}
+          {{#if (eq tab.link "edit.table.columns")}}
+            {{#if hasEmptyColumnsError}}
+              <div class="alert alert-danger create-table-error">
+                {{emptyColumnsErrorText}}
+              </div>
+            {{/if}}
+            {{table-columns columns=columns shouldAddBuckets=shouldAddBuckets editMode=true}}
+          {{/if}}
+          {{#if (eq tab.link "edit.table.properties")}}
+            {{table-properties properties=properties editMode=true}}
+          {{/if}}
+          {{#if (eq tab.link "edit.table.advanced")}}
+            {{table-advanced-settings settings=settings shouldAddBuckets=shouldAddBuckets
+                                      errors=settingErrors editMode=true}}
+          {{/if}}
+        {{/if}}
+      {{/each}}
+    </div>
+
+  </div>
+  <div class="create-table-controls">
+    <div class="row">
+      <div class="col-md-2">
+        <button class="btn btn-success" {{action "edit"}}>{{fa-icon "edit"}} Edit</button>
+        <button class="btn btn-warning" {{action "cancel"}}>{{fa-icon "times"}} Cancel</button>
+      </div>
+    </div>
+    <div class="row">
+      <div class=" col-md-12 warning">
+        <div class="alert alert-danger">
+          <p>{{fa-icon "exclamation-circle" size="2"}} <strong>Warning:</strong> Operation is executed as multiple statements and they are not transactional in its entirety.</p>
+        </div>
+      </div>
+    </div>
+  </div>
+
+
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
index e0ba696..26e5d9b 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
@@ -37,9 +37,11 @@
 
 <td>
   <div class="text-center">
-    {{#unless property.editing}}
-      <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
-    {{/unless}}
-    <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+    {{#if (or property.newProperty (not editMode)) }}
+      {{#unless property.editing}}
+        <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
+      {{/unless}}
+      <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+    {{/if}}
   </div>
 </td>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
index 18f22f9..f7a92ce 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
@@ -29,7 +29,7 @@
         <label class="col-md-2 control-label">Transactional</label>
         <div class="col-md-4">
           <label>
-            {{input type="checkbox" checked=settings.transactional}}
+            {{input type="checkbox" checked=settings.transactional  disabled=disableTransactionInput}}
           </label>
         </div>
       </div>
@@ -39,7 +39,6 @@
           <label class="col-md-2 control-label">Number of buckets</label>
           <div class="col-md-6">
             <div class="{{if hasNumBucketError 'has-error'}}">
-
               {{input type="number" class="form-control" value=settings.numBuckets}}
               {{#if hasNumBucketError}}
                 <span class="help-block">{{numBucketErrorText}}</span>
@@ -53,174 +52,178 @@
 
 </div>
 
-<div class="panel panel-info">
-  <div class="panel-heading">
-    <div class="panel-title">
-      <button class="btn btn-primary {{if showLocationInput 'active'}}" {{action "toggleLocation"}}>
-        {{fa-icon (if showLocationInput "minus" "plus")}}
-      </button>
-      &nbsp;&nbsp;&nbsp;Add Location
+{{#if (not editMode)}}
+  <div class="panel panel-info">
+    <div class="panel-heading">
+      <div class="panel-title">
+        <button class="btn btn-primary {{if showLocationInput 'active'}}" {{action "toggleLocation"}}>
+          {{fa-icon (if showLocationInput "minus" "plus")}}
+        </button>
+        &nbsp;&nbsp;&nbsp;Add Location
+      </div>
     </div>
-  </div>
-  {{#if showLocationInput}}
-    <div class="panel-body">
-      <div class="row">
-        <div class="col-md-6">
-          {{input type="text" class="form-control" value=settings.location}}
+    {{#if showLocationInput}}
+      <div class="panel-body">
+        <div class="row">
+          <div class="col-md-6">
+            {{input type="text" class="form-control" value=settings.location}}
+          </div>
+          <button class="btn btn-success" {{action "toggleDirectoryViewer"}}>Select HDFS Directory</button>
         </div>
-        <button class="btn btn-success" {{action "toggleDirectoryViewer"}}>Select HDFS Directory</button>
+        {{#if showDirectoryViewer}}
+          {{hdfs-viewer-modal
+            showSelectedPath=true
+            close="closeHdfsModal"
+            selected="hdfsPathSelected"
+          }}
+        {{/if}}
       </div>
-      {{#if showDirectoryViewer}}
-        {{hdfs-viewer-modal
-          showSelectedPath=true
-          close="closeHdfsModal"
-          selected="hdfsPathSelected"
-        }}
-      {{/if}}
-    </div>
-  {{/if}}
-</div>
+    {{/if}}
+  </div>
 
-<div class="panel panel-info">
-  <div class="panel-heading">
-    <div class="panel-title">
-      <button class="btn btn-primary {{if showFileFormatInput 'active'}}" {{action "toggleFileFormat"}}>
-        {{fa-icon (if showFileFormatInput "minus" "plus")}}
-      </button>
-      &nbsp;&nbsp;&nbsp;Add File Format
+  <div class="panel panel-info">
+    <div class="panel-heading">
+      <div class="panel-title">
+        <button class="btn btn-primary {{if showFileFormatInput 'active'}}" {{action "toggleFileFormat"}}>
+          {{fa-icon (if showFileFormatInput "minus" "plus")}}
+        </button>
+        &nbsp;&nbsp;&nbsp;Add File Format
+      </div>
     </div>
-  </div>
-  {{#if showFileFormatInput}}
-    <div class="panel-body">
-      <div class="row">
-        <div class="col-md-6">
-          {{#power-select
-            selected=selectedFileFormat
-            options=fileFormats
-            searchField="name"
-            searchPlaceholder="Enter data type"
-            onchange=(action "fileFormatSelected") as |parameter|}}
-            {{parameter.name}}
-          {{/power-select}}
+    {{#if showFileFormatInput}}
+      <div class="panel-body">
+        <div class="row">
+          <div class="col-md-6">
+            {{#power-select
+              selected=selectedFileFormat
+              options=fileFormats
+              searchField="name"
+              searchPlaceholder="Enter data type"
+              onchange=(action "fileFormatSelected") as |parameter|}}
+              {{parameter.name}}
+            {{/power-select}}
+          </div>
         </div>
-      </div>
-      {{#if customFileFormat}}
-        <div class="row fileformat-custom-row">
-          <div class="col-md-6 form-horizontal">
-            <div class="form-group">
-              <label class="col-md-3 control-label">Input Format</label>
-              <div class="col-md-9">
-                {{input type="text" class="form-control" value=settings.fileFormat.inputFormat
-                        placeholder="Input format class"}}
+        {{#if customFileFormat}}
+          <div class="row fileformat-custom-row">
+            <div class="col-md-6 form-horizontal">
+              <div class="form-group">
+                <label class="col-md-3 control-label">Input Format</label>
+                <div class="col-md-9">
+                  {{input type="text" class="form-control" value=settings.fileFormat.inputFormat
+                          placeholder="Input format class"}}
+                </div>
               </div>
-            </div>
-            <div class="form-group">
-              <label class="col-md-3 control-label">Output Format</label>
-              <div class="col-md-9">
-                {{input type="text" class="form-control" value=settings.fileFormat.outputFormat
-                        placeholder="Output format class"}}
+              <div class="form-group">
+                <label class="col-md-3 control-label">Output Format</label>
+                <div class="col-md-9">
+                  {{input type="text" class="form-control" value=settings.fileFormat.outputFormat
+                          placeholder="Output format class"}}
+                </div>
               </div>
             </div>
           </div>
-        </div>
-      {{/if}}
+        {{/if}}
 
-    </div>
-  {{/if}}
-</div>
+      </div>
+    {{/if}}
+  </div>
 
-<div class="panel panel-info">
-  <div class="panel-heading">
-    <div class="panel-title">
-      <button class="btn btn-primary {{if showRowFormatInput 'active'}}" {{action "toggleRowFormat"}}>
-        {{fa-icon (if showRowFormatInput "minus" "plus")}}
-      </button>
-      &nbsp;&nbsp;&nbsp;Add Row Format
+  <div class="panel panel-info">
+    <div class="panel-heading">
+      <div class="panel-title">
+        <button class="btn btn-primary {{if showRowFormatInput 'active'}}" {{action "toggleRowFormat"}}>
+          {{fa-icon (if showRowFormatInput "minus" "plus")}}
+        </button>
+        &nbsp;&nbsp;&nbsp;Add Row Format
+      </div>
     </div>
-  </div>
-  {{#if showRowFormatInput}}
-    <div class="panel-body rowformat-custom-row">
-      <div class="row">
-        <div class="col-md-6 form-horizontal">
-          <div class="form-group">
-            <label class="col-md-4 control-label">Fields Terminated By</label>
-            <div class="col-md-7">
-              {{#power-select
-                selected=selectedFieldTerminator
-                options=terminationChars
-                searchField="name"
-                searchPlaceholder="Enter terminator character"
-                onchange=(action "fieldTerminatorSelected") as |parameter|}}
-                {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
-              {{/power-select}}
-            </div>
-            <div class="col-md-1">
-              <a class="text-danger" {{action "clearFieldTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+    {{#if showRowFormatInput}}
+      <div class="panel-body rowformat-custom-row">
+        <div class="row">
+          <div class="col-md-6 form-horizontal">
+            <div class="form-group">
+              <label class="col-md-4 control-label">Fields Terminated By</label>
+              <div class="col-md-7">
+                {{#power-select
+                  selected=selectedFieldTerminator
+                  options=terminationChars
+                  searchField="name"
+                  searchPlaceholder="Enter terminator character"
+                  onchange=(action "fieldTerminatorSelected") as |parameter|}}
+                  {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+                {{/power-select}}
+              </div>
+              <div class="col-md-1">
+                <a class="text-danger" {{action "clearFieldTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+              </div>
             </div>
           </div>
         </div>
-      </div>
-      <div class="row">
-        <div class="col-md-6 form-horizontal">
-          <div class="form-group">
-            <label class="col-md-4 control-label">Lines Terminated By</label>
-            <div class="col-md-7">
-              {{#power-select
-                selected=selectedLinesTerminator
-                options=terminationChars
-                searchField="name"
-                searchPlaceholder="Enter terminator character"
-                onchange=(action "linesTerminatorSelected") as |parameter|}}
-                {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
-              {{/power-select}}
-            </div>
-            <div class="col-md-1">
-              <a class="text-danger" {{action "clearLinesTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+        <div class="row">
+          <div class="col-md-6 form-horizontal">
+            <div class="form-group">
+              <label class="col-md-4 control-label">Lines Terminated By</label>
+              <div class="col-md-7">
+                {{#power-select
+                  selected=selectedLinesTerminator
+                  options=terminationChars
+                  searchField="name"
+                  searchPlaceholder="Enter terminator character"
+                  onchange=(action "linesTerminatorSelected") as |parameter|}}
+                  {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+                {{/power-select}}
+              </div>
+              <div class="col-md-1">
+                <a class="text-danger" {{action "clearLinesTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+              </div>
             </div>
           </div>
         </div>
-      </div>
-      <div class="row">
-        <div class="col-md-6 form-horizontal">
-          <div class="form-group">
-            <label class="col-md-4 control-label">Null Defined As</label>
-            <div class="col-md-7">
-              {{#power-select
-                selected=selectedNullDefinition
-                options=terminationChars
-                searchField="name"
-                searchPlaceholder="Enter terminator character"
-                onchange=(action "nullDefinedAsSelected") as |parameter|}}
-                {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
-              {{/power-select}}
-            </div>
-            <div class="col-md-1">
-              <a class="text-danger" {{action "clearNullDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+        <div class="row">
+          <div class="col-md-6 form-horizontal">
+            <div class="form-group">
+              <label class="col-md-4 control-label">Null Defined As</label>
+              <div class="col-md-7">
+                {{#power-select
+                  selected=selectedNullDefinition
+                  options=terminationChars
+                  searchField="name"
+                  searchPlaceholder="Enter terminator character"
+                  onchange=(action "nullDefinedAsSelected") as |parameter|}}
+                  {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+                {{/power-select}}
+              </div>
+              <div class="col-md-1">
+                <a class="text-danger" {{action "clearNullDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+              </div>
             </div>
           </div>
         </div>
-      </div>
-      <div class="row">
-        <div class="col-md-6 form-horizontal">
-          <div class="form-group">
-            <label class="col-md-4 control-label">Escape Defined As</label>
-            <div class="col-md-7">
-              {{#power-select
-                selected=selectedEscapeDefinition
-                options=terminationChars
-                searchField="name"
-                searchPlaceholder="Enter terminator chanracter"
-                onchange=(action "escapeDefinedAsSelected") as |parameter|}}
-                {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
-              {{/power-select}}
-            </div>
-            <div class="col-md-1">
-              <a class="text-danger" {{action "clearEscapeDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+        <div class="row">
+          <div class="col-md-6 form-horizontal">
+            <div class="form-group">
+              <label class="col-md-4 control-label">Escape Defined As</label>
+              <div class="col-md-7">
+                {{#power-select
+                  selected=selectedEscapeDefinition
+                  options=terminationChars
+                  searchField="name"
+                  searchPlaceholder="Enter terminator chanracter"
+                  onchange=(action "escapeDefinedAsSelected") as |parameter|}}
+                  {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+                {{/power-select}}
+              </div>
+              <div class="col-md-1">
+                <a class="text-danger" {{action "clearEscapeDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+              </div>
             </div>
           </div>
         </div>
       </div>
-    </div>
-  {{/if}}
-</div>
+    {{/if}}
+  </div>
+{{/if}}
+
+
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
index f5fc547..b942136 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
@@ -31,6 +31,7 @@
     {{column-item column=column
                   columnDeleted="columnDeleted"
                   columnUpdated="columnUpdated"
+                  editMode=editMode
     }}
   {{/each}}
   <tr class="new-settings text-center">

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
index 953ef84..802941e 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
@@ -29,6 +29,7 @@
     {{property-item property=property
                   propertyItemDeleted="itemDeleted"
                   propertyItemUpdated="itemUpdated"
+                  editMode=editMode
     }}
   {{/each}}
   <tr class="new-settings text-center">

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
index 0ee3b13..5f62fca 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
@@ -51,6 +51,10 @@
           <td>{{tableStats.numFiles}}</td>
         </tr>
         <tr>
+          <td>Number of Rows</td>
+          <td>{{tableStats.numRows}}</td>
+        </tr>
+        <tr>
           <td>Raw Data Size</td>
           <td>{{tableStats.rawDataSize}}</td>
         </tr>

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
index e3fe400..9a1306a 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
@@ -25,7 +25,7 @@
           {{fa-icon "navicon"}}
         </button>
         <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1">
-          <li><a href="#" class="text-uppercase" {{action "editTable" model}}>{{fa-icon "edit"}} Edit</a></li>
+          <li>{{#link-to "databases.database.tables.table.edit" class="text-uppercase"}}{{fa-icon "edit"}} Edit{{/link-to}}</li>
           <li>{{#link-to "databases.database.tables.table.rename" class="text-uppercase"}}{{fa-icon "edit"}} Rename{{/link-to}}</li>
           <li><a href="#" class="text-uppercase" {{action "deleteTable" model}}>{{fa-icon "trash"}} Delete</a></li>
         </ul>

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs
new file mode 100644
index 0000000..79f1701
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs
@@ -0,0 +1,45 @@
+{{!
+* 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.
+}}
+
+<div class="row">
+  <div class="alert alert-info">
+    <p class="lead">{{fa-icon "pencil-square-o" size=1}} Edit table <strong class="text-uppercase">{{table.table}}</strong></p>
+  </div>
+</div>
+
+<div class="row">
+  {{edit-table   tabs=tabs
+                 table=table
+                 cancel="cancel"
+                 edit="edit"}}
+</div>
+
+{{#if showModal}}
+  {{#modal-dialog
+    translucentOverlay=true
+    container-class="modal-dialog modal-sm"}}
+    <div class="modal-content">
+      <div class="modal-header text-danger">
+        <p class="modal-title">{{fa-icon "plus"}}&nbsp;&nbsp;&nbsp; Create Database</p>
+      </div>
+      <div class="modal-body text-center text-primary">
+        <p>{{modalMessage}}</p>
+      </div>
+    </div><!-- /.modal-content -->
+  {{/modal-dialog}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy b/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy
deleted file mode 100644
index 874e268..0000000
--- a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-* 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.
-*/
-
-
-package org.apache.ambari.view.hive20.internal.query.generators
-
-import spock.lang.Specification
-
-class AlterTableQueryGenerationSpecTest extends Specification {
-//  def "alter simple table"() {
-//    // blocks go here
-//    setup:
-//    def oldTableMeta = new TableMeta()
-//    def newTableMeta = new TableMeta()
-//    def oldCols = new ArrayList<>();
-//    oldCols.add(new ColumnInfo())
-//    oldTableMeta.setColumns()
-//
-//    when:
-//    stack.push(elem)
-//
-//    then:
-//    println "inside AlterTableQueryGenerationSpecTest"
-//    !stack.empty
-//    stack.size() == 1
-//    stack.peek() == elem
-//  }
-//
-//  def "pushing again an element on the stack"() {
-//    // blocks go here
-//    setup:
-//    def stack = new Stack()
-//    def elem = "push me"
-//
-//    when:
-//    stack.push(elem)
-//
-//    then:
-//    println "inside AlterTableQueryGenerationSpecTest"
-//    !stack.empty
-//    stack.size() == 1
-//    stack.peek() == elem
-//  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java b/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
index 45f29da..35ea416 100644
--- a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
+++ b/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
@@ -19,24 +19,19 @@
 package org.apache.ambari.view.hive20.internal.query.generators;
 
 import com.google.common.base.Optional;
+import com.google.gson.Gson;
 import org.apache.ambari.view.hive20.internal.dto.ColumnInfo;
 import org.apache.ambari.view.hive20.internal.dto.TableMeta;
 import org.junit.Assert;
 import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Arrays;
 import java.util.List;
 
 public class AlterTableQueryGeneratorTest {
-  @Test
-  public void getQuery() throws Exception {
-
-  }
-
-  @Test
-  public void generateColumnQuery() throws Exception {
-
-  }
+  private static final Logger LOG = LoggerFactory.getLogger(AlterTableQueryGeneratorTest.class);
 
   @Test
   public void createColumnQueriesForSuccessfulChangeColumn() throws Exception {
@@ -86,9 +81,155 @@ public class AlterTableQueryGeneratorTest {
     List<String> queries = query.get();
 
     Assert.assertEquals("Expected number of column update queries were different.", 4, queries.size());
-    System.out.println(queries);
     String[] expectedQueries = new String[]{" CHANGE COLUMN `col1` `col4` VARCHAR(10) COMMENT \'COMMENT 4\'", " CHANGE COLUMN `col2` `col5` STRING COMMENT \'COMMENT 5\'", " CHANGE COLUMN `col3` `col6` INT"," ADD COLUMNS ( `col7` DATE, `col8` BOOLEAN COMMENT \'COMMENT 8\' )" };
 
     Assert.assertArrayEquals("Column change queries were not equal ", expectedQueries, queries.toArray());
   }
+
+  @Test
+  public void createColumnQueriesForSuccessfulChangeSomeColumns() throws Exception {
+
+    TableMeta oldMeta = new TableMeta();
+    TableMeta newMeta = new TableMeta();
+
+    ColumnInfo colInfo1 = new ColumnInfo("col1", "CHAR(1)", "COMMENT 1"); // with comment
+    ColumnInfo colInfo2 = new ColumnInfo("col2", "DECIMAL(10,5)"); // no comment
+    ColumnInfo colInfo3 = new ColumnInfo("col3", "STRING", "COMMENT-3");
+    ColumnInfo colInfo4 = new ColumnInfo("col4", "VARCHAR(10)", "COMMENT 4");
+    ColumnInfo colInfo5 = new ColumnInfo("col5", "STRING", "COMMENT 5");
+    ColumnInfo colInfo6 = new ColumnInfo("col6", "INT");
+    ColumnInfo colInfo7 = new ColumnInfo("col7", "DATE");
+    ColumnInfo colInfo8 = new ColumnInfo("col8", "BOOLEAN", "COMMENT 8");
+
+    List<ColumnInfo> oldColumns = Arrays.asList(colInfo1, colInfo2, colInfo3);
+    oldMeta.setColumns(oldColumns);
+
+    List<ColumnInfo> newColumns = Arrays.asList(colInfo1, colInfo5, colInfo6); // all changed
+    oldMeta.setColumns(newColumns);
+
+    Optional<List<String>> query = AlterTableQueryGenerator.createColumnQueries(oldColumns, newColumns, false);
+
+    Assert.assertTrue(query.isPresent());
+    List<String> queries = query.get();
+
+    Assert.assertEquals("Expected number of column update queries were different.", 2, queries.size());
+    String[] expectedQueries = new String[]{" CHANGE COLUMN `col2` `col5` STRING COMMENT 'COMMENT 5'", " CHANGE COLUMN `col3` `col6` INT"};
+
+    Assert.assertArrayEquals("Column change queries were not equal ", expectedQueries, queries.toArray());
+  }
+
+  @Test
+  public void createColumnQueriesForSuccessfulAddColumns() throws Exception {
+
+    TableMeta oldMeta = new TableMeta();
+    TableMeta newMeta = new TableMeta();
+
+    ColumnInfo colInfo1 = new ColumnInfo("col1", "CHAR(1)", "COMMENT 1"); // with comment
+    ColumnInfo colInfo2 = new ColumnInfo("col2", "DECIMAL(10,5)"); // no comment
+    ColumnInfo colInfo3 = new ColumnInfo("col3", "STRING", "COMMENT-3");
+    ColumnInfo colInfo4 = new ColumnInfo("col4", "VARCHAR(10)", "COMMENT 4");
+    ColumnInfo colInfo5 = new ColumnInfo("col5", "STRING", "COMMENT 5");
+    ColumnInfo colInfo6 = new ColumnInfo("col6", "INT");
+    ColumnInfo colInfo7 = new ColumnInfo("col7", "DATE");
+    ColumnInfo colInfo8 = new ColumnInfo("col8", "BOOLEAN", "COMMENT 8");
+
+    List<ColumnInfo> oldColumns = Arrays.asList(colInfo1, colInfo2, colInfo3);
+    oldMeta.setColumns(oldColumns);
+
+    List<ColumnInfo> newColumns = Arrays.asList(colInfo1, colInfo2, colInfo3, colInfo5, colInfo6); // all changed
+    oldMeta.setColumns(newColumns);
+
+    Optional<List<String>> query = AlterTableQueryGenerator.createColumnQueries(oldColumns, newColumns, false);
+
+    Assert.assertTrue(query.isPresent());
+    List<String> queries = query.get();
+
+    Assert.assertEquals("Expected number of column update queries were different.", 1, queries.size());
+    String[] expectedQueries = new String[]{" ADD COLUMNS ( `col5` STRING COMMENT 'COMMENT 5', `col6` INT )"};
+
+    Assert.assertArrayEquals("Column change queries were not equal ", expectedQueries, queries.toArray());
+  }
+
+  @Test
+  public void getQueryWithAlterColumn(){
+    String origMetaString = "{  " +
+        "  \"database\": \"default\",  " +
+        "  \"table\": \"table2\",  " +
+        "  \"columns\": [{  " +
+        "   \"name\": \"COL1\",  " +
+        "   \"type\": \"TINYINT\",  " +
+        "   \"comment\": \"\",  " +
+        "   \"precision\": null,  " +
+        "   \"scale\": null  " +
+        "  }, {  " +
+        "   \"name\": \"col2\",  " +
+        "   \"type\": \"VARCHAR\",  " +
+        "   \"comment\": \"\",  " +
+        "   \"precision\": \"333\",  " +
+        "   \"scale\": null  " +
+        "  }, {  " +
+        "   \"name\": \"col3\",  " +
+        "   \"type\": \"DECIMAL\",  " +
+        "   \"comment\": \"\",  " +
+        "   \"precision\": \"33\",  " +
+        "   \"scale\": \"3\"  " +
+        "  }],  " +
+        "  \"partitionInfo\": {  " +
+        "   \"columns\": []  " +
+        "  },  " +
+        "  \"detailedInfo\": {  " +
+        "   \"parameters\": {}  " +
+        "  },  " +
+        "  \"storageInfo\": {}  " +
+        " }";
+    
+    String newMetaString = "{  " +
+        "    \"database\": \"default\",  " +
+        "    \"table\": \"table2\",  " +
+        "    \"columns\": [{  " +
+        "      \"name\": \"col1\",  " +
+        "      \"type\": \"TINYINT\",  " +
+        "      \"comment\": \"\",  " +
+        "      \"precision\": null,  " +
+        "      \"scale\": null  " +
+        "    }, {  " +
+        "      \"name\": \"col3\",  " +
+        "      \"type\": \"STRING\",  " +
+        "      \"comment\": \"\",  " +
+        "      \"precision\": \"333\",  " +
+        "      \"scale\": null  " +
+        "    }, {  " +
+        "      \"name\": \"col4\",  " +
+        "      \"type\": \"TINYINT\",  " +
+        "      \"comment\": \"\",  " +
+        "      \"precision\": null,  " +
+        "      \"scale\": null  " +
+        "    }],  " +
+        "    \"partitionInfo\": {  " +
+        "      \"columns\": []  " +
+        "    },  " +
+        "    \"detailedInfo\": {  " +
+        "      \"parameters\": {}  " +
+        "    },  " +
+        "    \"storageInfo\": {}  " +
+        "  }";
+
+    Gson gson = new Gson();
+    TableMeta origTableMeta = gson.fromJson(origMetaString, TableMeta.class);
+    TableMeta updatedTableMeta = gson.fromJson(newMetaString, TableMeta.class);
+
+    LOG.info("origTableMeta : {},\n\nupdatedTableMeta : {}", origMetaString, updatedTableMeta);
+
+    AlterTableQueryGenerator generator = new AlterTableQueryGenerator(origTableMeta, updatedTableMeta);
+
+    Optional<String> query = generator.getQuery();
+    Assert.assertTrue(query.isPresent());
+    String hqlQuery = query.get();
+
+    LOG.info("hqlQuery : {}", hqlQuery);
+
+    String expectedQuery = " ALTER TABLE `default.table2`  CHANGE COLUMN `col2` `col3` STRING(333);\n" +
+        " ALTER TABLE `default.table2`  CHANGE COLUMN `col3` `col4` TINYINT";
+    Assert.assertEquals("Alter Edit table query did not match ", expectedQuery, hqlQuery);
+  }
 }
\ No newline at end of file