@@ -74,32 +74,6 @@ ::parquet::EncryptionAlgorithm FromThrift(
7474constexpr const char * kTypeMappingErrorFmtStr =
7575 " Schema mismatch, Column: [{}], From Kind: {}, To Kind: {}" ;
7676
77- // Checks whether 'type' is an integer type at least as wide as
78- // 'minTypeKind'. Used to gate integer widening:
79- // minTypeKind=TINYINT accepts TINYINT/SMALLINT/INTEGER/BIGINT (INT_8 leaf)
80- // minTypeKind=SMALLINT accepts SMALLINT/INTEGER/BIGINT (INT_16 leaf)
81- // minTypeKind=INTEGER accepts INTEGER/BIGINT (INT_32 leaf)
82- // minTypeKind=BIGINT accepts BIGINT only (INT_64 leaf)
83- bool isIntCompatible (
84- const bytedance::bolt::TypePtr& type,
85- bytedance::bolt::TypeKind minTypeKind) {
86- using TK = bytedance::bolt::TypeKind;
87- static_assert (
88- static_cast <int >(TK ::TINYINT ) < static_cast <int >(TK ::SMALLINT ) &&
89- static_cast <int >(TK ::SMALLINT ) < static_cast <int >(TK ::INTEGER ) &&
90- static_cast <int >(TK ::INTEGER ) < static_cast <int >(TK ::BIGINT ));
91- const auto kind = type->kind ();
92- switch (kind) {
93- case TK ::TINYINT :
94- case TK ::SMALLINT :
95- case TK ::INTEGER :
96- case TK ::BIGINT :
97- return static_cast <int >(kind) >= static_cast <int >(minTypeKind);
98- default :
99- return false ;
100- }
101- }
102-
10377// Predicates for the cross-family implicit cast that the column reader
10478// layer performs at read time (Spark/Hive STRING<->INT compatibility):
10579// - StringColumnReader::makeCastExpr handles VARCHAR/VARBINARY file ->
@@ -111,6 +85,11 @@ bool isIntCompatible(
11185// still get the strict check at ParquetColumnReader.cpp:95 via
11286// matchType() for the VARCHAR-file -> INT-requested direction, which
11387// fires after convertType and throws with its existing error message.
88+ // Cross-family implicit cast for VARCHAR/VARBINARY file columns:
89+ // StringColumnReader::makeCastExpr handles VARCHAR/VARBINARY file -> int
90+ // family requested type. Non-Spark builds also get a strict check at
91+ // ParquetColumnReader.cpp:95 via matchType() that fires after convertType
92+ // and throws with its own error message for that case.
11493bool acceptsVarcharFileForReaderCast (const bytedance::bolt::TypePtr& t) {
11594 using TK = bytedance::bolt::TypeKind;
11695 const auto k = t->kind ();
@@ -122,6 +101,30 @@ bool acceptsIntFileForReaderCast(const bytedance::bolt::TypePtr& t) {
122101 t->kind () == bytedance::bolt::TypeKind::VARBINARY ;
123102}
124103
104+ // Compatibility predicate for Parquet INT32-physical source columns
105+ // (INT_8 / INT_16 / INT_32 / UINT_* annotated, plus unannotated INT32).
106+ // Accepts:
107+ // - Any int-family target. Narrowing (file INT32 -> requested ByteType /
108+ // ShortType) is silently truncated at read time, matching Spark's
109+ // vectorized reader. Covers HIVE-14294 where Hive 1.x writes
110+ // TINYINT/SMALLINT as unannotated INT32 (SPARK-16632).
111+ // - VARCHAR / VARBINARY target via IntegerColumnReader::makeCastExpr,
112+ // which performs the int-to-string cast at read time.
113+ bool isInt32Compatible (const bytedance::bolt::TypePtr& type) {
114+ using TK = bytedance::bolt::TypeKind;
115+ const auto k = type->kind ();
116+ return k == TK ::TINYINT || k == TK ::SMALLINT || k == TK ::INTEGER ||
117+ k == TK ::BIGINT || acceptsIntFileForReaderCast (type);
118+ }
119+
120+ // Compatibility predicate for Parquet INT64-physical source columns.
121+ // Accepts BIGINT only (no integer narrowing), plus VARCHAR / VARBINARY
122+ // via IntegerColumnReader::makeCastExpr.
123+ bool isInt64Compatible (const bytedance::bolt::TypePtr& type) {
124+ using TK = bytedance::bolt::TypeKind;
125+ return type->kind () == TK ::BIGINT || acceptsIntFileForReaderCast (type);
126+ }
127+
125128} // namespace
126129
127130// / Metadata and options for reading Parquet.
@@ -1023,87 +1026,63 @@ TypePtr ReaderBase::convertType(
10231026 schemaElement.type ,
10241027 thrift::Type::INT32 ,
10251028 " INT8 converted type can only be set for value of thrift::Type::INT32" );
1026- checkRequested ([](const TypePtr& t) {
1027- return isIntCompatible (t, TypeKind::TINYINT ) ||
1028- acceptsIntFileForReaderCast (t);
1029- });
1029+ checkRequested ([](const TypePtr& t) { return isInt32Compatible (t); });
10301030 return TINYINT ();
10311031
10321032 case thrift::ConvertedType::INT_16 :
10331033 BOLT_CHECK_EQ (
10341034 schemaElement.type ,
10351035 thrift::Type::INT32 ,
10361036 " INT16 converted type can only be set for value of thrift::Type::INT32" );
1037- checkRequested ([](const TypePtr& t) {
1038- return isIntCompatible (t, TypeKind::SMALLINT ) ||
1039- acceptsIntFileForReaderCast (t);
1040- });
1037+ checkRequested ([](const TypePtr& t) { return isInt32Compatible (t); });
10411038 return SMALLINT ();
10421039
10431040 case thrift::ConvertedType::INT_32 :
10441041 BOLT_CHECK_EQ (
10451042 schemaElement.type ,
10461043 thrift::Type::INT32 ,
10471044 " INT32 converted type can only be set for value of thrift::Type::INT32" );
1048- checkRequested ([](const TypePtr& t) {
1049- return isIntCompatible (t, TypeKind::INTEGER ) ||
1050- acceptsIntFileForReaderCast (t);
1051- });
1045+ checkRequested ([](const TypePtr& t) { return isInt32Compatible (t); });
10521046 return INTEGER ();
10531047
10541048 case thrift::ConvertedType::INT_64 :
10551049 BOLT_CHECK_EQ (
10561050 schemaElement.type ,
10571051 thrift::Type::INT64 ,
10581052 " INT64 converted type can only be set for value of thrift::Type::INT64" );
1059- checkRequested ([](const TypePtr& t) {
1060- return isIntCompatible (t, TypeKind::BIGINT ) ||
1061- acceptsIntFileForReaderCast (t);
1062- });
1053+ checkRequested ([](const TypePtr& t) { return isInt64Compatible (t); });
10631054 return BIGINT ();
10641055
10651056 case thrift::ConvertedType::UINT_8 :
10661057 BOLT_CHECK_EQ (
10671058 schemaElement.type ,
10681059 thrift::Type::INT32 ,
10691060 " UINT_8 converted type can only be set for value of thrift::Type::INT32" );
1070- checkRequested ([](const TypePtr& t) {
1071- return isIntCompatible (t, TypeKind::TINYINT ) ||
1072- acceptsIntFileForReaderCast (t);
1073- });
1061+ checkRequested ([](const TypePtr& t) { return isInt32Compatible (t); });
10741062 return TINYINT ();
10751063
10761064 case thrift::ConvertedType::UINT_16 :
10771065 BOLT_CHECK_EQ (
10781066 schemaElement.type ,
10791067 thrift::Type::INT32 ,
10801068 " UINT_16 converted type can only be set for value of thrift::Type::INT32" );
1081- checkRequested ([](const TypePtr& t) {
1082- return isIntCompatible (t, TypeKind::SMALLINT ) ||
1083- acceptsIntFileForReaderCast (t);
1084- });
1069+ checkRequested ([](const TypePtr& t) { return isInt32Compatible (t); });
10851070 return SMALLINT ();
10861071
10871072 case thrift::ConvertedType::UINT_32 :
10881073 BOLT_CHECK_EQ (
10891074 schemaElement.type ,
10901075 thrift::Type::INT32 ,
10911076 " UINT_32 converted type can only be set for value of thrift::Type::INT32" );
1092- checkRequested ([](const TypePtr& t) {
1093- return isIntCompatible (t, TypeKind::INTEGER ) ||
1094- acceptsIntFileForReaderCast (t);
1095- });
1077+ checkRequested ([](const TypePtr& t) { return isInt32Compatible (t); });
10961078 return INTEGER ();
10971079
10981080 case thrift::ConvertedType::UINT_64 :
10991081 BOLT_CHECK_EQ (
11001082 schemaElement.type ,
11011083 thrift::Type::INT64 ,
11021084 " UINT_64 converted type can only be set for value of thrift::Type::INT64" );
1103- checkRequested ([](const TypePtr& t) {
1104- return isIntCompatible (t, TypeKind::BIGINT ) ||
1105- acceptsIntFileForReaderCast (t);
1106- });
1085+ checkRequested ([](const TypePtr& t) { return isInt64Compatible (t); });
11071086 return BIGINT ();
11081087
11091088 case thrift::ConvertedType::DATE :
@@ -1188,10 +1167,7 @@ TypePtr ReaderBase::convertType(
11881167 [](const TypePtr& t) { return t->kind () == TypeKind::BOOLEAN ; });
11891168 return BOOLEAN ();
11901169 case thrift::Type::type::INT32 :
1191- checkRequested ([](const TypePtr& t) {
1192- return isIntCompatible (t, TypeKind::INTEGER ) ||
1193- acceptsIntFileForReaderCast (t);
1194- });
1170+ checkRequested ([](const TypePtr& t) { return isInt32Compatible (t); });
11951171 return INTEGER ();
11961172 case thrift::Type::type::INT64 :
11971173 // For Int64 Timestamp in nano precision
@@ -1212,10 +1188,7 @@ TypePtr ReaderBase::convertType(
12121188 });
12131189 return TIMESTAMP ();
12141190 }
1215- checkRequested ([](const TypePtr& t) {
1216- return isIntCompatible (t, TypeKind::BIGINT ) ||
1217- acceptsIntFileForReaderCast (t);
1218- });
1191+ checkRequested ([](const TypePtr& t) { return isInt64Compatible (t); });
12191192 return BIGINT ();
12201193 case thrift::Type::type::INT96 :
12211194 checkRequested (
0 commit comments