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

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


The following commit(s) were added to refs/heads/master by this push:
     new 7a5bc54b614 HIVE-26882: Allow transactional check of Table parameter 
before altering the Table (#3888) (Peter Vary reviewed by Prasanth Jayachandran 
and Szehon Ho)
7a5bc54b614 is described below

commit 7a5bc54b614f5a14bcf99e63d544db84d2463253
Author: pvary <[email protected]>
AuthorDate: Sun Jan 8 23:02:27 2023 +0100

    HIVE-26882: Allow transactional check of Table parameter before altering 
the Table (#3888) (Peter Vary reviewed by Prasanth Jayachandran and Szehon Ho)
---
 .../thrift/gen-cpp/hive_metastore_constants.cpp    |   4 +
 .../gen/thrift/gen-cpp/hive_metastore_constants.h  |   2 +
 .../gen/thrift/gen-cpp/hive_metastore_types.cpp    |  44 +++++
 .../src/gen/thrift/gen-cpp/hive_metastore_types.h  |  22 ++-
 .../hive/metastore/api/AlterTableRequest.java      | 220 ++++++++++++++++++++-
 .../metastore/api/hive_metastoreConstants.java     |   7 +-
 .../thrift/gen-php/metastore/AlterTableRequest.php |  48 +++++
 .../src/gen/thrift/gen-php/metastore/Constant.php  |  12 ++
 .../gen/thrift/gen-py/hive_metastore/constants.py  |   2 +
 .../src/gen/thrift/gen-py/hive_metastore/ttypes.py |  26 ++-
 .../gen/thrift/gen-rb/hive_metastore_constants.rb  |   4 +
 .../src/gen/thrift/gen-rb/hive_metastore_types.rb  |   6 +-
 .../src/main/thrift/hive_metastore.thrift          |   8 +-
 .../apache/hadoop/hive/metastore/HMSHandler.java   |  20 +-
 .../hadoop/hive/metastore/HiveAlterHandler.java    |  19 +-
 .../apache/hadoop/hive/metastore/ObjectStore.java  |  28 ++-
 .../org/apache/hadoop/hive/metastore/RawStore.java |  16 +-
 .../client/TestTablesCreateDropAlterTruncate.java  | 103 ++++++++++
 18 files changed, 566 insertions(+), 25 deletions(-)

diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.cpp
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.cpp
index 16a9bf7f3c6..4dbdcc51047 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.cpp
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.cpp
@@ -91,6 +91,10 @@ hive_metastoreConstants::hive_metastoreConstants() {
 
   WRITE_ID = "writeId";
 
+  EXPECTED_PARAMETER_KEY = "expected_parameter_key";
+
+  EXPECTED_PARAMETER_VALUE = "expected_parameter_value";
+
 }
 
 }}} // namespace
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.h
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.h
index 2097a8e7f00..df7dd187fcf 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.h
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_constants.h
@@ -55,6 +55,8 @@ class hive_metastoreConstants {
   std::string DEFAULT_TABLE_TYPE;
   std::string TXN_ID;
   std::string WRITE_ID;
+  std::string EXPECTED_PARAMETER_KEY;
+  std::string EXPECTED_PARAMETER_VALUE;
 };
 
 extern const hive_metastoreConstants g_hive_metastore_constants;
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.cpp
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.cpp
index 77fc3ec076d..a482833ebec 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.cpp
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.cpp
@@ -45654,6 +45654,16 @@ void 
AlterTableRequest::__set_processorIdentifier(const std::string& val) {
   this->processorIdentifier = val;
 __isset.processorIdentifier = true;
 }
+
+void AlterTableRequest::__set_expectedParameterKey(const std::string& val) {
+  this->expectedParameterKey = val;
+__isset.expectedParameterKey = true;
+}
+
+void AlterTableRequest::__set_expectedParameterValue(const std::string& val) {
+  this->expectedParameterValue = val;
+__isset.expectedParameterValue = true;
+}
 std::ostream& operator<<(std::ostream& out, const AlterTableRequest& obj)
 {
   obj.printTo(out);
@@ -45769,6 +45779,22 @@ uint32_t 
AlterTableRequest::read(::apache::thrift::protocol::TProtocol* iprot) {
           xfer += iprot->skip(ftype);
         }
         break;
+      case 10:
+        if (ftype == ::apache::thrift::protocol::T_STRING) {
+          xfer += iprot->readString(this->expectedParameterKey);
+          this->__isset.expectedParameterKey = true;
+        } else {
+          xfer += iprot->skip(ftype);
+        }
+        break;
+      case 11:
+        if (ftype == ::apache::thrift::protocol::T_STRING) {
+          xfer += iprot->readString(this->expectedParameterValue);
+          this->__isset.expectedParameterValue = true;
+        } else {
+          xfer += iprot->skip(ftype);
+        }
+        break;
       default:
         xfer += iprot->skip(ftype);
         break;
@@ -45842,6 +45868,16 @@ uint32_t 
AlterTableRequest::write(::apache::thrift::protocol::TProtocol* oprot)
     xfer += oprot->writeString(this->processorIdentifier);
     xfer += oprot->writeFieldEnd();
   }
+  if (this->__isset.expectedParameterKey) {
+    xfer += oprot->writeFieldBegin("expectedParameterKey", 
::apache::thrift::protocol::T_STRING, 10);
+    xfer += oprot->writeString(this->expectedParameterKey);
+    xfer += oprot->writeFieldEnd();
+  }
+  if (this->__isset.expectedParameterValue) {
+    xfer += oprot->writeFieldBegin("expectedParameterValue", 
::apache::thrift::protocol::T_STRING, 11);
+    xfer += oprot->writeString(this->expectedParameterValue);
+    xfer += oprot->writeFieldEnd();
+  }
   xfer += oprot->writeFieldStop();
   xfer += oprot->writeStructEnd();
   return xfer;
@@ -45858,6 +45894,8 @@ void swap(AlterTableRequest &a, AlterTableRequest &b) {
   swap(a.validWriteIdList, b.validWriteIdList);
   swap(a.processorCapabilities, b.processorCapabilities);
   swap(a.processorIdentifier, b.processorIdentifier);
+  swap(a.expectedParameterKey, b.expectedParameterKey);
+  swap(a.expectedParameterValue, b.expectedParameterValue);
   swap(a.__isset, b.__isset);
 }
 
