@@ -855,6 +855,50 @@ void CArrowTableIterator::convertTimestampTZColumn_nanoarrow(
855
855
ArrowSchemaInit (newSchema);
856
856
newSchema->flags &=
857
857
(field->schema ->flags & ARROW_FLAG_NULLABLE); // map to nullable()
858
+
859
+ // Find epoch and fraction arrays
860
+ ArrowArrayView* epochArray;
861
+ ArrowArrayView* fractionArray;
862
+ for (int64_t i = 0 ; i < field->schema ->n_children ; i++) {
863
+ ArrowSchema* c_schema = field->schema ->children [i];
864
+ if (std::strcmp (c_schema->name , internal::FIELD_NAME_EPOCH.c_str ()) == 0 ) {
865
+ epochArray = columnArray->children [i];
866
+ } else if (std::strcmp (c_schema->name ,
867
+ internal::FIELD_NAME_FRACTION.c_str ()) == 0 ) {
868
+ fractionArray = columnArray->children [i];
869
+ } else {
870
+ // do nothing
871
+ }
872
+ }
873
+
874
+ // Calculate has_overflow_to_downscale for timestamps that would overflow
875
+ bool has_overflow_to_downscale = false ;
876
+ if (scale > 6 && byteLength == 16 ) {
877
+ int powTenSB4 = sf::internal::powTenSB4[9 ];
878
+ for (int64_t rowIdx = 0 ; rowIdx < columnArray->array ->length ; rowIdx++) {
879
+ if (!ArrowArrayViewIsNull (columnArray, rowIdx)) {
880
+ int64_t epoch = ArrowArrayViewGetIntUnsafe (epochArray, rowIdx);
881
+ int64_t fraction = ArrowArrayViewGetIntUnsafe (fractionArray, rowIdx);
882
+ if (epoch > (INT64_MAX / powTenSB4) ||
883
+ epoch < (INT64_MIN / powTenSB4)) {
884
+ if (fraction % 1000 != 0 ) {
885
+ std::string errorInfo = Logger::formatString (
886
+ " The total number of nanoseconds %d%d overflows int64 range. "
887
+ " If you use a timestamp with "
888
+ " the nanosecond part over 6-digits in the Snowflake database, "
889
+ " the timestamp must be "
890
+ " between '1677-09-21 00:12:43.145224192' and '2262-04-11 "
891
+ " 23:47:16.854775807' to not overflow." ,
892
+ epoch, fraction);
893
+ throw std::overflow_error (errorInfo.c_str ());
894
+ } else {
895
+ has_overflow_to_downscale = true ;
896
+ }
897
+ }
898
+ }
899
+ }
900
+ }
901
+
858
902
auto timeunit = NANOARROW_TIME_UNIT_SECOND;
859
903
if (scale == 0 ) {
860
904
timeunit = NANOARROW_TIME_UNIT_SECOND;
@@ -863,7 +907,9 @@ void CArrowTableIterator::convertTimestampTZColumn_nanoarrow(
863
907
} else if (scale <= 6 ) {
864
908
timeunit = NANOARROW_TIME_UNIT_MICRO;
865
909
} else {
866
- timeunit = NANOARROW_TIME_UNIT_NANO;
910
+ // Use microsecond precision if we detected overflow, otherwise nanosecond
911
+ timeunit = has_overflow_to_downscale ? NANOARROW_TIME_UNIT_MICRO
912
+ : NANOARROW_TIME_UNIT_NANO;
867
913
}
868
914
869
915
if (!timezone.empty ()) {
@@ -893,20 +939,6 @@ void CArrowTableIterator::convertTimestampTZColumn_nanoarrow(
893
939
" from schema : %s, error code: %d" ,
894
940
ArrowErrorMessage (&error), returnCode);
895
941
896
- ArrowArrayView* epochArray;
897
- ArrowArrayView* fractionArray;
898
- for (int64_t i = 0 ; i < field->schema ->n_children ; i++) {
899
- ArrowSchema* c_schema = field->schema ->children [i];
900
- if (std::strcmp (c_schema->name , internal::FIELD_NAME_EPOCH.c_str ()) == 0 ) {
901
- epochArray = columnArray->children [i];
902
- } else if (std::strcmp (c_schema->name ,
903
- internal::FIELD_NAME_FRACTION.c_str ()) == 0 ) {
904
- fractionArray = columnArray->children [i];
905
- } else {
906
- // do nothing
907
- }
908
- }
909
-
910
942
for (int64_t rowIdx = 0 ; rowIdx < columnArray->array ->length ; rowIdx++) {
911
943
if (!ArrowArrayViewIsNull (columnArray, rowIdx)) {
912
944
if (byteLength == 8 ) {
@@ -920,8 +952,14 @@ void CArrowTableIterator::convertTimestampTZColumn_nanoarrow(
920
952
returnCode = ArrowArrayAppendInt (
921
953
newArray, epoch * sf::internal::powTenSB4[6 - scale]);
922
954
} else {
923
- returnCode = ArrowArrayAppendInt (
924
- newArray, epoch * sf::internal::powTenSB4[9 - scale]);
955
+ // Handle overflow by falling back to microsecond precision
956
+ if (has_overflow_to_downscale) {
957
+ returnCode = ArrowArrayAppendInt (
958
+ newArray, epoch * sf::internal::powTenSB4[6 ]);
959
+ } else {
960
+ returnCode = ArrowArrayAppendInt (
961
+ newArray, epoch * sf::internal::powTenSB4[9 - scale]);
962
+ }
925
963
}
926
964
SF_CHECK_ARROW_RC (returnCode,
927
965
" [Snowflake Exception] error appending int to "
@@ -941,8 +979,14 @@ void CArrowTableIterator::convertTimestampTZColumn_nanoarrow(
941
979
newArray, epoch * sf::internal::powTenSB4[6 ] +
942
980
fraction / sf::internal::powTenSB4[3 ]);
943
981
} else {
944
- returnCode = ArrowArrayAppendInt (
945
- newArray, epoch * sf::internal::powTenSB4[9 ] + fraction);
982
+ // Handle overflow by falling back to microsecond precision
983
+ if (has_overflow_to_downscale) {
984
+ returnCode = ArrowArrayAppendInt (
985
+ newArray, epoch * sf::internal::powTenSB4[6 ] + fraction / 1000 );
986
+ } else {
987
+ returnCode = ArrowArrayAppendInt (
988
+ newArray, epoch * sf::internal::powTenSB4[9 ] + fraction);
989
+ }
946
990
}
947
991
SF_CHECK_ARROW_RC (returnCode,
948
992
" [Snowflake Exception] error appending int to "
0 commit comments