@@ -491,11 +491,28 @@ typedef struct
491
491
492
492
/* ----------
493
493
* Datetime to char conversion
494
+ *
495
+ * To support intervals as well as timestamps, we use a custom "tm" struct
496
+ * that is almost like struct pg_tm, but has a 64-bit tm_hour field.
497
+ * We omit the tm_isdst and tm_zone fields, which are not used here.
494
498
* ----------
495
499
*/
500
+ struct fmt_tm
501
+ {
502
+ int tm_sec ;
503
+ int tm_min ;
504
+ int64 tm_hour ;
505
+ int tm_mday ;
506
+ int tm_mon ;
507
+ int tm_year ;
508
+ int tm_wday ;
509
+ int tm_yday ;
510
+ long int tm_gmtoff ;
511
+ };
512
+
496
513
typedef struct TmToChar
497
514
{
498
- struct pg_tm tm ; /* classic 'tm' struct */
515
+ struct fmt_tm tm ; /* almost the classic 'tm' struct */
499
516
fsec_t fsec ; /* fractional seconds */
500
517
const char * tzn ; /* timezone */
501
518
} TmToChar ;
@@ -504,12 +521,25 @@ typedef struct TmToChar
504
521
#define tmtcTzn (_X ) ((_X)->tzn)
505
522
#define tmtcFsec (_X ) ((_X)->fsec)
506
523
524
+ /* Note: this is used to copy pg_tm to fmt_tm, so not quite a bitwise copy */
525
+ #define COPY_tm (_DST , _SRC ) \
526
+ do { \
527
+ (_DST)->tm_sec = (_SRC)->tm_sec; \
528
+ (_DST)->tm_min = (_SRC)->tm_min; \
529
+ (_DST)->tm_hour = (_SRC)->tm_hour; \
530
+ (_DST)->tm_mday = (_SRC)->tm_mday; \
531
+ (_DST)->tm_mon = (_SRC)->tm_mon; \
532
+ (_DST)->tm_year = (_SRC)->tm_year; \
533
+ (_DST)->tm_wday = (_SRC)->tm_wday; \
534
+ (_DST)->tm_yday = (_SRC)->tm_yday; \
535
+ (_DST)->tm_gmtoff = (_SRC)->tm_gmtoff; \
536
+ } while(0)
537
+
538
+ /* Caution: this is used to zero both pg_tm and fmt_tm structs */
507
539
#define ZERO_tm (_X ) \
508
540
do { \
509
- (_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
510
- (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
511
- (_X)->tm_mday = (_X)->tm_mon = 1; \
512
- (_X)->tm_zone = NULL; \
541
+ memset(_X, 0, sizeof(*(_X))); \
542
+ (_X)->tm_mday = (_X)->tm_mon = 1; \
513
543
} while(0)
514
544
515
545
#define ZERO_tmtc (_X ) \
@@ -2649,7 +2679,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
2649
2679
{
2650
2680
FormatNode * n ;
2651
2681
char * s ;
2652
- struct pg_tm * tm = & in -> tm ;
2682
+ struct fmt_tm * tm = & in -> tm ;
2653
2683
int i ;
2654
2684
2655
2685
/* cache localized days and months */
@@ -2698,16 +2728,17 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
2698
2728
* display time as shown on a 12-hour clock, even for
2699
2729
* intervals
2700
2730
*/
2701
- sprintf (s , "%0*d" , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2702
- tm -> tm_hour % (HOURS_PER_DAY / 2 ) == 0 ? HOURS_PER_DAY / 2 :
2703
- tm -> tm_hour % (HOURS_PER_DAY / 2 ));
2731
+ sprintf (s , "%0*lld" , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2732
+ tm -> tm_hour % (HOURS_PER_DAY / 2 ) == 0 ?
2733
+ (long long ) (HOURS_PER_DAY / 2 ) :
2734
+ (long long ) (tm -> tm_hour % (HOURS_PER_DAY / 2 )));
2704
2735
if (S_THth (n -> suffix ))
2705
2736
str_numth (s , s , S_TH_TYPE (n -> suffix ));
2706
2737
s += strlen (s );
2707
2738
break ;
2708
2739
case DCH_HH24 :
2709
- sprintf (s , "%0*d " , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2710
- tm -> tm_hour );
2740
+ sprintf (s , "%0*lld " , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2741
+ ( long long ) tm -> tm_hour );
2711
2742
if (S_THth (n -> suffix ))
2712
2743
str_numth (s , s , S_TH_TYPE (n -> suffix ));
2713
2744
s += strlen (s );
@@ -2755,9 +2786,10 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
2755
2786
break ;
2756
2787
#undef DCH_to_char_fsec
2757
2788
case DCH_SSSS :
2758
- sprintf (s , "%d" , tm -> tm_hour * SECS_PER_HOUR +
2759
- tm -> tm_min * SECS_PER_MINUTE +
2760
- tm -> tm_sec );
2789
+ sprintf (s , "%lld" ,
2790
+ (long long ) (tm -> tm_hour * SECS_PER_HOUR +
2791
+ tm -> tm_min * SECS_PER_MINUTE +
2792
+ tm -> tm_sec ));
2761
2793
if (S_THth (n -> suffix ))
2762
2794
str_numth (s , s , S_TH_TYPE (n -> suffix ));
2763
2795
s += strlen (s );
@@ -4088,7 +4120,8 @@ timestamp_to_char(PG_FUNCTION_ARGS)
4088
4120
text * fmt = PG_GETARG_TEXT_PP (1 ),
4089
4121
* res ;
4090
4122
TmToChar tmtc ;
4091
- struct pg_tm * tm ;
4123
+ struct pg_tm tt ;
4124
+ struct fmt_tm * tm ;
4092
4125
int thisdate ;
4093
4126
4094
4127
if (VARSIZE_ANY_EXHDR (fmt ) <= 0 || TIMESTAMP_NOT_FINITE (dt ))
@@ -4097,10 +4130,11 @@ timestamp_to_char(PG_FUNCTION_ARGS)
4097
4130
ZERO_tmtc (& tmtc );
4098
4131
tm = tmtcTm (& tmtc );
4099
4132
4100
- if (timestamp2tm (dt , NULL , tm , & tmtcFsec (& tmtc ), NULL , NULL ) != 0 )
4133
+ if (timestamp2tm (dt , NULL , & tt , & tmtcFsec (& tmtc ), NULL , NULL ) != 0 )
4101
4134
ereport (ERROR ,
4102
4135
(errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
4103
4136
errmsg ("timestamp out of range" )));
4137
+ COPY_tm (tm , & tt );
4104
4138
4105
4139
thisdate = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday );
4106
4140
tm -> tm_wday = (thisdate + 1 ) % 7 ;
@@ -4120,7 +4154,8 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
4120
4154
* res ;
4121
4155
TmToChar tmtc ;
4122
4156
int tz ;
4123
- struct pg_tm * tm ;
4157
+ struct pg_tm tt ;
4158
+ struct fmt_tm * tm ;
4124
4159
int thisdate ;
4125
4160
4126
4161
if (VARSIZE_ANY_EXHDR (fmt ) <= 0 || TIMESTAMP_NOT_FINITE (dt ))
@@ -4129,10 +4164,11 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
4129
4164
ZERO_tmtc (& tmtc );
4130
4165
tm = tmtcTm (& tmtc );
4131
4166
4132
- if (timestamp2tm (dt , & tz , tm , & tmtcFsec (& tmtc ), & tmtcTzn (& tmtc ), NULL ) != 0 )
4167
+ if (timestamp2tm (dt , & tz , & tt , & tmtcFsec (& tmtc ), & tmtcTzn (& tmtc ), NULL ) != 0 )
4133
4168
ereport (ERROR ,
4134
4169
(errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
4135
4170
errmsg ("timestamp out of range" )));
4171
+ COPY_tm (tm , & tt );
4136
4172
4137
4173
thisdate = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday );
4138
4174
tm -> tm_wday = (thisdate + 1 ) % 7 ;
@@ -4156,16 +4192,24 @@ interval_to_char(PG_FUNCTION_ARGS)
4156
4192
text * fmt = PG_GETARG_TEXT_PP (1 ),
4157
4193
* res ;
4158
4194
TmToChar tmtc ;
4159
- struct pg_tm * tm ;
4195
+ struct fmt_tm * tm ;
4196
+ struct pg_itm tt ,
4197
+ * itm = & tt ;
4160
4198
4161
4199
if (VARSIZE_ANY_EXHDR (fmt ) <= 0 )
4162
4200
PG_RETURN_NULL ();
4163
4201
4164
4202
ZERO_tmtc (& tmtc );
4165
4203
tm = tmtcTm (& tmtc );
4166
4204
4167
- if (interval2tm (* it , tm , & tmtcFsec (& tmtc )) != 0 )
4168
- PG_RETURN_NULL ();
4205
+ interval2itm (* it , itm );
4206
+ tmtc .fsec = itm -> tm_usec ;
4207
+ tm -> tm_sec = itm -> tm_sec ;
4208
+ tm -> tm_min = itm -> tm_min ;
4209
+ tm -> tm_hour = itm -> tm_hour ;
4210
+ tm -> tm_mday = itm -> tm_mday ;
4211
+ tm -> tm_mon = itm -> tm_mon ;
4212
+ tm -> tm_year = itm -> tm_year ;
4169
4213
4170
4214
/* wday is meaningless, yday approximates the total span in days */
4171
4215
tm -> tm_yday = (tm -> tm_year * MONTHS_PER_YEAR + tm -> tm_mon ) * DAYS_PER_MONTH + tm -> tm_mday ;
0 commit comments