@@ -45871,6 +45909,8 @@ AlterTableRequest::AlterTableRequest(const 
AlterTableRequest& other1573) {
   validWriteIdList = other1573.validWriteIdList;
   processorCapabilities = other1573.processorCapabilities;
   processorIdentifier = other1573.processorIdentifier;
+  expectedParameterKey = other1573.expectedParameterKey;
+  expectedParameterValue = other1573.expectedParameterValue;
   __isset = other1573.__isset;
 }
 AlterTableRequest& AlterTableRequest::operator=(const AlterTableRequest& 
other1574) {
@@ -45883,6 +45923,8 @@ AlterTableRequest& AlterTableRequest::operator=(const 
AlterTableRequest& other15
   validWriteIdList = other1574.validWriteIdList;
   processorCapabilities = other1574.processorCapabilities;
   processorIdentifier = other1574.processorIdentifier;
+  expectedParameterKey = other1574.expectedParameterKey;
+  expectedParameterValue = other1574.expectedParameterValue;
   __isset = other1574.__isset;
   return *this;
 }
@@ -45898,6 +45940,8 @@ void AlterTableRequest::printTo(std::ostream& out) 
const {
   out << ", " << "validWriteIdList="; (__isset.validWriteIdList ? (out << 
to_string(validWriteIdList)) : (out << "<null>"));
   out << ", " << "processorCapabilities="; (__isset.processorCapabilities ? 
(out << to_string(processorCapabilities)) : (out << "<null>"));
   out << ", " << "processorIdentifier="; (__isset.processorIdentifier ? (out 
<< to_string(processorIdentifier)) : (out << "<null>"));
+  out << ", " << "expectedParameterKey="; (__isset.expectedParameterKey ? (out 
<< to_string(expectedParameterKey)) : (out << "<null>"));
+  out << ", " << "expectedParameterValue="; (__isset.expectedParameterValue ? 
(out << to_string(expectedParameterValue)) : (out << "<null>"));
   out << ")";
 }
 
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.h
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.h
index 02df01b1042..bac4f87320d 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.h
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-cpp/hive_metastore_types.h
@@ -18054,13 +18054,15 @@ void swap(RenamePartitionResponse &a, 
RenamePartitionResponse &b);
 std::ostream& operator<<(std::ostream& out, const RenamePartitionResponse& 
obj);
 
 typedef struct _AlterTableRequest__isset {
-  _AlterTableRequest__isset() : catName(false), environmentContext(false), 
writeId(true), validWriteIdList(false), processorCapabilities(false), 
processorIdentifier(false) {}
+  _AlterTableRequest__isset() : catName(false), environmentContext(false), 
writeId(true), validWriteIdList(false), processorCapabilities(false), 
processorIdentifier(false), expectedParameterKey(false), 
expectedParameterValue(false) {}
   bool catName :1;
   bool environmentContext :1;
   bool writeId :1;
   bool validWriteIdList :1;
   bool processorCapabilities :1;
   bool processorIdentifier :1;
+  bool expectedParameterKey :1;
+  bool expectedParameterValue :1;
 } _AlterTableRequest__isset;
 
 class AlterTableRequest : public virtual ::apache::thrift::TBase {
@@ -18074,7 +18076,9 @@ class AlterTableRequest : public virtual 
::apache::thrift::TBase {
                       tableName(),
                       writeId(-1LL),
                       validWriteIdList(),
-                      processorIdentifier() {
+                      processorIdentifier(),
+                      expectedParameterKey(),
+                      expectedParameterValue() {
   }
 
   virtual ~AlterTableRequest() noexcept;
@@ -18087,6 +18091,8 @@ class AlterTableRequest : public virtual 
::apache::thrift::TBase {
   std::string validWriteIdList;
   std::vector<std::string>  processorCapabilities;
   std::string processorIdentifier;
+  std::string expectedParameterKey;
+  std::string expectedParameterValue;
 
   _AlterTableRequest__isset __isset;
 
@@ -18108,6 +18114,10 @@ class AlterTableRequest : public virtual 
::apache::thrift::TBase {
 
   void __set_processorIdentifier(const std::string& val);
 
+  void __set_expectedParameterKey(const std::string& val);
+
+  void __set_expectedParameterValue(const std::string& val);
+
   bool operator == (const AlterTableRequest & rhs) const
   {
     if (__isset.catName != rhs.__isset.catName)
@@ -18140,6 +18150,14 @@ class AlterTableRequest : public virtual 
::apache::thrift::TBase {
       return false;
     else if (__isset.processorIdentifier && !(processorIdentifier == 
rhs.processorIdentifier))
       return false;
+    if (__isset.expectedParameterKey != rhs.__isset.expectedParameterKey)
+      return false;
+    else if (__isset.expectedParameterKey && !(expectedParameterKey == 
rhs.expectedParameterKey))
+      return false;
+    if (__isset.expectedParameterValue != rhs.__isset.expectedParameterValue)
+      return false;
+    else if (__isset.expectedParameterValue && !(expectedParameterValue == 
rhs.expectedParameterValue))
+      return false;
     return true;
   }
   bool operator != (const AlterTableRequest &rhs) const {
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/AlterTableRequest.java
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/AlterTableRequest.java
index 54644cbf8be..8caab7fb277 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/AlterTableRequest.java
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/AlterTableRequest.java
@@ -20,6 +20,8 @@ package org.apache.hadoop.hive.metastore.api;
   private static final org.apache.thrift.protocol.TField 
VALID_WRITE_ID_LIST_FIELD_DESC = new 
org.apache.thrift.protocol.TField("validWriteIdList", 
org.apache.thrift.protocol.TType.STRING, (short)7);
   private static final org.apache.thrift.protocol.TField 
PROCESSOR_CAPABILITIES_FIELD_DESC = new 
org.apache.thrift.protocol.TField("processorCapabilities", 
org.apache.thrift.protocol.TType.LIST, (short)8);
   private static final org.apache.thrift.protocol.TField 
PROCESSOR_IDENTIFIER_FIELD_DESC = new 
org.apache.thrift.protocol.TField("processorIdentifier", 
org.apache.thrift.protocol.TType.STRING, (short)9);
+  private static final org.apache.thrift.protocol.TField 
EXPECTED_PARAMETER_KEY_FIELD_DESC = new 
org.apache.thrift.protocol.TField("expectedParameterKey", 
org.apache.thrift.protocol.TType.STRING, (short)10);
+  private static final org.apache.thrift.protocol.TField 
EXPECTED_PARAMETER_VALUE_FIELD_DESC = new 
org.apache.thrift.protocol.TField("expectedParameterValue", 
org.apache.thrift.protocol.TType.STRING, (short)11);
 
   private static final org.apache.thrift.scheme.SchemeFactory 
STANDARD_SCHEME_FACTORY = new AlterTableRequestStandardSchemeFactory();
   private static final org.apache.thrift.scheme.SchemeFactory 
TUPLE_SCHEME_FACTORY = new AlterTableRequestTupleSchemeFactory();
@@ -33,6 +35,8 @@ package org.apache.hadoop.hive.metastore.api;
   private @org.apache.thrift.annotation.Nullable java.lang.String 
validWriteIdList; // optional
   private @org.apache.thrift.annotation.Nullable 
java.util.List<java.lang.String> processorCapabilities; // optional
   private @org.apache.thrift.annotation.Nullable java.lang.String 
processorIdentifier; // optional
+  private @org.apache.thrift.annotation.Nullable java.lang.String 
expectedParameterKey; // optional
+  private @org.apache.thrift.annotation.Nullable java.lang.String 
expectedParameterValue; // optional
 
   /** The set of fields this struct contains, along with convenience methods 
for finding and manipulating them. */
   public enum _Fields implements org.apache.thrift.TFieldIdEnum {
@@ -44,7 +48,9 @@ package org.apache.hadoop.hive.metastore.api;
     WRITE_ID((short)6, "writeId"),
     VALID_WRITE_ID_LIST((short)7, "validWriteIdList"),
     PROCESSOR_CAPABILITIES((short)8, "processorCapabilities"),
-    PROCESSOR_IDENTIFIER((short)9, "processorIdentifier");
+    PROCESSOR_IDENTIFIER((short)9, "processorIdentifier"),
+    EXPECTED_PARAMETER_KEY((short)10, "expectedParameterKey"),
+    EXPECTED_PARAMETER_VALUE((short)11, "expectedParameterValue");
 
     private static final java.util.Map<java.lang.String, _Fields> byName = new 
java.util.HashMap<java.lang.String, _Fields>();
 
@@ -78,6 +84,10 @@ package org.apache.hadoop.hive.metastore.api;
           return PROCESSOR_CAPABILITIES;
         case 9: // PROCESSOR_IDENTIFIER
           return PROCESSOR_IDENTIFIER;
+        case 10: // EXPECTED_PARAMETER_KEY
+          return EXPECTED_PARAMETER_KEY;
+        case 11: // EXPECTED_PARAMETER_VALUE
+          return EXPECTED_PARAMETER_VALUE;
         default:
           return null;
       }
@@ -121,7 +131,7 @@ package org.apache.hadoop.hive.metastore.api;
   // isset id assignments
   private static final int __WRITEID_ISSET_ID = 0;
   private byte __isset_bitfield = 0;
-  private static final _Fields optionals[] = 
{_Fields.CAT_NAME,_Fields.ENVIRONMENT_CONTEXT,_Fields.WRITE_ID,_Fields.VALID_WRITE_ID_LIST,_Fields.PROCESSOR_CAPABILITIES,_Fields.PROCESSOR_IDENTIFIER};
+  private static final _Fields optionals[] = 
{_Fields.CAT_NAME,_Fields.ENVIRONMENT_CONTEXT,_Fields.WRITE_ID,_Fields.VALID_WRITE_ID_LIST,_Fields.PROCESSOR_CAPABILITIES,_Fields.PROCESSOR_IDENTIFIER,_Fields.EXPECTED_PARAMETER_KEY,_Fields.EXPECTED_PARAMETER_VALUE};
   public static final java.util.Map<_Fields, 
org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
   static {
     java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = 
new java.util.EnumMap<_Fields, 
org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
@@ -144,6 +154,10 @@ package org.apache.hadoop.hive.metastore.api;
             new 
org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))));
     tmpMap.put(_Fields.PROCESSOR_IDENTIFIER, new 
org.apache.thrift.meta_data.FieldMetaData("processorIdentifier", 
org.apache.thrift.TFieldRequirementType.OPTIONAL, 
         new 
org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.EXPECTED_PARAMETER_KEY, new 
org.apache.thrift.meta_data.FieldMetaData("expectedParameterKey", 
org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new 
org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.EXPECTED_PARAMETER_VALUE, new 
org.apache.thrift.meta_data.FieldMetaData("expectedParameterValue", 
org.apache.thrift.TFieldRequirementType.OPTIONAL, 
+        new 
org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
     metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
     
org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(AlterTableRequest.class,
 metaDataMap);
   }
@@ -195,6 +209,12 @@ package org.apache.hadoop.hive.metastore.api;
     if (other.isSetProcessorIdentifier()) {
       this.processorIdentifier = other.processorIdentifier;
     }
+    if (other.isSetExpectedParameterKey()) {
+      this.expectedParameterKey = other.expectedParameterKey;
+    }
+    if (other.isSetExpectedParameterValue()) {
+      this.expectedParameterValue = other.expectedParameterValue;
+    }
   }
 
   public AlterTableRequest deepCopy() {
@@ -213,6 +233,8 @@ package org.apache.hadoop.hive.metastore.api;
     this.validWriteIdList = null;
     this.processorCapabilities = null;
     this.processorIdentifier = null;
+    this.expectedParameterKey = null;
+    this.expectedParameterValue = null;
   }
 
   @org.apache.thrift.annotation.Nullable
@@ -445,6 +467,54 @@ package org.apache.hadoop.hive.metastore.api;
     }
   }
 
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getExpectedParameterKey() {
+    return this.expectedParameterKey;
+  }
+
+  public void setExpectedParameterKey(@org.apache.thrift.annotation.Nullable 
java.lang.String expectedParameterKey) {
+    this.expectedParameterKey = expectedParameterKey;
+  }
+
+  public void unsetExpectedParameterKey() {
+    this.expectedParameterKey = null;
+  }
+
+  /** Returns true if field expectedParameterKey is set (has been assigned a 
value) and false otherwise */
+  public boolean isSetExpectedParameterKey() {
+    return this.expectedParameterKey != null;
+  }
+
+  public void setExpectedParameterKeyIsSet(boolean value) {
+    if (!value) {
+      this.expectedParameterKey = null;
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getExpectedParameterValue() {
+    return this.expectedParameterValue;
+  }
+
+  public void setExpectedParameterValue(@org.apache.thrift.annotation.Nullable 
java.lang.String expectedParameterValue) {
+    this.expectedParameterValue = expectedParameterValue;
+  }
+
+  public void unsetExpectedParameterValue() {
+    this.expectedParameterValue = null;
+  }
+
+  /** Returns true if field expectedParameterValue is set (has been assigned a 
value) and false otherwise */
+  public boolean isSetExpectedParameterValue() {
+    return this.expectedParameterValue != null;
+  }
+
+  public void setExpectedParameterValueIsSet(boolean value) {
+    if (!value) {
+      this.expectedParameterValue = null;
+    }
+  }
+
   public void setFieldValue(_Fields field, 
@org.apache.thrift.annotation.Nullable java.lang.Object value) {
     switch (field) {
     case CAT_NAME:
@@ -519,6 +589,22 @@ package org.apache.hadoop.hive.metastore.api;
       }
       break;
 
+    case EXPECTED_PARAMETER_KEY:
+      if (value == null) {
+        unsetExpectedParameterKey();
+      } else {
+        setExpectedParameterKey((java.lang.String)value);
+      }
+      break;
+
+    case EXPECTED_PARAMETER_VALUE:
+      if (value == null) {
+        unsetExpectedParameterValue();
+      } else {
+        setExpectedParameterValue((java.lang.String)value);
+      }
+      break;
+
     }
   }
 
@@ -552,6 +638,12 @@ package org.apache.hadoop.hive.metastore.api;
     case PROCESSOR_IDENTIFIER:
       return getProcessorIdentifier();
 
+    case EXPECTED_PARAMETER_KEY:
+      return getExpectedParameterKey();
+
+    case EXPECTED_PARAMETER_VALUE:
+      return getExpectedParameterValue();
+
     }
     throw new java.lang.IllegalStateException();
   }
@@ -581,6 +673,10 @@ package org.apache.hadoop.hive.metastore.api;
       return isSetProcessorCapabilities();
     case PROCESSOR_IDENTIFIER:
       return isSetProcessorIdentifier();
+    case EXPECTED_PARAMETER_KEY:
+      return isSetExpectedParameterKey();
+    case EXPECTED_PARAMETER_VALUE:
+      return isSetExpectedParameterValue();
     }
     throw new java.lang.IllegalStateException();
   }
@@ -679,6 +775,24 @@ package org.apache.hadoop.hive.metastore.api;
         return false;
     }
 
+    boolean this_present_expectedParameterKey = true && 
this.isSetExpectedParameterKey();
+    boolean that_present_expectedParameterKey = true && 
that.isSetExpectedParameterKey();
+    if (this_present_expectedParameterKey || 
that_present_expectedParameterKey) {
+      if (!(this_present_expectedParameterKey && 
that_present_expectedParameterKey))
+        return false;
+      if (!this.expectedParameterKey.equals(that.expectedParameterKey))
+        return false;
+    }
+
+    boolean this_present_expectedParameterValue = true && 
this.isSetExpectedParameterValue();
+    boolean that_present_expectedParameterValue = true && 
that.isSetExpectedParameterValue();
+    if (this_present_expectedParameterValue || 
that_present_expectedParameterValue) {
+      if (!(this_present_expectedParameterValue && 
that_present_expectedParameterValue))
+        return false;
+      if (!this.expectedParameterValue.equals(that.expectedParameterValue))
+        return false;
+    }
+
     return true;
   }
 
@@ -722,6 +836,14 @@ package org.apache.hadoop.hive.metastore.api;
     if (isSetProcessorIdentifier())
       hashCode = hashCode * 8191 + processorIdentifier.hashCode();
 
+    hashCode = hashCode * 8191 + ((isSetExpectedParameterKey()) ? 131071 : 
524287);
+    if (isSetExpectedParameterKey())
+      hashCode = hashCode * 8191 + expectedParameterKey.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetExpectedParameterValue()) ? 131071 : 
524287);
+    if (isSetExpectedParameterValue())
+      hashCode = hashCode * 8191 + expectedParameterValue.hashCode();
+
     return hashCode;
   }
 
@@ -823,6 +945,26 @@ package org.apache.hadoop.hive.metastore.api;
         return lastComparison;
       }
     }
+    lastComparison = java.lang.Boolean.compare(isSetExpectedParameterKey(), 
other.isSetExpectedParameterKey());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetExpectedParameterKey()) {
+      lastComparison = 
org.apache.thrift.TBaseHelper.compareTo(this.expectedParameterKey, 
other.expectedParameterKey);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetExpectedParameterValue(), 
other.isSetExpectedParameterValue());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetExpectedParameterValue()) {
+      lastComparison = 
org.apache.thrift.TBaseHelper.compareTo(this.expectedParameterValue, 
other.expectedParameterValue);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
     return 0;
   }
 
