http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/gen/thrift/gen-rb/thrift_hive_metastore.rb
----------------------------------------------------------------------
diff --git a/metastore/src/gen/thrift/gen-rb/thrift_hive_metastore.rb 
b/metastore/src/gen/thrift/gen-rb/thrift_hive_metastore.rb
index e782bb5..99a764e 100644
--- a/metastore/src/gen/thrift/gen-rb/thrift_hive_metastore.rb
+++ b/metastore/src/gen/thrift/gen-rb/thrift_hive_metastore.rb
@@ -318,6 +318,24 @@ module ThriftHiveMetastore
       return
     end
 
+    def create_table_with_constraints(tbl, primaryKeys, foreignKeys)
+      send_create_table_with_constraints(tbl, primaryKeys, foreignKeys)
+      recv_create_table_with_constraints()
+    end
+
+    def send_create_table_with_constraints(tbl, primaryKeys, foreignKeys)
+      send_message('create_table_with_constraints', 
Create_table_with_constraints_args, :tbl => tbl, :primaryKeys => primaryKeys, 
:foreignKeys => foreignKeys)
+    end
+
+    def recv_create_table_with_constraints()
+      result = receive_message(Create_table_with_constraints_result)
+      raise result.o1 unless result.o1.nil?
+      raise result.o2 unless result.o2.nil?
+      raise result.o3 unless result.o3.nil?
+      raise result.o4 unless result.o4.nil?
+      return
+    end
+
     def drop_table(dbname, name, deleteData)
       send_drop_table(dbname, name, deleteData)
       recv_drop_table()
@@ -1324,6 +1342,40 @@ module ThriftHiveMetastore
       raise 
::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT,
 'get_index_names failed: unknown result')
     end
 
+    def get_primary_keys(request)
+      send_get_primary_keys(request)
+      return recv_get_primary_keys()
+    end
+
+    def send_get_primary_keys(request)
+      send_message('get_primary_keys', Get_primary_keys_args, :request => 
request)
+    end
+
+    def recv_get_primary_keys()
+      result = receive_message(Get_primary_keys_result)
+      return result.success unless result.success.nil?
+      raise result.o1 unless result.o1.nil?
+      raise result.o2 unless result.o2.nil?
+      raise 
::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT,
 'get_primary_keys failed: unknown result')
+    end
+
+    def get_foreign_keys(request)
+      send_get_foreign_keys(request)
+      return recv_get_foreign_keys()
+    end
+
+    def send_get_foreign_keys(request)
+      send_message('get_foreign_keys', Get_foreign_keys_args, :request => 
request)
+    end
+
+    def recv_get_foreign_keys()
+      result = receive_message(Get_foreign_keys_result)
+      return result.success unless result.success.nil?
+      raise result.o1 unless result.o1.nil?
+      raise result.o2 unless result.o2.nil?
+      raise 
::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT,
 'get_foreign_keys failed: unknown result')
+    end
+
     def update_table_column_statistics(stats_obj)
       send_update_table_column_statistics(stats_obj)
       return recv_update_table_column_statistics()
@@ -2635,6 +2687,23 @@ module ThriftHiveMetastore
       write_result(result, oprot, 'create_table_with_environment_context', 
seqid)
     end
 
+    def process_create_table_with_constraints(seqid, iprot, oprot)
+      args = read_args(iprot, Create_table_with_constraints_args)
+      result = Create_table_with_constraints_result.new()
+      begin
+        @handler.create_table_with_constraints(args.tbl, args.primaryKeys, 
args.foreignKeys)
+      rescue ::AlreadyExistsException => o1
+        result.o1 = o1
+      rescue ::InvalidObjectException => o2
+        result.o2 = o2
+      rescue ::MetaException => o3
+        result.o3 = o3
+      rescue ::NoSuchObjectException => o4
+        result.o4 = o4
+      end
+      write_result(result, oprot, 'create_table_with_constraints', seqid)
+    end
+
     def process_drop_table(seqid, iprot, oprot)
       args = read_args(iprot, Drop_table_args)
       result = Drop_table_result.new()
@@ -3432,6 +3501,32 @@ module ThriftHiveMetastore
       write_result(result, oprot, 'get_index_names', seqid)
     end
 
+    def process_get_primary_keys(seqid, iprot, oprot)
+      args = read_args(iprot, Get_primary_keys_args)
+      result = Get_primary_keys_result.new()
+      begin
+        result.success = @handler.get_primary_keys(args.request)
+      rescue ::MetaException => o1
+        result.o1 = o1
+      rescue ::NoSuchObjectException => o2
+        result.o2 = o2
+      end
+      write_result(result, oprot, 'get_primary_keys', seqid)
+    end
+
+    def process_get_foreign_keys(seqid, iprot, oprot)
+      args = read_args(iprot, Get_foreign_keys_args)
+      result = Get_foreign_keys_result.new()
+      begin
+        result.success = @handler.get_foreign_keys(args.request)
+      rescue ::MetaException => o1
+        result.o1 = o1
+      rescue ::NoSuchObjectException => o2
+        result.o2 = o2
+      end
+      write_result(result, oprot, 'get_foreign_keys', seqid)
+    end
+
     def process_update_table_column_statistics(seqid, iprot, oprot)
       args = read_args(iprot, Update_table_column_statistics_args)
       result = Update_table_column_statistics_result.new()
@@ -4817,6 +4912,48 @@ module ThriftHiveMetastore
     ::Thrift::Struct.generate_accessors self
   end
 
+  class Create_table_with_constraints_args
+    include ::Thrift::Struct, ::Thrift::Struct_Union
+    TBL = 1
+    PRIMARYKEYS = 2
+    FOREIGNKEYS = 3
+
+    FIELDS = {
+      TBL => {:type => ::Thrift::Types::STRUCT, :name => 'tbl', :class => 
::Table},
+      PRIMARYKEYS => {:type => ::Thrift::Types::LIST, :name => 'primaryKeys', 
:element => {:type => ::Thrift::Types::STRUCT, :class => ::SQLPrimaryKey}},
+      FOREIGNKEYS => {:type => ::Thrift::Types::LIST, :name => 'foreignKeys', 
:element => {:type => ::Thrift::Types::STRUCT, :class => ::SQLForeignKey}}
+    }
+
+    def struct_fields; FIELDS; end
+
+    def validate
+    end
+
+    ::Thrift::Struct.generate_accessors self
+  end
+
+  class Create_table_with_constraints_result
+    include ::Thrift::Struct, ::Thrift::Struct_Union
+    O1 = 1
+    O2 = 2
+    O3 = 3
+    O4 = 4
+
+    FIELDS = {
+      O1 => {:type => ::Thrift::Types::STRUCT, :name => 'o1', :class => 
::AlreadyExistsException},
+      O2 => {:type => ::Thrift::Types::STRUCT, :name => 'o2', :class => 
::InvalidObjectException},
+      O3 => {:type => ::Thrift::Types::STRUCT, :name => 'o3', :class => 
::MetaException},
+      O4 => {:type => ::Thrift::Types::STRUCT, :name => 'o4', :class => 
::NoSuchObjectException}
+    }
+
+    def struct_fields; FIELDS; end
+
+    def validate
+    end
+
+    ::Thrift::Struct.generate_accessors self
+  end
+
   class Drop_table_args
     include ::Thrift::Struct, ::Thrift::Struct_Union
     DBNAME = 1
@@ -7205,6 +7342,78 @@ module ThriftHiveMetastore
     ::Thrift::Struct.generate_accessors self
   end
 
