This is an automated email from the ASF dual-hosted git repository.
wgtmac pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 99084bbc55 GH-50265: [C++][Parquet] Update parquet.thrift to sync with
2.13.0 (#50266)
99084bbc55 is described below
commit 99084bbc55b8300cdc2336278ff3479093053ff8
Author: Zehua Zou <[email protected]>
AuthorDate: Mon Jun 29 11:10:39 2026 +0800
GH-50265: [C++][Parquet] Update parquet.thrift to sync with 2.13.0 (#50266)
### Rationale for this change
Apache Parquet has just released its format version 2.13.0. We need to
update parquet.thirft and its generated source files to be in sync.
### What changes are included in this PR?
Update parquet.thirft and its generated source files.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
No.
* GitHub Issue: #50265
Authored-by: Zehua Zou <[email protected]>
Signed-off-by: Gang Wu <[email protected]>
---
cpp/src/generated/parquet_types.cpp | 510 +++++++++++++++++++++---------------
cpp/src/generated/parquet_types.h | 195 ++++++++++++--
cpp/src/generated/parquet_types.tcc | 345 +++++++++++++++---------
cpp/src/parquet/parquet.thrift | 217 +++++++++++----
4 files changed, 860 insertions(+), 407 deletions(-)
diff --git a/cpp/src/generated/parquet_types.cpp
b/cpp/src/generated/parquet_types.cpp
index 0ee973f2a2..cbec2ccd65 100644
--- a/cpp/src/generated/parquet_types.cpp
+++ b/cpp/src/generated/parquet_types.cpp
@@ -420,10 +420,10 @@ int _kEncodingValues[] = {
*/
Encoding::PLAIN,
/**
- * Deprecated: Dictionary encoding. The values in the dictionary are encoded
in the
+ * DEPRECATED: Dictionary encoding. The values in the dictionary are encoded
in the
* plain type.
- * in a data page use RLE_DICTIONARY instead.
- * in a Dictionary page use PLAIN instead
+ * For a data page use RLE_DICTIONARY instead.
+ * For a Dictionary page use PLAIN instead.
*/
Encoding::PLAIN_DICTIONARY,
/**
@@ -432,8 +432,9 @@ int _kEncodingValues[] = {
*/
Encoding::RLE,
/**
- * Bit packed encoding. This can only be used if the data has a known max
+ * DEPRECATED: Bit packed encoding. This can only be used if the data has a
known max
* width. Usable for definition/repetition levels encoding.
+ * Superseded by RLE (which is a hybrid of RLE and bit packing); see
Encodings.md.
*/
Encoding::BIT_PACKED,
/**
@@ -481,10 +482,10 @@ const char* _kEncodingNames[] = {
*/
"PLAIN",
/**
- * Deprecated: Dictionary encoding. The values in the dictionary are encoded
in the
+ * DEPRECATED: Dictionary encoding. The values in the dictionary are encoded
in the
* plain type.
- * in a data page use RLE_DICTIONARY instead.
- * in a Dictionary page use PLAIN instead
+ * For a data page use RLE_DICTIONARY instead.
+ * For a Dictionary page use PLAIN instead.
*/
"PLAIN_DICTIONARY",
/**
@@ -493,8 +494,9 @@ const char* _kEncodingNames[] = {
*/
"RLE",
/**
- * Bit packed encoding. This can only be used if the data has a known max
+ * DEPRECATED: Bit packed encoding. This can only be used if the data has a
known max
* width. Usable for definition/repetition levels encoding.
+ * Superseded by RLE (which is a hybrid of RLE and bit packing); see
Encodings.md.
*/
"BIT_PACKED",
/**
@@ -988,7 +990,8 @@ Statistics::Statistics() noexcept
max_value(),
min_value(),
is_max_value_exact(0),
- is_min_value_exact(0) {
+ is_min_value_exact(0),
+ nan_count(0) {
}
void Statistics::__set_max(const std::string& val) {
@@ -1030,6 +1033,11 @@ void Statistics::__set_is_min_value_exact(const bool
val) {
this->is_min_value_exact = val;
__isset.is_min_value_exact = true;
}
+
+void Statistics::__set_nan_count(const int64_t val) {
+ this->nan_count = val;
+__isset.nan_count = true;
+}
std::ostream& operator<<(std::ostream& out, const Statistics& obj)
{
obj.printTo(out);
@@ -1047,6 +1055,7 @@ void swap(Statistics &a, Statistics &b) {
swap(a.min_value, b.min_value);
swap(a.is_max_value_exact, b.is_max_value_exact);
swap(a.is_min_value_exact, b.is_min_value_exact);
+ swap(a.nan_count, b.nan_count);
swap(a.__isset, b.__isset);
}
@@ -1084,6 +1093,10 @@ bool Statistics::operator==(const Statistics & rhs) const
return false;
else if (__isset.is_min_value_exact && !(is_min_value_exact ==
rhs.is_min_value_exact))
return false;
+ if (__isset.nan_count != rhs.__isset.nan_count)
+ return false;
+ else if (__isset.nan_count && !(nan_count == rhs.nan_count))
+ return false;
return true;
}
@@ -1096,6 +1109,7 @@ Statistics::Statistics(const Statistics& other30) {
min_value = other30.min_value;
is_max_value_exact = other30.is_max_value_exact;
is_min_value_exact = other30.is_min_value_exact;
+ nan_count = other30.nan_count;
__isset = other30.__isset;
}
Statistics::Statistics(Statistics&& other31) noexcept {
@@ -1107,6 +1121,7 @@ Statistics::Statistics(Statistics&& other31) noexcept {
min_value = std::move(other31.min_value);
is_max_value_exact = other31.is_max_value_exact;
is_min_value_exact = other31.is_min_value_exact;
+ nan_count = other31.nan_count;
__isset = other31.__isset;
}
Statistics& Statistics::operator=(const Statistics& other32) {
@@ -1118,6 +1133,7 @@ Statistics& Statistics::operator=(const Statistics&
other32) {
min_value = other32.min_value;
is_max_value_exact = other32.is_max_value_exact;
is_min_value_exact = other32.is_min_value_exact;
+ nan_count = other32.nan_count;
__isset = other32.__isset;
return *this;
}
@@ -1130,6 +1146,7 @@ Statistics& Statistics::operator=(Statistics&& other33)
noexcept {
min_value = std::move(other33.min_value);
is_max_value_exact = other33.is_max_value_exact;
is_min_value_exact = other33.is_min_value_exact;
+ nan_count = other33.nan_count;
__isset = other33.__isset;
return *this;
}
@@ -1144,6 +1161,7 @@ void Statistics::printTo(std::ostream& out) const {
out << ", " << "min_value="; (__isset.min_value ? (out <<
to_string(min_value)) : (out << "<null>"));
out << ", " << "is_max_value_exact="; (__isset.is_max_value_exact ? (out <<
to_string(is_max_value_exact)) : (out << "<null>"));
out << ", " << "is_min_value_exact="; (__isset.is_min_value_exact ? (out <<
to_string(is_min_value_exact)) : (out << "<null>"));
+ out << ", " << "nan_count="; (__isset.nan_count ? (out <<
to_string(nan_count)) : (out << "<null>"));
out << ")";
}
@@ -4762,6 +4780,50 @@ void TypeDefinedOrder::printTo(std::ostream& out) const {
}
+IEEE754TotalOrder::~IEEE754TotalOrder() noexcept {
+}
+
+IEEE754TotalOrder::IEEE754TotalOrder() noexcept {
+}
+std::ostream& operator<<(std::ostream& out, const IEEE754TotalOrder& obj)
+{
+ obj.printTo(out);
+ return out;
+}
+
+
+void swap(IEEE754TotalOrder &a, IEEE754TotalOrder &b) {
+ using ::std::swap;
+ (void) a;
+ (void) b;
+}
+
+bool IEEE754TotalOrder::operator==(const IEEE754TotalOrder & /* rhs */) const
+{
+ return true;
+}
+
+IEEE754TotalOrder::IEEE754TotalOrder(const IEEE754TotalOrder& other271)
noexcept {
+ (void) other271;
+}
+IEEE754TotalOrder::IEEE754TotalOrder(IEEE754TotalOrder&& other272) noexcept {
+ (void) other272;
+}
+IEEE754TotalOrder& IEEE754TotalOrder::operator=(const IEEE754TotalOrder&
other273) noexcept {
+ (void) other273;
+ return *this;
+}
+IEEE754TotalOrder& IEEE754TotalOrder::operator=(IEEE754TotalOrder&& other274)
noexcept {
+ (void) other274;
+ return *this;
+}
+void IEEE754TotalOrder::printTo(std::ostream& out) const {
+ using ::apache::thrift::to_string;
+ out << "IEEE754TotalOrder(";
+ out << ")";
+}
+
+
ColumnOrder::~ColumnOrder() noexcept {
}
@@ -4772,6 +4834,11 @@ void ColumnOrder::__set_TYPE_ORDER(const
TypeDefinedOrder& val) {
this->TYPE_ORDER = val;
__isset.TYPE_ORDER = true;
}
+
+void ColumnOrder::__set_IEEE_754_TOTAL_ORDER(const IEEE754TotalOrder& val) {
+ this->IEEE_754_TOTAL_ORDER = val;
+__isset.IEEE_754_TOTAL_ORDER = true;
+}
std::ostream& operator<<(std::ostream& out, const ColumnOrder& obj)
{
obj.printTo(out);
@@ -4782,6 +4849,7 @@ std::ostream& operator<<(std::ostream& out, const
ColumnOrder& obj)
void swap(ColumnOrder &a, ColumnOrder &b) {
using ::std::swap;
swap(a.TYPE_ORDER, b.TYPE_ORDER);
+ swap(a.IEEE_754_TOTAL_ORDER, b.IEEE_754_TOTAL_ORDER);
swap(a.__isset, b.__isset);
}
@@ -4791,31 +4859,40 @@ bool ColumnOrder::operator==(const ColumnOrder & rhs)
const
return false;
else if (__isset.TYPE_ORDER && !(TYPE_ORDER == rhs.TYPE_ORDER))
return false;
+ if (__isset.IEEE_754_TOTAL_ORDER != rhs.__isset.IEEE_754_TOTAL_ORDER)
+ return false;
+ else if (__isset.IEEE_754_TOTAL_ORDER && !(IEEE_754_TOTAL_ORDER ==
rhs.IEEE_754_TOTAL_ORDER))
+ return false;
return true;
}
-ColumnOrder::ColumnOrder(const ColumnOrder& other271) noexcept {
- TYPE_ORDER = other271.TYPE_ORDER;
- __isset = other271.__isset;
+ColumnOrder::ColumnOrder(const ColumnOrder& other275) noexcept {
+ TYPE_ORDER = other275.TYPE_ORDER;
+ IEEE_754_TOTAL_ORDER = other275.IEEE_754_TOTAL_ORDER;
+ __isset = other275.__isset;
}
-ColumnOrder::ColumnOrder(ColumnOrder&& other272) noexcept {
- TYPE_ORDER = std::move(other272.TYPE_ORDER);
- __isset = other272.__isset;
+ColumnOrder::ColumnOrder(ColumnOrder&& other276) noexcept {
+ TYPE_ORDER = std::move(other276.TYPE_ORDER);
+ IEEE_754_TOTAL_ORDER = std::move(other276.IEEE_754_TOTAL_ORDER);
+ __isset = other276.__isset;
}
-ColumnOrder& ColumnOrder::operator=(const ColumnOrder& other273) noexcept {
- TYPE_ORDER = other273.TYPE_ORDER;
- __isset = other273.__isset;
+ColumnOrder& ColumnOrder::operator=(const ColumnOrder& other277) noexcept {
+ TYPE_ORDER = other277.TYPE_ORDER;
+ IEEE_754_TOTAL_ORDER = other277.IEEE_754_TOTAL_ORDER;
+ __isset = other277.__isset;
return *this;
}
-ColumnOrder& ColumnOrder::operator=(ColumnOrder&& other274) noexcept {
- TYPE_ORDER = std::move(other274.TYPE_ORDER);
- __isset = other274.__isset;
+ColumnOrder& ColumnOrder::operator=(ColumnOrder&& other278) noexcept {
+ TYPE_ORDER = std::move(other278.TYPE_ORDER);
+ IEEE_754_TOTAL_ORDER = std::move(other278.IEEE_754_TOTAL_ORDER);
+ __isset = other278.__isset;
return *this;
}
void ColumnOrder::printTo(std::ostream& out) const {
using ::apache::thrift::to_string;
out << "ColumnOrder(";
out << "TYPE_ORDER="; (__isset.TYPE_ORDER ? (out << to_string(TYPE_ORDER)) :
(out << "<null>"));
+ out << ", " << "IEEE_754_TOTAL_ORDER="; (__isset.IEEE_754_TOTAL_ORDER ? (out
<< to_string(IEEE_754_TOTAL_ORDER)) : (out << "<null>"));
out << ")";
}
@@ -4865,26 +4942,26 @@ bool PageLocation::operator==(const PageLocation & rhs)
const
return true;
}
-PageLocation::PageLocation(const PageLocation& other275) noexcept {
- offset = other275.offset;
- compressed_page_size = other275.compressed_page_size;
- first_row_index = other275.first_row_index;
+PageLocation::PageLocation(const PageLocation& other279) noexcept {
+ offset = other279.offset;
+ compressed_page_size = other279.compressed_page_size;
+ first_row_index = other279.first_row_index;
}
-PageLocation::PageLocation(PageLocation&& other276) noexcept {
- offset = other276.offset;
- compressed_page_size = other276.compressed_page_size;
- first_row_index = other276.first_row_index;
+PageLocation::PageLocation(PageLocation&& other280) noexcept {
+ offset = other280.offset;
+ compressed_page_size = other280.compressed_page_size;
+ first_row_index = other280.first_row_index;
}
-PageLocation& PageLocation::operator=(const PageLocation& other277) noexcept {
- offset = other277.offset;
- compressed_page_size = other277.compressed_page_size;
- first_row_index = other277.first_row_index;
+PageLocation& PageLocation::operator=(const PageLocation& other281) noexcept {
+ offset = other281.offset;
+ compressed_page_size = other281.compressed_page_size;
+ first_row_index = other281.first_row_index;
return *this;
}
-PageLocation& PageLocation::operator=(PageLocation&& other278) noexcept {
- offset = other278.offset;
- compressed_page_size = other278.compressed_page_size;
- first_row_index = other278.first_row_index;
+PageLocation& PageLocation::operator=(PageLocation&& other282) noexcept {
+ offset = other282.offset;
+ compressed_page_size = other282.compressed_page_size;
+ first_row_index = other282.first_row_index;
return *this;
}
void PageLocation::printTo(std::ostream& out) const {
@@ -4936,26 +5013,26 @@ bool OffsetIndex::operator==(const OffsetIndex & rhs)
const
return true;
}
-OffsetIndex::OffsetIndex(const OffsetIndex& other291) {
- page_locations = other291.page_locations;
- unencoded_byte_array_data_bytes = other291.unencoded_byte_array_data_bytes;
- __isset = other291.__isset;
+OffsetIndex::OffsetIndex(const OffsetIndex& other295) {
+ page_locations = other295.page_locations;
+ unencoded_byte_array_data_bytes = other295.unencoded_byte_array_data_bytes;
+ __isset = other295.__isset;
}
-OffsetIndex::OffsetIndex(OffsetIndex&& other292) noexcept {
- page_locations = std::move(other292.page_locations);
- unencoded_byte_array_data_bytes =
std::move(other292.unencoded_byte_array_data_bytes);
- __isset = other292.__isset;
+OffsetIndex::OffsetIndex(OffsetIndex&& other296) noexcept {
+ page_locations = std::move(other296.page_locations);
+ unencoded_byte_array_data_bytes =
std::move(other296.unencoded_byte_array_data_bytes);
+ __isset = other296.__isset;
}
-OffsetIndex& OffsetIndex::operator=(const OffsetIndex& other293) {
- page_locations = other293.page_locations;
- unencoded_byte_array_data_bytes = other293.unencoded_byte_array_data_bytes;
- __isset = other293.__isset;
+OffsetIndex& OffsetIndex::operator=(const OffsetIndex& other297) {
+ page_locations = other297.page_locations;
+ unencoded_byte_array_data_bytes = other297.unencoded_byte_array_data_bytes;
+ __isset = other297.__isset;
return *this;
}
-OffsetIndex& OffsetIndex::operator=(OffsetIndex&& other294) noexcept {
- page_locations = std::move(other294.page_locations);
- unencoded_byte_array_data_bytes =
std::move(other294.unencoded_byte_array_data_bytes);
- __isset = other294.__isset;
+OffsetIndex& OffsetIndex::operator=(OffsetIndex&& other298) noexcept {
+ page_locations = std::move(other298.page_locations);
+ unencoded_byte_array_data_bytes =
std::move(other298.unencoded_byte_array_data_bytes);
+ __isset = other298.__isset;
return *this;
}
void OffsetIndex::printTo(std::ostream& out) const {
@@ -5004,6 +5081,11 @@ void
ColumnIndex::__set_definition_level_histograms(const std::vector<int64_t> &
this->definition_level_histograms = val;
__isset.definition_level_histograms = true;
}
+
+void ColumnIndex::__set_nan_counts(const std::vector<int64_t> & val) {
+ this->nan_counts = val;
+__isset.nan_counts = true;
+}
std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj)
{
obj.printTo(out);
@@ -5020,6 +5102,7 @@ void swap(ColumnIndex &a, ColumnIndex &b) {
swap(a.null_counts, b.null_counts);
swap(a.repetition_level_histograms, b.repetition_level_histograms);
swap(a.definition_level_histograms, b.definition_level_histograms);
+ swap(a.nan_counts, b.nan_counts);
swap(a.__isset, b.__isset);
}
@@ -5045,49 +5128,57 @@ bool ColumnIndex::operator==(const ColumnIndex & rhs)
const
return false;
else if (__isset.definition_level_histograms &&
!(definition_level_histograms == rhs.definition_level_histograms))
return false;
+ if (__isset.nan_counts != rhs.__isset.nan_counts)
+ return false;
+ else if (__isset.nan_counts && !(nan_counts == rhs.nan_counts))
+ return false;
return true;
}
-ColumnIndex::ColumnIndex(const ColumnIndex& other332) {
- null_pages = other332.null_pages;
- min_values = other332.min_values;
- max_values = other332.max_values;
- boundary_order = other332.boundary_order;
- null_counts = other332.null_counts;
- repetition_level_histograms = other332.repetition_level_histograms;
- definition_level_histograms = other332.definition_level_histograms;
- __isset = other332.__isset;
-}
-ColumnIndex::ColumnIndex(ColumnIndex&& other333) noexcept {
- null_pages = std::move(other333.null_pages);
- min_values = std::move(other333.min_values);
- max_values = std::move(other333.max_values);
- boundary_order = other333.boundary_order;
- null_counts = std::move(other333.null_counts);
- repetition_level_histograms =
std::move(other333.repetition_level_histograms);
- definition_level_histograms =
std::move(other333.definition_level_histograms);
- __isset = other333.__isset;
-}
-ColumnIndex& ColumnIndex::operator=(const ColumnIndex& other334) {
- null_pages = other334.null_pages;
- min_values = other334.min_values;
- max_values = other334.max_values;
- boundary_order = other334.boundary_order;
- null_counts = other334.null_counts;
- repetition_level_histograms = other334.repetition_level_histograms;
- definition_level_histograms = other334.definition_level_histograms;
- __isset = other334.__isset;
+ColumnIndex::ColumnIndex(const ColumnIndex& other342) {
+ null_pages = other342.null_pages;
+ min_values = other342.min_values;
+ max_values = other342.max_values;
+ boundary_order = other342.boundary_order;
+ null_counts = other342.null_counts;
+ repetition_level_histograms = other342.repetition_level_histograms;
+ definition_level_histograms = other342.definition_level_histograms;
+ nan_counts = other342.nan_counts;
+ __isset = other342.__isset;
+}
+ColumnIndex::ColumnIndex(ColumnIndex&& other343) noexcept {
+ null_pages = std::move(other343.null_pages);
+ min_values = std::move(other343.min_values);
+ max_values = std::move(other343.max_values);
+ boundary_order = other343.boundary_order;
+ null_counts = std::move(other343.null_counts);
+ repetition_level_histograms =
std::move(other343.repetition_level_histograms);
+ definition_level_histograms =
std::move(other343.definition_level_histograms);
+ nan_counts = std::move(other343.nan_counts);
+ __isset = other343.__isset;
+}
+ColumnIndex& ColumnIndex::operator=(const ColumnIndex& other344) {
+ null_pages = other344.null_pages;
+ min_values = other344.min_values;
+ max_values = other344.max_values;
+ boundary_order = other344.boundary_order;
+ null_counts = other344.null_counts;
+ repetition_level_histograms = other344.repetition_level_histograms;
+ definition_level_histograms = other344.definition_level_histograms;
+ nan_counts = other344.nan_counts;
+ __isset = other344.__isset;
return *this;
}
-ColumnIndex& ColumnIndex::operator=(ColumnIndex&& other335) noexcept {
- null_pages = std::move(other335.null_pages);
- min_values = std::move(other335.min_values);
- max_values = std::move(other335.max_values);
- boundary_order = other335.boundary_order;
- null_counts = std::move(other335.null_counts);
- repetition_level_histograms =
std::move(other335.repetition_level_histograms);
- definition_level_histograms =
std::move(other335.definition_level_histograms);
- __isset = other335.__isset;
+ColumnIndex& ColumnIndex::operator=(ColumnIndex&& other345) noexcept {
+ null_pages = std::move(other345.null_pages);
+ min_values = std::move(other345.min_values);
+ max_values = std::move(other345.max_values);
+ boundary_order = other345.boundary_order;
+ null_counts = std::move(other345.null_counts);
+ repetition_level_histograms =
std::move(other345.repetition_level_histograms);
+ definition_level_histograms =
std::move(other345.definition_level_histograms);
+ nan_counts = std::move(other345.nan_counts);
+ __isset = other345.__isset;
return *this;
}
void ColumnIndex::printTo(std::ostream& out) const {
@@ -5100,6 +5191,7 @@ void ColumnIndex::printTo(std::ostream& out) const {
out << ", " << "null_counts="; (__isset.null_counts ? (out <<
to_string(null_counts)) : (out << "<null>"));
out << ", " << "repetition_level_histograms=";
(__isset.repetition_level_histograms ? (out <<
to_string(repetition_level_histograms)) : (out << "<null>"));
out << ", " << "definition_level_histograms=";
(__isset.definition_level_histograms ? (out <<
to_string(definition_level_histograms)) : (out << "<null>"));
+ out << ", " << "nan_counts="; (__isset.nan_counts ? (out <<
to_string(nan_counts)) : (out << "<null>"));
out << ")";
}
@@ -5159,30 +5251,30 @@ bool AesGcmV1::operator==(const AesGcmV1 & rhs) const
return true;
}
-AesGcmV1::AesGcmV1(const AesGcmV1& other336) {
- aad_prefix = other336.aad_prefix;
- aad_file_unique = other336.aad_file_unique;
- supply_aad_prefix = other336.supply_aad_prefix;
- __isset = other336.__isset;
+AesGcmV1::AesGcmV1(const AesGcmV1& other346) {
+ aad_prefix = other346.aad_prefix;
+ aad_file_unique = other346.aad_file_unique;
+ supply_aad_prefix = other346.supply_aad_prefix;
+ __isset = other346.__isset;
}
-AesGcmV1::AesGcmV1(AesGcmV1&& other337) noexcept {
- aad_prefix = std::move(other337.aad_prefix);
- aad_file_unique = std::move(other337.aad_file_unique);
- supply_aad_prefix = other337.supply_aad_prefix;
- __isset = other337.__isset;
+AesGcmV1::AesGcmV1(AesGcmV1&& other347) noexcept {
+ aad_prefix = std::move(other347.aad_prefix);
+ aad_file_unique = std::move(other347.aad_file_unique);
+ supply_aad_prefix = other347.supply_aad_prefix;
+ __isset = other347.__isset;
}
-AesGcmV1& AesGcmV1::operator=(const AesGcmV1& other338) {
- aad_prefix = other338.aad_prefix;
- aad_file_unique = other338.aad_file_unique;
- supply_aad_prefix = other338.supply_aad_prefix;
- __isset = other338.__isset;
+AesGcmV1& AesGcmV1::operator=(const AesGcmV1& other348) {
+ aad_prefix = other348.aad_prefix;
+ aad_file_unique = other348.aad_file_unique;
+ supply_aad_prefix = other348.supply_aad_prefix;
+ __isset = other348.__isset;
return *this;
}
-AesGcmV1& AesGcmV1::operator=(AesGcmV1&& other339) noexcept {
- aad_prefix = std::move(other339.aad_prefix);
- aad_file_unique = std::move(other339.aad_file_unique);
- supply_aad_prefix = other339.supply_aad_prefix;
- __isset = other339.__isset;
+AesGcmV1& AesGcmV1::operator=(AesGcmV1&& other349) noexcept {
+ aad_prefix = std::move(other349.aad_prefix);
+ aad_file_unique = std::move(other349.aad_file_unique);
+ supply_aad_prefix = other349.supply_aad_prefix;
+ __isset = other349.__isset;
return *this;
}
void AesGcmV1::printTo(std::ostream& out) const {
@@ -5250,30 +5342,30 @@ bool AesGcmCtrV1::operator==(const AesGcmCtrV1 & rhs)
const
return true;
}
-AesGcmCtrV1::AesGcmCtrV1(const AesGcmCtrV1& other340) {
- aad_prefix = other340.aad_prefix;
- aad_file_unique = other340.aad_file_unique;
- supply_aad_prefix = other340.supply_aad_prefix;
- __isset = other340.__isset;
+AesGcmCtrV1::AesGcmCtrV1(const AesGcmCtrV1& other350) {
+ aad_prefix = other350.aad_prefix;
+ aad_file_unique = other350.aad_file_unique;
+ supply_aad_prefix = other350.supply_aad_prefix;
+ __isset = other350.__isset;
}
-AesGcmCtrV1::AesGcmCtrV1(AesGcmCtrV1&& other341) noexcept {
- aad_prefix = std::move(other341.aad_prefix);
- aad_file_unique = std::move(other341.aad_file_unique);
- supply_aad_prefix = other341.supply_aad_prefix;
- __isset = other341.__isset;
+AesGcmCtrV1::AesGcmCtrV1(AesGcmCtrV1&& other351) noexcept {
+ aad_prefix = std::move(other351.aad_prefix);
+ aad_file_unique = std::move(other351.aad_file_unique);
+ supply_aad_prefix = other351.supply_aad_prefix;
+ __isset = other351.__isset;
}
-AesGcmCtrV1& AesGcmCtrV1::operator=(const AesGcmCtrV1& other342) {
- aad_prefix = other342.aad_prefix;
- aad_file_unique = other342.aad_file_unique;
- supply_aad_prefix = other342.supply_aad_prefix;
- __isset = other342.__isset;
+AesGcmCtrV1& AesGcmCtrV1::operator=(const AesGcmCtrV1& other352) {
+ aad_prefix = other352.aad_prefix;
+ aad_file_unique = other352.aad_file_unique;
+ supply_aad_prefix = other352.supply_aad_prefix;
+ __isset = other352.__isset;
return *this;
}
-AesGcmCtrV1& AesGcmCtrV1::operator=(AesGcmCtrV1&& other343) noexcept {
- aad_prefix = std::move(other343.aad_prefix);
- aad_file_unique = std::move(other343.aad_file_unique);
- supply_aad_prefix = other343.supply_aad_prefix;
- __isset = other343.__isset;
+AesGcmCtrV1& AesGcmCtrV1::operator=(AesGcmCtrV1&& other353) noexcept {
+ aad_prefix = std::move(other353.aad_prefix);
+ aad_file_unique = std::move(other353.aad_file_unique);
+ supply_aad_prefix = other353.supply_aad_prefix;
+ __isset = other353.__isset;
return *this;
}
void AesGcmCtrV1::printTo(std::ostream& out) const {
@@ -5328,26 +5420,26 @@ bool EncryptionAlgorithm::operator==(const
EncryptionAlgorithm & rhs) const
return true;
}
-EncryptionAlgorithm::EncryptionAlgorithm(const EncryptionAlgorithm& other344) {
- AES_GCM_V1 = other344.AES_GCM_V1;
- AES_GCM_CTR_V1 = other344.AES_GCM_CTR_V1;
- __isset = other344.__isset;
+EncryptionAlgorithm::EncryptionAlgorithm(const EncryptionAlgorithm& other354) {
+ AES_GCM_V1 = other354.AES_GCM_V1;
+ AES_GCM_CTR_V1 = other354.AES_GCM_CTR_V1;
+ __isset = other354.__isset;
}
-EncryptionAlgorithm::EncryptionAlgorithm(EncryptionAlgorithm&& other345)
noexcept {
- AES_GCM_V1 = std::move(other345.AES_GCM_V1);
- AES_GCM_CTR_V1 = std::move(other345.AES_GCM_CTR_V1);
- __isset = other345.__isset;
+EncryptionAlgorithm::EncryptionAlgorithm(EncryptionAlgorithm&& other355)
noexcept {
+ AES_GCM_V1 = std::move(other355.AES_GCM_V1);
+ AES_GCM_CTR_V1 = std::move(other355.AES_GCM_CTR_V1);
+ __isset = other355.__isset;
}
-EncryptionAlgorithm& EncryptionAlgorithm::operator=(const EncryptionAlgorithm&
other346) {
- AES_GCM_V1 = other346.AES_GCM_V1;
- AES_GCM_CTR_V1 = other346.AES_GCM_CTR_V1;
- __isset = other346.__isset;
+EncryptionAlgorithm& EncryptionAlgorithm::operator=(const EncryptionAlgorithm&
other356) {
+ AES_GCM_V1 = other356.AES_GCM_V1;
+ AES_GCM_CTR_V1 = other356.AES_GCM_CTR_V1;
+ __isset = other356.__isset;
return *this;
}
-EncryptionAlgorithm& EncryptionAlgorithm::operator=(EncryptionAlgorithm&&
other347) noexcept {
- AES_GCM_V1 = std::move(other347.AES_GCM_V1);
- AES_GCM_CTR_V1 = std::move(other347.AES_GCM_CTR_V1);
- __isset = other347.__isset;
+EncryptionAlgorithm& EncryptionAlgorithm::operator=(EncryptionAlgorithm&&
other357) noexcept {
+ AES_GCM_V1 = std::move(other357.AES_GCM_V1);
+ AES_GCM_CTR_V1 = std::move(other357.AES_GCM_CTR_V1);
+ __isset = other357.__isset;
return *this;
}
void EncryptionAlgorithm::printTo(std::ostream& out) const {
@@ -5463,54 +5555,54 @@ bool FileMetaData::operator==(const FileMetaData & rhs)
const
return true;
}
-FileMetaData::FileMetaData(const FileMetaData& other372) {
- version = other372.version;
- schema = other372.schema;
- num_rows = other372.num_rows;
- row_groups = other372.row_groups;
- key_value_metadata = other372.key_value_metadata;
- created_by = other372.created_by;
- column_orders = other372.column_orders;
- encryption_algorithm = other372.encryption_algorithm;
- footer_signing_key_metadata = other372.footer_signing_key_metadata;
- __isset = other372.__isset;
-}
-FileMetaData::FileMetaData(FileMetaData&& other373) noexcept {
- version = other373.version;
- schema = std::move(other373.schema);
- num_rows = other373.num_rows;
- row_groups = std::move(other373.row_groups);
- key_value_metadata = std::move(other373.key_value_metadata);
- created_by = std::move(other373.created_by);
- column_orders = std::move(other373.column_orders);
- encryption_algorithm = std::move(other373.encryption_algorithm);
- footer_signing_key_metadata =
std::move(other373.footer_signing_key_metadata);
- __isset = other373.__isset;
-}
-FileMetaData& FileMetaData::operator=(const FileMetaData& other374) {
- version = other374.version;
- schema = other374.schema;
- num_rows = other374.num_rows;
- row_groups = other374.row_groups;
- key_value_metadata = other374.key_value_metadata;
- created_by = other374.created_by;
- column_orders = other374.column_orders;
- encryption_algorithm = other374.encryption_algorithm;
- footer_signing_key_metadata = other374.footer_signing_key_metadata;
- __isset = other374.__isset;
+FileMetaData::FileMetaData(const FileMetaData& other382) {
+ version = other382.version;
+ schema = other382.schema;
+ num_rows = other382.num_rows;
+ row_groups = other382.row_groups;
+ key_value_metadata = other382.key_value_metadata;
+ created_by = other382.created_by;
+ column_orders = other382.column_orders;
+ encryption_algorithm = other382.encryption_algorithm;
+ footer_signing_key_metadata = other382.footer_signing_key_metadata;
+ __isset = other382.__isset;
+}
+FileMetaData::FileMetaData(FileMetaData&& other383) noexcept {
+ version = other383.version;
+ schema = std::move(other383.schema);
+ num_rows = other383.num_rows;
+ row_groups = std::move(other383.row_groups);
+ key_value_metadata = std::move(other383.key_value_metadata);
+ created_by = std::move(other383.created_by);
+ column_orders = std::move(other383.column_orders);
+ encryption_algorithm = std::move(other383.encryption_algorithm);
+ footer_signing_key_metadata =
std::move(other383.footer_signing_key_metadata);
+ __isset = other383.__isset;
+}
+FileMetaData& FileMetaData::operator=(const FileMetaData& other384) {
+ version = other384.version;
+ schema = other384.schema;
+ num_rows = other384.num_rows;
+ row_groups = other384.row_groups;
+ key_value_metadata = other384.key_value_metadata;
+ created_by = other384.created_by;
+ column_orders = other384.column_orders;
+ encryption_algorithm = other384.encryption_algorithm;
+ footer_signing_key_metadata = other384.footer_signing_key_metadata;
+ __isset = other384.__isset;
return *this;
}
-FileMetaData& FileMetaData::operator=(FileMetaData&& other375) noexcept {
- version = other375.version;
- schema = std::move(other375.schema);
- num_rows = other375.num_rows;
- row_groups = std::move(other375.row_groups);
- key_value_metadata = std::move(other375.key_value_metadata);
- created_by = std::move(other375.created_by);
- column_orders = std::move(other375.column_orders);
- encryption_algorithm = std::move(other375.encryption_algorithm);
- footer_signing_key_metadata =
std::move(other375.footer_signing_key_metadata);
- __isset = other375.__isset;
+FileMetaData& FileMetaData::operator=(FileMetaData&& other385) noexcept {
+ version = other385.version;
+ schema = std::move(other385.schema);
+ num_rows = other385.num_rows;
+ row_groups = std::move(other385.row_groups);
+ key_value_metadata = std::move(other385.key_value_metadata);
+ created_by = std::move(other385.created_by);
+ column_orders = std::move(other385.column_orders);
+ encryption_algorithm = std::move(other385.encryption_algorithm);
+ footer_signing_key_metadata =
std::move(other385.footer_signing_key_metadata);
+ __isset = other385.__isset;
return *this;
}
void FileMetaData::printTo(std::ostream& out) const {
@@ -5569,26 +5661,26 @@ bool FileCryptoMetaData::operator==(const
FileCryptoMetaData & rhs) const
return true;
}
-FileCryptoMetaData::FileCryptoMetaData(const FileCryptoMetaData& other376) {
- encryption_algorithm = other376.encryption_algorithm;
- key_metadata = other376.key_metadata;
- __isset = other376.__isset;
+FileCryptoMetaData::FileCryptoMetaData(const FileCryptoMetaData& other386) {
+ encryption_algorithm = other386.encryption_algorithm;
+ key_metadata = other386.key_metadata;
+ __isset = other386.__isset;
}
-FileCryptoMetaData::FileCryptoMetaData(FileCryptoMetaData&& other377) noexcept
{
- encryption_algorithm = std::move(other377.encryption_algorithm);
- key_metadata = std::move(other377.key_metadata);
- __isset = other377.__isset;
+FileCryptoMetaData::FileCryptoMetaData(FileCryptoMetaData&& other387) noexcept
{
+ encryption_algorithm = std::move(other387.encryption_algorithm);
+ key_metadata = std::move(other387.key_metadata);
+ __isset = other387.__isset;
}
-FileCryptoMetaData& FileCryptoMetaData::operator=(const FileCryptoMetaData&
other378) {
- encryption_algorithm = other378.encryption_algorithm;
- key_metadata = other378.key_metadata;
- __isset = other378.__isset;
+FileCryptoMetaData& FileCryptoMetaData::operator=(const FileCryptoMetaData&
other388) {
+ encryption_algorithm = other388.encryption_algorithm;
+ key_metadata = other388.key_metadata;
+ __isset = other388.__isset;
return *this;
}
-FileCryptoMetaData& FileCryptoMetaData::operator=(FileCryptoMetaData&&
other379) noexcept {
- encryption_algorithm = std::move(other379.encryption_algorithm);
- key_metadata = std::move(other379.key_metadata);
- __isset = other379.__isset;
+FileCryptoMetaData& FileCryptoMetaData::operator=(FileCryptoMetaData&&
other389) noexcept {
+ encryption_algorithm = std::move(other389.encryption_algorithm);
+ key_metadata = std::move(other389.key_metadata);
+ __isset = other389.__isset;
return *this;
}
void FileCryptoMetaData::printTo(std::ostream& out) const {
diff --git a/cpp/src/generated/parquet_types.h
b/cpp/src/generated/parquet_types.h
index 1f1e254f5c..3dffae3c2a 100644
--- a/cpp/src/generated/parquet_types.h
+++ b/cpp/src/generated/parquet_types.h
@@ -48,7 +48,7 @@ std::ostream& operator<<(std::ostream& out, const Type::type&
val);
std::string to_string(const Type::type& val);
/**
- * DEPRECATED: Common types used by frameworks(e.g. hive, pig) using parquet.
+ * DEPRECATED: Common types used by frameworks (e.g. Hive, Pig) using parquet.
* ConvertedType is superseded by LogicalType. This enum should not be
extended.
*
* See LogicalTypes.md for conversion between ConvertedType and LogicalType.
@@ -250,10 +250,10 @@ struct Encoding {
*/
PLAIN = 0,
/**
- * Deprecated: Dictionary encoding. The values in the dictionary are
encoded in the
+ * DEPRECATED: Dictionary encoding. The values in the dictionary are
encoded in the
* plain type.
- * in a data page use RLE_DICTIONARY instead.
- * in a Dictionary page use PLAIN instead
+ * For a data page use RLE_DICTIONARY instead.
+ * For a Dictionary page use PLAIN instead.
*/
PLAIN_DICTIONARY = 2,
/**
@@ -262,8 +262,9 @@ struct Encoding {
*/
RLE = 3,
/**
- * Bit packed encoding. This can only be used if the data has a known max
+ * DEPRECATED: Bit packed encoding. This can only be used if the data has
a known max
* width. Usable for definition/repetition levels encoding.
+ * Superseded by RLE (which is a hybrid of RLE and bit packing); see
Encodings.md.
*/
BIT_PACKED = 4,
/**
@@ -465,6 +466,8 @@ class RowGroup;
class TypeDefinedOrder;
+class IEEE754TotalOrder;
+
class ColumnOrder;
class PageLocation;
@@ -695,7 +698,7 @@ void swap(GeospatialStatistics &a, GeospatialStatistics &b);
std::ostream& operator<<(std::ostream& out, const GeospatialStatistics& obj);
typedef struct _Statistics__isset {
- _Statistics__isset() : max(false), min(false), null_count(false),
distinct_count(false), max_value(false), min_value(false),
is_max_value_exact(false), is_min_value_exact(false) {}
+ _Statistics__isset() : max(false), min(false), null_count(false),
distinct_count(false), max_value(false), min_value(false),
is_max_value_exact(false), is_min_value_exact(false), nan_count(false) {}
bool max :1;
bool min :1;
bool null_count :1;
@@ -704,6 +707,7 @@ typedef struct _Statistics__isset {
bool min_value :1;
bool is_max_value_exact :1;
bool is_min_value_exact :1;
+ bool nan_count :1;
} _Statistics__isset;
/**
@@ -770,6 +774,13 @@ class Statistics {
* If true, min_value is the actual minimum value for a column
*/
bool is_min_value_exact;
+ /**
+ * Count of NaN values in the column; only present if physical type is FLOAT
+ * or DOUBLE, or logical type is FLOAT16.
+ * If this field is not present, readers MUST assume NaNs may be present
+ * (i.e. MUST assume nan_count > 0 and MAY NOT assume nan_count == 0).
+ */
+ int64_t nan_count;
_Statistics__isset __isset;
@@ -789,6 +800,8 @@ class Statistics {
void __set_is_min_value_exact(const bool val);
+ void __set_nan_count(const int64_t val);
+
bool operator == (const Statistics & rhs) const;
bool operator != (const Statistics &rhs) const {
return !(*this == rhs);
@@ -1509,7 +1522,7 @@ typedef struct _GeometryType__isset {
/**
* Embedded Geometry logical type annotation
*
- * Geospatial features in the Well-Known Binary (WKB) format and edges
interpolation
+ * Geospatial features in the Well-Known Binary (WKB) format and `edges`
interpolation
* is always linear/planar.
*
* A custom CRS can be set by the crs field. If unset, it defaults to
"OGC:CRS84",
@@ -1565,13 +1578,13 @@ typedef struct _GeographyType__isset {
* Embedded Geography logical type annotation
*
* Geospatial features in the WKB format with an explicit
(non-linear/non-planar)
- * edges interpolation algorithm.
+ * `edges` interpolation algorithm.
*
* A custom geographic CRS can be set by the crs field, where longitudes are
* bound by [-180, 180] and latitudes are bound by [-90, 90]. If unset, the CRS
* defaults to "OGC:CRS84".
*
- * An optional algorithm can be set to correctly interpret edges interpolation
+ * An optional algorithm can be set to correctly interpret `edges`
interpolation
* of the geometries. If unset, the algorithm defaults to SPHERICAL.
*
* Allowed for physical type: BYTE_ARRAY.
@@ -1745,7 +1758,7 @@ typedef struct _SchemaElement__isset {
} _SchemaElement__isset;
/**
- * Represents a element inside a schema definition.
+ * Represents an element inside a schema definition.
* - if it is a group (inner node) then type is undefined and num_children is
defined
* - if it is a primitive type (leaf) then type is defined and num_children
is undefined
* the nodes are listed in depth first traversal order.
@@ -1883,7 +1896,7 @@ class DataPageHeader {
/**
* Number of values, including NULLs, in this data page.
*
- * If a OffsetIndex is present, a page must begin at a row
+ * If an OffsetIndex is present, a page must begin at a row
* boundary (repetition_level = 0). Otherwise, pages may begin
* within a row (repetition_level > 0).
*
@@ -2044,10 +2057,15 @@ typedef struct _DataPageHeaderV2__isset {
} _DataPageHeaderV2__isset;
/**
- * New page format allowing reading levels without decompressing the data
+ * Alternate page format allowing reading levels without decompressing the data
* Repetition and definition levels are uncompressed
* The remaining section containing the data is compressed if is_compressed is
true
*
+ * Implementation note - this header is not necessarily a strict improvement
over
+ * `DataPageHeader` (in particular the original header might provide better
compression
+ * in some scenarios). Page indexes require pages to start and end at row
boundaries,
+ * regardless of which page header is used.
+ *
*/
class DataPageHeaderV2 {
public:
@@ -2092,7 +2110,7 @@ class DataPageHeaderV2 {
/**
* Whether the values are compressed.
* Which means the section of the page between
- * definition_levels_byte_length + repetition_levels_byte_length + 1 and
compressed_page_size (included)
+ * definition_levels_byte_length + repetition_levels_byte_length and
compressed_page_size (included)
* is compressed with the compression_codec.
* If missing it is considered compressed
*/
@@ -2472,10 +2490,10 @@ class PageHeader {
*/
int32_t compressed_page_size;
/**
- * The 32-bit CRC checksum for the page, to be be calculated as follows:
+ * The 32-bit CRC checksum for the page, to be calculated as follows:
*
* - The standard CRC32 algorithm is used (with polynomial 0x04C11DB7,
- * the same as in e.g. GZip).
+ * the same as in e.g. GZIP).
* - All page types can have a CRC (v1 and v2 data pages, dictionary pages,
* etc.).
* - The CRC is computed on the serialization binary representation of the
page
@@ -3002,10 +3020,25 @@ class ColumnChunk {
* File where column data is stored. If not set, assumed to be same file as
* metadata. This path is relative to the current file.
*
+ * As of December 2025, the only known use-case for this field is writing
summary
+ * parquet files (i.e. "_metadata" files). These files consolidate footers
from
+ * multiple parquet files to allow for efficient reading of footers to avoid
file
+ * listing costs and prune out files that do not need to be read based on
statistics.
+ *
+ * These files do not appear to have ever been formally specified in the
specification.
+ * and are potentially problematic from a correctness perspective [1].
+ *
+ * [1] https://lists.apache.org/thread/ootf2kmyg3p01b1bvplpvp4ftd1bt72d
+ *
+ * There is no other known usage of this field. Specifically, there are no
known
+ * reference implementations that will read externally stored column data if
this field is populated
+ * within a standard parquet file. Making use of the field for this purpose
is
+ * not considered part of the Parquet specification.
+ *
*/
std::string file_path;
/**
- * Deprecated: Byte offset in file_path to the ColumnMetaData
+ * DEPRECATED: Byte offset in file_path to the ColumnMetaData
*
* Past use of this field has been inconsistent, with some implementations
* using it to point to the ColumnMetaData and some using it to point to
@@ -3208,9 +3241,44 @@ void swap(TypeDefinedOrder &a, TypeDefinedOrder &b);
std::ostream& operator<<(std::ostream& out, const TypeDefinedOrder& obj);
+
+/**
+ * Empty struct to signal IEEE 754 total order for floating point types
+ */
+class IEEE754TotalOrder {
+ public:
+
+ IEEE754TotalOrder(const IEEE754TotalOrder&) noexcept;
+ IEEE754TotalOrder(IEEE754TotalOrder&&) noexcept;
+ IEEE754TotalOrder& operator=(const IEEE754TotalOrder&) noexcept;
+ IEEE754TotalOrder& operator=(IEEE754TotalOrder&&) noexcept;
+ IEEE754TotalOrder() noexcept;
+
+ virtual ~IEEE754TotalOrder() noexcept;
+
+ bool operator == (const IEEE754TotalOrder & /* rhs */) const;
+ bool operator != (const IEEE754TotalOrder &rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool operator < (const IEEE754TotalOrder & ) const;
+
+ template <class Protocol_>
+ uint32_t read(Protocol_* iprot);
+ template <class Protocol_>
+ uint32_t write(Protocol_* oprot) const;
+
+ virtual void printTo(std::ostream& out) const;
+};
+
+void swap(IEEE754TotalOrder &a, IEEE754TotalOrder &b);
+
+std::ostream& operator<<(std::ostream& out, const IEEE754TotalOrder& obj);
+
typedef struct _ColumnOrder__isset {
- _ColumnOrder__isset() : TYPE_ORDER(false) {}
+ _ColumnOrder__isset() : TYPE_ORDER(false), IEEE_754_TOTAL_ORDER(false) {}
bool TYPE_ORDER :1;
+ bool IEEE_754_TOTAL_ORDER :1;
} _ColumnOrder__isset;
/**
@@ -3221,6 +3289,7 @@ typedef struct _ColumnOrder__isset {
* Possible values are:
* * TypeDefinedOrder - the column uses the order defined by its logical or
* physical type (if there is no logical type).
+ * * IEEE754TotalOrder - the floating point column uses IEEE 754 total order.
*
* If the reader does not support the value of this union, min and max stats
* for this column should be ignored.
@@ -3248,6 +3317,7 @@ class ColumnOrder {
* UINT64 - unsigned comparison
* DECIMAL - signed comparison of the represented value
* DATE - signed comparison
+ * FLOAT16 - signed comparison of the represented value (*)
* TIME_MILLIS - signed comparison
* TIME_MICROS - signed comparison
* TIMESTAMP_MILLIS - signed comparison
@@ -3266,34 +3336,73 @@ class ColumnOrder {
* BOOLEAN - false, true
* INT32 - signed comparison
* INT64 - signed comparison
- * INT96 (only used for legacy timestamps) - undefined
+ * INT96 (only used for legacy timestamps) - undefined(+)
* FLOAT - signed comparison of the represented value (*)
* DOUBLE - signed comparison of the represented value (*)
* BYTE_ARRAY - unsigned byte-wise comparison
* FIXED_LEN_BYTE_ARRAY - unsigned byte-wise comparison
*
- * (*) Because the sorting order is not specified properly for floating
- * point values (relations vs. total ordering) the following
+ * (+) While the INT96 type has been deprecated, at the time of writing it is
+ * still used in many legacy systems. If a Parquet implementation chooses
+ * to write statistics for INT96 columns, it is recommended to order them
+ * according to the legacy rules:
+ * - compare the last 4 bytes (days) as a little-endian 32-bit signed
integer
+ * - if equal last 4 bytes, compare the first 8 bytes as a little-endian
+ * 64-bit signed integer (nanos)
+ * See https://github.com/apache/parquet-format/issues/502 for more
details
+ *
+ * (*) Because TYPE_ORDER is ambiguous for floating point types due to
+ * underspecified handling of NaN and -0/+0, it is recommended that
writers
+ * use IEEE_754_TOTAL_ORDER for these types.
+ *
+ * If TYPE_ORDER is used for floating point types, then the following
* compatibility rules should be applied when reading statistics:
* - If the min is a NaN, it should be ignored.
* - If the max is a NaN, it should be ignored.
+ * - If the nan_count field is set, a reader can compute
+ * nan_count + null_count == num_values to deduce whether all non-null
+ * values are NaN.
* - If the min is +0, the row group may contain -0 values as well.
* - If the max is -0, the row group may contain +0 values as well.
* - When looking for NaN values, min and max should be ignored.
+ * If the nan_count field is set, it can be used to check whether
+ * NaNs are present.
*
- * When writing statistics the following rules should be followed:
- * - NaNs should not be written to min or max statistics fields.
+ * When writing page or column chunk statistics for columns with
+ * TYPE_ORDER order, the following rules must be followed:
+ * - The nan_count field must be set for floating point types, even if
+ * it is zero.
+ * - If the nan_count field is set, min and max statistics fields, when
+ * present, must not contain NaN values and must be computed from
+ * non-NaN values only. This signals to readers that the min and max
+ * statistics are reliable for non-NaN values.
+ * - If all non-null values are NaN, min and max statistics must not be
+ * written.
* - If the computed max value is zero (whether negative or positive),
* `+0.0` should be written into the max statistics field.
* - If the computed min value is zero (whether negative or positive),
* `-0.0` should be written into the min statistics field.
+ *
+ * When writing column indexes for columns with TYPE_ORDER order, the
+ * following rules must be followed:
+ * - NaNs must not be written to min_values or max_values.
+ * - If all non-null values of a page are NaN, a column index must not
+ * be written for this column chunk because min_values and max_values
+ * are required.
+ * - If the computed max value is zero (whether negative or positive),
+ * `+0.0` should be written into the corresponding max_values entry.
+ * - If the computed min value is zero (whether negative or positive),
+ * `-0.0` should be written into the corresponding min_values entry.
*/
TypeDefinedOrder TYPE_ORDER;
+ IEEE754TotalOrder IEEE_754_TOTAL_ORDER;
_ColumnOrder__isset __isset;
void __set_TYPE_ORDER(const TypeDefinedOrder& val);
+ void __set_IEEE_754_TOTAL_ORDER(const IEEE754TotalOrder& val);
+
bool operator == (const ColumnOrder & rhs) const;
bool operator != (const ColumnOrder &rhs) const {
return !(*this == rhs);
@@ -3329,8 +3438,8 @@ class PageLocation {
*/
int64_t offset;
/**
- * Size of the page, including header. Sum of compressed_page_size and header
- * length
+ * Size of the page, including header. Equal to the sum of the page's
+ * PageHeader.compressed_page_size and the size of the serialized PageHeader.
*/
int32_t compressed_page_size;
/**
@@ -3395,7 +3504,7 @@ class OffsetIndex {
/**
* Unencoded/uncompressed size for BYTE_ARRAY types.
*
- * See documention for unencoded_byte_array_data_bytes in SizeStatistics for
+ * See documentation for unencoded_byte_array_data_bytes in SizeStatistics
for
* more details on this field.
*/
std::vector<int64_t> unencoded_byte_array_data_bytes;
@@ -3426,10 +3535,11 @@ void swap(OffsetIndex &a, OffsetIndex &b);
std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj);
typedef struct _ColumnIndex__isset {
- _ColumnIndex__isset() : null_counts(false),
repetition_level_histograms(false), definition_level_histograms(false) {}
+ _ColumnIndex__isset() : null_counts(false),
repetition_level_histograms(false), definition_level_histograms(false),
nan_counts(false) {}
bool null_counts :1;
bool repetition_level_histograms :1;
bool definition_level_histograms :1;
+ bool nan_counts :1;
} _ColumnIndex__isset;
/**
@@ -3464,11 +3574,23 @@ class ColumnIndex {
* Two lists containing lower and upper bounds for the values of each page
* determined by the ColumnOrder of the column. These may be the actual
* minimum and maximum values found on a page, but can also be (more compact)
- * values that do not exist on a page. For example, instead of storing
""Blart
+ * values that do not exist on a page. For example, instead of storing "Blart
* Versenwald III", a writer may set min_values[i]="B", max_values[i]="C".
* Such more compact values must still be valid values within the column's
* logical type. Readers must make sure that list entries are populated
before
* using them by inspecting null_pages.
+ *
+ * For columns of physical type FLOAT or DOUBLE, or logical type FLOAT16,
+ * NaN values are not to be included in these bounds. If all non-null values
+ * of a page are NaN, then a writer must do the following:
+ * - If the order of this column is TYPE_ORDER, then a column index must
+ * not be written for this column chunk. While this is unfortunate for
+ * performance, it is necessary to avoid conflict with legacy files that
+ * still included NaN in min_values and max_values even if the page had
+ * non-NaN values. To mitigate this, IEEE754_TOTAL_ORDER is recommended.
+ * - If the order of this column is IEEE754_TOTAL_ORDER, then min_values[i]
+ * and max_values[i] of that page must be set to the smallest and largest
+ * NaN values as defined by IEEE 754 total order.
*/
std::vector<std::string> min_values;
std::vector<std::string> max_values;
@@ -3511,6 +3633,13 @@ class ColumnIndex {
*
*/
std::vector<int64_t> definition_level_histograms;
+ /**
+ * A list containing the number of NaN values for each page. Only present
+ * for columns of physical type FLOAT or DOUBLE, or logical type FLOAT16.
+ * If this field is not present, readers MUST assume that there might be
+ * NaN values in any page.
+ */
+ std::vector<int64_t> nan_counts;
_ColumnIndex__isset __isset;
@@ -3528,6 +3657,8 @@ class ColumnIndex {
void __set_definition_level_histograms(const std::vector<int64_t> & val);
+ void __set_nan_counts(const std::vector<int64_t> & val);
+
bool operator == (const ColumnIndex & rhs) const;
bool operator != (const ColumnIndex &rhs) const {
return !(*this == rhs);
@@ -3730,7 +3861,13 @@ class FileMetaData {
virtual ~FileMetaData() noexcept;
/**
- * Version of this file *
+ * Version of this file
+ *
+ * As of December 2025, there is no agreed upon consensus of what constitutes
+ * version 2 of the file. For maximum compatibility with readers, writers
should
+ * always populate "1" for version. For maximum compatibility with writers,
+ * readers should accept "1" and "2" interchangeably. All other versions are
+ * reserved for potential future use-cases.
*/
int32_t version;
/**
@@ -3765,7 +3902,7 @@ class FileMetaData {
* Sort order used for the min_value and max_value fields in the Statistics
* objects and the min_values and max_values fields in the ColumnIndex
* objects of each column in this file. Sort orders are listed in the order
- * matching the columns in the schema. The indexes are not necessary the same
+ * matching the columns in the schema. The indexes are not necessarily the
same
* though, because only leaf nodes of the schema are represented in the list
* of sort orders.
*
diff --git a/cpp/src/generated/parquet_types.tcc
b/cpp/src/generated/parquet_types.tcc
index 78e3e25493..0a58fa79d3 100644
--- a/cpp/src/generated/parquet_types.tcc
+++ b/cpp/src/generated/parquet_types.tcc
@@ -469,6 +469,14 @@ uint32_t Statistics::read(Protocol_* iprot) {
xfer += iprot->skip(ftype);
}
break;
+ case 9:
+ if (ftype == ::apache::thrift::protocol::T_I64) {
+ xfer += iprot->readI64(this->nan_count);
+ this->__isset.nan_count = true;
+ } else {
+ xfer += iprot->skip(ftype);
+ }
+ break;
default:
xfer += iprot->skip(ftype);
break;
@@ -527,6 +535,11 @@ uint32_t Statistics::write(Protocol_* oprot) const {
xfer += oprot->writeBool(this->is_min_value_exact);
xfer += oprot->writeFieldEnd();
}
+ if (this->__isset.nan_count) {
+ xfer += oprot->writeFieldBegin("nan_count",
::apache::thrift::protocol::T_I64, 9);
+ xfer += oprot->writeI64(this->nan_count);
+ xfer += oprot->writeFieldEnd();
+ }
xfer += oprot->writeFieldStop();
xfer += oprot->writeStructEnd();
return xfer;
@@ -4262,6 +4275,46 @@ uint32_t TypeDefinedOrder::write(Protocol_* oprot) const
{
return xfer;
}
+template <class Protocol_>
+uint32_t IEEE754TotalOrder::read(Protocol_* iprot) {
+
+ ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot);
+ uint32_t xfer = 0;
+ std::string fname;
+ ::apache::thrift::protocol::TType ftype;
+ int16_t fid;
+
+ xfer += iprot->readStructBegin(fname);
+
+ using ::apache::thrift::protocol::TProtocolException;
+
+
+ while (true)
+ {
+ xfer += iprot->readFieldBegin(fname, ftype, fid);
+ if (ftype == ::apache::thrift::protocol::T_STOP) {
+ break;
+ }
+ xfer += iprot->skip(ftype);
+ xfer += iprot->readFieldEnd();
+ }
+
+ xfer += iprot->readStructEnd();
+
+ return xfer;
+}
+
+template <class Protocol_>
+uint32_t IEEE754TotalOrder::write(Protocol_* oprot) const {
+ uint32_t xfer = 0;
+ ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot);
+ xfer += oprot->writeStructBegin("IEEE754TotalOrder");
+
+ xfer += oprot->writeFieldStop();
+ xfer += oprot->writeStructEnd();
+ return xfer;
+}
+
template <class Protocol_>
uint32_t ColumnOrder::read(Protocol_* iprot) {
@@ -4292,6 +4345,14 @@ uint32_t ColumnOrder::read(Protocol_* iprot) {
xfer += iprot->skip(ftype);
}
break;
+ case 2:
+ if (ftype == ::apache::thrift::protocol::T_STRUCT) {
+ xfer += this->IEEE_754_TOTAL_ORDER.read(iprot);
+ this->__isset.IEEE_754_TOTAL_ORDER = true;
+ } else {
+ xfer += iprot->skip(ftype);
+ }
+ break;
default:
xfer += iprot->skip(ftype);
break;
@@ -4315,6 +4376,11 @@ uint32_t ColumnOrder::write(Protocol_* oprot) const {
xfer += this->TYPE_ORDER.write(oprot);
xfer += oprot->writeFieldEnd();
}
+ if (this->__isset.IEEE_754_TOTAL_ORDER) {
+ xfer += oprot->writeFieldBegin("IEEE_754_TOTAL_ORDER",
::apache::thrift::protocol::T_STRUCT, 2);
+ xfer += this->IEEE_754_TOTAL_ORDER.write(oprot);
+ xfer += oprot->writeFieldEnd();
+ }
xfer += oprot->writeFieldStop();
xfer += oprot->writeStructEnd();
return xfer;
@@ -4437,14 +4503,14 @@ uint32_t OffsetIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->page_locations.clear();
- uint32_t _size279;
- ::apache::thrift::protocol::TType _etype282;
- xfer += iprot->readListBegin(_etype282, _size279);
- this->page_locations.resize(_size279);
- uint32_t _i283;
- for (_i283 = 0; _i283 < _size279; ++_i283)
+ uint32_t _size283;
+ ::apache::thrift::protocol::TType _etype286;
+ xfer += iprot->readListBegin(_etype286, _size283);
+ this->page_locations.resize(_size283);
+ uint32_t _i287;
+ for (_i287 = 0; _i287 < _size283; ++_i287)
{
- xfer += this->page_locations[_i283].read(iprot);
+ xfer += this->page_locations[_i287].read(iprot);
}
xfer += iprot->readListEnd();
}
@@ -4457,14 +4523,14 @@ uint32_t OffsetIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->unencoded_byte_array_data_bytes.clear();
- uint32_t _size284;
- ::apache::thrift::protocol::TType _etype287;
- xfer += iprot->readListBegin(_etype287, _size284);
- this->unencoded_byte_array_data_bytes.resize(_size284);
- uint32_t _i288;
- for (_i288 = 0; _i288 < _size284; ++_i288)
+ uint32_t _size288;
+ ::apache::thrift::protocol::TType _etype291;
+ xfer += iprot->readListBegin(_etype291, _size288);
+ this->unencoded_byte_array_data_bytes.resize(_size288);
+ uint32_t _i292;
+ for (_i292 = 0; _i292 < _size288; ++_i292)
{
- xfer +=
iprot->readI64(this->unencoded_byte_array_data_bytes[_i288]);
+ xfer +=
iprot->readI64(this->unencoded_byte_array_data_bytes[_i292]);
}
xfer += iprot->readListEnd();
}
@@ -4496,10 +4562,10 @@ uint32_t OffsetIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("page_locations",
::apache::thrift::protocol::T_LIST, 1);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT,
static_cast<uint32_t>(this->page_locations.size()));
- std::vector<PageLocation> ::const_iterator _iter289;
- for (_iter289 = this->page_locations.begin(); _iter289 !=
this->page_locations.end(); ++_iter289)
+ std::vector<PageLocation> ::const_iterator _iter293;
+ for (_iter293 = this->page_locations.begin(); _iter293 !=
this->page_locations.end(); ++_iter293)
{
- xfer += (*_iter289).write(oprot);
+ xfer += (*_iter293).write(oprot);
}
xfer += oprot->writeListEnd();
}
@@ -4509,10 +4575,10 @@ uint32_t OffsetIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("unencoded_byte_array_data_bytes",
::apache::thrift::protocol::T_LIST, 2);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64,
static_cast<uint32_t>(this->unencoded_byte_array_data_bytes.size()));
- std::vector<int64_t> ::const_iterator _iter290;
- for (_iter290 = this->unencoded_byte_array_data_bytes.begin(); _iter290
!= this->unencoded_byte_array_data_bytes.end(); ++_iter290)
+ std::vector<int64_t> ::const_iterator _iter294;
+ for (_iter294 = this->unencoded_byte_array_data_bytes.begin(); _iter294
!= this->unencoded_byte_array_data_bytes.end(); ++_iter294)
{
- xfer += oprot->writeI64((*_iter290));
+ xfer += oprot->writeI64((*_iter294));
}
xfer += oprot->writeListEnd();
}
@@ -4553,14 +4619,14 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->null_pages.clear();
- uint32_t _size295;
- ::apache::thrift::protocol::TType _etype298;
- xfer += iprot->readListBegin(_etype298, _size295);
- this->null_pages.resize(_size295);
- uint32_t _i299;
- for (_i299 = 0; _i299 < _size295; ++_i299)
+ uint32_t _size299;
+ ::apache::thrift::protocol::TType _etype302;
+ xfer += iprot->readListBegin(_etype302, _size299);
+ this->null_pages.resize(_size299);
+ uint32_t _i303;
+ for (_i303 = 0; _i303 < _size299; ++_i303)
{
- xfer += iprot->readBool(this->null_pages[_i299]);
+ xfer += iprot->readBool(this->null_pages[_i303]);
}
xfer += iprot->readListEnd();
}
@@ -4573,14 +4639,14 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->min_values.clear();
- uint32_t _size300;
- ::apache::thrift::protocol::TType _etype303;
- xfer += iprot->readListBegin(_etype303, _size300);
- this->min_values.resize(_size300);
- uint32_t _i304;
- for (_i304 = 0; _i304 < _size300; ++_i304)
+ uint32_t _size304;
+ ::apache::thrift::protocol::TType _etype307;
+ xfer += iprot->readListBegin(_etype307, _size304);
+ this->min_values.resize(_size304);
+ uint32_t _i308;
+ for (_i308 = 0; _i308 < _size304; ++_i308)
{
- xfer += iprot->readBinary(this->min_values[_i304]);
+ xfer += iprot->readBinary(this->min_values[_i308]);
}
xfer += iprot->readListEnd();
}
@@ -4593,14 +4659,14 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->max_values.clear();
- uint32_t _size305;
- ::apache::thrift::protocol::TType _etype308;
- xfer += iprot->readListBegin(_etype308, _size305);
- this->max_values.resize(_size305);
- uint32_t _i309;
- for (_i309 = 0; _i309 < _size305; ++_i309)
+ uint32_t _size309;
+ ::apache::thrift::protocol::TType _etype312;
+ xfer += iprot->readListBegin(_etype312, _size309);
+ this->max_values.resize(_size309);
+ uint32_t _i313;
+ for (_i313 = 0; _i313 < _size309; ++_i313)
{
- xfer += iprot->readBinary(this->max_values[_i309]);
+ xfer += iprot->readBinary(this->max_values[_i313]);
}
xfer += iprot->readListEnd();
}
@@ -4611,9 +4677,9 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
break;
case 4:
if (ftype == ::apache::thrift::protocol::T_I32) {
- int32_t ecast310;
- xfer += iprot->readI32(ecast310);
- this->boundary_order = static_cast<BoundaryOrder::type>(ecast310);
+ int32_t ecast314;
+ xfer += iprot->readI32(ecast314);
+ this->boundary_order = static_cast<BoundaryOrder::type>(ecast314);
isset_boundary_order = true;
} else {
xfer += iprot->skip(ftype);
@@ -4623,14 +4689,14 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->null_counts.clear();
- uint32_t _size311;
- ::apache::thrift::protocol::TType _etype314;
- xfer += iprot->readListBegin(_etype314, _size311);
- this->null_counts.resize(_size311);
- uint32_t _i315;
- for (_i315 = 0; _i315 < _size311; ++_i315)
+ uint32_t _size315;
+ ::apache::thrift::protocol::TType _etype318;
+ xfer += iprot->readListBegin(_etype318, _size315);
+ this->null_counts.resize(_size315);
+ uint32_t _i319;
+ for (_i319 = 0; _i319 < _size315; ++_i319)
{
- xfer += iprot->readI64(this->null_counts[_i315]);
+ xfer += iprot->readI64(this->null_counts[_i319]);
}
xfer += iprot->readListEnd();
}
@@ -4643,14 +4709,14 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->repetition_level_histograms.clear();
- uint32_t _size316;
- ::apache::thrift::protocol::TType _etype319;
- xfer += iprot->readListBegin(_etype319, _size316);
- this->repetition_level_histograms.resize(_size316);
- uint32_t _i320;
- for (_i320 = 0; _i320 < _size316; ++_i320)
+ uint32_t _size320;
+ ::apache::thrift::protocol::TType _etype323;
+ xfer += iprot->readListBegin(_etype323, _size320);
+ this->repetition_level_histograms.resize(_size320);
+ uint32_t _i324;
+ for (_i324 = 0; _i324 < _size320; ++_i324)
{
- xfer += iprot->readI64(this->repetition_level_histograms[_i320]);
+ xfer += iprot->readI64(this->repetition_level_histograms[_i324]);
}
xfer += iprot->readListEnd();
}
@@ -4663,14 +4729,14 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->definition_level_histograms.clear();
- uint32_t _size321;
- ::apache::thrift::protocol::TType _etype324;
- xfer += iprot->readListBegin(_etype324, _size321);
- this->definition_level_histograms.resize(_size321);
- uint32_t _i325;
- for (_i325 = 0; _i325 < _size321; ++_i325)
+ uint32_t _size325;
+ ::apache::thrift::protocol::TType _etype328;
+ xfer += iprot->readListBegin(_etype328, _size325);
+ this->definition_level_histograms.resize(_size325);
+ uint32_t _i329;
+ for (_i329 = 0; _i329 < _size325; ++_i329)
{
- xfer += iprot->readI64(this->definition_level_histograms[_i325]);
+ xfer += iprot->readI64(this->definition_level_histograms[_i329]);
}
xfer += iprot->readListEnd();
}
@@ -4679,6 +4745,26 @@ uint32_t ColumnIndex::read(Protocol_* iprot) {
xfer += iprot->skip(ftype);
}
break;
+ case 8:
+ if (ftype == ::apache::thrift::protocol::T_LIST) {
+ {
+ this->nan_counts.clear();
+ uint32_t _size330;
+ ::apache::thrift::protocol::TType _etype333;
+ xfer += iprot->readListBegin(_etype333, _size330);
+ this->nan_counts.resize(_size330);
+ uint32_t _i334;
+ for (_i334 = 0; _i334 < _size330; ++_i334)
+ {
+ xfer += iprot->readI64(this->nan_counts[_i334]);
+ }
+ xfer += iprot->readListEnd();
+ }
+ this->__isset.nan_counts = true;
+ } else {
+ xfer += iprot->skip(ftype);
+ }
+ break;
default:
xfer += iprot->skip(ftype);
break;
@@ -4708,10 +4794,10 @@ uint32_t ColumnIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("null_pages",
::apache::thrift::protocol::T_LIST, 1);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_BOOL,
static_cast<uint32_t>(this->null_pages.size()));
- std::vector<bool> ::const_iterator _iter326;
- for (_iter326 = this->null_pages.begin(); _iter326 !=
this->null_pages.end(); ++_iter326)
+ std::vector<bool> ::const_iterator _iter335;
+ for (_iter335 = this->null_pages.begin(); _iter335 !=
this->null_pages.end(); ++_iter335)
{
- xfer += oprot->writeBool((*_iter326));
+ xfer += oprot->writeBool((*_iter335));
}
xfer += oprot->writeListEnd();
}
@@ -4720,10 +4806,10 @@ uint32_t ColumnIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("min_values",
::apache::thrift::protocol::T_LIST, 2);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING,
static_cast<uint32_t>(this->min_values.size()));
- std::vector<std::string> ::const_iterator _iter327;
- for (_iter327 = this->min_values.begin(); _iter327 !=
this->min_values.end(); ++_iter327)
+ std::vector<std::string> ::const_iterator _iter336;
+ for (_iter336 = this->min_values.begin(); _iter336 !=
this->min_values.end(); ++_iter336)
{
- xfer += oprot->writeBinary((*_iter327));
+ xfer += oprot->writeBinary((*_iter336));
}
xfer += oprot->writeListEnd();
}
@@ -4732,10 +4818,10 @@ uint32_t ColumnIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("max_values",
::apache::thrift::protocol::T_LIST, 3);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING,
static_cast<uint32_t>(this->max_values.size()));
- std::vector<std::string> ::const_iterator _iter328;
- for (_iter328 = this->max_values.begin(); _iter328 !=
this->max_values.end(); ++_iter328)
+ std::vector<std::string> ::const_iterator _iter337;
+ for (_iter337 = this->max_values.begin(); _iter337 !=
this->max_values.end(); ++_iter337)
{
- xfer += oprot->writeBinary((*_iter328));
+ xfer += oprot->writeBinary((*_iter337));
}
xfer += oprot->writeListEnd();
}
@@ -4749,10 +4835,10 @@ uint32_t ColumnIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("null_counts",
::apache::thrift::protocol::T_LIST, 5);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64,
static_cast<uint32_t>(this->null_counts.size()));
- std::vector<int64_t> ::const_iterator _iter329;
- for (_iter329 = this->null_counts.begin(); _iter329 !=
this->null_counts.end(); ++_iter329)
+ std::vector<int64_t> ::const_iterator _iter338;
+ for (_iter338 = this->null_counts.begin(); _iter338 !=
this->null_counts.end(); ++_iter338)
{
- xfer += oprot->writeI64((*_iter329));
+ xfer += oprot->writeI64((*_iter338));
}
xfer += oprot->writeListEnd();
}
@@ -4762,10 +4848,10 @@ uint32_t ColumnIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("repetition_level_histograms",
::apache::thrift::protocol::T_LIST, 6);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64,
static_cast<uint32_t>(this->repetition_level_histograms.size()));
- std::vector<int64_t> ::const_iterator _iter330;
- for (_iter330 = this->repetition_level_histograms.begin(); _iter330 !=
this->repetition_level_histograms.end(); ++_iter330)
+ std::vector<int64_t> ::const_iterator _iter339;
+ for (_iter339 = this->repetition_level_histograms.begin(); _iter339 !=
this->repetition_level_histograms.end(); ++_iter339)
{
- xfer += oprot->writeI64((*_iter330));
+ xfer += oprot->writeI64((*_iter339));
}
xfer += oprot->writeListEnd();
}
@@ -4775,10 +4861,23 @@ uint32_t ColumnIndex::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("definition_level_histograms",
::apache::thrift::protocol::T_LIST, 7);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64,
static_cast<uint32_t>(this->definition_level_histograms.size()));
- std::vector<int64_t> ::const_iterator _iter331;
- for (_iter331 = this->definition_level_histograms.begin(); _iter331 !=
this->definition_level_histograms.end(); ++_iter331)
+ std::vector<int64_t> ::const_iterator _iter340;
+ for (_iter340 = this->definition_level_histograms.begin(); _iter340 !=
this->definition_level_histograms.end(); ++_iter340)
{
- xfer += oprot->writeI64((*_iter331));
+ xfer += oprot->writeI64((*_iter340));
+ }
+ xfer += oprot->writeListEnd();
+ }
+ xfer += oprot->writeFieldEnd();
+ }
+ if (this->__isset.nan_counts) {
+ xfer += oprot->writeFieldBegin("nan_counts",
::apache::thrift::protocol::T_LIST, 8);
+ {
+ xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64,
static_cast<uint32_t>(this->nan_counts.size()));
+ std::vector<int64_t> ::const_iterator _iter341;
+ for (_iter341 = this->nan_counts.begin(); _iter341 !=
this->nan_counts.end(); ++_iter341)
+ {
+ xfer += oprot->writeI64((*_iter341));
}
xfer += oprot->writeListEnd();
}
@@ -5066,14 +5165,14 @@ uint32_t FileMetaData::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->schema.clear();
- uint32_t _size348;
- ::apache::thrift::protocol::TType _etype351;
- xfer += iprot->readListBegin(_etype351, _size348);
- this->schema.resize(_size348);
- uint32_t _i352;
- for (_i352 = 0; _i352 < _size348; ++_i352)
+ uint32_t _size358;
+ ::apache::thrift::protocol::TType _etype361;
+ xfer += iprot->readListBegin(_etype361, _size358);
+ this->schema.resize(_size358);
+ uint32_t _i362;
+ for (_i362 = 0; _i362 < _size358; ++_i362)
{
- xfer += this->schema[_i352].read(iprot);
+ xfer += this->schema[_i362].read(iprot);
}
xfer += iprot->readListEnd();
}
@@ -5094,14 +5193,14 @@ uint32_t FileMetaData::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->row_groups.clear();
- uint32_t _size353;
- ::apache::thrift::protocol::TType _etype356;
- xfer += iprot->readListBegin(_etype356, _size353);
- this->row_groups.resize(_size353);
- uint32_t _i357;
- for (_i357 = 0; _i357 < _size353; ++_i357)
+ uint32_t _size363;
+ ::apache::thrift::protocol::TType _etype366;
+ xfer += iprot->readListBegin(_etype366, _size363);
+ this->row_groups.resize(_size363);
+ uint32_t _i367;
+ for (_i367 = 0; _i367 < _size363; ++_i367)
{
- xfer += this->row_groups[_i357].read(iprot);
+ xfer += this->row_groups[_i367].read(iprot);
}
xfer += iprot->readListEnd();
}
@@ -5114,14 +5213,14 @@ uint32_t FileMetaData::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->key_value_metadata.clear();
- uint32_t _size358;
- ::apache::thrift::protocol::TType _etype361;
- xfer += iprot->readListBegin(_etype361, _size358);
- this->key_value_metadata.resize(_size358);
- uint32_t _i362;
- for (_i362 = 0; _i362 < _size358; ++_i362)
+ uint32_t _size368;
+ ::apache::thrift::protocol::TType _etype371;
+ xfer += iprot->readListBegin(_etype371, _size368);
+ this->key_value_metadata.resize(_size368);
+ uint32_t _i372;
+ for (_i372 = 0; _i372 < _size368; ++_i372)
{
- xfer += this->key_value_metadata[_i362].read(iprot);
+ xfer += this->key_value_metadata[_i372].read(iprot);
}
xfer += iprot->readListEnd();
}
@@ -5142,14 +5241,14 @@ uint32_t FileMetaData::read(Protocol_* iprot) {
if (ftype == ::apache::thrift::protocol::T_LIST) {
{
this->column_orders.clear();
- uint32_t _size363;
- ::apache::thrift::protocol::TType _etype366;
- xfer += iprot->readListBegin(_etype366, _size363);
- this->column_orders.resize(_size363);
- uint32_t _i367;
- for (_i367 = 0; _i367 < _size363; ++_i367)
+ uint32_t _size373;
+ ::apache::thrift::protocol::TType _etype376;
+ xfer += iprot->readListBegin(_etype376, _size373);
+ this->column_orders.resize(_size373);
+ uint32_t _i377;
+ for (_i377 = 0; _i377 < _size373; ++_i377)
{
- xfer += this->column_orders[_i367].read(iprot);
+ xfer += this->column_orders[_i377].read(iprot);
}
xfer += iprot->readListEnd();
}
@@ -5207,10 +5306,10 @@ uint32_t FileMetaData::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("schema", ::apache::thrift::protocol::T_LIST,
2);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT,
static_cast<uint32_t>(this->schema.size()));
- std::vector<SchemaElement> ::const_iterator _iter368;
- for (_iter368 = this->schema.begin(); _iter368 != this->schema.end();
++_iter368)
+ std::vector<SchemaElement> ::const_iterator _iter378;
+ for (_iter378 = this->schema.begin(); _iter378 != this->schema.end();
++_iter378)
{
- xfer += (*_iter368).write(oprot);
+ xfer += (*_iter378).write(oprot);
}
xfer += oprot->writeListEnd();
}
@@ -5223,10 +5322,10 @@ uint32_t FileMetaData::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("row_groups",
::apache::thrift::protocol::T_LIST, 4);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT,
static_cast<uint32_t>(this->row_groups.size()));
- std::vector<RowGroup> ::const_iterator _iter369;
- for (_iter369 = this->row_groups.begin(); _iter369 !=
this->row_groups.end(); ++_iter369)
+ std::vector<RowGroup> ::const_iterator _iter379;
+ for (_iter379 = this->row_groups.begin(); _iter379 !=
this->row_groups.end(); ++_iter379)
{
- xfer += (*_iter369).write(oprot);
+ xfer += (*_iter379).write(oprot);
}
xfer += oprot->writeListEnd();
}
@@ -5236,10 +5335,10 @@ uint32_t FileMetaData::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("key_value_metadata",
::apache::thrift::protocol::T_LIST, 5);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT,
static_cast<uint32_t>(this->key_value_metadata.size()));
- std::vector<KeyValue> ::const_iterator _iter370;
- for (_iter370 = this->key_value_metadata.begin(); _iter370 !=
this->key_value_metadata.end(); ++_iter370)
+ std::vector<KeyValue> ::const_iterator _iter380;
+ for (_iter380 = this->key_value_metadata.begin(); _iter380 !=
this->key_value_metadata.end(); ++_iter380)
{
- xfer += (*_iter370).write(oprot);
+ xfer += (*_iter380).write(oprot);
}
xfer += oprot->writeListEnd();
}
@@ -5254,10 +5353,10 @@ uint32_t FileMetaData::write(Protocol_* oprot) const {
xfer += oprot->writeFieldBegin("column_orders",
::apache::thrift::protocol::T_LIST, 7);
{
xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT,
static_cast<uint32_t>(this->column_orders.size()));
- std::vector<ColumnOrder> ::const_iterator _iter371;
- for (_iter371 = this->column_orders.begin(); _iter371 !=
this->column_orders.end(); ++_iter371)
+ std::vector<ColumnOrder> ::const_iterator _iter381;
+ for (_iter381 = this->column_orders.begin(); _iter381 !=
this->column_orders.end(); ++_iter381)
{
- xfer += (*_iter371).write(oprot);
+ xfer += (*_iter381).write(oprot);
}
xfer += oprot->writeListEnd();
}
diff --git a/cpp/src/parquet/parquet.thrift b/cpp/src/parquet/parquet.thrift
index e3cc5adb96..9603cefed3 100644
--- a/cpp/src/parquet/parquet.thrift
+++ b/cpp/src/parquet/parquet.thrift
@@ -34,7 +34,7 @@ enum Type {
BOOLEAN = 0;
INT32 = 1;
INT64 = 2;
- INT96 = 3; // deprecated, only used by legacy implementations.
+ INT96 = 3; // deprecated, new Parquet writers should not write data in INT96
FLOAT = 4;
DOUBLE = 5;
BYTE_ARRAY = 6;
@@ -42,7 +42,7 @@ enum Type {
}
/**
- * DEPRECATED: Common types used by frameworks(e.g. hive, pig) using parquet.
+ * DEPRECATED: Common types used by frameworks (e.g. Hive, Pig) using parquet.
* ConvertedType is superseded by LogicalType. This enum should not be
extended.
*
* See LogicalTypes.md for conversion between ConvertedType and LogicalType.
@@ -281,7 +281,7 @@ struct Statistics {
*/
1: optional binary max;
2: optional binary min;
- /**
+ /**
* Count of null values in the column.
*
* Writers SHOULD always write this field even if it is zero (i.e. no null
value)
@@ -310,16 +310,23 @@ struct Statistics {
7: optional bool is_max_value_exact;
/** If true, min_value is the actual minimum value for a column */
8: optional bool is_min_value_exact;
+ /**
+ * Count of NaN values in the column; only present if physical type is FLOAT
+ * or DOUBLE, or logical type is FLOAT16.
+ * If this field is not present, readers MUST assume NaNs may be present
+ * (i.e. MUST assume nan_count > 0 and MAY NOT assume nan_count == 0).
+ */
+ 9: optional i64 nan_count;
}
/** Empty structs to use as logical type annotations */
struct StringType {} // allowed for BYTE_ARRAY, must be encoded with UTF-8
-struct UUIDType {} // allowed for FIXED[16], must encoded raw UUID bytes
+struct UUIDType {} // allowed for FIXED[16], must be encoded as raw UUID
bytes
struct MapType {} // see LogicalTypes.md
struct ListType {} // see LogicalTypes.md
struct EnumType {} // allowed for BYTE_ARRAY, must be encoded with UTF-8
struct DateType {} // allowed for INT32
-struct Float16Type {} // allowed for FIXED[2], must encoded raw FLOAT16 bytes
+struct Float16Type {} // allowed for FIXED[2], must be encoded as raw FLOAT16
bytes (see LogicalTypes.md)
/**
* Logical type to annotate a column that is always null.
@@ -425,7 +432,7 @@ enum EdgeInterpolationAlgorithm {
/**
* Embedded Geometry logical type annotation
*
- * Geospatial features in the Well-Known Binary (WKB) format and edges
interpolation
+ * Geospatial features in the Well-Known Binary (WKB) format and `edges`
interpolation
* is always linear/planar.
*
* A custom CRS can be set by the crs field. If unset, it defaults to
"OGC:CRS84",
@@ -444,13 +451,13 @@ struct GeometryType {
* Embedded Geography logical type annotation
*
* Geospatial features in the WKB format with an explicit
(non-linear/non-planar)
- * edges interpolation algorithm.
+ * `edges` interpolation algorithm.
*
* A custom geographic CRS can be set by the crs field, where longitudes are
* bound by [-180, 180] and latitudes are bound by [-90, 90]. If unset, the CRS
* defaults to "OGC:CRS84".
*
- * An optional algorithm can be set to correctly interpret edges interpolation
+ * An optional algorithm can be set to correctly interpret `edges`
interpolation
* of the geometries. If unset, the algorithm defaults to SPHERICAL.
*
* Allowed for physical type: BYTE_ARRAY.
@@ -498,7 +505,7 @@ union LogicalType {
}
/**
- * Represents a element inside a schema definition.
+ * Represents an element inside a schema definition.
* - if it is a group (inner node) then type is undefined and num_children is
defined
* - if it is a primitive type (leaf) then type is defined and num_children
is undefined
* the nodes are listed in depth first traversal order.
@@ -577,15 +584,15 @@ enum Encoding {
PLAIN = 0;
/** Group VarInt encoding for INT32/INT64.
- * This encoding is deprecated. It was never used
+ * This encoding is deprecated. It was never used.
*/
// GROUP_VAR_INT = 1;
/**
- * Deprecated: Dictionary encoding. The values in the dictionary are encoded
in the
+ * DEPRECATED: Dictionary encoding. The values in the dictionary are encoded
in the
* plain type.
- * in a data page use RLE_DICTIONARY instead.
- * in a Dictionary page use PLAIN instead
+ * For a data page use RLE_DICTIONARY instead.
+ * For a Dictionary page use PLAIN instead.
*/
PLAIN_DICTIONARY = 2;
@@ -594,8 +601,9 @@ enum Encoding {
*/
RLE = 3;
- /** Bit packed encoding. This can only be used if the data has a known max
+ /** DEPRECATED: Bit packed encoding. This can only be used if the data has
a known max
* width. Usable for definition/repetition levels encoding.
+ * Superseded by RLE (which is a hybrid of RLE and bit packing); see
Encodings.md.
*/
BIT_PACKED = 4;
@@ -673,7 +681,7 @@ struct DataPageHeader {
/**
* Number of values, including NULLs, in this data page.
*
- * If a OffsetIndex is present, a page must begin at a row
+ * If an OffsetIndex is present, a page must begin at a row
* boundary (repetition_level = 0). Otherwise, pages may begin
* within a row (repetition_level > 0).
**/
@@ -713,9 +721,14 @@ struct DictionaryPageHeader {
}
/**
- * New page format allowing reading levels without decompressing the data
+ * Alternate page format allowing reading levels without decompressing the data
* Repetition and definition levels are uncompressed
* The remaining section containing the data is compressed if is_compressed is
true
+ *
+ * Implementation note - this header is not necessarily a strict improvement
over
+ * `DataPageHeader` (in particular the original header might provide better
compression
+ * in some scenarios). Page indexes require pages to start and end at row
boundaries,
+ * regardless of which page header is used.
**/
struct DataPageHeaderV2 {
/** Number of values, including NULLs, in this data page. **/
@@ -741,7 +754,7 @@ struct DataPageHeaderV2 {
/** Whether the values are compressed.
Which means the section of the page between
- definition_levels_byte_length + repetition_levels_byte_length + 1 and
compressed_page_size (included)
+ definition_levels_byte_length + repetition_levels_byte_length and
compressed_page_size (included)
is compressed with the compression_codec.
If missing it is considered compressed */
7: optional bool is_compressed = true;
@@ -805,10 +818,10 @@ struct PageHeader {
/** Compressed (and potentially encrypted) page size in bytes, not including
this header **/
3: required i32 compressed_page_size
- /** The 32-bit CRC checksum for the page, to be be calculated as follows:
+ /** The 32-bit CRC checksum for the page, to be calculated as follows:
*
* - The standard CRC32 algorithm is used (with polynomial 0x04C11DB7,
- * the same as in e.g. GZip).
+ * the same as in e.g. GZIP).
* - All page types can have a CRC (v1 and v2 data pages, dictionary pages,
* etc.).
* - The CRC is computed on the serialization binary representation of the
page
@@ -893,7 +906,7 @@ struct ColumnMetaData {
/** total byte size of all uncompressed pages in this column chunk
(including the headers) **/
6: required i64 total_uncompressed_size
- /** total byte size of all compressed, and potentially encrypted, pages
+ /** total byte size of all compressed, and potentially encrypted, pages
* in this column chunk (including the headers) **/
7: required i64 total_compressed_size
@@ -959,10 +972,25 @@ union ColumnCryptoMetaData {
struct ColumnChunk {
/** File where column data is stored. If not set, assumed to be same file as
* metadata. This path is relative to the current file.
+ *
+ * As of December 2025, the only known use-case for this field is writing
summary
+ * parquet files (i.e. "_metadata" files). These files consolidate footers
from
+ * multiple parquet files to allow for efficient reading of footers to
avoid file
+ * listing costs and prune out files that do not need to be read based on
statistics.
+ *
+ * These files do not appear to have ever been formally specified in the
specification.
+ * and are potentially problematic from a correctness perspective [1].
+ *
+ * [1] https://lists.apache.org/thread/ootf2kmyg3p01b1bvplpvp4ftd1bt72d
+ *
+ * There is no other known usage of this field. Specifically, there are no
known
+ * reference implementations that will read externally stored column data
if this field is populated
+ * within a standard parquet file. Making use of the field for this purpose
is
+ * not considered part of the Parquet specification.
**/
1: optional string file_path
- /** Deprecated: Byte offset in file_path to the ColumnMetaData
+ /** DEPRECATED: Byte offset in file_path to the ColumnMetaData
*
* Past use of this field has been inconsistent, with some implementations
* using it to point to the ColumnMetaData and some using it to point to
@@ -1020,10 +1048,10 @@ struct RowGroup {
* in this row group **/
5: optional i64 file_offset
- /** Total byte size of all compressed (and potentially encrypted) column
data
+ /** Total byte size of all compressed (and potentially encrypted) column data
* in this row group **/
6: optional i64 total_compressed_size
-
+
/** Row group ordinal in the file **/
7: optional i16 ordinal
}
@@ -1031,6 +1059,9 @@ struct RowGroup {
/** Empty struct to signal the order defined by the physical or logical type */
struct TypeDefinedOrder {}
+/** Empty struct to signal IEEE 754 total order for floating point types */
+struct IEEE754TotalOrder {}
+
/**
* Union to specify the order used for the min_value and max_value fields for a
* column. This union takes the role of an enhanced enum that allows rich
@@ -1039,6 +1070,7 @@ struct TypeDefinedOrder {}
* Possible values are:
* * TypeDefinedOrder - the column uses the order defined by its logical or
* physical type (if there is no logical type).
+ * * IEEE754TotalOrder - the floating point column uses IEEE 754 total order.
*
* If the reader does not support the value of this union, min and max stats
* for this column should be ignored.
@@ -1058,6 +1090,7 @@ union ColumnOrder {
* UINT64 - unsigned comparison
* DECIMAL - signed comparison of the represented value
* DATE - signed comparison
+ * FLOAT16 - signed comparison of the represented value (*)
* TIME_MILLIS - signed comparison
* TIME_MICROS - signed comparison
* TIMESTAMP_MILLIS - signed comparison
@@ -1076,29 +1109,93 @@ union ColumnOrder {
* BOOLEAN - false, true
* INT32 - signed comparison
* INT64 - signed comparison
- * INT96 (only used for legacy timestamps) - undefined
+ * INT96 (only used for legacy timestamps) - undefined(+)
* FLOAT - signed comparison of the represented value (*)
* DOUBLE - signed comparison of the represented value (*)
* BYTE_ARRAY - unsigned byte-wise comparison
* FIXED_LEN_BYTE_ARRAY - unsigned byte-wise comparison
*
- * (*) Because the sorting order is not specified properly for floating
- * point values (relations vs. total ordering) the following
+ * (+) While the INT96 type has been deprecated, at the time of writing it is
+ * still used in many legacy systems. If a Parquet implementation chooses
+ * to write statistics for INT96 columns, it is recommended to order them
+ * according to the legacy rules:
+ * - compare the last 4 bytes (days) as a little-endian 32-bit signed
integer
+ * - if equal last 4 bytes, compare the first 8 bytes as a little-endian
+ * 64-bit signed integer (nanos)
+ * See https://github.com/apache/parquet-format/issues/502 for more
details
+ *
+ * (*) Because TYPE_ORDER is ambiguous for floating point types due to
+ * underspecified handling of NaN and -0/+0, it is recommended that
writers
+ * use IEEE_754_TOTAL_ORDER for these types.
+ *
+ * If TYPE_ORDER is used for floating point types, then the following
* compatibility rules should be applied when reading statistics:
* - If the min is a NaN, it should be ignored.
* - If the max is a NaN, it should be ignored.
+ * - If the nan_count field is set, a reader can compute
+ * nan_count + null_count == num_values to deduce whether all non-null
+ * values are NaN.
* - If the min is +0, the row group may contain -0 values as well.
* - If the max is -0, the row group may contain +0 values as well.
* - When looking for NaN values, min and max should be ignored.
- *
- * When writing statistics the following rules should be followed:
- * - NaNs should not be written to min or max statistics fields.
+ * If the nan_count field is set, it can be used to check whether
+ * NaNs are present.
+ *
+ * When writing page or column chunk statistics for columns with
+ * TYPE_ORDER order, the following rules must be followed:
+ * - The nan_count field must be set for floating point types, even if
+ * it is zero.
+ * - If the nan_count field is set, min and max statistics fields, when
+ * present, must not contain NaN values and must be computed from
+ * non-NaN values only. This signals to readers that the min and max
+ * statistics are reliable for non-NaN values.
+ * - If all non-null values are NaN, min and max statistics must not be
+ * written.
* - If the computed max value is zero (whether negative or positive),
* `+0.0` should be written into the max statistics field.
* - If the computed min value is zero (whether negative or positive),
* `-0.0` should be written into the min statistics field.
+ *
+ * When writing column indexes for columns with TYPE_ORDER order, the
+ * following rules must be followed:
+ * - NaNs must not be written to min_values or max_values.
+ * - If all non-null values of a page are NaN, a column index must not
+ * be written for this column chunk because min_values and max_values
+ * are required.
+ * - If the computed max value is zero (whether negative or positive),
+ * `+0.0` should be written into the corresponding max_values entry.
+ * - If the computed min value is zero (whether negative or positive),
+ * `-0.0` should be written into the corresponding min_values entry.
*/
1: TypeDefinedOrder TYPE_ORDER;
+
+ /*
+ * The floating point type is ordered according to the totalOrder predicate,
+ * as defined in section 5.10 of IEEE-754 (2008 revision). Only columns of
+ * physical type FLOAT or DOUBLE, or logical type FLOAT16 may use this
ordering.
+ *
+ * Intuitively, this orders floats mathematically, but defines -0 to be less
+ * than +0, -NaN to be less than anything else, and +NaN to be greater than
+ * anything else. It also defines an order between different bit
representations
+ * of the same value.
+ *
+ * When writing statistics for columns with IEEE_754_TOTAL_ORDER order, then
+ * following rules must be followed:
+ * - Writing the nan_count field is mandatory when using this ordering.
+ * - Min and max statistics must contain the smallest and largest non-NaN
+ * values respectively, or if all non-null values are NaN, the smallest and
+ * largest NaN values as defined by IEEE 754 total order.
+ *
+ * When reading statistics for columns with this order, the following rules
+ * should be followed:
+ * - Readers should consult the nan_count field to determine whether NaNs
+ * are present.
+ * - A reader can compute nan_count + null_count == num_values to deduce
+ * whether all non-null values are NaN. In the page index, which does not
+ * have a num_values field, the presence of a NaN value in min_values
+ * or max_values indicates that all non-null values are NaN.
+ */
+ 2: IEEE754TotalOrder IEEE_754_TOTAL_ORDER;
}
struct PageLocation {
@@ -1106,8 +1203,8 @@ struct PageLocation {
1: required i64 offset
/**
- * Size of the page, including header. Sum of compressed_page_size and header
- * length
+ * Size of the page, including header. Equal to the sum of the page's
+ * PageHeader.compressed_page_size and the size of the serialized PageHeader.
*/
2: required i32 compressed_page_size
@@ -1135,7 +1232,7 @@ struct OffsetIndex {
/**
* Unencoded/uncompressed size for BYTE_ARRAY types.
*
- * See documention for unencoded_byte_array_data_bytes in SizeStatistics for
+ * See documentation for unencoded_byte_array_data_bytes in SizeStatistics
for
* more details on this field.
*/
2: optional list<i64> unencoded_byte_array_data_bytes
@@ -1165,11 +1262,23 @@ struct ColumnIndex {
* Two lists containing lower and upper bounds for the values of each page
* determined by the ColumnOrder of the column. These may be the actual
* minimum and maximum values found on a page, but can also be (more compact)
- * values that do not exist on a page. For example, instead of storing
""Blart
+ * values that do not exist on a page. For example, instead of storing "Blart
* Versenwald III", a writer may set min_values[i]="B", max_values[i]="C".
* Such more compact values must still be valid values within the column's
* logical type. Readers must make sure that list entries are populated
before
* using them by inspecting null_pages.
+ *
+ * For columns of physical type FLOAT or DOUBLE, or logical type FLOAT16,
+ * NaN values are not to be included in these bounds. If all non-null values
+ * of a page are NaN, then a writer must do the following:
+ * - If the order of this column is TYPE_ORDER, then a column index must
+ * not be written for this column chunk. While this is unfortunate for
+ * performance, it is necessary to avoid conflict with legacy files that
+ * still included NaN in min_values and max_values even if the page had
+ * non-NaN values. To mitigate this, IEEE754_TOTAL_ORDER is recommended.
+ * - If the order of this column is IEEE754_TOTAL_ORDER, then min_values[i]
+ * and max_values[i] of that page must be set to the smallest and largest
+ * NaN values as defined by IEEE 754 total order.
*/
2: required list<binary> min_values
3: required list<binary> max_values
@@ -1183,13 +1292,13 @@ struct ColumnIndex {
4: required BoundaryOrder boundary_order
/**
- * A list containing the number of null values for each page
+ * A list containing the number of null values for each page
*
* Writers SHOULD always write this field even if no null values
* are present or the column is not nullable.
- * Readers MUST distinguish between null_counts not being present
+ * Readers MUST distinguish between null_counts not being present
* and null_count being 0.
- * If null_counts are not present, readers MUST NOT assume all
+ * If null_counts are not present, readers MUST NOT assume all
* null counts are 0.
*/
5: optional list<i64> null_counts
@@ -1211,6 +1320,15 @@ struct ColumnIndex {
* Same as repetition_level_histograms except for definitions levels.
**/
7: optional list<i64> definition_level_histograms;
+
+ /**
+ * A list containing the number of NaN values for each page. Only present
+ * for columns of physical type FLOAT or DOUBLE, or logical type FLOAT16.
+ * If this field is not present, readers MUST assume that there might be
+ * NaN values in any page.
+ */
+ 8: optional list<i64> nan_counts
+
}
struct AesGcmV1 {
@@ -1246,7 +1364,14 @@ union EncryptionAlgorithm {
* Description for file metadata
*/
struct FileMetaData {
- /** Version of this file **/
+ /** Version of this file
+ *
+ * As of December 2025, there is no agreed upon consensus of what
constitutes
+ * version 2 of the file. For maximum compatibility with readers, writers
should
+ * always populate "1" for version. For maximum compatibility with writers,
+ * readers should accept "1" and "2" interchangeably. All other versions
are
+ * reserved for potential future use-cases.
+ */
1: required i32 version
/** Parquet schema for this file. This schema contains metadata for all the
columns.
@@ -1276,7 +1401,7 @@ struct FileMetaData {
* Sort order used for the min_value and max_value fields in the Statistics
* objects and the min_values and max_values fields in the ColumnIndex
* objects of each column in this file. Sort orders are listed in the order
- * matching the columns in the schema. The indexes are not necessary the same
+ * matching the columns in the schema. The indexes are not necessarily the
same
* though, because only leaf nodes of the schema are represented in the list
* of sort orders.
*
@@ -1290,30 +1415,30 @@ struct FileMetaData {
*/
7: optional list<ColumnOrder> column_orders;
- /**
+ /**
* Encryption algorithm. This field is set only in encrypted files
* with plaintext footer. Files with encrypted footer store algorithm id
* in FileCryptoMetaData structure.
*/
8: optional EncryptionAlgorithm encryption_algorithm
- /**
- * Retrieval metadata of key used for signing the footer.
- * Used only in encrypted files with plaintext footer.
- */
+ /**
+ * Retrieval metadata of key used for signing the footer.
+ * Used only in encrypted files with plaintext footer.
+ */
9: optional binary footer_signing_key_metadata
}
/** Crypto metadata for files with encrypted footer **/
struct FileCryptoMetaData {
- /**
+ /**
* Encryption algorithm. This field is only used for files
* with encrypted footer. Files with plaintext footer store algorithm id
* inside footer (FileMetaData structure).
*/
1: required EncryptionAlgorithm encryption_algorithm
-
- /** Retrieval metadata of key used for encryption of footer,
+
+ /** Retrieval metadata of key used for encryption of footer,
* and (possibly) columns **/
2: optional binary key_metadata
}