@@ -923,6 +1065,26 @@ package org.apache.hadoop.hive.metastore.api;
       }
       first = false;
     }
+    if (isSetExpectedParameterKey()) {
+      if (!first) sb.append(", ");
+      sb.append("expectedParameterKey:");
+      if (this.expectedParameterKey == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.expectedParameterKey);
+      }
+      first = false;
+    }
+    if (isSetExpectedParameterValue()) {
+      if (!first) sb.append(", ");
+      sb.append("expectedParameterValue:");
+      if (this.expectedParameterValue == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.expectedParameterValue);
+      }
+      first = false;
+    }
     sb.append(")");
     return sb.toString();
   }
@@ -1070,6 +1232,22 @@ package org.apache.hadoop.hive.metastore.api;
               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
             }
             break;
+          case 10: // EXPECTED_PARAMETER_KEY
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.expectedParameterKey = iprot.readString();
+              struct.setExpectedParameterKeyIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+            }
+            break;
+          case 11: // EXPECTED_PARAMETER_VALUE
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.expectedParameterValue = iprot.readString();
+              struct.setExpectedParameterValueIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+            }
+            break;
           default:
             org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
         }
@@ -1145,6 +1323,20 @@ package org.apache.hadoop.hive.metastore.api;
           oprot.writeFieldEnd();
         }
       }
+      if (struct.expectedParameterKey != null) {
+        if (struct.isSetExpectedParameterKey()) {
+          oprot.writeFieldBegin(EXPECTED_PARAMETER_KEY_FIELD_DESC);
+          oprot.writeString(struct.expectedParameterKey);
+          oprot.writeFieldEnd();
+        }
+      }
+      if (struct.expectedParameterValue != null) {
+        if (struct.isSetExpectedParameterValue()) {
+          oprot.writeFieldBegin(EXPECTED_PARAMETER_VALUE_FIELD_DESC);
+          oprot.writeString(struct.expectedParameterValue);
+          oprot.writeFieldEnd();
+        }
+      }
       oprot.writeFieldStop();
       oprot.writeStructEnd();
     }
@@ -1184,7 +1376,13 @@ package org.apache.hadoop.hive.metastore.api;
       if (struct.isSetProcessorIdentifier()) {
         optionals.set(5);
       }
-      oprot.writeBitSet(optionals, 6);
+      if (struct.isSetExpectedParameterKey()) {
+        optionals.set(6);
+      }
+      if (struct.isSetExpectedParameterValue()) {
+        optionals.set(7);
+      }
+      oprot.writeBitSet(optionals, 8);
       if (struct.isSetCatName()) {
         oprot.writeString(struct.catName);
       }
@@ -1209,6 +1407,12 @@ package org.apache.hadoop.hive.metastore.api;
       if (struct.isSetProcessorIdentifier()) {
         oprot.writeString(struct.processorIdentifier);
       }
+      if (struct.isSetExpectedParameterKey()) {
+        oprot.writeString(struct.expectedParameterKey);
+      }
+      if (struct.isSetExpectedParameterValue()) {
+        oprot.writeString(struct.expectedParameterValue);
+      }
     }
 
     @Override
@@ -1221,7 +1425,7 @@ package org.apache.hadoop.hive.metastore.api;
       struct.table = new Table();
       struct.table.read(iprot);
       struct.setTableIsSet(true);
-      java.util.BitSet incoming = iprot.readBitSet(6);
+      java.util.BitSet incoming = iprot.readBitSet(8);
       if (incoming.get(0)) {
         struct.catName = iprot.readString();
         struct.setCatNameIsSet(true);
@@ -1256,6 +1460,14 @@ package org.apache.hadoop.hive.metastore.api;
         struct.processorIdentifier = iprot.readString();
         struct.setProcessorIdentifierIsSet(true);
       }
+      if (incoming.get(6)) {
+        struct.expectedParameterKey = iprot.readString();
+        struct.setExpectedParameterKeyIsSet(true);
+      }
+      if (incoming.get(7)) {
+        struct.expectedParameterValue = iprot.readString();
+        struct.setExpectedParameterValueIsSet(true);
+      }
     }
   }
 
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/hive_metastoreConstants.java
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/hive_metastoreConstants.java
index 38981623437..e4cc6f74044 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/hive_metastoreConstants.java
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-javabean/org/apache/hadoop/hive/metastore/api/hive_metastoreConstants.java
@@ -73,9 +73,6 @@ package org.apache.hadoop.hive.metastore.api;
 
   public static final java.lang.String JDBC_CONFIG_PREFIX = "hive.sql.";
 
-  /**
-   * Table is created via create table as select or create materialized view 
statement
-   */
   public static final java.lang.String TABLE_IS_CTAS = "created_with_ctas";
 
   public static final java.lang.String TABLE_IS_CTLT = "created_with_ctlt";
@@ -92,4 +89,8 @@ package org.apache.hadoop.hive.metastore.api;
 
   public static final java.lang.String WRITE_ID = "writeId";
 
+  public static final java.lang.String EXPECTED_PARAMETER_KEY = 
"expected_parameter_key";
+
+  public static final java.lang.String EXPECTED_PARAMETER_VALUE = 
"expected_parameter_value";
+
 }
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/AlterTableRequest.php
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/AlterTableRequest.php
index e5c07617ca8..a89e0790660 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/AlterTableRequest.php
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/AlterTableRequest.php
@@ -72,6 +72,16 @@ class AlterTableRequest
             'isRequired' => false,
             'type' => TType::STRING,
         ),
+        10 => array(
+            'var' => 'expectedParameterKey',
+            'isRequired' => false,
+            'type' => TType::STRING,
+        ),
+        11 => array(
+            'var' => 'expectedParameterValue',
+            'isRequired' => false,
+            'type' => TType::STRING,
+        ),
     );
 
     /**
@@ -110,6 +120,14 @@ class AlterTableRequest
      * @var string
      */
     public $processorIdentifier = null;
+    /**
+     * @var string
+     */
+    public $expectedParameterKey = null;
+    /**
+     * @var string
+     */
+    public $expectedParameterValue = null;
 
     public function __construct($vals = null)
     {
@@ -141,6 +159,12 @@ class AlterTableRequest
             if (isset($vals['processorIdentifier'])) {
                 $this->processorIdentifier = $vals['processorIdentifier'];
             }
+            if (isset($vals['expectedParameterKey'])) {
+                $this->expectedParameterKey = $vals['expectedParameterKey'];
+            }
+            if (isset($vals['expectedParameterValue'])) {
+                $this->expectedParameterValue = 
$vals['expectedParameterValue'];
+            }
         }
     }
 
@@ -237,6 +261,20 @@ class AlterTableRequest
                         $xfer += $input->skip($ftype);
                     }
                     break;
+                case 10:
+                    if ($ftype == TType::STRING) {
+                        $xfer += 
$input->readString($this->expectedParameterKey);
+                    } else {
+                        $xfer += $input->skip($ftype);
+                    }
+                    break;
+                case 11:
+                    if ($ftype == TType::STRING) {
+                        $xfer += 
$input->readString($this->expectedParameterValue);
+                    } else {
+                        $xfer += $input->skip($ftype);
+                    }
+                    break;
                 default:
                     $xfer += $input->skip($ftype);
                     break;
@@ -309,6 +347,16 @@ class AlterTableRequest
             $xfer += $output->writeString($this->processorIdentifier);
             $xfer += $output->writeFieldEnd();
         }
+        if ($this->expectedParameterKey !== null) {
+            $xfer += $output->writeFieldBegin('expectedParameterKey', 
TType::STRING, 10);
+            $xfer += $output->writeString($this->expectedParameterKey);
+            $xfer += $output->writeFieldEnd();
+        }
+        if ($this->expectedParameterValue !== null) {
+            $xfer += $output->writeFieldBegin('expectedParameterValue', 
TType::STRING, 11);
+            $xfer += $output->writeString($this->expectedParameterValue);
+            $xfer += $output->writeFieldEnd();
+        }
         $xfer += $output->writeFieldStop();
         $xfer += $output->writeStructEnd();
         return $xfer;
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/Constant.php
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/Constant.php
index 616b7f32117..783157a630d 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/Constant.php
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-php/metastore/Constant.php
@@ -58,6 +58,8 @@ final class Constant extends \Thrift\Type\TConstant
     static protected $DEFAULT_TABLE_TYPE;
     static protected $TXN_ID;
     static protected $WRITE_ID;
+    static protected $EXPECTED_PARAMETER_KEY;
+    static protected $EXPECTED_PARAMETER_VALUE;
 
     protected static function init_DDL_TIME()
     {
@@ -258,4 +260,14 @@ final class Constant extends \Thrift\Type\TConstant
     {
         return "writeId";
     }
+
+    protected static function init_EXPECTED_PARAMETER_KEY()
+    {
+        return "expected_parameter_key";
+    }
+
+    protected static function init_EXPECTED_PARAMETER_VALUE()
+    {
+        return "expected_parameter_value";
+    }
 }
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/constants.py
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/constants.py
index a65791d8939..8e36c5160a9 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/constants.py
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/constants.py
@@ -52,3 +52,5 @@ CTAS_LEGACY_CONFIG = "create_table_as_external"
 DEFAULT_TABLE_TYPE = "defaultTableType"
 TXN_ID = "txnId"
 WRITE_ID = "writeId"
+EXPECTED_PARAMETER_KEY = "expected_parameter_key"
+EXPECTED_PARAMETER_VALUE = "expected_parameter_value"
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/ttypes.py
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/ttypes.py
index 041b55dc0ca..5f0c58a0ed7 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/ttypes.py
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-py/hive_metastore/ttypes.py
@@ -26102,11 +26102,13 @@ class AlterTableRequest(object):
      - validWriteIdList
      - processorCapabilities
      - processorIdentifier
