Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit82dd570

Browse files
committed
Fix out-of-bound memory access for interval -> char conversion
Using Roman numbers (via "RM" or "rm") for a conversion to calculate anumber of months has never considered the case of negative numbers,where a conversion could easily cause out-of-bound memory accesses. Theconversions in themselves were not completely consistent either, asspecifying 12 would result in NULL, but it should mean XII.This commit reworks the conversion calculation to have a moreconsistent behavior:- If the number of months and years is 0, return NULL.- If the number of months is positive, return the exact month number.- If the number of months is negative, do a backward calculation, with-1 meaning December, -2 November, etc.Reported-by: Theodor Arsenij Larionov-TrichkinAuthor: Julien RouhaudDiscussion:https://postgr.es/m/16953-f255a18f8c51f1d5@postgresql.orgbackpatch-through: 9.6
1 parent2bf44fb commit82dd570

File tree

3 files changed

+95
-10
lines changed

3 files changed

+95
-10
lines changed

‎src/backend/utils/adt/formatting.c

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2973,18 +2973,61 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
29732973
s+=strlen(s);
29742974
break;
29752975
caseDCH_RM:
2976-
if (!tm->tm_mon)
2977-
break;
2978-
sprintf(s,"%*s",S_FM(n->suffix) ?0 :-4,
2979-
rm_months_upper[MONTHS_PER_YEAR-tm->tm_mon]);
2980-
s+=strlen(s);
2981-
break;
2976+
/* FALLTHROUGH */
29822977
caseDCH_rm:
2983-
if (!tm->tm_mon)
2978+
2979+
/*
2980+
* For intervals, values like '12 month' will be reduced to 0
2981+
* month and some years. These should be processed.
2982+
*/
2983+
if (!tm->tm_mon&& !tm->tm_year)
29842984
break;
2985-
sprintf(s,"%*s",S_FM(n->suffix) ?0 :-4,
2986-
rm_months_lower[MONTHS_PER_YEAR-tm->tm_mon]);
2987-
s+=strlen(s);
2985+
else
2986+
{
2987+
intmon=0;
2988+
constchar*const*months;
2989+
2990+
if (n->key->id==DCH_RM)
2991+
months=rm_months_upper;
2992+
else
2993+
months=rm_months_lower;
2994+
2995+
/*
2996+
* Compute the position in the roman-numeral array. Note
2997+
* that the contents of the array are reversed, December
2998+
* being first and January last.
2999+
*/
3000+
if (tm->tm_mon==0)
3001+
{
3002+
/*
3003+
* This case is special, and tracks the case of full
3004+
* interval years.
3005+
*/
3006+
mon=tm->tm_year >=0 ?0 :MONTHS_PER_YEAR-1;
3007+
}
3008+
elseif (tm->tm_mon<0)
3009+
{
3010+
/*
3011+
* Negative case. In this case, the calculation is
3012+
* reversed, where -1 means December, -2 November,
3013+
* etc.
3014+
*/
3015+
mon=-1* (tm->tm_mon+1);
3016+
}
3017+
else
3018+
{
3019+
/*
3020+
* Common case, with a strictly positive value. The
3021+
* position in the array matches with the value of
3022+
* tm_mon.
3023+
*/
3024+
mon=MONTHS_PER_YEAR-tm->tm_mon;
3025+
}
3026+
3027+
sprintf(s,"%*s",S_FM(n->suffix) ?0 :-4,
3028+
months[mon]);
3029+
s+=strlen(s);
3030+
}
29883031
break;
29893032
caseDCH_W:
29903033
sprintf(s,"%d", (tm->tm_mday-1) /7+1);

‎src/test/regress/expected/timestamp.out

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,42 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
16881688
| 2001 1 1 1 1 1 1
16891689
(65 rows)
16901690

1691+
-- Roman months, with upper and lower case.
1692+
SELECT i,
1693+
to_char(i * interval '1mon', 'rm'),
1694+
to_char(i * interval '1mon', 'RM')
1695+
FROM generate_series(-13, 13) i;
1696+
i | to_char | to_char
1697+
-----+---------+---------
1698+
-13 | xii | XII
1699+
-12 | i | I
1700+
-11 | ii | II
1701+
-10 | iii | III
1702+
-9 | iv | IV
1703+
-8 | v | V
1704+
-7 | vi | VI
1705+
-6 | vii | VII
1706+
-5 | viii | VIII
1707+
-4 | ix | IX
1708+
-3 | x | X
1709+
-2 | xi | XI
1710+
-1 | xii | XII
1711+
0 | |
1712+
1 | i | I
1713+
2 | ii | II
1714+
3 | iii | III
1715+
4 | iv | IV
1716+
5 | v | V
1717+
6 | vi | VI
1718+
7 | vii | VII
1719+
8 | viii | VIII
1720+
9 | ix | IX
1721+
10 | x | X
1722+
11 | xi | XI
1723+
12 | xii | XII
1724+
13 | i | I
1725+
(27 rows)
1726+
16911727
-- timestamp numeric fields constructor
16921728
SELECT make_timestamp(2014,12,28,6,30,45.887);
16931729
make_timestamp

‎src/test/regress/sql/timestamp.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,11 @@ SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID')
231231
SELECT''AS to_char_11, to_char(d1,'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
232232
FROM TIMESTAMP_TBL;
233233

234+
-- Roman months, with upper and lower case.
235+
SELECT i,
236+
to_char(i* interval'1mon','rm'),
237+
to_char(i* interval'1mon','RM')
238+
FROM generate_series(-13,13) i;
239+
234240
-- timestamp numeric fields constructor
235241
SELECT make_timestamp(2014,12,28,6,30,45.887);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp