public MixedTable createTable(
      org.apache.amoro.table.TableIdentifier identifier,
      Schema schema,
      PartitionSpec partitionSpec,
      PrimaryKeySpec keySpec,
      Map<String, String> properties) {
    TableIdentifier baseIdentifier =
        TableIdentifier.of(identifier.getDatabase(), identifier.getTableName());
    TableIdentifier changeIdentifier = generateChangeStoreIdentifier(baseIdentifier);

    Table base = createBaseStore(baseIdentifier, schema, partitionSpec, keySpec, properties);
    AuthenticatedFileIO io =
        AuthenticatedFileIOs.buildAdaptIcebergFileIO(this.tableMetaStore, base.io());
    if (!keySpec.primaryKeyExisted()) {
      return new BasicUnkeyedTable(
          identifier, useMixedTableOperation(base, io), io, catalogProperties);
    }

    Table change =
        createChangeStore(
            baseIdentifier, changeIdentifier, schema, partitionSpec, keySpec, properties);
    BaseTable baseStore =
        new BasicKeyedTable.BaseInternalTable(
            identifier, useMixedTableOperation(base, io), io, catalogProperties);
    ChangeTable changeStore =
        new BasicKeyedTable.ChangeInternalTable(
            identifier, useMixedTableOperation(change, io), io, catalogProperties);
    return new BasicKeyedTable(keySpec, baseStore, changeStore);
  }
create a mixed iceberg table

@param identifier mixed catalog table identifier.
@param schema table schema
@param partitionSpec partition spec
@param keySpec key spec
@param properties table properties
@return mixed format table.
amoro-format-iceberg/src/main/java/org/apache/amoro/mixed/MixedTables.java