|
20 | 20 | #include "iceberg/table_metadata.h" |
21 | 21 |
|
22 | 22 | #include <algorithm> |
| 23 | +#include <chrono> |
23 | 24 | #include <format> |
24 | 25 | #include <string> |
25 | 26 |
|
|
36 | 37 | #include "iceberg/table_update.h" |
37 | 38 | #include "iceberg/util/gzip_internal.h" |
38 | 39 | #include "iceberg/util/macros.h" |
| 40 | +#include "iceberg/util/uuid.h" |
39 | 41 |
|
40 | 42 | namespace iceberg { |
41 | 43 |
|
| 44 | +namespace { |
| 45 | +const TimePointMs kInvalidLastUpdatedMs = TimePointMs::min(); |
| 46 | +} |
| 47 | + |
42 | 48 | std::string ToString(const SnapshotLogEntry& entry) { |
43 | 49 | return std::format("SnapshotLogEntry[timestampMillis={},snapshotId={}]", |
44 | 50 | entry.timestamp_ms, entry.snapshot_id); |
@@ -201,13 +207,46 @@ Status TableMetadataUtil::Write(FileIO& io, const std::string& location, |
201 | 207 |
|
202 | 208 | // TableMetadataBuilder implementation |
203 | 209 |
|
204 | | -struct TableMetadataBuilder::Impl {}; |
| 210 | +struct TableMetadataBuilder::Impl { |
| 211 | + // Base metadata (nullptr for new tables) |
| 212 | + const TableMetadata* base; |
| 213 | + |
| 214 | + // Working metadata copy |
| 215 | + TableMetadata metadata; |
| 216 | + |
| 217 | + // Change tracking |
| 218 | + std::vector<std::unique_ptr<TableUpdate>> changes; |
| 219 | + |
| 220 | + // Error collection (since methods return *this and cannot throw) |
| 221 | + std::vector<Error> errors; |
| 222 | + |
| 223 | + // Metadata location tracking |
| 224 | + std::optional<std::string> metadata_location; |
| 225 | + std::optional<std::string> previous_metadata_location; |
| 226 | + |
| 227 | + // Constructor for new table |
| 228 | + explicit Impl(int8_t format_version) : base(nullptr), metadata{} { |
| 229 | + metadata.format_version = format_version; |
| 230 | + metadata.last_sequence_number = TableMetadata::kInitialSequenceNumber; |
| 231 | + metadata.last_updated_ms = kInvalidLastUpdatedMs; |
| 232 | + metadata.last_column_id = Schema::kInvalidColumnId; |
| 233 | + metadata.default_spec_id = PartitionSpec::kInitialSpecId; |
| 234 | + metadata.last_partition_id = PartitionSpec::kInvalidPartitionFieldId; |
| 235 | + metadata.current_snapshot_id = Snapshot::kInvalidSnapshotId; |
| 236 | + metadata.default_sort_order_id = SortOrder::kInitialSortOrderId; |
| 237 | + metadata.next_row_id = TableMetadata::kInitialRowId; |
| 238 | + } |
| 239 | + |
| 240 | + // Constructor from existing metadata |
| 241 | + explicit Impl(const TableMetadata* base_metadata) |
| 242 | + : base(base_metadata), metadata(*base_metadata) {} |
| 243 | +}; |
205 | 244 |
|
206 | 245 | TableMetadataBuilder::TableMetadataBuilder(int8_t format_version) |
207 | | - : impl_(std::make_unique<Impl>()) {} |
| 246 | + : impl_(std::make_unique<Impl>(format_version)) {} |
208 | 247 |
|
209 | 248 | TableMetadataBuilder::TableMetadataBuilder(const TableMetadata* base) |
210 | | - : impl_(std::make_unique<Impl>()) {} |
| 249 | + : impl_(std::make_unique<Impl>(base)) {} |
211 | 250 |
|
212 | 251 | TableMetadataBuilder::~TableMetadataBuilder() = default; |
213 | 252 |
|
@@ -238,12 +277,35 @@ TableMetadataBuilder& TableMetadataBuilder::SetPreviousMetadataLocation( |
238 | 277 | } |
239 | 278 |
|
240 | 279 | TableMetadataBuilder& TableMetadataBuilder::AssignUUID() { |
241 | | - throw IcebergError(std::format("{} not implemented", __FUNCTION__)); |
| 280 | + if (impl_->metadata.table_uuid.empty()) { |
| 281 | + // Generate a random UUID |
| 282 | + return AssignUUID(Uuid::GenerateV4().ToString()); |
| 283 | + } |
| 284 | + |
| 285 | + return *this; |
242 | 286 | } |
243 | 287 |
|
244 | 288 | TableMetadataBuilder& TableMetadataBuilder::AssignUUID(std::string_view uuid) { |
245 | | - throw IcebergError(std::format("{} not implemented", __FUNCTION__)); |
246 | | - ; |
| 289 | + std::string uuid_str(uuid); |
| 290 | + |
| 291 | + // Validation: UUID cannot be empty |
| 292 | + if (uuid_str.empty()) { |
| 293 | + impl_->errors.emplace_back(ErrorKind::kInvalidArgument, "Cannot assign empty UUID"); |
| 294 | + return *this; |
| 295 | + } |
| 296 | + |
| 297 | + // Check if UUID is already set to the same value (no-op) |
| 298 | + if (StringUtils::EqualsIgnoreCase(impl_->metadata.table_uuid, uuid_str)) { |
| 299 | + return *this; |
| 300 | + } |
| 301 | + |
| 302 | + // Update the metadata |
| 303 | + impl_->metadata.table_uuid = uuid_str; |
| 304 | + |
| 305 | + // Record the change |
| 306 | + impl_->changes.push_back(std::make_unique<table::AssignUUID>(std::move(uuid_str))); |
| 307 | + |
| 308 | + return *this; |
247 | 309 | } |
248 | 310 |
|
249 | 311 | TableMetadataBuilder& TableMetadataBuilder::UpgradeFormatVersion( |
@@ -377,12 +439,29 @@ TableMetadataBuilder& TableMetadataBuilder::RemoveEncryptionKey(std::string_view |
377 | 439 | throw IcebergError(std::format("{} not implemented", __FUNCTION__)); |
378 | 440 | } |
379 | 441 |
|
380 | | -TableMetadataBuilder& TableMetadataBuilder::DiscardChanges() { |
381 | | - throw IcebergError(std::format("{} not implemented", __FUNCTION__)); |
382 | | -} |
383 | | - |
384 | 442 | Result<std::unique_ptr<TableMetadata>> TableMetadataBuilder::Build() { |
385 | | - return NotImplemented("TableMetadataBuilder::Build not implemented"); |
| 443 | + // 1. Check for accumulated errors |
| 444 | + if (!impl_->errors.empty()) { |
| 445 | + std::string error_msg = "Failed to build TableMetadata due to validation errors:\n"; |
| 446 | + for (const auto& [kind, message] : impl_->errors) { |
| 447 | + error_msg += " - " + message + "\n"; |
| 448 | + } |
| 449 | + return CommitFailed("{}", error_msg); |
| 450 | + } |
| 451 | + |
| 452 | + // 2. Validate metadata consistency through TableMetadata#Validate |
| 453 | + |
| 454 | + // 3. Update last_updated_ms if there are changes |
| 455 | + if (impl_->metadata.last_updated_ms == kInvalidLastUpdatedMs) { |
| 456 | + impl_->metadata.last_updated_ms = |
| 457 | + TimePointMs{std::chrono::duration_cast<std::chrono::milliseconds>( |
| 458 | + std::chrono::system_clock::now().time_since_epoch())}; |
| 459 | + } |
| 460 | + |
| 461 | + // 4. Create and return the TableMetadata |
| 462 | + auto result = std::make_unique<TableMetadata>(std::move(impl_->metadata)); |
| 463 | + |
| 464 | + return result; |
386 | 465 | } |
387 | 466 |
|
388 | 467 | } // namespace iceberg |
0 commit comments