@@ -155,6 +155,42 @@ Status PartitionSpec::Validate(const Schema& schema, bool allow_missing_fields)
155155 return {};
156156}
157157
158+ Status PartitionSpec::ValidatePartitionName (const Schema& schema) const {
159+ std::unordered_set<std::string> partition_names;
160+ for (const auto & partition_field : fields_) {
161+ auto name = std::string (partition_field.name ());
162+ if (name.empty ()) {
163+ return InvalidArgument (" Cannot use empty partition name: {}" , name);
164+ }
165+ if (partition_names.contains (name)) {
166+ return InvalidArgument (" Cannot use partition name more than once: {}" , name);
167+ }
168+ partition_names.insert (name);
169+
170+ ICEBERG_ASSIGN_OR_RAISE (auto schema_field, schema.FindFieldByName (name));
171+ auto transform_type = partition_field.transform ()->transform_type ();
172+ if (transform_type == TransformType::kIdentity ) {
173+ // for identity transform case we allow conflicts between partition and schema field
174+ // name as long as they are sourced from the same schema field
175+ if (schema_field.has_value () &&
176+ schema_field.value ().get ().field_id () != partition_field.source_id ()) {
177+ return InvalidArgument (
178+ " Cannot create identity partition sourced from different field in schema: {}" ,
179+ name);
180+ }
181+ } else {
182+ // for all other transforms we don't allow conflicts between partition name and
183+ // schema field name
184+ if (schema_field.has_value ()) {
185+ return InvalidArgument (
186+ " Cannot create partition from name that exists in schema: {}" , name);
187+ }
188+ }
189+ }
190+
191+ return {};
192+ }
193+
158194Result<std::vector<std::reference_wrapper<const PartitionField>>>
159195PartitionSpec::GetFieldsBySourceId (int32_t source_id) const {
160196 ICEBERG_ASSIGN_OR_RAISE (auto source_id_to_fields, source_id_to_fields_.Get (*this ));
0 commit comments