+     - expectedParameterKey
+     - expectedParameterValue
 
     """
 
 
-    def __init__(self, catName=None, dbName=None, tableName=None, table=None, 
environmentContext=None, writeId=-1, validWriteIdList=None, 
processorCapabilities=None, processorIdentifier=None,):
+    def __init__(self, catName=None, dbName=None, tableName=None, table=None, 
environmentContext=None, writeId=-1, validWriteIdList=None, 
processorCapabilities=None, processorIdentifier=None, 
expectedParameterKey=None, expectedParameterValue=None,):
         self.catName = catName
         self.dbName = dbName
         self.tableName = tableName
@@ -26116,6 +26118,8 @@ class AlterTableRequest(object):
         self.validWriteIdList = validWriteIdList
         self.processorCapabilities = processorCapabilities
         self.processorIdentifier = processorIdentifier
+        self.expectedParameterKey = expectedParameterKey
+        self.expectedParameterValue = expectedParameterValue
 
     def read(self, iprot):
         if iprot._fast_decode is not None and isinstance(iprot.trans, 
TTransport.CReadableTransport) and self.thrift_spec is not None:
@@ -26178,6 +26182,16 @@ class AlterTableRequest(object):
                     self.processorIdentifier = 
iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 
2 else iprot.readString()
                 else:
                     iprot.skip(ftype)
+            elif fid == 10:
+                if ftype == TType.STRING:
+                    self.expectedParameterKey = 
iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 
2 else iprot.readString()
+                else:
+                    iprot.skip(ftype)
+            elif fid == 11:
+                if ftype == TType.STRING:
+                    self.expectedParameterValue = 
iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 
2 else iprot.readString()
+                else:
+                    iprot.skip(ftype)
             else:
                 iprot.skip(ftype)
             iprot.readFieldEnd()
@@ -26227,6 +26241,14 @@ class AlterTableRequest(object):
             oprot.writeFieldBegin('processorIdentifier', TType.STRING, 9)
             oprot.writeString(self.processorIdentifier.encode('utf-8') if 
sys.version_info[0] == 2 else self.processorIdentifier)
             oprot.writeFieldEnd()
+        if self.expectedParameterKey is not None:
+            oprot.writeFieldBegin('expectedParameterKey', TType.STRING, 10)
+            oprot.writeString(self.expectedParameterKey.encode('utf-8') if 
sys.version_info[0] == 2 else self.expectedParameterKey)
+            oprot.writeFieldEnd()
+        if self.expectedParameterValue is not None:
+            oprot.writeFieldBegin('expectedParameterValue', TType.STRING, 11)
+            oprot.writeString(self.expectedParameterValue.encode('utf-8') if 
sys.version_info[0] == 2 else self.expectedParameterValue)
+            oprot.writeFieldEnd()
         oprot.writeFieldStop()
         oprot.writeStructEnd()
 
@@ -32107,6 +32129,8 @@ AlterTableRequest.thrift_spec = (
     (7, TType.STRING, 'validWriteIdList', 'UTF8', None, ),  # 7
     (8, TType.LIST, 'processorCapabilities', (TType.STRING, 'UTF8', False), 
None, ),  # 8
     (9, TType.STRING, 'processorIdentifier', 'UTF8', None, ),  # 9
+    (10, TType.STRING, 'expectedParameterKey', 'UTF8', None, ),  # 10
+    (11, TType.STRING, 'expectedParameterValue', 'UTF8', None, ),  # 11
 )
 all_structs.append(AlterTableResponse)
 AlterTableResponse.thrift_spec = (
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_constants.rb
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_constants.rb
index 36e026eda18..4418e6f32a8 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_constants.rb
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_constants.rb
@@ -87,3 +87,7 @@ TXN_ID = %q"txnId"
 
 WRITE_ID = %q"writeId"
 
+EXPECTED_PARAMETER_KEY = %q"expected_parameter_key"
+
+EXPECTED_PARAMETER_VALUE = %q"expected_parameter_value"
+
diff --git 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_types.rb
 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_types.rb
index 9268ab93551..c30dd8203f5 100644
--- 
a/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_types.rb
+++ 
b/standalone-metastore/metastore-common/src/gen/thrift/gen-rb/hive_metastore_types.rb
@@ -7213,6 +7213,8 @@ class AlterTableRequest
   VALIDWRITEIDLIST = 7
   PROCESSORCAPABILITIES = 8
   PROCESSORIDENTIFIER = 9
+  EXPECTEDPARAMETERKEY = 10
+  EXPECTEDPARAMETERVALUE = 11
 
   FIELDS = {
     CATNAME => {:type => ::Thrift::Types::STRING, :name => 'catName', 
:optional => true},
@@ -7223,7 +7225,9 @@ class AlterTableRequest
     WRITEID => {:type => ::Thrift::Types::I64, :name => 'writeId', :default => 
-1, :optional => true},
     VALIDWRITEIDLIST => {:type => ::Thrift::Types::STRING, :name => 
'validWriteIdList', :optional => true},
     PROCESSORCAPABILITIES => {:type => ::Thrift::Types::LIST, :name => 
'processorCapabilities', :element => {:type => ::Thrift::Types::STRING}, 
:optional => true},
-    PROCESSORIDENTIFIER => {:type => ::Thrift::Types::STRING, :name => 
'processorIdentifier', :optional => true}
+    PROCESSORIDENTIFIER => {:type => ::Thrift::Types::STRING, :name => 
'processorIdentifier', :optional => true},
+    EXPECTEDPARAMETERKEY => {:type => ::Thrift::Types::STRING, :name => 
'expectedParameterKey', :optional => true},
+    EXPECTEDPARAMETERVALUE => {:type => ::Thrift::Types::STRING, :name => 
'expectedParameterValue', :optional => true}
   }
 
   def struct_fields; FIELDS; end
diff --git 
a/standalone-metastore/metastore-common/src/main/thrift/hive_metastore.thrift 
b/standalone-metastore/metastore-common/src/main/thrift/hive_metastore.thrift
index f2faf732296..78bf0b7466a 100644
--- 
a/standalone-metastore/metastore-common/src/main/thrift/hive_metastore.thrift
+++ 
b/standalone-metastore/metastore-common/src/main/thrift/hive_metastore.thrift
@@ -2168,7 +2168,9 @@ struct AlterTableRequest {
   6: optional i64 writeId=-1,
   7: optional string validWriteIdList
   8: optional list<string> processorCapabilities,
-  9: optional string processorIdentifier
+  9: optional string processorIdentifier,
+  10: optional string expectedParameterKey,
+  11: optional string expectedParameterValue
 // TODO: also add cascade here, out of envCtx
 }
 
@@ -3192,3 +3194,7 @@ const string DEFAULT_TABLE_TYPE = "defaultTableType",
 // ACID
 const string TXN_ID = "txnId",
 const string WRITE_ID = "writeId",
+
+// Keys for alter table environment context parameters
+const string EXPECTED_PARAMETER_KEY = "expected_parameter_key",
+const string EXPECTED_PARAMETER_VALUE = "expected_parameter_value",
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java
index 222ff14f061..6f8e8de17ec 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HMSHandler.java
@@ -6005,7 +6005,7 @@ public class HMSHandler extends FacebookBase implements 
IHMSHandler {
     // Do not set an environment context.
     String[] parsedDbName = parseDbName(dbname, conf);
     alter_table_core(parsedDbName[CAT_NAME], parsedDbName[DB_NAME], name, 
newTable,
-        null, null, null, null);
+        null, null, null, null, null, null);
   }
 
   @Override
@@ -6019,7 +6019,7 @@ public class HMSHandler extends FacebookBase implements 
IHMSHandler {
     }
     String[] parsedDbName = parseDbName(dbname, conf);
     alter_table_core(parsedDbName[CAT_NAME], parsedDbName[DB_NAME], name, 
newTable,
-        envContext, null, null, null);
+        envContext, null, null, null, null, null);
   }
 
   @Override
@@ -6027,7 +6027,8 @@ public class HMSHandler extends FacebookBase implements 
IHMSHandler {
       throws InvalidOperationException, MetaException, TException {
     alter_table_core(req.getCatName(), req.getDbName(), req.getTableName(),
         req.getTable(), req.getEnvironmentContext(), req.getValidWriteIdList(),
-        req.getProcessorCapabilities(), req.getProcessorIdentifier());
+        req.getProcessorCapabilities(), req.getProcessorIdentifier(),
+        req.getExpectedParameterKey(), req.getExpectedParameterValue());
     return new AlterTableResponse();
   }
 
@@ -6038,17 +6039,26 @@ public class HMSHandler extends FacebookBase implements 
IHMSHandler {
       throws InvalidOperationException, MetaException {
     String[] parsedDbName = parseDbName(dbname, conf);
     alter_table_core(parsedDbName[CAT_NAME], parsedDbName[DB_NAME],
-        name, newTable, envContext, null, null, null);
+        name, newTable, envContext, null, null, null, null, null);
   }
 
   private void alter_table_core(String catName, String dbname, String name, 
Table newTable,
-                                EnvironmentContext envContext, String 
validWriteIdList, List<String> processorCapabilities, String processorId)
+                                EnvironmentContext envContext, String 
validWriteIdList, List<String> processorCapabilities,
+                                String processorId, String 
expectedPropertyKey, String expectedPropertyValue)
           throws InvalidOperationException, MetaException {
     startFunction("alter_table", ": " + TableName.getQualified(catName, 
dbname, name)
         + " newtbl=" + newTable.getTableName());
     if (envContext == null) {
       envContext = new EnvironmentContext();
     }
+    // Set the values to the envContext, so we do not have to change the 
HiveAlterHandler API
+    if (expectedPropertyKey != null) {
+      
envContext.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_KEY, 
expectedPropertyKey);
+    }
+    if (expectedPropertyValue != null) {
+      
envContext.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_VALUE, 
expectedPropertyValue);
+    }
+
     if (catName == null) {
       catName = getDefaultCatalog(conf);
     }
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HiveAlterHandler.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HiveAlterHandler.java
index 1226cd1a1ab..4c293f6aeca 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HiveAlterHandler.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HiveAlterHandler.java
@@ -57,6 +57,7 @@ import org.apache.hadoop.hive.metastore.api.Partition;
 import org.apache.hadoop.hive.metastore.api.Table;
 import org.apache.hadoop.hive.metastore.api.hive_metastoreConstants;
 
+import javax.jdo.Constants;
 import java.io.IOException;
 import java.net.URI;
 import java.util.ArrayList;
@@ -177,7 +178,17 @@ public class HiveAlterHandler implements AlterHandler {
         rename = true;
       }
 
-      msdb.openTransaction();
+      String expectedKey = environmentContext != null && 
environmentContext.getProperties() != null ?
+              
environmentContext.getProperties().get(hive_metastoreConstants.EXPECTED_PARAMETER_KEY)
 : null;
+      String expectedValue = environmentContext != null && 
environmentContext.getProperties() != null ?
+              
environmentContext.getProperties().get(hive_metastoreConstants.EXPECTED_PARAMETER_VALUE)
 : null;
+
+      if (expectedKey != null) {
+        // If we have to check the expected state of the table we have to 
prevent nonrepeatable reads.
+        msdb.openTransaction(Constants.TX_REPEATABLE_READ);
+      } else {
+        msdb.openTransaction();
+      }
       // get old table
       // Note: we don't verify stats here; it's done below in 
alterTableUpdateTableColumnStats.
       olddb = msdb.getDatabase(catName, dbname);
@@ -187,6 +198,12 @@ public class HiveAlterHandler implements AlterHandler {
             TableName.getQualified(catName, dbname, name) + " doesn't exist");
       }
 
+      if (expectedKey != null && expectedValue != null
+              && !expectedValue.equals(oldt.getParameters().get(expectedKey))) 
{
+        throw new MetaException("The table has been modified. The parameter 
value for key '" + expectedKey + "' is '"
+                + oldt.getParameters().get(expectedKey) + "'. The expected was 
value was '" + expectedValue + "'");
+      }
+
       validateTableChangesOnReplSource(olddb, oldt, newt, environmentContext);
 
       // On a replica this alter table will be executed only if old and new 
both the databases are
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
index 06f60478875..d7e938732b7 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
@@ -548,17 +548,31 @@ public class ObjectStore implements RawStore, 
Configurable {
   }
 
   /**
-   * Opens a new one or the one already created Every call of this function 
must
-   * have corresponding commit or rollback function call
+   * Opens a new one or the one already created. Every call of this function 
must
+   * have corresponding commit or rollback function call.
    *
    * @return an active transaction
    */
-
   @Override
   public boolean openTransaction() {
+    return openTransaction(null);
+  }
+
+  /**
+   * Opens a new one or the one already created. Every call of this function 
must
+   * have corresponding commit or rollback function call.
+   *
+   * @param isolationLevel The transaction isolation level. Only possible to 
set on the first call.
+   * @return an active transaction
+   */
+  @Override
+  public boolean openTransaction(String isolationLevel) {
     openTrasactionCalls++;
     if (openTrasactionCalls == 1) {
       currentTransaction = pm.currentTransaction();
+      if (isolationLevel != null) {
+        currentTransaction.setIsolationLevel(isolationLevel);
+      }
       currentTransaction.begin();
       transactionStatus = TXN_STATUS.OPEN;
     } else {
@@ -568,10 +582,16 @@ public class ObjectStore implements RawStore, 
Configurable {
         throw new RuntimeException("openTransaction called in an interior"
             + " transaction scope, but currentTransaction is not active.");
       }
+
+      // Can not change the isolation level on an already open transaction
+      if (isolationLevel != null && 
!isolationLevel.equals(currentTransaction.getIsolationLevel())) {
+        throw new RuntimeException("Can not set isolation level on an open 
transaction");
+      }
     }
 
     boolean result = currentTransaction.isActive();
-    debugLog("Open transaction: count = " + openTrasactionCalls + ", isActive 
= " + result);
+    debugLog("Open transaction: count = " + openTrasactionCalls + ", isActive 
= " + result + ", isolationLevel = "
+            + currentTransaction.getIsolationLevel());
     return result;
   }
 
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
index 9ec66c48bbf..acfb617805d 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
@@ -129,14 +129,24 @@ public interface RawStore extends Configurable {
   void shutdown();
 
   /**
-   * Opens a new one or the one already created Every call of this function 
must
-   * have corresponding commit or rollback function call
+   * Opens a new one or the one already created. Every call of this function 
must
+   * have corresponding commit or rollback function call.
    *
    * @return an active transaction
    */
-
   boolean openTransaction();
 
+  /**
+   * Opens a new one or the one already created. Every call of this function 
must
+   * have corresponding commit or rollback function call.
+   *
+   * @param isolationLevel The transaction isolation level. Only possible to 
set on the first call.
+   * @return an active transaction
+   */
+  default boolean openTransaction(String isolationLevel) {
+    throw new UnsupportedOperationException("Setting isolation level for this 
Store is not supported");
+  }
+
   /**
    * if this is the commit of the first open call then an actual commit is
    * called.
diff --git 
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestTablesCreateDropAlterTruncate.java
 
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestTablesCreateDropAlterTruncate.java
index b92790adc0d..8dc4d1dfcf0 100644
--- 
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestTablesCreateDropAlterTruncate.java
+++ 
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/client/TestTablesCreateDropAlterTruncate.java
@@ -22,9 +22,12 @@ import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hive.common.StatsSetupConst;
 import org.apache.hadoop.hive.common.TableName;
 import org.apache.hadoop.hive.metastore.ColumnType;
+import org.apache.hadoop.hive.metastore.IHMSHandler;
 import org.apache.hadoop.hive.metastore.IMetaStoreClient;
 import org.apache.hadoop.hive.metastore.MetaStoreTestUtils;
+import org.apache.hadoop.hive.metastore.RawStore;
 import org.apache.hadoop.hive.metastore.TableType;
+import org.apache.hadoop.hive.metastore.Warehouse;
 import org.apache.hadoop.hive.metastore.annotation.MetastoreCheckinTest;
 import org.apache.hadoop.hive.metastore.api.AlreadyExistsException;
 import org.apache.hadoop.hive.metastore.api.Catalog;
@@ -34,6 +37,7 @@ import 
org.apache.hadoop.hive.metastore.api.EnvironmentContext;
 import org.apache.hadoop.hive.metastore.api.FieldSchema;
 import org.apache.hadoop.hive.metastore.api.InvalidObjectException;
 import org.apache.hadoop.hive.metastore.api.InvalidOperationException;
+import org.apache.hadoop.hive.metastore.api.hive_metastoreConstants;
 import org.apache.hadoop.hive.metastore.api.MetaException;
 import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;
 import org.apache.hadoop.hive.metastore.api.Partition;
@@ -68,17 +72,23 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 import static 
org.apache.hadoop.hive.metastore.TestHiveMetaStore.createSourceTable;
 import static org.apache.hadoop.hive.metastore.Warehouse.DEFAULT_CATALOG_NAME;
 import static org.apache.hadoop.hive.metastore.Warehouse.DEFAULT_DATABASE_NAME;
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Test class for IMetaStoreClient API. Testing the Table related functions 
for metadata
@@ -1183,6 +1193,99 @@ public class TestTablesCreateDropAlterTruncate extends 
MetaStoreClientTest {
     }
   }
 
+  @Test
+  public void testAlterTableExpectedPropertyMatch() throws Exception {
+    Table originalTable = testTables[0];
+
+    EnvironmentContext context = new EnvironmentContext();
+    context.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_KEY, 
"transient_lastDdlTime");
+    context.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_VALUE,
+            originalTable.getParameters().get("transient_lastDdlTime"));
+
+    client.alter_table(originalTable.getCatName(), originalTable.getDbName(), 
originalTable.getTableName(),
+            originalTable, context);
+  }
+
+  @Test(expected = MetaException.class)
+  public void testAlterTableExpectedPropertyDifferent() throws Exception {
+    Table originalTable = testTables[0];
+
+    EnvironmentContext context = new EnvironmentContext();
+    context.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_KEY, 
"transient_lastDdlTime");
+    context.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_VALUE, 
"alma");
+
+    client.alter_table(originalTable.getCatName(), originalTable.getDbName(), 
originalTable.getTableName(),
+            originalTable, context);
+  }
+
+  /**
+   * This tests ensures that concurrent Iceberg commits will fail. Acceptable 
as a first sanity check.
+   * <p>
+   * I have not found a good way to check that HMS side database commits are 
parallel in the
+   * {@link 
org.apache.hadoop.hive.metastore.HiveAlterHandler#alterTable(RawStore, 
Warehouse, String, String, String, Table, EnvironmentContext, IHMSHandler, 
String)}
+   * call, but this test could be used to manually ensure that using 
breakpoints.
+   */
+  @Test
+  public void testAlterTableExpectedPropertyConcurrent() throws Exception {
+    Table originalTable = testTables[0];
+
+    originalTable.getParameters().put("snapshot", "0");
+    client.alter_table(originalTable.getCatName(), originalTable.getDbName(), 
originalTable.getTableName(),
+            originalTable, null);
+
+    ExecutorService threads = null;
+    try {
+      threads = Executors.newFixedThreadPool(2);
+      for (int i = 0; i < 3; i++) {
+        EnvironmentContext context = new EnvironmentContext();
+        
context.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_KEY, 
"snapshot");
+        
context.putToProperties(hive_metastoreConstants.EXPECTED_PARAMETER_VALUE, 
String.valueOf(i));
+
+        Table newTable = originalTable.deepCopy();
+        newTable.getParameters().put("snapshot", String.valueOf(i + 1));
+
+        IMetaStoreClient client1 = metaStore.getClient();
+        IMetaStoreClient client2 = metaStore.getClient();
+
+        Collection<Callable<Boolean>> concurrentTasks = new ArrayList<>(2);
+        concurrentTasks.add(alterTask(client1, newTable, context));
+        concurrentTasks.add(alterTask(client2, newTable, context));
+
+        Collection<Future<Boolean>> results = 
threads.invokeAll(concurrentTasks);
+
+        boolean foundSuccess = false;
+        boolean foundFailure = false;
+
+        for (Future<Boolean> result : results) {
+          if (result.get()) {
+            foundSuccess = true;
+          } else {
+            foundFailure = true;
+          }
+        }
+
+        assertTrue("At least one success is expected", foundSuccess);
+        assertTrue("At least one failure is expected", foundFailure);
+      }
+    } finally {
+      if (threads != null) {
+        threads.shutdown();
+      }
+    }
+  }
+
+  private Callable<Boolean> alterTask(IMetaStoreClient hmsClient, Table 
newTable, EnvironmentContext context) {
+    return () -> {
+      try {
+        hmsClient.alter_table(newTable.getCatName(), newTable.getDbName(), 
newTable.getTableName(),
+                newTable, context);
+      } catch (Throwable e) {
+        return false;
+      }
+      return true;
+    };
+  }
+
   @Test
   public void tablesInOtherCatalogs() throws TException, URISyntaxException {
     String catName = "create_etc_tables_in_other_catalogs";

Reply via email to