protected KeyedTable createKeyedTable(
      TableMeta tableMeta,
      Schema schema,
      PrimaryKeySpec primaryKeySpec,
      PartitionSpec partitionSpec) {
    TableIdentifier tableIdentifier = TableIdentifier.of(tableMeta.getTableIdentifier());
    String tableLocation = checkLocation(tableMeta, MetaTableProperties.LOCATION_KEY_TABLE);
    String baseLocation = checkLocation(tableMeta, MetaTableProperties.LOCATION_KEY_BASE);
    String changeLocation = checkLocation(tableMeta, MetaTableProperties.LOCATION_KEY_CHANGE);

    fillTableProperties(tableMeta);
    AuthenticatedFileIO fileIO =
        AuthenticatedFileIOs.buildRecoverableHadoopFileIO(
            tableIdentifier,
            tableLocation,
            tableMeta.getProperties(),
            tableMetaStore,
            catalogProperties);
    Table baseIcebergTable =
        tableMetaStore.doAs(
            () -> {
              try {
                return tables.create(
                    schema, partitionSpec, tableMeta.getProperties(), baseLocation);
              } catch (Exception e) {
                throw new IllegalStateException("create base table failed", e);
              }
            });
    BaseTable baseTable =
        new BasicKeyedTable.BaseInternalTable(
            tableIdentifier,
            MixedFormatCatalogUtil.useMixedTableOperations(
                baseIcebergTable, baseLocation, fileIO, tableMetaStore.getConfiguration()),
            fileIO,
            catalogProperties);

    Table changeIcebergTable =
        tableMetaStore.doAs(
            () -> {
              try {
                return tables.create(
                    schema, partitionSpec, tableMeta.getProperties(), changeLocation);
              } catch (Exception e) {
                throw new IllegalStateException("create change table failed", e);
              }
            });
    ChangeTable changeTable =
        new BasicKeyedTable.ChangeInternalTable(
            tableIdentifier,
            MixedFormatCatalogUtil.useMixedTableOperations(
                changeIcebergTable, changeLocation, fileIO, tableMetaStore.getConfiguration()),
            fileIO,
            catalogProperties);
    return new BasicKeyedTable(tableLocation, primaryKeySpec, baseTable, changeTable);
  }
TODO: this class will be removed when we support using restCatalog as base store for
InternalCatalog
amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/MixedTables.java