+  class Get_primary_keys_args
+    include ::Thrift::Struct, ::Thrift::Struct_Union
+    REQUEST = 1
+
+    FIELDS = {
+      REQUEST => {:type => ::Thrift::Types::STRUCT, :name => 'request', :class 
=> ::PrimaryKeysRequest}
+    }
+
+    def struct_fields; FIELDS; end
+
+    def validate
+    end
+
+    ::Thrift::Struct.generate_accessors self
+  end
+
+  class Get_primary_keys_result
+    include ::Thrift::Struct, ::Thrift::Struct_Union
+    SUCCESS = 0
+    O1 = 1
+    O2 = 2
+
+    FIELDS = {
+      SUCCESS => {:type => ::Thrift::Types::STRUCT, :name => 'success', :class 
=> ::PrimaryKeysResponse},
+      O1 => {:type => ::Thrift::Types::STRUCT, :name => 'o1', :class => 
::MetaException},
+      O2 => {:type => ::Thrift::Types::STRUCT, :name => 'o2', :class => 
::NoSuchObjectException}
+    }
+
+    def struct_fields; FIELDS; end
+
+    def validate
+    end
+
+    ::Thrift::Struct.generate_accessors self
+  end
+
+  class Get_foreign_keys_args
+    include ::Thrift::Struct, ::Thrift::Struct_Union
+    REQUEST = 1
+
+    FIELDS = {
+      REQUEST => {:type => ::Thrift::Types::STRUCT, :name => 'request', :class 
=> ::ForeignKeysRequest}
+    }
+
+    def struct_fields; FIELDS; end
+
+    def validate
+    end
+
+    ::Thrift::Struct.generate_accessors self
+  end
+
+  class Get_foreign_keys_result
+    include ::Thrift::Struct, ::Thrift::Struct_Union
+    SUCCESS = 0
+    O1 = 1
+    O2 = 2
+
+    FIELDS = {
+      SUCCESS => {:type => ::Thrift::Types::STRUCT, :name => 'success', :class 
=> ::ForeignKeysResponse},
+      O1 => {:type => ::Thrift::Types::STRUCT, :name => 'o1', :class => 
::MetaException},
+      O2 => {:type => ::Thrift::Types::STRUCT, :name => 'o2', :class => 
::NoSuchObjectException}
+    }
+
+    def struct_fields; FIELDS; end
+
+    def validate
+    end
+
+    ::Thrift::Struct.generate_accessors self
+  end
+
   class Update_table_column_statistics_args
     include ::Thrift::Struct, ::Thrift::Struct_Union
     STATS_OBJ = 1

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java 
b/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java
index c9fadad..ed2057a 100644
--- a/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java
+++ b/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Multimaps;
+
 import org.apache.commons.cli.OptionBuilder;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
