TEST_F(ConstraintsTests, ForeignKeyInsertTest) {
  // First, initial 2 tables like following
  //     TABLE A -- src table          TABLE B -- sink table
  // int(primary, ref B)  int            int(primary)  int
  //    0                 0               0             0
  //    1                 0               1             0
  //    2                 0               2             0
  //                                      .....
  //                                      9             0

  // create new db
  auto &manager = catalog::Manager::GetInstance();
  oid_t current_db_oid = bridge::Bridge::GetCurrentDatabaseOid();
  auto newdb = new storage::Database(current_db_oid);
  manager.AddDatabase(newdb);

  auto table_A =
      TransactionTestsUtil::CreateTable(3, "tableA", 0, 1000, 1000, true);
  // we wouldn't use table_B later here so we don't save the return value
  TransactionTestsUtil::CreateTable(10, "tableB", 0, 1001, 1001, true);

  // add the foreign key constraints for table_A
  std::unique_ptr<catalog::ForeignKey> foreign_key(new catalog::ForeignKey(
      1001, {"id"}, {0}, {"id"}, {0}, 'r', 'c', "THIS_IS_FOREIGN_CONSTRAINT"));
  table_A->AddForeignKey(foreign_key.get());

  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();

  // Test1: insert 2 tuple, one of which doesn't follow foreign key constraint
  // txn0 insert (10,10) --> fail
  // txn1 insert (9,10) --> success
  // txn0 commit
  // txn1 commit
  {
    TransactionScheduler scheduler(2, table_A, &txn_manager);
    scheduler.Txn(0).Insert(10, 10);
    scheduler.Txn(1).Insert(9, 10);
    scheduler.Txn(0).Commit();
    scheduler.Txn(1).Commit();

    scheduler.Run();

    EXPECT_TRUE(RESULT_ABORTED == scheduler.schedules[0].txn_result);
    EXPECT_TRUE(RESULT_SUCCESS == scheduler.schedules[1].txn_result);
  }

  // this will also indirectly delete all tables in this database
  delete newdb;
}
void raw_foreign_key_info::CreateForeignkey(void) const {
    // Get source table, sink table, and database oid
    oid_t source_table_oid = source_table_id;
    assert(source_table_oid);
    oid_t sink_table_oid = sink_table_id;
    assert(sink_table_oid);
    oid_t database_oid = Bridge::GetCurrentDatabaseOid();

    // get source, sink tables
    auto &manager = catalog::Manager::GetInstance();
    auto source_table = manager.GetTableWithOid(database_oid, source_table_oid);
    assert(source_table);
    auto sink_table = manager.GetTableWithOid(database_oid, sink_table_oid);
    assert(sink_table);

    // extract column_names
    std::vector<std::string> sink_column_names;
    std::vector<std::string> source_column_names;

    auto source_table_schema = source_table->GetSchema();
    auto sink_table_schema = sink_table->GetSchema();

    // Populate primary key column names
    for (auto sink_offset : sink_column_offsets) {
        catalog::Column column = sink_table_schema->GetColumn(sink_offset - 1);
        sink_column_names.push_back(column.GetName());
    }

    // Populate source key column names
    for (auto source_offset : source_column_offsets) {
        catalog::Column column = source_table_schema->GetColumn(source_offset - 1);
        source_column_names.push_back(column.GetName());
    }

    catalog::ForeignKey *foreign_key = new catalog::ForeignKey(
        sink_table_oid, sink_column_names, source_column_names, update_action,
        delete_action, fk_name);

    source_table->AddForeignKey(foreign_key);
}