wangyong9999 commented on code in PR #315:
URL: https://github.com/apache/paimon-cpp/pull/315#discussion_r3975004298


##########
src/paimon/core/schema/schema_validation.cpp:
##########
@@ -802,6 +804,73 @@ Status SchemaValidation::ValidateMosaicDataFields(const 
TableSchema& schema,
     return Status::OK();
 }
 
+Status SchemaValidation::ValidateLanceDataField(const 
std::shared_ptr<arrow::Field>& field) {
+    if (VariantTypeUtils::IsVariantField(field)) {
+        return Status::Invalid("Lance file format does not support type 
VARIANT");
+    }
+    if (BlobUtils::IsBlobField(field)) {
+        return Status::Invalid("Lance file format does not support type BLOB");
+    }
+
+    const std::shared_ptr<arrow::DataType>& type = field->type();
+    switch (type->id()) {
+        case arrow::Type::BOOL:
+        case arrow::Type::INT8:
+        case arrow::Type::INT16:
+        case arrow::Type::INT32:
+        case arrow::Type::INT64:
+        case arrow::Type::FLOAT:
+        case arrow::Type::DOUBLE:
+        case arrow::Type::DATE32:
+        case arrow::Type::STRING:
+        case arrow::Type::BINARY:
+        case arrow::Type::TIME32:
+        case arrow::Type::DECIMAL128:
+        case arrow::Type::FIXED_SIZE_LIST:
+            return Status::OK();
+        case arrow::Type::TIMESTAMP: {
+            const auto& timestamp_type = checked_cast<const 
arrow::TimestampType&>(*type);
+            if (!timestamp_type.timezone().empty()) {
+                return Status::Invalid(
+                    "Lance file format does not support type 
LOCAL_ZONED_TIMESTAMP");
+            }
+            return Status::OK();
+        }
+        case arrow::Type::LIST:
+            return ValidateLanceDataField(type->field(0));
+        case arrow::Type::STRUCT:
+            for (const std::shared_ptr<arrow::Field>& child : type->fields()) {
+                PAIMON_RETURN_NOT_OK(ValidateLanceDataField(child));
+            }
+            return Status::OK();

Review Comment:
   Nullable structs cannot be accepted here. This PR already skips 
`TestWriteWithNestedSchema` because Lance 0.39 v2.0 drops the parent validity 
bitmap, so a null struct round-trips as a non-null struct with null children 
and silently changes the data. Reject nullable `STRUCT` fields recursively, or 
use an encoding that preserves parent validity.



##########
src/paimon/core/schema/schema_validation.cpp:
##########
@@ -802,6 +804,73 @@ Status SchemaValidation::ValidateMosaicDataFields(const 
TableSchema& schema,
     return Status::OK();
 }
 
+Status SchemaValidation::ValidateLanceDataField(const 
std::shared_ptr<arrow::Field>& field) {
+    if (VariantTypeUtils::IsVariantField(field)) {
+        return Status::Invalid("Lance file format does not support type 
VARIANT");
+    }
+    if (BlobUtils::IsBlobField(field)) {
+        return Status::Invalid("Lance file format does not support type BLOB");
+    }
+
+    const std::shared_ptr<arrow::DataType>& type = field->type();
+    switch (type->id()) {
+        case arrow::Type::BOOL:
+        case arrow::Type::INT8:
+        case arrow::Type::INT16:
+        case arrow::Type::INT32:
+        case arrow::Type::INT64:
+        case arrow::Type::FLOAT:
+        case arrow::Type::DOUBLE:
+        case arrow::Type::DATE32:
+        case arrow::Type::STRING:
+        case arrow::Type::BINARY:
+        case arrow::Type::TIME32:
+        case arrow::Type::DECIMAL128:
+        case arrow::Type::FIXED_SIZE_LIST:
+            return Status::OK();
+        case arrow::Type::TIMESTAMP: {
+            const auto& timestamp_type = checked_cast<const 
arrow::TimestampType&>(*type);
+            if (!timestamp_type.timezone().empty()) {
+                return Status::Invalid(
+                    "Lance file format does not support type 
LOCAL_ZONED_TIMESTAMP");
+            }
+            return Status::OK();
+        }
+        case arrow::Type::LIST:
+            return ValidateLanceDataField(type->field(0));
+        case arrow::Type::STRUCT:
+            for (const std::shared_ptr<arrow::Field>& child : type->fields()) {
+                PAIMON_RETURN_NOT_OK(ValidateLanceDataField(child));
+            }
+            return Status::OK();
+        case arrow::Type::MAP:
+            return Status::Invalid("Lance file format does not support type 
MAP");
+        default:
+            break;
+    }
+    return Status::Invalid(
+        fmt::format("Lance file format does not support type {}", 
type->ToString()));
+}
+
+Status SchemaValidation::ValidateLanceDataFields(const TableSchema& schema,
+                                                 const CoreOptions& options) {
+    if (StringUtils::ToLowerCase(options.GetFileFormat()->Identifier()) != 
"lance") {

Review Comment:
   This only validates the default `file.format`. A table using 
`file.format.per.level=...:lance` or `changelog-file.format=lance` can 
therefore pass validation with unsupported types such as MAP, then fail later 
during compaction or changelog writing. Apply the Lance type checks to every 
configured write format.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to