@@ -815,11 +815,15 @@ public String translateExtractField(TemporalUnit unit) {
815815
816816 /**
817817 * {@code microsecond} is the smallest unit for an {@code interval},
818- * and the highest precision for a {@code timestamp}.
818+ * and the highest precision for a {@code timestamp}, so we could
819+ * use it as the "native" precision, but it's more convenient to use
820+ * whole seconds (with the fractional part), since we want to use
821+ * {@code extract(epoch from ...)} in our emulation of
822+ * {@code timestampdiff()}.
819823 */
820824 @ Override
821825 public long getFractionalSecondPrecisionInNanos () {
822- return 1_000 ; //microseconds
826+ return 1_000_000_000 ; //seconds
823827 }
824828
825829 @ Override @ SuppressWarnings ("deprecation" )
@@ -831,8 +835,8 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType,
831835
832836 private static String intervalPattern (TemporalUnit unit ) {
833837 return switch (unit ) {
834- case NATIVE -> "(?2)*interval '1 microsecond'" ;
835838 case NANOSECOND -> "(?2)/1e3*interval '1 microsecond'" ;
839+ case NATIVE -> "(?2)*interval '1 second'" ;
836840 case QUARTER -> "(?2)*interval '3 month'" ; // quarter is not supported in interval literals
837841 case WEEK -> "(?2)*interval '7 day'" ; // week is not supported in interval literals
838842 default -> "(?2)*interval '1 " + unit + "'" ;
@@ -849,9 +853,9 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT
849853 // results in an integer number of days
850854 // instead of an INTERVAL
851855 return switch (unit ) {
852- case YEAR , MONTH , QUARTER ->
853- // age only supports timestamptz, so we have to cast the date expressions
854- "extract(" + translateDurationField ( unit )
856+ case YEAR , MONTH , QUARTER
857+ -> "extract(" + translateDurationField ( unit )
858+ // age only supports timestamptz, so we have to cast the date expressions
855859 + " from age(cast(?3 as timestamptz),cast(?2 as timestamptz)))" ;
856860 default -> "(?3-?2)" + DAY .conversionFactor ( unit , this );
857861 };
@@ -863,28 +867,21 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT
863867 case MONTH -> "(extract(year from ?3-?2)*12+extract(month from ?3-?2))" ;
864868 case WEEK -> "(extract(day from ?3-?2)/7)" ; // week is not supported by extract() when the argument is a duration
865869 case DAY -> "extract(day from ?3-?2)" ;
866- //in order to avoid multiple calls to extract(),
867- //we use extract(epoch from x - y) * factor for
868- //all the following units:
869870 // Note that CockroachDB also has an extract_duration function which returns an int,
870871 // but we don't use that here because it is deprecated since v20.
871872 // We need to use round() instead of cast(... as int) because extract epoch returns
872- // float8 which can cause loss-of- precision in some cases
873+ // float8 which can cause loss of precision in some cases
873874 // https://github.com/cockroachdb/cockroach/issues/72523
875+ // in order to avoid multiple calls to extract(),
876+ // we use extract(epoch from x - y) * factor for
877+ // all the following units:
874878 case HOUR , MINUTE , SECOND , NANOSECOND , NATIVE ->
875879 "round(extract(epoch from ?3-?2)" + EPOCH .conversionFactor ( unit , this ) + ")::int" ;
876880 default -> throw new SemanticException ( "Unrecognized field: " + unit );
877881 };
878882 }
879883 }
880884
881- @ Override
882- public String translateDurationField (TemporalUnit unit ) {
883- return unit ==NATIVE
884- ? "microsecond"
885- : super .translateDurationField ( unit );
886- }
887-
888885 @ Override
889886 public void appendDatetimeFormat (SqlAppender appender , String format ) {
890887 appender .appendSql ( SpannerDialect .datetimeFormat ( format ).result () );
0 commit comments