From 7218aab7a2d14a446945887b3ea80cfa1f0034f0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 20 Oct 2005 15:59:46 +0000 Subject: [PATCH] Adjust not-too-sane calculation of DDD value for to_char(interval). Per gripe from Chris Matheson. --- src/backend/utils/adt/formatting.c | 62 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 90e940e7b9..de84afe42c 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.100 2005/10/15 02:49:28 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.101 2005/10/20 15:59:46 tgl Exp $ * * * Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group @@ -2724,15 +2724,12 @@ static text * datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval) { FormatNode *format; - struct pg_tm *tm = NULL; char *fmt_str, *result; bool incache; int fmt_len = VARSIZE(fmt) - VARHDRSZ; - - tm = tmtcTm(tmtc); - tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7; - tm->tm_yday = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(tm->tm_year, 1, 1) + 1; + int reslen; + text *res; /* * Convert fmt to C string @@ -2742,9 +2739,10 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval) *(fmt_str + fmt_len) = '\0'; /* - * Allocate result + * Allocate workspace for result as C string */ result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1); + *result = '\0'; /* * Allocate new memory if format picture is bigger than static cache and @@ -2790,6 +2788,7 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval) format = ent->format; } + /* The real work is here */ DCH_processor(format, result, true, is_interval, (void *) tmtc); if (!incache) @@ -2797,26 +2796,14 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval) pfree(fmt_str); - /* - * for result is allocated max memory, which current format-picture needs, - * now it allocate result with real size - */ - if (result && *result) - { - int len = strlen(result); + /* convert C-string result to TEXT format */ + reslen = strlen(result); + res = (text *) palloc(reslen + VARHDRSZ); + memcpy(VARDATA(res), result, reslen); + VARATT_SIZEP(res) = reslen + VARHDRSZ; - if (len) - { - text *res = (text *) palloc(len + 1 + VARHDRSZ); - - memcpy(VARDATA(res), result, len); - VARATT_SIZEP(res) = len + VARHDRSZ; - pfree(result); - return res; - } - } pfree(result); - return NULL; + return res; } /**************************************************************************** @@ -2834,17 +2821,24 @@ timestamp_to_char(PG_FUNCTION_ARGS) text *fmt = PG_GETARG_TEXT_P(1), *res; TmToChar tmtc; + struct pg_tm *tm; + int thisdate; if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt)) PG_RETURN_NULL(); ZERO_tmtc(&tmtc); + tm = tmtcTm(&tmtc); - if (timestamp2tm(dt, NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL, NULL) != 0) + if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); + thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); + tm->tm_wday = (thisdate + 1) % 7; + tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1; + if (!(res = datetime_to_char_body(&tmtc, fmt, false))) PG_RETURN_NULL(); @@ -2859,17 +2853,24 @@ timestamptz_to_char(PG_FUNCTION_ARGS) *res; TmToChar tmtc; int tz; + struct pg_tm *tm; + int thisdate; if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt)) PG_RETURN_NULL(); ZERO_tmtc(&tmtc); + tm = tmtcTm(&tmtc); - if (timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0) + if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); + thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); + tm->tm_wday = (thisdate + 1) % 7; + tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1; + if (!(res = datetime_to_char_body(&tmtc, fmt, false))) PG_RETURN_NULL(); @@ -2888,15 +2889,20 @@ interval_to_char(PG_FUNCTION_ARGS) text *fmt = PG_GETARG_TEXT_P(1), *res; TmToChar tmtc; + struct pg_tm *tm; if ((VARSIZE(fmt) - VARHDRSZ) <= 0) PG_RETURN_NULL(); ZERO_tmtc(&tmtc); + tm = tmtcTm(&tmtc); - if (interval2tm(*it, tmtcTm(&tmtc), &tmtcFsec(&tmtc)) != 0) + if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0) PG_RETURN_NULL(); + /* wday is meaningless, yday approximates the total span in days */ + tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday; + if (!(res = datetime_to_char_body(&tmtc, fmt, true))) PG_RETURN_NULL();