3636#include " iceberg/exception.h"
3737#include " iceberg/file_io.h"
3838#include " iceberg/json_internal.h"
39+ #include " iceberg/metrics_config.h"
3940#include " iceberg/partition_spec.h"
4041#include " iceberg/result.h"
4142#include " iceberg/schema.h"
4243#include " iceberg/snapshot.h"
4344#include " iceberg/sort_order.h"
4445#include " iceberg/table_properties.h"
4546#include " iceberg/table_update.h"
47+ #include " iceberg/util/error_collector.h"
4648#include " iceberg/util/gzip_internal.h"
4749#include " iceberg/util/location_util.h"
4850#include " iceberg/util/macros.h"
51+ #include " iceberg/util/type_util.h"
4952#include " iceberg/util/uuid.h"
5053namespace iceberg {
5154namespace {
@@ -64,6 +67,47 @@ std::string ToString(const MetadataLogEntry& entry) {
6467 entry.metadata_file );
6568}
6669
70+ Result<std::unique_ptr<TableMetadata>> TableMetadata::Make (
71+ const std::string& location, const iceberg::Schema& schema,
72+ const iceberg::PartitionSpec& spec, const iceberg::SortOrder& sort_order,
73+ const std::unordered_map<std::string, std::string>& properties, int format_version) {
74+ for (const auto & [key, _] : properties) {
75+ if (TableProperties::reserved_properties ().contains (key)) {
76+ return InvalidArgument (
77+ " Table properties should not contain reserved properties, but got {}" , key);
78+ }
79+ }
80+
81+ int last_column_id = 0 ;
82+ auto next_id = [&last_column_id]() -> int32_t { return ++last_column_id; };
83+
84+ auto fresh_schema =
85+ IdAssigner::AssignFreshIds (Schema::kInitialSchemaId , schema, next_id);
86+
87+ ICEBERG_ASSIGN_OR_RAISE (
88+ auto fresh_spec,
89+ PartitionSpec::Make (
90+ *fresh_schema, PartitionSpec::kInitialSpecId ,
91+ std::vector<PartitionField>(spec.fields ().begin (), spec.fields ().end ()),
92+ false ));
93+ ICEBERG_ASSIGN_OR_RAISE (
94+ auto fresh_order,
95+ SortOrder::Make (sort_order.is_unsorted () ? sort_order.order_id ()
96+ : SortOrder::kInitialSortOrderId ,
97+ std::vector<SortField>(sort_order.fields ().begin (),
98+ sort_order.fields ().end ())));
99+ ICEBERG_RETURN_UNEXPECTED (
100+ MetricsConfig::VerifyReferencedColumns (properties, *fresh_schema));
101+
102+ return TableMetadataBuilder::BuildFromEmpty (format_version)
103+ ->SetLocation (location)
104+ .SetCurrentSchema (fresh_schema, next_id ())
105+ .AddPartitionSpec (std::move (fresh_spec))
106+ .AddSortOrder (std::move (fresh_order))
107+ .SetProperties (properties)
108+ .Build ();
109+ }
110+
67111Result<std::shared_ptr<Schema>> TableMetadata::Schema () const {
68112 return SchemaById (current_schema_id);
69113}
@@ -417,6 +461,33 @@ struct TableMetadataBuilder::Impl {
417461
418462 metadata.last_updated_ms = kInvalidLastUpdatedMs ;
419463 }
464+
465+ // TODO(zhuo.wang) Do validation
466+ Status AddSchema (const std::shared_ptr<Schema>& schema, int new_last_column_id) {
467+ if (new_last_column_id < metadata.last_column_id ) {
468+ return InvalidArgument (" Invalid last column ID: {} < {} (previous last column ID)" ,
469+ new_last_column_id, metadata.last_column_id );
470+ }
471+ metadata.schemas .push_back (schema);
472+ schemas_by_id.emplace (schema->schema_id ().value (), schema);
473+ metadata.current_schema_id = schema->schema_id ().value ();
474+
475+ return {};
476+ }
477+
478+ // TODO(zhuo.wang) Do validation
479+ Status AddPartitionSpec (const std::shared_ptr<PartitionSpec>& spec) {
480+ metadata.partition_specs .push_back (spec);
481+ specs_by_id.emplace (spec->spec_id (), spec);
482+ return {};
483+ }
484+
485+ // TODO(zhuo.wang) Do validation
486+ Status AddSortOrder (const std::shared_ptr<SortOrder>& order) {
487+ metadata.sort_orders .push_back (order);
488+ sort_orders_by_id.emplace (order->order_id (), order);
489+ return {};
490+ }
420491};
421492
422493TableMetadataBuilder::TableMetadataBuilder (int8_t format_version)
@@ -529,7 +600,7 @@ TableMetadataBuilder& TableMetadataBuilder::UpgradeFormatVersion(
529600
530601TableMetadataBuilder& TableMetadataBuilder::SetCurrentSchema (
531602 std::shared_ptr<Schema> schema, int32_t new_last_column_id) {
532- throw IcebergError ( std::format ( " {} not implemented " , __FUNCTION__ ));
603+ BUILDER_RETURN (impl_-> AddSchema (schema, new_last_column_id ));
533604}
534605
535606TableMetadataBuilder& TableMetadataBuilder::SetCurrentSchema (int32_t schema_id) {
@@ -551,7 +622,7 @@ TableMetadataBuilder& TableMetadataBuilder::SetDefaultPartitionSpec(int32_t spec
551622
552623TableMetadataBuilder& TableMetadataBuilder::AddPartitionSpec (
553624 std::shared_ptr<PartitionSpec> spec) {
554- throw IcebergError ( std::format ( " {} not implemented " , __FUNCTION__ ));
625+ BUILDER_RETURN (impl_-> AddPartitionSpec (spec ));
555626}
556627
557628TableMetadataBuilder& TableMetadataBuilder::RemovePartitionSpecs (
@@ -746,7 +817,8 @@ TableMetadataBuilder& TableMetadataBuilder::RemoveProperties(
746817}
747818
748819TableMetadataBuilder& TableMetadataBuilder::SetLocation (std::string_view location) {
749- throw IcebergError (std::format (" {} not implemented" , __FUNCTION__));
820+ impl_->metadata .location = location;
821+ return *this ;
750822}
751823
752824TableMetadataBuilder& TableMetadataBuilder::AddEncryptionKey (
0 commit comments