Skip to content

Commit 7218aab

Browse files
committed
Adjust not-too-sane calculation of DDD value for to_char(interval).
Per gripe from Chris Matheson.
1 parent 8130cbc commit 7218aab

File tree

1 file changed

+34
-28
lines changed

1 file changed

+34
-28
lines changed

src/backend/utils/adt/formatting.c

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* -----------------------------------------------------------------------
22
* formatting.c
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.100 2005/10/15 02:49:28 momjian Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.101 2005/10/20 15:59:46 tgl Exp $
55
*
66
*
77
* Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
@@ -2724,15 +2724,12 @@ static text *
27242724
datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval)
27252725
{
27262726
FormatNode *format;
2727-
struct pg_tm *tm = NULL;
27282727
char *fmt_str,
27292728
*result;
27302729
bool incache;
27312730
int fmt_len = VARSIZE(fmt) - VARHDRSZ;
2732-
2733-
tm = tmtcTm(tmtc);
2734-
tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7;
2735-
tm->tm_yday = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(tm->tm_year, 1, 1) + 1;
2731+
int reslen;
2732+
text *res;
27362733

27372734
/*
27382735
* Convert fmt to C string
@@ -2742,9 +2739,10 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval)
27422739
*(fmt_str + fmt_len) = '\0';
27432740

27442741
/*
2745-
* Allocate result
2742+
* Allocate workspace for result as C string
27462743
*/
27472744
result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
2745+
*result = '\0';
27482746

27492747
/*
27502748
* Allocate new memory if format picture is bigger than static cache and
@@ -2790,33 +2788,22 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval)
27902788
format = ent->format;
27912789
}
27922790

2791+
/* The real work is here */
27932792
DCH_processor(format, result, true, is_interval, (void *) tmtc);
27942793

27952794
if (!incache)
27962795
pfree(format);
27972796

27982797
pfree(fmt_str);
27992798

2800-
/*
2801-
* for result is allocated max memory, which current format-picture needs,
2802-
* now it allocate result with real size
2803-
*/
2804-
if (result && *result)
2805-
{
2806-
int len = strlen(result);
2807-
2808-
if (len)
2809-
{
2810-
text *res = (text *) palloc(len + 1 + VARHDRSZ);
2799+
/* convert C-string result to TEXT format */
2800+
reslen = strlen(result);
2801+
res = (text *) palloc(reslen + VARHDRSZ);
2802+
memcpy(VARDATA(res), result, reslen);
2803+
VARATT_SIZEP(res) = reslen + VARHDRSZ;
28112804

2812-
memcpy(VARDATA(res), result, len);
2813-
VARATT_SIZEP(res) = len + VARHDRSZ;
2814-
pfree(result);
2815-
return res;
2816-
}
2817-
}
28182805
pfree(result);
2819-
return NULL;
2806+
return res;
28202807
}
28212808

28222809
/****************************************************************************
@@ -2834,17 +2821,24 @@ timestamp_to_char(PG_FUNCTION_ARGS)
28342821
text *fmt = PG_GETARG_TEXT_P(1),
28352822
*res;
28362823
TmToChar tmtc;
2824+
struct pg_tm *tm;
2825+
int thisdate;
28372826

28382827
if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
28392828
PG_RETURN_NULL();
28402829

28412830
ZERO_tmtc(&tmtc);
2831+
tm = tmtcTm(&tmtc);
28422832

2843-
if (timestamp2tm(dt, NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL, NULL) != 0)
2833+
if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0)
28442834
ereport(ERROR,
28452835
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
28462836
errmsg("timestamp out of range")));
28472837

2838+
thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
2839+
tm->tm_wday = (thisdate + 1) % 7;
2840+
tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
2841+
28482842
if (!(res = datetime_to_char_body(&tmtc, fmt, false)))
28492843
PG_RETURN_NULL();
28502844

@@ -2859,17 +2853,24 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
28592853
*res;
28602854
TmToChar tmtc;
28612855
int tz;
2856+
struct pg_tm *tm;
2857+
int thisdate;
28622858

28632859
if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
28642860
PG_RETURN_NULL();
28652861

28662862
ZERO_tmtc(&tmtc);
2863+
tm = tmtcTm(&tmtc);
28672864

2868-
if (timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
2865+
if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
28692866
ereport(ERROR,
28702867
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
28712868
errmsg("timestamp out of range")));
28722869

2870+
thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
2871+
tm->tm_wday = (thisdate + 1) % 7;
2872+
tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
2873+
28732874
if (!(res = datetime_to_char_body(&tmtc, fmt, false)))
28742875
PG_RETURN_NULL();
28752876

@@ -2888,15 +2889,20 @@ interval_to_char(PG_FUNCTION_ARGS)
28882889
text *fmt = PG_GETARG_TEXT_P(1),
28892890
*res;
28902891
TmToChar tmtc;
2892+
struct pg_tm *tm;
28912893

28922894
if ((VARSIZE(fmt) - VARHDRSZ) <= 0)
28932895
PG_RETURN_NULL();
28942896

28952897
ZERO_tmtc(&tmtc);
2898+
tm = tmtcTm(&tmtc);
28962899

2897-
if (interval2tm(*it, tmtcTm(&tmtc), &tmtcFsec(&tmtc)) != 0)
2900+
if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0)
28982901
PG_RETURN_NULL();
28992902

2903+
/* wday is meaningless, yday approximates the total span in days */
2904+
tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
2905+
29002906
if (!(res = datetime_to_char_body(&tmtc, fmt, true)))
29012907
PG_RETURN_NULL();
29022908

0 commit comments

Comments
 (0)