@@ -112,6 +113,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.jdo.JDOException;
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.text.DateFormat;
@@ -1310,7 +1312,7 @@ public class HiveMetaStore extends ThriftHiveMetastore {
     }
 
     private void create_table_core(final RawStore ms, final Table tbl,
-        final EnvironmentContext envContext)
+        final EnvironmentContext envContext, List<SQLPrimaryKey> primaryKeys, 
List<SQLForeignKey> foreignKeys)
         throws AlreadyExistsException, MetaException,
         InvalidObjectException, NoSuchObjectException {
 
@@ -1395,7 +1397,11 @@ public class HiveMetaStore extends ThriftHiveMetastore {
             tbl.getParameters().get(hive_metastoreConstants.DDL_TIME) == null) 
{
           tbl.putToParameters(hive_metastoreConstants.DDL_TIME, 
Long.toString(time));
         }
-        ms.createTable(tbl);
+        if (primaryKeys == null && foreignKeys == null) {
+          ms.createTable(tbl);
+        } else {
+          ms.createTableWithConstraints(tbl, primaryKeys, foreignKeys);
+        }
         success = ms.commitTransaction();
 
       } finally {
@@ -1428,7 +1434,7 @@ public class HiveMetaStore extends ThriftHiveMetastore {
       boolean success = false;
       Exception ex = null;
       try {
-        create_table_core(getMS(), tbl, envContext);
+        create_table_core(getMS(), tbl, envContext, null, null);
         success = true;
       } catch (NoSuchObjectException e) {
         ex = e;
@@ -1449,6 +1455,34 @@ public class HiveMetaStore extends ThriftHiveMetastore {
       }
     }
 
+    @Override
+    public void create_table_with_constraints(final Table tbl,
+        final List<SQLPrimaryKey> primaryKeys, final List<SQLForeignKey> 
foreignKeys)
+        throws AlreadyExistsException, MetaException, InvalidObjectException {
+      startFunction("create_table", ": " + tbl.toString());
+      boolean success = false;
+      Exception ex = null;
+      try {
+        create_table_core(getMS(), tbl, null, primaryKeys, foreignKeys);
+        success = true;
+      } catch (NoSuchObjectException e) {
+        ex = e;
+        throw new InvalidObjectException(e.getMessage());
+      } catch (Exception e) {
+        ex = e;
+        if (e instanceof MetaException) {
+          throw (MetaException) e;
+        } else if (e instanceof InvalidObjectException) {
+          throw (InvalidObjectException) e;
+        } else if (e instanceof AlreadyExistsException) {
+          throw (AlreadyExistsException) e;
+        } else {
+          throw newMetaException(e);
+        }
+      } finally {
+        endFunction("create_table", success, ex, tbl.getTableName());
+      }
+    }
     private boolean is_table_exists(RawStore ms, String dbname, String name)
         throws MetaException {
       return (ms.getTable(dbname, name) != null);
@@ -6131,6 +6165,63 @@ public class HiveMetaStore extends ThriftHiveMetastore {
         throws TException {
       return new 
GetChangeVersionResult(getMS().getChangeVersion(req.getTopic()));
     }
+
+
+    @Override
+    public PrimaryKeysResponse get_primary_keys(PrimaryKeysRequest request)
+      throws MetaException, NoSuchObjectException, TException {
+      String db_name = request.getDb_name();
+      String tbl_name = request.getTbl_name();
+      startTableFunction("get_primary_keys", db_name, tbl_name);
+      List<SQLPrimaryKey> ret = null;
+      Exception ex = null;
+      try {
+        ret = getMS().getPrimaryKeys(db_name, tbl_name);
+      } catch (Exception e) {
+       ex = e;
+       if (e instanceof MetaException) {
+         throw (MetaException) e;
+       } else if (e instanceof NoSuchObjectException) {
+         throw (NoSuchObjectException) e;
+       } else {
+         throw newMetaException(e);
+       }
+     } finally {
+       endFunction("get_primary_keys", ret != null, ex, tbl_name);
+     }
+     return new PrimaryKeysResponse(ret);
+    }
+
+    @Override
+    public ForeignKeysResponse get_foreign_keys(ForeignKeysRequest request) 
throws MetaException,
+      NoSuchObjectException, TException {
+      String parent_db_name = request.getParent_db_name();
+      String parent_tbl_name = request.getParent_tbl_name();
+      String foreign_db_name = request.getForeign_db_name();
+      String foreign_tbl_name = request.getForeign_tbl_name();
+      startFunction("get_foreign_keys", " : parentdb=" + parent_db_name +
+        " parenttbl=" + parent_tbl_name + " foreigndb=" + foreign_db_name +
+        " foreigntbl=" + foreign_tbl_name);
+      List<SQLForeignKey> ret = null;
+      Exception ex = null;
+      try {
+        ret = getMS().getForeignKeys(parent_db_name, parent_tbl_name,
+              foreign_db_name, foreign_tbl_name);
+      } catch (Exception e) {
+        ex = e;
+        if (e instanceof MetaException) {
+          throw (MetaException) e;
+        } else if (e instanceof NoSuchObjectException) {
+          throw (NoSuchObjectException) e;
+        } else {
+          throw newMetaException(e);
+        }
+      } finally {
+        endFunction("get_foreign_keys", ret != null, ex, foreign_tbl_name);
+      }
+      return new ForeignKeysResponse(ret);
+    }
+
   }
 
 

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java 
b/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java
index cdd12ab..7d37d07 100644
--- 
a/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java
+++ 
b/metastore/src/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java
@@ -50,6 +50,7 @@ import 
org.apache.hadoop.hive.metastore.api.EnvironmentContext;
 import org.apache.hadoop.hive.metastore.api.FieldSchema;
 import org.apache.hadoop.hive.metastore.api.FireEventRequest;
 import org.apache.hadoop.hive.metastore.api.FireEventResponse;
+import org.apache.hadoop.hive.metastore.api.ForeignKeysRequest;
 import org.apache.hadoop.hive.metastore.api.Function;
 import org.apache.hadoop.hive.metastore.api.GetAllFunctionsResponse;
 import org.apache.hadoop.hive.metastore.api.GetChangeVersionRequest;
@@ -94,12 +95,15 @@ import 
org.apache.hadoop.hive.metastore.api.PartitionEventType;
 import org.apache.hadoop.hive.metastore.api.PartitionsByExprRequest;
 import org.apache.hadoop.hive.metastore.api.PartitionsByExprResult;
 import org.apache.hadoop.hive.metastore.api.PartitionsStatsRequest;
+import org.apache.hadoop.hive.metastore.api.PrimaryKeysRequest;
 import org.apache.hadoop.hive.metastore.api.PrincipalPrivilegeSet;
 import org.apache.hadoop.hive.metastore.api.PrincipalType;
 import org.apache.hadoop.hive.metastore.api.PrivilegeBag;
 import org.apache.hadoop.hive.metastore.api.PutFileMetadataRequest;
 import org.apache.hadoop.hive.metastore.api.RequestPartsSpec;
 import org.apache.hadoop.hive.metastore.api.Role;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.SetPartitionsStatsRequest;
 import org.apache.hadoop.hive.metastore.api.ShowCompactRequest;
 import org.apache.hadoop.hive.metastore.api.ShowCompactResponse;
@@ -136,6 +140,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.security.auth.login.LoginException;
+
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
@@ -736,7 +741,32 @@ public class HiveMetaStoreClient implements 
IMetaStoreClient {
     }
   }
 
-  /**
+  @Override
+  public void createTableWithConstraints(Table tbl,
+    List<SQLPrimaryKey> primaryKeys, List<SQLForeignKey> foreignKeys)
+    throws AlreadyExistsException, InvalidObjectException,
+    MetaException, NoSuchObjectException, TException {
+    HiveMetaHook hook = getHook(tbl);
+    if (hook != null) {
+      hook.preCreateTable(tbl);
+    }
+    boolean success = false;
+    try {
+      // Subclasses can override this step (for example, for temporary tables)
+      client.create_table_with_constraints(tbl, primaryKeys, foreignKeys);
+      if (hook != null) {
+        hook.commitCreateTable(tbl);
+      }
+      success = true;
+    } finally {
+      if (!success && (hook != null)) {
+        hook.rollbackCreateTable(tbl);
+      }
+    }
+  }
+
+
+/**
    * @param type
    * @return true or false
    * @throws AlreadyExistsException
@@ -1528,6 +1558,19 @@ public class HiveMetaStoreClient implements 
IMetaStoreClient {
     return filterHook.filterIndexes(client.get_indexes(dbName, tblName, max));
   }
 
+  @Override
+  public List<SQLPrimaryKey> getPrimaryKeys(PrimaryKeysRequest req)
+    throws MetaException, NoSuchObjectException, TException {
+    return client.get_primary_keys(req).getPrimaryKeys();
+  }
+
+  @Override
+  public List<SQLForeignKey> getForeignKeys(ForeignKeysRequest req) throws 
MetaException,
+    NoSuchObjectException, TException {
+    return client.get_foreign_keys(req).getForeignKeys();
+  }
+
+
   /** {@inheritDoc} */
   @Override
   public boolean updateTableColumnStatistics(ColumnStatistics statsObj)
@@ -2375,4 +2418,5 @@ public class HiveMetaStoreClient implements 
IMetaStoreClient {
   public long getChangeVersion(String topic) throws TException {
     return client.get_change_version(new 
GetChangeVersionRequest(topic)).getVersion();
   }
+
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/java/org/apache/hadoop/hive/metastore/IMetaStoreClient.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/java/org/apache/hadoop/hive/metastore/IMetaStoreClient.java 
b/metastore/src/java/org/apache/hadoop/hive/metastore/IMetaStoreClient.java
index 39cf927..c900a2d 100644
--- a/metastore/src/java/org/apache/hadoop/hive/metastore/IMetaStoreClient.java
+++ b/metastore/src/java/org/apache/hadoop/hive/metastore/IMetaStoreClient.java
@@ -37,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.FireEventRequest;
 import org.apache.hadoop.hive.metastore.api.FireEventResponse;
+import org.apache.hadoop.hive.metastore.api.ForeignKeysRequest;
 import org.apache.hadoop.hive.metastore.api.Function;
 import org.apache.hadoop.hive.metastore.api.GetAllFunctionsResponse;
 import org.apache.hadoop.hive.metastore.api.GetOpenTxnsInfoResponse;
@@ -64,10 +65,13 @@ import 
org.apache.hadoop.hive.metastore.api.NotificationEventResponse;
 import org.apache.hadoop.hive.metastore.api.OpenTxnsResponse;
 import org.apache.hadoop.hive.metastore.api.Partition;
 import org.apache.hadoop.hive.metastore.api.PartitionEventType;
+import org.apache.hadoop.hive.metastore.api.PrimaryKeysRequest;
 import org.apache.hadoop.hive.metastore.api.PrincipalPrivilegeSet;
 import org.apache.hadoop.hive.metastore.api.PrincipalType;
 import org.apache.hadoop.hive.metastore.api.PrivilegeBag;
 import org.apache.hadoop.hive.metastore.api.Role;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.SetPartitionsStatsRequest;
 import org.apache.hadoop.hive.metastore.api.ShowCompactResponse;
 import org.apache.hadoop.hive.metastore.api.ShowLocksResponse;
@@ -1554,4 +1558,16 @@ public interface IMetaStoreClient {
       boolean allParts) throws TException;
 
   long getChangeVersion(String topic) throws TException;
+
+  List<SQLPrimaryKey> getPrimaryKeys(PrimaryKeysRequest request)
+    throws MetaException, NoSuchObjectException, TException;
+
+  List<SQLForeignKey> getForeignKeys(ForeignKeysRequest request) throws 
MetaException,
+    NoSuchObjectException, TException;
+
+  void createTableWithConstraints(
+    org.apache.hadoop.hive.metastore.api.Table tTbl,
+    List<SQLPrimaryKey> primaryKeys, List<SQLForeignKey> foreignKeys)
+    throws AlreadyExistsException, InvalidObjectException, MetaException, 
NoSuchObjectException, TException;
+
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java 
b/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java
index 06e9f78..744512f 100644
--- 
a/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java
+++ 
b/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java
@@ -53,10 +53,13 @@ import org.apache.hadoop.hive.metastore.api.MetaException;
 import org.apache.hadoop.hive.metastore.api.Order;
 import org.apache.hadoop.hive.metastore.api.Partition;
 import org.apache.hadoop.hive.metastore.api.PrincipalType;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.SerDeInfo;
 import org.apache.hadoop.hive.metastore.api.SkewedInfo;
 import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
 import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.hadoop.hive.metastore.model.MConstraint;
 import org.apache.hadoop.hive.metastore.model.MDatabase;
 import org.apache.hadoop.hive.metastore.model.MPartitionColumnStatistics;
 import org.apache.hadoop.hive.metastore.model.MTableColumnStatistics;
@@ -1809,4 +1812,135 @@ class MetaStoreDirectSql {
     }
     return result;
   }
+
+  public List<SQLForeignKey> getForeignKeys(String parent_db_name, String 
parent_tbl_name, String foreign_db_name, String foreign_tbl_name) throws 
MetaException {
+    List<SQLForeignKey> ret = new ArrayList<SQLForeignKey>();
+    String queryText =
+      "SELECT  \"D2\".\"NAME\", \"T2\".\"TBL_NAME\", \"C2\".\"COLUMN_NAME\","
+      + "\"DBS\".\"NAME\", \"TBLS\".\"TBL_NAME\", 
\"COLUMNS_V2\".\"COLUMN_NAME\", "
+      + "\"KEY_CONSTRAINTS\".\"POSITION\", 
\"KEY_CONSTRAINTS\".\"UPDATE_RULE\", \"KEY_CONSTRAINTS\".\"DELETE_RULE\", "
+      + "\"KEY_CONSTRAINTS\".\"CONSTRAINT_NAME\" , 
\"KEY_CONSTRAINTS2\".\"CONSTRAINT_NAME\", 
\"KEY_CONSTRAINTS\".\"ENABLE_VALIDATE_RELY\""
+      + " FROM \"TBLS\" "
+      + " INNER JOIN \"KEY_CONSTRAINTS\" ON \"TBLS\".\"TBL_ID\" = 
\"KEY_CONSTRAINTS\".\"CHILD_TBL_ID\" "
+      + " INNER JOIN \"KEY_CONSTRAINTS\" \"KEY_CONSTRAINTS2\" ON 
\"KEY_CONSTRAINTS2\".\"PARENT_TBL_ID\"  = \"KEY_CONSTRAINTS\".\"PARENT_TBL_ID\" 
"
+      + " INNER JOIN \"DBS\" ON \"TBLS\".\"DB_ID\" = \"DBS\".\"DB_ID\" "
+      + " INNER JOIN \"TBLS\" \"T2\" ON  \"KEY_CONSTRAINTS\".\"PARENT_TBL_ID\" 
= \"T2\".\"TBL_ID\" "
+      + " INNER JOIN \"DBS\" \"D2\" ON \"T2\".\"DB_ID\" = \"D2\".\"DB_ID\" "
+      + " INNER JOIN \"COLUMNS_V2\"  ON \"COLUMNS_V2\".\"CD_ID\" = 
\"KEY_CONSTRAINTS\".\"CHILD_CD_ID\" "
+      + " INNER JOIN \"COLUMNS_V2\" \"C2\" ON \"C2\".\"CD_ID\" = 
\"KEY_CONSTRAINTS\".\"PARENT_CD_ID\" "
+      + " WHERE \"KEY_CONSTRAINTS\".\"CONSTRAINT_TYPE\" = "
+      + MConstraint.FOREIGN_KEY_CONSTRAINT
+      + " AND \"KEY_CONSTRAINTS2\".\"CONSTRAINT_TYPE\" = "
+      + MConstraint.PRIMARY_KEY_CONSTRAINT
+      + (foreign_db_name == null ? "" : "\"DBS\".\"NAME\" = ? AND")
+      + (foreign_tbl_name == null ? "" : " \"TBLS\".\"TBL_NAME\" = ? AND ")
+      + (parent_tbl_name == null ? "" : " \"T2\".\"TBL_NAME\" = ? AND ")
+      + (parent_db_name == null ? "" : "\"D2\".\"NAME\" = ?") ;
+
+    queryText = queryText.trim();
+    if (queryText.endsWith("WHERE")) {
+      queryText = queryText.substring(0, queryText.length()-5);
+    }
+    if (queryText.endsWith("AND")) {
+      queryText = queryText.substring(0, queryText.length()-3);
+    }
+    List<String> pms = new ArrayList<String>();
+    if (foreign_db_name != null) {
+      pms.add(foreign_db_name);
+    }
+    if (foreign_tbl_name != null) {
+      pms.add(foreign_tbl_name);
+    }
+    if (parent_tbl_name != null) {
+      pms.add(parent_tbl_name);
+    }
+    if (parent_db_name != null) {
+      pms.add(parent_db_name);
+    }
+
+    Query queryParams = pm.newQuery("javax.jdo.query.SQL", queryText);
+      List<Object[]> sqlResult = ensureList(executeWithArray(
+        queryParams, pms.toArray(), queryText));
+
+    if (!sqlResult.isEmpty()) {
+      for (Object[] line : sqlResult) {
+        int enableValidateRely = extractSqlInt(line[11]);
+        boolean enable = (enableValidateRely & 4) != 0;
+        boolean validate = (enableValidateRely & 2) != 0;
+        boolean rely = (enableValidateRely & 1) != 0;
+        SQLForeignKey currKey = new SQLForeignKey(
+          extractSqlString(line[0]),
+          extractSqlString(line[1]),
+          extractSqlString(line[2]),
+          extractSqlString(line[3]),
+          extractSqlString(line[4]),
+          extractSqlString(line[5]),
+          extractSqlInt(line[6]),
+          extractSqlInt(line[7]),
+          extractSqlInt(line[8]),
+          extractSqlString(line[9]),
+          extractSqlString(line[10]),
+          enable,
+          validate,
+          rely
+          );
+          ret.add(currKey);
+      }
+    }
+    return ret;
+  }
+
+  public List<SQLPrimaryKey> getPrimaryKeys(String db_name, String tbl_name) 
throws MetaException {
+    List<SQLPrimaryKey> ret = new ArrayList<SQLPrimaryKey>();
+    String queryText =
+      "SELECT \"DBS\".\"NAME\", \"TBLS\".\"TBL_NAME\", 
\"COLUMNS_V2\".\"COLUMN_NAME\","
+      + "\"KEY_CONSTRAINTS\".\"POSITION\", "
+      + "\"KEY_CONSTRAINTS\".\"CONSTRAINT_NAME\", 
\"KEY_CONSTRAINTS\".\"ENABLE_VALIDATE_RELY\" "
+      + " FROM  \"TBLS\" "
+      + " INNER  JOIN \"KEY_CONSTRAINTS\" ON \"TBLS\".\"TBL_ID\" = 
\"KEY_CONSTRAINTS\".\"PARENT_TBL_ID\" "
+      + " INNER JOIN \"DBS\" ON \"TBLS\".\"DB_ID\" = \"DBS\".\"DB_ID\" "
+      + " INNER JOIN \"TBLS\" ON \"KEY_CONSTRAINTS\".\"PARENT_TBL_ID\" = 
\"TBLS\".\"TBL_ID\" "
+      + " INNER JOIN \"COLUMNS_V2\" ON \"COLUMNS_V2\".\"CD_ID\" = 
\"KEY_CONSTRAINTS\".\"PARENT_CD_ID\" "
+      + " WHERE \"KEY_CONSTRAINTS\".\"CONSTRAINT_TYPE\" = "+ 
MConstraint.PRIMARY_KEY_CONSTRAINT + " AND "
+      + (db_name == null ? "" : "\"DBS\".\"NAME\" = ? AND")
+      + (tbl_name == null ? "" : " \"TBLS\".\"TBL_NAME\" = ? ") ;
+
+    queryText = queryText.trim();
+    if (queryText.endsWith("WHERE")) {
+      queryText = queryText.substring(0, queryText.length()-5);
+    }
+    if (queryText.endsWith("AND")) {
+      queryText = queryText.substring(0, queryText.length()-3);
+    }
+    List<String> pms = new ArrayList<String>();
+    if (db_name != null) {
+      pms.add(db_name);
+    }
+    if (tbl_name != null) {
+      pms.add(tbl_name);
+    }
+
+    Query queryParams = pm.newQuery("javax.jdo.query.SQL", queryText);
+      List<Object[]> sqlResult = ensureList(executeWithArray(
+        queryParams, pms.toArray(), queryText));
+
+    if (!sqlResult.isEmpty()) {
+      for (Object[] line : sqlResult) {
+          int enableValidateRely = extractSqlInt(line[5]);
+          boolean enable = (enableValidateRely & 4) != 0;
+          boolean validate = (enableValidateRely & 2) != 0;
+          boolean rely = (enableValidateRely & 1) != 0;
+        SQLPrimaryKey currKey = new SQLPrimaryKey(
+          extractSqlString(line[0]),
+          extractSqlString(line[1]),
+          extractSqlString(line[2]),
+          extractSqlInt(line[3]), extractSqlString(line[4]),
+          enable,
+          validate,
+          rely);
+          ret.add(currKey);
+      }
+    }
+    return ret;
+  }
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java 
b/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java
index ac293b9..ae6f084 100644
--- a/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java
+++ b/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java
@@ -54,6 +54,7 @@ import javax.jdo.Transaction;
 import javax.jdo.datastore.DataStoreCache;
 import javax.jdo.identity.IntIdentity;
 
+import org.apache.commons.lang.ArrayUtils;
 import org.apache.hadoop.conf.Configurable;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.Path;
@@ -97,6 +98,8 @@ import org.apache.hadoop.hive.metastore.api.ResourceType;
 import org.apache.hadoop.hive.metastore.api.ResourceUri;
 import org.apache.hadoop.hive.metastore.api.Role;
 import org.apache.hadoop.hive.metastore.api.RolePrincipalGrant;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.SerDeInfo;
 import org.apache.hadoop.hive.metastore.api.SkewedInfo;
 import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
@@ -108,6 +111,7 @@ import 
org.apache.hadoop.hive.metastore.api.UnknownPartitionException;
 import org.apache.hadoop.hive.metastore.api.UnknownTableException;
 import org.apache.hadoop.hive.metastore.model.MChangeVersion;
 import org.apache.hadoop.hive.metastore.model.MColumnDescriptor;
+import org.apache.hadoop.hive.metastore.model.MConstraint;
 import org.apache.hadoop.hive.metastore.model.MDBPrivilege;
 import org.apache.hadoop.hive.metastore.model.MDatabase;
 import org.apache.hadoop.hive.metastore.model.MDelegationToken;
@@ -899,12 +903,31 @@ public class ObjectStore implements RawStore, 
Configurable {
   }
 
   @Override
+  public void createTableWithConstraints(Table tbl,
+    List<SQLPrimaryKey> primaryKeys, List<SQLForeignKey> foreignKeys)
+    throws InvalidObjectException, MetaException {
+    boolean success = false;
+    try {
+      openTransaction();
+      createTable(tbl);
+      addPrimaryKeys(primaryKeys);
+      addForeignKeys(foreignKeys);
+         success = commitTransaction();
+    } finally {
+      if (!success) {
+        rollbackTransaction();
+      }
+    }
+  }
+
+  @Override
   public void createTable(Table tbl) throws InvalidObjectException, 
MetaException {
     boolean commited = false;
     try {
       openTransaction();
       MTable mtbl = convertToMTable(tbl);
       pm.makePersistent(mtbl);
+
       PrincipalPrivilegeSet principalPrivs = tbl.getPrivileges();
       List<Object> toPersistPrivObjs = new ArrayList<Object>();
       if (principalPrivs != null) {
@@ -1328,7 +1351,7 @@ public class ObjectStore implements RawStore, 
Configurable {
     // A new table is always created with a new column descriptor
     return new MTable(HiveStringUtils.normalizeIdentifier(tbl.getTableName()), 
mdb,
         convertToMStorageDescriptor(tbl.getSd()), tbl.getOwner(), tbl
-            .getCreateTime(), tbl.getLastAccessTime(), tbl.getRetention(),
+        .getCreateTime(), tbl.getLastAccessTime(), tbl.getRetention(),
         convertToMFieldSchemas(tbl.getPartitionKeys()), tbl.getParameters(),
         tbl.getViewOriginalText(), tbl.getViewExpandedText(),
         tableType);
@@ -3200,6 +3223,165 @@ public class ObjectStore implements RawStore, 
Configurable {
     return sds;
   }
 
+  private MColumnDescriptor getColumnFromTable(MTable mtbl, String col) {
+   for (MFieldSchema mfs: mtbl.getSd().getCD().getCols()) {
+     if (mfs.getName().equals(col)) {
+       List<MFieldSchema> mfsl = new ArrayList<MFieldSchema>();
+       mfsl.add(mfs);
+       return new MColumnDescriptor(mfsl);
+     }
+   }
+   return null;
+  }
+
+  private  boolean constraintNameAlreadyExists(String name) {
+    boolean commited = false;
+    Query constraintExistsQuery = null;
+    String constraintNameIfExists = null;
+    try {
+      openTransaction();
+      name = HiveStringUtils.normalizeIdentifier(name);
+      constraintExistsQuery = pm.newQuery(MConstraint.class, "constraintName 
== name");
+      constraintExistsQuery.declareParameters("java.lang.String name");
+      constraintExistsQuery.setUnique(true);
+      constraintExistsQuery.setResult("name");
+      constraintNameIfExists = (String) constraintExistsQuery.execute(name);
+      commited = commitTransaction();
+    } finally {
+      if (!commited) {
+        rollbackTransaction();
+      }
+      if (constraintExistsQuery != null) {
+          constraintExistsQuery.closeAll();
+      }
+    }
+    return constraintNameIfExists != null && !constraintNameIfExists.isEmpty();
+  }
+
+  private String generateConstraintName(String... parameters) throws 
MetaException {
+    int hashcode = ArrayUtils.toString(parameters).hashCode();
+    int counter = 0;
+    final int MAX_RETRIES = 10;
+    while (counter < MAX_RETRIES) {
+      String currName = (parameters.length == 0 ? "constraint_" : 
parameters[parameters.length-1]) +
+        "_" + hashcode + "_" + System.currentTimeMillis() + "_" + (counter++);
+      if (!constraintNameAlreadyExists(currName)) {
+        return currName;
+      }
+    }
+    throw new MetaException("Error while trying to generate the constraint 
name for " + ArrayUtils.toString(parameters));
+  }
+
+  private void addForeignKeys(
+    List<SQLForeignKey> fks) throws InvalidObjectException,
+    MetaException {
+    List<MConstraint> mpkfks = new ArrayList<MConstraint>();
+    String currentConstraintName = null;
+
+    for (int i = 0; i < fks.size(); i++) {
+      MTable parentTable =
+        getMTable(fks.get(i).getPktable_db(), fks.get(i).getPktable_name());
+      MTable childTable =
+        getMTable(fks.get(i).getFktable_db(), fks.get(i).getFktable_name());
+      MColumnDescriptor parentColumn =
+        getColumnFromTable(parentTable, fks.get(i).getPkcolumn_name());
+      MColumnDescriptor childColumn =
+        getColumnFromTable(childTable, fks.get(i).getFkcolumn_name());
+      if (parentTable == null) {
+        throw new InvalidObjectException("Parent table not found: " + 
fks.get(i).getPktable_name());
+      }
+      if (childTable == null) {
+        throw new InvalidObjectException("Child table not found: " + 
fks.get(i).getFktable_name());
+      }
+      if (parentColumn == null) {
+        throw new InvalidObjectException("Parent column not found: " + 
fks.get(i).getPkcolumn_name());
+      }
+      if (childColumn == null) {
+        throw new InvalidObjectException("Child column not found" + 
fks.get(i).getFkcolumn_name());
+      }
+      if (fks.get(i).getFk_name() == null) {
+        // When there is no explicit foreign key name associated with the 
constraint and the key is composite,
+        // we expect the foreign keys to be send in order in the input list.
+        // Otherwise, the below code will break.
+        // If this is the first column of the FK constraint, generate the 
foreign key name
+        // NB: The below code can result in race condition where duplicate 
names can be generated (in theory).
+        // However, this scenario can be ignored for practical purposes 
because of
+        // the uniqueness of the generated constraint name.
+        if (fks.get(i).getKey_seq() == 1) {
+          currentConstraintName = 
generateConstraintName(fks.get(i).getFktable_db(), fks.get(i).getFktable_name(),
+            fks.get(i).getPktable_db(), fks.get(i).getPktable_name(),
+            fks.get(i).getPkcolumn_name(), fks.get(i).getFkcolumn_name(), 
"fk");
+        }
+      } else {
+        currentConstraintName = fks.get(i).getFk_name();
+      }
+      Integer updateRule = fks.get(i).getUpdate_rule();
+      Integer deleteRule = fks.get(i).getDelete_rule();
+      int enableValidateRely = (fks.get(i).isEnable_cstr() ? 4 : 0) +
+      (fks.get(i).isValidate_cstr() ? 2 : 0) + (fks.get(i).isRely_cstr() ? 1 : 
0);
+      MConstraint mpkfk = new MConstraint(
+        currentConstraintName,
+        MConstraint.FOREIGN_KEY_CONSTRAINT,
+        fks.get(i).getKey_seq(),
+        deleteRule,
+        updateRule,
+        enableValidateRely,
+        parentTable,
+        childTable,
+        parentColumn,
+        childColumn
+      );
+      mpkfks.add(mpkfk);
+    }
+    pm.makePersistentAll(mpkfks);
+  }
+
+  private void addPrimaryKeys(List<SQLPrimaryKey> pks) throws 
InvalidObjectException,
+    MetaException {
+    List<MConstraint> mpks = new ArrayList<MConstraint>();
+    String constraintName = null;
+    for (int i = 0; i < pks.size(); i++) {
+      MTable parentTable =
+        getMTable(pks.get(i).getTable_db(), pks.get(i).getTable_name());
+      MColumnDescriptor parentColumn =
+        getColumnFromTable(parentTable, pks.get(i).getColumn_name());
+      if (parentTable == null) {
+        throw new InvalidObjectException("Parent table not found: " + 
pks.get(i).getTable_name());
+      }
+      if (parentColumn == null) {
+        throw new InvalidObjectException("Parent column not found: " + 
pks.get(i).getColumn_name());
+      }
+      if (getPrimaryKeyConstraintName(
+          parentTable.getDatabase().getName(), parentTable.getTableName()) != 
null) {
+        throw new MetaException(" Primary key already exists for: " +
+          parentTable.getDatabase().getName() + "." + 
pks.get(i).getTable_name());
+      }
+      if (pks.get(i).getPk_name() == null) {
+        if (pks.get(i).getKey_seq() == 1) {
+          constraintName = generateConstraintName(pks.get(i).getTable_db(), 
pks.get(i).getTable_name(),
+            pks.get(i).getColumn_name(), "pk");
+        }
+      } else {
+        constraintName = pks.get(i).getPk_name();
+      }
+      int enableValidateRely = (pks.get(i).isEnable_cstr() ? 4 : 0) +
+      (pks.get(i).isValidate_cstr() ? 2 : 0) + (pks.get(i).isRely_cstr() ? 1 : 
0);
+      MConstraint mpk = new MConstraint(
+        constraintName,
+        MConstraint.PRIMARY_KEY_CONSTRAINT,
+        pks.get(i).getKey_seq(),
+        null,
+        null,
+        enableValidateRely,
+        parentTable,
+        null,
+        parentColumn,
+        null);
+      mpks.add(mpk);
+    }
+    pm.makePersistentAll(mpks);
+  }
+
   @Override
   public boolean addIndex(Index index) throws InvalidObjectException,
       MetaException {
@@ -7940,4 +8122,217 @@ public class ObjectStore implements RawStore, 
Configurable {
       }
     }
   }
+
+  @Override
+  public List<SQLPrimaryKey> getPrimaryKeys(String db_name, String tbl_name) 
throws MetaException {
+    try {
+      return getPrimaryKeysInternal(db_name, tbl_name, true, true);
+    } catch (NoSuchObjectException e) {
+      throw new MetaException(e.getMessage());
+    }
+  }
+
+  protected List<SQLPrimaryKey> getPrimaryKeysInternal(final String db_name,
+    final String tbl_name,
+    boolean allowSql, boolean allowJdo)
+  throws MetaException, NoSuchObjectException {
+    return new GetListHelper<SQLPrimaryKey>(db_name, tbl_name, allowSql, 
allowJdo) {
+
+      @Override
+      protected List<SQLPrimaryKey> 
getSqlResult(GetHelper<List<SQLPrimaryKey>> ctx) throws MetaException {
+        return directSql.getPrimaryKeys(db_name, tbl_name);
+      }
+
+      @Override
+      protected List<SQLPrimaryKey> getJdoResult(
+        GetHelper<List<SQLPrimaryKey>> ctx) throws MetaException, 
NoSuchObjectException {
+        return getPrimaryKeysViaJdo(db_name, tbl_name);
+      }
+    }.run(false);
+  }
+
+  private List<SQLPrimaryKey> getPrimaryKeysViaJdo(String db_name, String 
tbl_name) throws MetaException {
+    boolean commited = false;
+    List<SQLPrimaryKey> primaryKeys = null;
+    Query query = null;
+    try {
+      openTransaction();
+      query = pm.newQuery(MConstraint.class,
+        "parentTable.tableName == tbl_name && parentTable.database.name == 
db_name &&"
+        + " constraintType == MConstraint.PRIMARY_KEY_CONSTRAINT");
+      query.declareParameters("java.lang.String tbl_name, java.lang.String 
db_name");
+      Collection<?> constraints = (Collection<?>) query.execute(tbl_name, 
db_name);
+      pm.retrieveAll(constraints);
+      primaryKeys = new ArrayList<SQLPrimaryKey>();
+      for (Iterator<?> i = constraints.iterator(); i.hasNext();) {
+        MConstraint currPK = (MConstraint) i.next();
+        int enableValidateRely = currPK.getEnableValidateRely();
+        boolean enable = (enableValidateRely & 4) != 0;
+        boolean validate = (enableValidateRely & 2) != 0;
+        boolean rely = (enableValidateRely & 1) != 0;
+        primaryKeys.add(new SQLPrimaryKey(db_name,
+         tbl_name,
+         currPK.getParentColumn().getCols().get(0).getName(),
+         currPK.getPosition(),
+         currPK.getConstraintName(), enable, validate, rely));
+      }
+      commited = commitTransaction();
+    } finally {
+      if (!commited) {
+        rollbackTransaction();
+      }
+      if (query != null) {
+        query.closeAll();
+      }
+    }
+    return primaryKeys;
+  }
+
+  private String getPrimaryKeyConstraintName(String db_name, String tbl_name) 
throws MetaException {
+    boolean commited = false;
+    String ret = null;
+    Query query = null;
+
+    try {
+      openTransaction();
+      query = pm.newQuery(MConstraint.class,
+        "parentTable.tableName == tbl_name && parentTable.database.name == 
db_name &&"
+        + " constraintType == MConstraint.PRIMARY_KEY_CONSTRAINT");
+      query.declareParameters("java.lang.String tbl_name, java.lang.String 
db_name");
+      Collection<?> constraints = (Collection<?>) query.execute(tbl_name, 
db_name);
+      pm.retrieveAll(constraints);
+      for (Iterator<?> i = constraints.iterator(); i.hasNext();) {
+        MConstraint currPK = (MConstraint) i.next();
+        ret = currPK.getConstraintName();
+        break;
+      }
+      commited = commitTransaction();
+     } finally {
+       if (!commited) {
+        rollbackTransaction();
+       }
+       if (query != null) {
+        query.closeAll();
+       }
+     }
+     return ret;
+   }
+
+  @Override
+  public List<SQLForeignKey> getForeignKeys(String parent_db_name,
+    String parent_tbl_name, String foreign_db_name, String foreign_tbl_name) 
throws MetaException {
+    try {
+      return getForeignKeysInternal(parent_db_name,
+        parent_tbl_name, foreign_db_name, foreign_tbl_name, true, true);
+    } catch (NoSuchObjectException e) {
+      throw new MetaException(e.getMessage());
+    }
+  }
+
+  protected List<SQLForeignKey> getForeignKeysInternal(final String 
parent_db_name,
+    final String parent_tbl_name, final String foreign_db_name, final String 
foreign_tbl_name,
+    boolean allowSql, boolean allowJdo) throws MetaException, 
NoSuchObjectException {
+    return new GetListHelper<SQLForeignKey>(foreign_db_name, foreign_tbl_name, 
allowSql, allowJdo) {
+
+      @Override
+      protected List<SQLForeignKey> 
getSqlResult(GetHelper<List<SQLForeignKey>> ctx) throws MetaException {
+        return directSql.getForeignKeys(parent_db_name,
+          parent_tbl_name, foreign_db_name, foreign_tbl_name);
+      }
+
+      @Override
+      protected List<SQLForeignKey> getJdoResult(
+        GetHelper<List<SQLForeignKey>> ctx) throws MetaException, 
NoSuchObjectException {
+        return getForeignKeysViaJdo(parent_db_name,
+          parent_tbl_name, foreign_db_name, foreign_tbl_name);
+      }
+    }.run(false);
+  }
+
+  private List<SQLForeignKey> getForeignKeysViaJdo(String parent_db_name,
+    String parent_tbl_name, String foreign_db_name, String foreign_tbl_name) 
throws MetaException {
+    boolean commited = false;
+    List<SQLForeignKey> foreignKeys = null;
+    Collection<?> constraints = null;
+    Query query = null;
+    Map<String, String> tblToConstraint = new HashMap<String, String>();
+    try {
+      openTransaction();
+      String queryText = (parent_tbl_name != null ? "parentTable.tableName == 
parent_tbl_name &&" : "")
+        + (parent_db_name != null ? "parentTable.database.name == 
parent_db_name &&" : "")
+        + (foreign_tbl_name != null ? "childTable.tableName == 
foreign_tbl_name &&" : "")
+        + (parent_db_name != null ? "childTable.database.name == 
foreign_db_name &&" : "")
+        + "constraintType == MConstraint.FOREIGN_KEY_CONSTRAINT";
+      queryText = queryText.trim();
+      query = pm.newQuery(MConstraint.class, queryText);
+      String paramText = (parent_tbl_name == null ? "" : "java.lang.String 
parent_tbl_name,")
+        + (parent_db_name == null ? "" : " java.lang.String parent_db_name, ")
+        + (foreign_tbl_name == null ? "" : "java.lang.String 
foreign_tbl_name,")
+        + (foreign_db_name == null ? "" : " java.lang.String foreign_db_name");
+      paramText=paramText.trim();
+      if (paramText.endsWith(",")) {
+        paramText = paramText.substring(0, paramText.length()-1);
+      }
+      query.declareParameters(paramText);
+      List<String> params = new ArrayList<String>();
+      if (parent_tbl_name != null) {
+        params.add(parent_tbl_name);
+      }
+      if (parent_db_name != null) {
+        params.add(parent_db_name);
+      }
+      if (foreign_tbl_name != null) {
+        params.add(foreign_tbl_name);
+      }
+      if (parent_db_name != null) {
+        params.add(foreign_db_name);
+      }
+      if (params.size() == 0) {
+        constraints = (Collection<?>) query.execute();
+      } else {
+        constraints = (Collection<?>) query.executeWithArray(params);
+      }
+      pm.retrieveAll(constraints);
+      foreignKeys = new ArrayList<SQLForeignKey>();
+      for (Iterator<?> i = constraints.iterator(); i.hasNext();) {
+        MConstraint currPKFK = (MConstraint) i.next();
+        int enableValidateRely = currPKFK.getEnableValidateRely();
+        boolean enable = (enableValidateRely & 4) != 0;
+        boolean validate = (enableValidateRely & 2) != 0;
+        boolean rely = (enableValidateRely & 1) != 0;
+        String consolidatedtblName =
+          currPKFK.getParentTable().getDatabase().getName() + "." +
+          currPKFK.getParentTable().getTableName();
+        String pkName;
+        if (tblToConstraint.containsKey(consolidatedtblName)) {
+          pkName = tblToConstraint.get(consolidatedtblName);
+        } else {
+          pkName = 
getPrimaryKeyConstraintName(currPKFK.getParentTable().getDatabase().getName(),
+            currPKFK.getParentTable().getDatabase().getName());
+          tblToConstraint.put(consolidatedtblName, pkName);
+        }
+        foreignKeys.add(new SQLForeignKey(
+          currPKFK.getParentTable().getDatabase().getName(),
+          currPKFK.getParentTable().getDatabase().getName(),
+          currPKFK.getParentColumn().getCols().get(0).getName(),
+          currPKFK.getChildTable().getDatabase().getName(),
+          currPKFK.getChildTable().getTableName(),
+          currPKFK.getChildColumn().getCols().get(0).getName(),
+          currPKFK.getPosition(),
+          currPKFK.getUpdateRule(),
+          currPKFK.getDeleteRule(),
+          currPKFK.getConstraintName(), pkName, enable, validate, rely));
+      }
+      commited = commitTransaction();
+    } finally {
+      if (!commited) {
+        rollbackTransaction();
+      }
+      if (query != null) {
+        query.closeAll();
+      }
+    }
+    return foreignKeys;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/java/org/apache/hadoop/hive/metastore/RawStore.java
----------------------------------------------------------------------
diff --git a/metastore/src/java/org/apache/hadoop/hive/metastore/RawStore.java 
b/metastore/src/java/org/apache/hadoop/hive/metastore/RawStore.java
index e49f757..100c396 100644
--- a/metastore/src/java/org/apache/hadoop/hive/metastore/RawStore.java
+++ b/metastore/src/java/org/apache/hadoop/hive/metastore/RawStore.java
@@ -51,6 +51,8 @@ import org.apache.hadoop.hive.metastore.api.PrincipalType;
 import org.apache.hadoop.hive.metastore.api.PrivilegeBag;
 import org.apache.hadoop.hive.metastore.api.Role;
 import org.apache.hadoop.hive.metastore.api.RolePrincipalGrant;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.Table;
 import org.apache.hadoop.hive.metastore.api.TableMeta;
 import org.apache.hadoop.hive.metastore.api.Type;
@@ -663,4 +665,14 @@ public interface RawStore extends Configurable {
 
   @InterfaceStability.Evolving
   long getChangeVersion(String topic) throws MetaException;
+
+  public abstract List<SQLPrimaryKey> getPrimaryKeys(String db_name,
+    String tbl_name) throws MetaException;
+
+  public abstract List<SQLForeignKey> getForeignKeys(String parent_db_name,
+    String parent_tbl_name, String foreign_db_name, String foreign_tbl_name)
+    throws MetaException;
+
+  void createTableWithConstraints(Table tbl, List<SQLPrimaryKey> primaryKeys,
+    List<SQLForeignKey> foreignKeys) throws InvalidObjectException, 
MetaException;
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/java/org/apache/hadoop/hive/metastore/hbase/HBaseStore.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/java/org/apache/hadoop/hive/metastore/hbase/HBaseStore.java 
b/metastore/src/java/org/apache/hadoop/hive/metastore/hbase/HBaseStore.java
index a73dbeb..d4e5da4 100644
--- a/metastore/src/java/org/apache/hadoop/hive/metastore/hbase/HBaseStore.java
+++ b/metastore/src/java/org/apache/hadoop/hive/metastore/hbase/HBaseStore.java
@@ -63,6 +63,8 @@ import org.apache.hadoop.hive.metastore.api.PrivilegeBag;
 import org.apache.hadoop.hive.metastore.api.PrivilegeGrantInfo;
 import org.apache.hadoop.hive.metastore.api.Role;
 import org.apache.hadoop.hive.metastore.api.RolePrincipalGrant;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.Table;
 import org.apache.hadoop.hive.metastore.api.TableMeta;
 import org.apache.hadoop.hive.metastore.api.Type;
@@ -2591,4 +2593,26 @@ public class HBaseStore implements RawStore {
       commitOrRoleBack(commit);
     }
   }
+
+  @Override
+  public List<SQLPrimaryKey> getPrimaryKeys(String db_name, String tbl_name)
+    throws MetaException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public List<SQLForeignKey> getForeignKeys(String parent_db_name,
+    String parent_tbl_name, String foreign_db_name, String foreign_tbl_name)
+    throws MetaException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void createTableWithConstraints(Table tbl,
+    List<SQLPrimaryKey> primaryKeys, List<SQLForeignKey> foreignKeys)
+    throws InvalidObjectException, MetaException {
+    // TODO Auto-generated method stub
+  }
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/model/org/apache/hadoop/hive/metastore/model/MConstraint.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/model/org/apache/hadoop/hive/metastore/model/MConstraint.java 
b/metastore/src/model/org/apache/hadoop/hive/metastore/model/MConstraint.java
new file mode 100644
index 0000000..3806e28
--- /dev/null
+++ 
b/metastore/src/model/org/apache/hadoop/hive/metastore/model/MConstraint.java
@@ -0,0 +1,148 @@
+package org.apache.hadoop.hive.metastore.model;
+
+import java.io.Serializable;
+
+public class MConstraint
+{
+  String constraintName;
+  int constraintType;
+  int position;
+  Integer deleteRule;
+  Integer updateRule;
+  MTable parentTable;
+  MTable childTable;
+  MColumnDescriptor parentColumn;
+  MColumnDescriptor childColumn;
+  int enableValidateRely;
+
+  // 0 - Primary Key
+  // 1 - PK-FK relationship
+  public final static int PRIMARY_KEY_CONSTRAINT = 0;
+  public final static int FOREIGN_KEY_CONSTRAINT = 1;
+
+  @SuppressWarnings("serial")
+  public static class PK implements Serializable {
+    public String constraintName;
+    public int position;
+
+    public PK() {}
+
+    public PK(String constraintName, int position) {
+      this.constraintName = constraintName;
+      this.position = position;
+    }
+
+    public String toString() {
+      return constraintName+":"+position;
+    }
+
+    public int hashCode() {
+      return toString().hashCode();
+    }
+
+    public boolean equals(Object other) {
+      if (other != null && (other instanceof PK)) {
+        PK otherPK = (PK) other;
+        return otherPK.constraintName.equals(constraintName) && 
otherPK.position == position;
+      }
+      return false;
+    }
+  }
+
+  public MConstraint() {}
+
+  public MConstraint(String constraintName, int constraintType, int position, 
Integer deleteRule, Integer updateRule, int enableRelyValidate, MTable 
parentTable,
+    MTable childTable, MColumnDescriptor parentColumn,
+    MColumnDescriptor childColumn) {
+   this.constraintName = constraintName;
+   this.constraintType = constraintType;
+   this.parentColumn = parentColumn;
+   this.parentTable = parentTable;
+   this.childColumn = childColumn;
+   this.childTable = childTable;
+   this.position = position;
+   this.deleteRule = deleteRule;
+   this.updateRule = updateRule;
+   this.enableValidateRely = enableRelyValidate;
+  }
+
+  public String getConstraintName() {
+    return constraintName;
+  }
+
+  public void setConstraintName(String fkName) {
+    this.constraintName = fkName;
+  }
+
+  public int getConstraintType() {
+    return constraintType;
+  }
+
+  public void setConstraintType(int ct) {
+    this.constraintType = ct;
+  }
+
+  public int getPosition() {
+    return position;
+  }
+
+  public void setPosition(int po) {
+    this.position = po;
+  }
+
+  public Integer getDeleteRule() {
+    return deleteRule;
+  }
+
+  public void setDeleteRule(Integer de) {
+    this.deleteRule = de;
+  }
+
+  public int getEnableValidateRely() {
+    return enableValidateRely;
+  }
+
+  public void setEnableValidateRely(int enableValidateRely) {
+    this.enableValidateRely = enableValidateRely;
+  }
+
+  public Integer getUpdateRule() {
+    return updateRule;
+  }
+
+  public void setUpdateRule(Integer ur) {
+    this.updateRule = ur;
+  }
+
+  public MTable getChildTable() {
+    return childTable;
+  }
+
+  public void setChildTable(MTable ft) {
+    this.childTable = ft;
+  }
+
+  public MTable getParentTable() {
+    return parentTable;
+  }
+
+  public void setParentTable(MTable pt) {
+    this.parentTable = pt;
+  }
+
+  public MColumnDescriptor getChildColumn() {
+    return childColumn;
+  }
+
+  public void setChildColumn(MColumnDescriptor cc) {
+    this.childColumn = cc;
+  }
+
+  public MColumnDescriptor getParentColumn() {
+    return parentColumn;
+  }
+
+  public void setParentColumn(MColumnDescriptor pc) {
+    this.parentColumn = pc;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/model/package.jdo
----------------------------------------------------------------------
diff --git a/metastore/src/model/package.jdo b/metastore/src/model/package.jdo
index 7385a13..b40df39 100644
--- a/metastore/src/model/package.jdo
+++ b/metastore/src/model/package.jdo
@@ -184,6 +184,39 @@
       </field>
     </class>
 
+    <class name="MConstraint" identity-type="application" 
table="KEY_CONSTRAINTS" detachable="true" objectid-class="MConstraint$PK">
+      <field name="constraintName" primary-key="true">
+        <column name="CONSTRAINT_NAME"/>
+      </field>
+      <field name="position" primary-key="true">
+        <column name="POSITION"/>
+      </field>
+      <field name="childColumn">
+        <column name="CHILD_CD_ID"/>
+      </field>
+      <field name="childTable">
+        <column name="CHILD_TBL_ID"/>
+      </field>
+      <field name="parentColumn">
+        <column name="PARENT_CD_ID"/>
+      </field>
+      <field name="parentTable">
+        <column name="PARENT_TBL_ID"/>
+      </field>
+      <field name="constraintType">
+        <column name="CONSTRAINT_TYPE"/>
+      </field>
+      <field name="deleteRule">
+       <column name="DELETE_RULE"/>
+      </field>
+      <field name="updateRule">
+        <column name="UPDATE_RULE"/>
+      </field>
+      <field name="enableValidateRely">
+        <column name="ENABLE_VALIDATE_RELY"/>
+      </field>
+    </class>
+
     <class name="MSerDeInfo" identity-type="datastore" table="SERDES" 
detachable="true">
       <datastore-identity>
         <column name="SERDE_ID"/>

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreControlledCommit.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreControlledCommit.java
 
b/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreControlledCommit.java
index 94ca835..86e7bea 100644
--- 
a/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreControlledCommit.java
+++ 
b/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreControlledCommit.java
@@ -49,6 +49,8 @@ import org.apache.hadoop.hive.metastore.api.PrincipalType;
 import org.apache.hadoop.hive.metastore.api.PrivilegeBag;
 import org.apache.hadoop.hive.metastore.api.Role;
 import org.apache.hadoop.hive.metastore.api.RolePrincipalGrant;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.Table;
 import org.apache.hadoop.hive.metastore.api.TableMeta;
 import org.apache.hadoop.hive.metastore.api.Type;
@@ -820,4 +822,26 @@ public class DummyRawStoreControlledCommit implements 
RawStore, Configurable {
   public long getChangeVersion(String topic) throws MetaException {
     return 0;
   }
+
+  @Override
+  public List<SQLPrimaryKey> getPrimaryKeys(String db_name, String tbl_name)
+    throws MetaException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public List<SQLForeignKey> getForeignKeys(String parent_db_name,
+    String parent_tbl_name, String foreign_db_name, String foreign_tbl_name)
+    throws MetaException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void createTableWithConstraints(Table tbl,
+    List<SQLPrimaryKey> primaryKeys, List<SQLForeignKey> foreignKeys)
+    throws InvalidObjectException, MetaException {
+    // TODO Auto-generated method stub
+  }
 }

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreForJdoConnection.java
----------------------------------------------------------------------
diff --git 
a/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreForJdoConnection.java
 
b/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreForJdoConnection.java
index b108f95..5b32f00 100644
--- 
a/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreForJdoConnection.java
+++ 
b/metastore/src/test/org/apache/hadoop/hive/metastore/DummyRawStoreForJdoConnection.java
@@ -50,6 +50,8 @@ import org.apache.hadoop.hive.metastore.api.PrincipalType;
 import org.apache.hadoop.hive.metastore.api.PrivilegeBag;
 import org.apache.hadoop.hive.metastore.api.Role;
 import org.apache.hadoop.hive.metastore.api.RolePrincipalGrant;
+import org.apache.hadoop.hive.metastore.api.SQLForeignKey;
+import org.apache.hadoop.hive.metastore.api.SQLPrimaryKey;
 import org.apache.hadoop.hive.metastore.api.Table;
 import org.apache.hadoop.hive.metastore.api.TableMeta;
 import org.apache.hadoop.hive.metastore.api.Type;
@@ -836,6 +838,28 @@ public class DummyRawStoreForJdoConnection implements 
RawStore {
   public long getChangeVersion(String topic) throws MetaException {
     return 0;
   }
+
+  @Override
+  public List<SQLPrimaryKey> getPrimaryKeys(String db_name, String tbl_name)
+    throws MetaException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public List<SQLForeignKey> getForeignKeys(String parent_db_name,
+    String parent_tbl_name, String foreign_db_name, String foreign_tbl_name)
+    throws MetaException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void createTableWithConstraints(Table tbl,
+    List<SQLPrimaryKey> primaryKeys, List<SQLForeignKey> foreignKeys)
+    throws InvalidObjectException, MetaException {
+    // TODO Auto-generated method stub
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/hive/blob/55375ec1/service/src/gen/thrift/gen-py/hive_service/ThriftHive-remote
----------------------------------------------------------------------
diff --git a/service/src/gen/thrift/gen-py/hive_service/ThriftHive-remote 
b/service/src/gen/thrift/gen-py/hive_service/ThriftHive-remote
index 9a2322f..4dfa83d 100755
--- a/service/src/gen/thrift/gen-py/hive_service/ThriftHive-remote
+++ b/service/src/gen/thrift/gen-py/hive_service/ThriftHive-remote
@@ -51,6 +51,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help':
   print('   get_schema_with_environment_context(string db_name, string 
table_name, EnvironmentContext environment_context)')
   print('  void create_table(Table tbl)')
   print('  void create_table_with_environment_context(Table tbl, 
EnvironmentContext environment_context)')
+  print('  void create_table_with_constraints(Table tbl,  primaryKeys,  
foreignKeys)')
   print('  void drop_table(string dbname, string name, bool deleteData)')
   print('  void drop_table_with_environment_context(string dbname, string 
name, bool deleteData, EnvironmentContext environment_context)')
   print('   get_tables(string db_name, string pattern)')
@@ -110,6 +111,8 @@ if len(sys.argv) <= 1 or sys.argv[1] == '--help':
   print('  Index get_index_by_name(string db_name, string tbl_name, string 
index_name)')
   print('   get_indexes(string db_name, string tbl_name, i16 max_indexes)')
   print('   get_index_names(string db_name, string tbl_name, i16 max_indexes)')
+  print('  PrimaryKeysResponse get_primary_keys(PrimaryKeysRequest request)')
+  print('  ForeignKeysResponse get_foreign_keys(ForeignKeysRequest request)')
   print('  bool update_table_column_statistics(ColumnStatistics stats_obj)')
   print('  bool update_partition_column_statistics(ColumnStatistics 
stats_obj)')
   print('  ColumnStatistics get_table_column_statistics(string db_name, string 
tbl_name, string col_name)')
@@ -407,6 +410,12 @@ elif cmd == 'create_table_with_environment_context':
     sys.exit(1)
   
pp.pprint(client.create_table_with_environment_context(eval(args[0]),eval(args[1]),))
 
+elif cmd == 'create_table_with_constraints':
+  if len(args) != 3:
+    print('create_table_with_constraints requires 3 args')
+    sys.exit(1)
+  
pp.pprint(client.create_table_with_constraints(eval(args[0]),eval(args[1]),eval(args[2]),))
+
 elif cmd == 'drop_table':
   if len(args) != 3:
     print('drop_table requires 3 args')
@@ -761,6 +770,18 @@ elif cmd == 'get_index_names':
     sys.exit(1)
   pp.pprint(client.get_index_names(args[0],args[1],eval(args[2]),))
 
+elif cmd == 'get_primary_keys':
+  if len(args) != 1:
+    print('get_primary_keys requires 1 args')
+    sys.exit(1)
+  pp.pprint(client.get_primary_keys(eval(args[0]),))
+
+elif cmd == 'get_foreign_keys':
+  if len(args) != 1:
+    print('get_foreign_keys requires 1 args')
+    sys.exit(1)
+  pp.pprint(client.get_foreign_keys(eval(args[0]),))
+
 elif cmd == 'update_table_column_statistics':
   if len(args) != 1:
     print('update_table_column_statistics requires 1 args')

Reply via email to