v2-fix_rm.diff
text/plain
Filename: v2-fix_rm.diff
Type: text/plain
Part: 0
Patch
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/utils/adt/formatting.c | 28 | 10 |
| src/test/regress/expected/timestamp.out | 33 | 0 |
| src/test/regress/sql/timestamp.sql | 3 | 0 |
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 783c7b5e7a..80138d6347 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -3207,18 +3207,36 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
s += strlen(s);
break;
case DCH_RM:
- if (!tm->tm_mon)
- break;
- sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
- rm_months_upper[MONTHS_PER_YEAR - tm->tm_mon]);
- s += strlen(s);
- break;
+ /* FALLTHROUGH */
case DCH_rm:
- if (!tm->tm_mon)
+ /*
+ * For intervals, values like '12 month' will be reduced to 0
+ * month and some years, which we want to process.
+ */
+ if (!tm->tm_mon && !tm->tm_year)
break;
- sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
- rm_months_lower[MONTHS_PER_YEAR - tm->tm_mon]);
- s += strlen(s);
+ else
+ {
+ int mon = tm->tm_mon;
+ const char * const* months;
+
+ if (n->key->id == DCH_RM)
+ months = rm_months_upper;
+ else
+ months = rm_months_lower;
+
+ if (mon == 0)
+ {
+ Assert(is_interval);
+ mon = tm->tm_year >= 0 ? MONTHS_PER_YEAR : 1;
+ }
+ else if (mon < 0)
+ mon = MONTHS_PER_YEAR + mon + 1;
+
+ sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
+ months[MONTHS_PER_YEAR - mon]);
+ s += strlen(s);
+ }
break;
case DCH_W:
sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index 690656dfb2..7c77fcae71 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -1907,6 +1907,39 @@ SELECT to_char(d, 'FF1 FF2 FF3 FF4 FF5 FF6 ff1 ff2 ff3 ff4 ff5 ff6 MS US')
7 78 789 7890 78901 789012 7 78 789 7890 78901 789012 789 789012
(4 rows)
+SELECT i, to_char(i * interval '1mon', 'rm'), to_char(i * interval '1mon', 'RM')
+ FROM generate_series(-13, 13) i;
+ i | to_char | to_char
+-----+---------+---------
+ -13 | xii | XII
+ -12 | i | I
+ -11 | ii | II
+ -10 | iii | III
+ -9 | iv | IV
+ -8 | v | V
+ -7 | vi | VI
+ -6 | vii | VII
+ -5 | viii | VIII
+ -4 | ix | IX
+ -3 | x | X
+ -2 | xi | XI
+ -1 | xii | XII
+ 0 | |
+ 1 | i | I
+ 2 | ii | II
+ 3 | iii | III
+ 4 | iv | IV
+ 5 | v | V
+ 6 | vi | VI
+ 7 | vii | VII
+ 8 | viii | VIII
+ 9 | ix | IX
+ 10 | x | X
+ 11 | xi | XI
+ 12 | xii | XII
+ 13 | i | I
+(27 rows)
+
-- timestamp numeric fields constructor
SELECT make_timestamp(2014, 12, 28, 6, 30, 45.887);
make_timestamp
diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql
index c43a1f2268..3ae9a52347 100644
--- a/src/test/regress/sql/timestamp.sql
+++ b/src/test/regress/sql/timestamp.sql
@@ -319,6 +319,9 @@ SELECT to_char(d, 'FF1 FF2 FF3 FF4 FF5 FF6 ff1 ff2 ff3 ff4 ff5 ff6 MS US')
('2018-11-02 12:34:56.78901234')
) d(d);
+SELECT i, to_char(i * interval '1mon', 'rm'), to_char(i * interval '1mon', 'RM')
+ FROM generate_series(-13, 13) i;
+
-- timestamp numeric fields constructor
SELECT make_timestamp(2014, 12, 28, 6, 30, 45.887);
SELECT make_timestamp(-44, 3, 15, 12, 30, 15);