Commit e2026112 authored by Bruce Momjian's avatar Bruce Momjian

Fix to_char(interval) to return proper year and century values.

Fix to_char(interval) to return large year/month/day/hour values that
are larger than possible timestamp values.
Prevent to_char(interval) format specifications that make no sense, like
Month.
Clean up formatting.c code to more logically handle return lengths.
parent f8d0a82b
/* -----------------------------------------------------------------------
* formatting.c
*
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.97 2005/08/17 22:06:53 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.98 2005/08/18 04:37:08 momjian Exp $
*
*
* Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
......@@ -136,7 +136,7 @@ typedef struct
const char *name; /* keyword */
int len; /* keyword length */
int (*action) (int arg, char *inout, /* action for keyword */
int suf, bool is_to_char,
int suf, bool is_to_char, bool is_interval,
FormatNode *node, void *data);
int id; /* keyword id */
bool isitdigit; /* is expected output/input digit */
......@@ -171,7 +171,12 @@ static char *months_full[] = {
* AC / DC
* ----------
*/
#define YEAR_ABS(_y) ((_y) <= 0 ? -((_y) - 1) : _y)
/*
* There is no 0 AD. Years go from 1 BC to 1 AD, so we make it
* positive and map year == -1 to year zero, and shift all negative
* years up one. For interval years, we just return the year.
*/
#define ADJUST_YEAR(year, is_interval) ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
#define BC_STR_ORIG " BC"
#define A_D_STR "A.D."
......@@ -429,13 +434,24 @@ typedef struct TmToChar
tmtcTzn(_X) = NULL; \
} while(0)
#define INVALID_FOR_INTERVAL \
do { \
if (is_interval) \
ereport(ERROR, \
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
errmsg("invalid format specification for an interval value"))); \
} while(0)
/*****************************************************************************
* KeyWords definition & action
*****************************************************************************/
static int dch_global(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void *data);
static int dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void *data);
static int dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void *data);
static int dch_global(int arg, char *inout, int suf, bool is_to_char,
bool is_interval, FormatNode *node, void *data);
static int dch_time(int arg, char *inout, int suf, bool is_to_char,
bool is_interval, FormatNode *node, void *data);
static int dch_date(int arg, char *inout, int suf, bool is_to_char,
bool is_interval, FormatNode *node, void *data);
/* ----------
* Suffixes:
......@@ -875,7 +891,8 @@ static KeySuffix *suff_search(char *str, KeySuffix *suf, int type);
static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
static void parse_format(FormatNode *node, char *str, const KeyWord *kw,
KeySuffix *suf, const int *index, int ver, NUMDesc *Num);
static char *DCH_processor(FormatNode *node, char *inout, bool is_to_char, void *data);
static char *DCH_processor(FormatNode *node, char *inout, bool is_to_char,
bool is_interval, void *data);
#ifdef DEBUG_TO_FROM_CHAR
static void dump_index(const KeyWord *k, const int *index);
......@@ -1290,12 +1307,12 @@ parse_format(FormatNode *node, char *str, const KeyWord *kw,
* ----------
*/
static char *
DCH_processor(FormatNode *node, char *inout, bool is_to_char, void *data)
DCH_processor(FormatNode *node, char *inout, bool is_to_char,
bool is_interval, void *data)
{
FormatNode *n;
char *s;
/*
* Zeroing global flags
*/
......@@ -1321,12 +1338,12 @@ DCH_processor(FormatNode *node, char *inout, bool is_to_char, void *data)
/*
* Call node action function
*/
len = n->key->action(n->key->id, s, n->suffix, is_to_char, n, data);
len = n->key->action(n->key->id, s, n->suffix, is_to_char,
is_interval, n, data);
if (len > 0)
s += len;
s += len - 1; /* s++ is at the end of the loop */
else if (len == -1)
continue;
}
else
{
......@@ -1618,7 +1635,8 @@ dump_index(const KeyWord *k, const int *index)
* ----------
*/
static int
dch_global(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void *data)
dch_global(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
FormatNode *node, void *data)
{
if (arg == DCH_FX)
DCH_global_fx = true;
......@@ -1684,7 +1702,8 @@ strdigits_len(char *str)
* ----------
*/
static int
dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void *data)
dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
FormatNode *node, void *data)
{
char *p_inout = inout;
struct pg_tm *tm = NULL;
......@@ -1703,11 +1722,12 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
{
case DCH_A_M:
case DCH_P_M:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, ((tm->tm_hour > 11
&& tm->tm_hour < HOURS_PER_DAY) ? P_M_STR : A_M_STR));
return 3;
return strlen(p_inout);
}
else
{
......@@ -1717,16 +1737,17 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
tmfc->am = TRUE;
else
AMPM_ERROR;
return 3;
return strlen(p_inout);
}
break;
case DCH_AM:
case DCH_PM:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, ((tm->tm_hour > 11
&& tm->tm_hour < HOURS_PER_DAY) ? PM_STR : AM_STR));
return 1;
return strlen(p_inout);
}
else
{
......@@ -1736,16 +1757,17 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
tmfc->am = TRUE;
else
AMPM_ERROR;
return 1;
return strlen(p_inout);
}
break;
case DCH_a_m:
case DCH_p_m:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, ((tm->tm_hour > 11
&& tm->tm_hour < HOURS_PER_DAY) ? p_m_STR : a_m_STR));
return 3;
return strlen(p_inout);
}
else
{
......@@ -1755,16 +1777,17 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
tmfc->am = TRUE;
else
AMPM_ERROR;
return 3;
return strlen(p_inout);
}
break;
case DCH_am:
case DCH_pm:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, ((tm->tm_hour > 11
&& tm->tm_hour < HOURS_PER_DAY) ? pm_STR : am_STR));
return 1;
return strlen(p_inout);
}
else
{
......@@ -1774,35 +1797,34 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
tmfc->am = TRUE;
else
AMPM_ERROR;
return 1;
return strlen(p_inout);
}
break;
case DCH_HH:
case DCH_HH12:
if (is_to_char)
{
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2,
tm->tm_hour == 0 ? 12 :
tm->tm_hour < 13 ? tm->tm_hour : tm->tm_hour - 12);
if (is_interval)
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_hour);
else
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2,
tm->tm_hour == 0 ? 12 :
tm->tm_hour < 13 ? tm->tm_hour : tm->tm_hour - 12);
if (S_THth(suf))
str_numth(p_inout, inout, 0);
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->hh);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->hh);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
......@@ -1812,23 +1834,19 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_hour);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->hh);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->hh);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
......@@ -1838,23 +1856,19 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_min);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->mi);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->mi);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
......@@ -1864,23 +1878,19 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_sec);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->ss);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->ss);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
......@@ -1894,11 +1904,7 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
#endif
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
return strlen(p_inout) - 1;
else
return 2;
return strlen(p_inout);
}
else
{
......@@ -1928,7 +1934,7 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
* elog(DEBUG3, "X: %d, MS: %d, LEN: %d", x, tmfc->ms,
* len);
*/
return len - 1 + SKIP_THth(suf);
return len + SKIP_THth(suf);
}
break;
case DCH_US: /* microsecond */
......@@ -1941,10 +1947,7 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
#endif
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
return strlen(p_inout) - 1;
else
return 5;
return strlen(p_inout);
}
else
{
......@@ -1973,7 +1976,7 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
* elog(DEBUG3, "X: %d, US: %d, LEN: %d", x, tmfc->us,
* len);
*/
return len - 1 + SKIP_THth(suf);
return len + SKIP_THth(suf);
}
break;
case DCH_SSSS:
......@@ -1984,24 +1987,25 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
tm->tm_sec);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout) - 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->ssss);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%05d", &tmfc->ssss);
return 4 + SKIP_THth(suf);
return 5 + SKIP_THth(suf);
}
}
break;
case DCH_tz:
case DCH_TZ:
INVALID_FOR_INTERVAL;
if (is_to_char && tmtcTzn(tmtc))
{
int siz = strlen(tmtcTzn(tmtc));
......@@ -2016,7 +2020,7 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
strcpy(inout, str_tolower(p));
pfree(p);
}
return siz - 1;
return siz;
}
else if (!is_to_char)
ereport(ERROR,
......@@ -2043,11 +2047,12 @@ do { \
* ----------
*/
static int
dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void *data)
dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
FormatNode *node, void *data)
{
char buff[DCH_CACHE_SIZE],
workbuff[32],
*p_inout;
*p_inout = inout;
int i,
len;
struct pg_tm *tm = NULL;
......@@ -2062,8 +2067,6 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
else
tmfc = (TmFromChar *) data;
p_inout = inout;
/*
* In the FROM-char is not difference between "January" or "JANUARY"
* or "january", all is before search convert to "first-upper". This
......@@ -2076,32 +2079,30 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
tmfc->mm = seq_search(inout, months_full, ONE_UPPER, FULL_SIZ, &len) + 1;
CHECK_SEQ_SEARCH(len, "MONTH/Month/month");
if (S_FM(suf))
return len - 1;
return len;
else
return 8;
return 9;
}
else if (arg == DCH_MON || arg == DCH_Mon || arg == DCH_mon)
{
tmfc->mm = seq_search(inout, months, ONE_UPPER, MAX_MON_LEN, &len) + 1;
CHECK_SEQ_SEARCH(len, "MON/Mon/mon");
return 2;
return 3;
}
else if (arg == DCH_DAY || arg == DCH_Day || arg == DCH_day)
{
tmfc->d = seq_search(inout, days, ONE_UPPER, FULL_SIZ, &len);
CHECK_SEQ_SEARCH(len, "DAY/Day/day");
if (S_FM(suf))
return len - 1;
return len;
else
return 8;
return 9;
}
else if (arg == DCH_DY || arg == DCH_Dy || arg == DCH_dy)
{
tmfc->d = seq_search(inout, days, ONE_UPPER, MAX_DY_LEN, &len);
CHECK_SEQ_SEARCH(len, "DY/Dy/dy");
return 2;
return 3;
}
}
......@@ -2109,112 +2110,109 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
{
case DCH_A_D:
case DCH_B_C:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
return 3;
return strlen(p_inout);
}
else
{
if (strncmp(inout, B_C_STR, 4) == 0)
tmfc->bc = TRUE;
return 3;
return 4;
}
break;
case DCH_AD:
case DCH_BC:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, (tm->tm_year <= 0 ? BC_STR : AD_STR));
return 1;
return strlen(p_inout);
}
else
{
if (strncmp(inout, BC_STR, 2) == 0)
tmfc->bc = TRUE;
return 1;
return 2;
}
break;
case DCH_a_d:
case DCH_b_c:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
return 3;
return strlen(p_inout);
}
else
{
if (strncmp(inout, b_c_STR, 4) == 0)
tmfc->bc = TRUE;
return 3;
return 4;
}
break;
case DCH_ad:
case DCH_bc:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
strcpy(inout, (tm->tm_year <= 0 ? bc_STR : ad_STR));
return 1;
return strlen(p_inout);
}
else
{
if (strncmp(inout, bc_STR, 2) == 0)
tmfc->bc = TRUE;
return 1;
return 2;
}
break;
case DCH_MONTH:
INVALID_FOR_INTERVAL;
if (!tm->tm_mon)
return -1;
strcpy(workbuff, months_full[tm->tm_mon - 1]);
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(workbuff));
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 8;
return strlen(p_inout);
case DCH_Month:
INVALID_FOR_INTERVAL;
if (!tm->tm_mon)
return -1;
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 8;
return strlen(p_inout);
case DCH_month:
INVALID_FOR_INTERVAL;
if (!tm->tm_mon)
return -1;
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
*inout = pg_tolower((unsigned char) *inout);
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 8;
return strlen(p_inout);
case DCH_MON:
INVALID_FOR_INTERVAL;
if (!tm->tm_mon)
return -1;
strcpy(inout, months[tm->tm_mon - 1]);
inout = str_toupper(inout);
return 2;
str_toupper(inout);
return strlen(p_inout);
case DCH_Mon:
INVALID_FOR_INTERVAL;
if (!tm->tm_mon)
return -1;
strcpy(inout, months[tm->tm_mon - 1]);
return 2;
return strlen(p_inout);
case DCH_mon:
INVALID_FOR_INTERVAL;
if (!tm->tm_mon)
return -1;
strcpy(inout, months[tm->tm_mon - 1]);
*inout = pg_tolower((unsigned char) *inout);
return 2;
return strlen(p_inout);
case DCH_MM:
if (is_to_char)
......@@ -2222,61 +2220,55 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mon);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->mm);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->mm);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
case DCH_DAY:
INVALID_FOR_INTERVAL;
strcpy(workbuff, days[tm->tm_wday]);
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(workbuff));
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 8;
return strlen(p_inout);
case DCH_Day:
INVALID_FOR_INTERVAL;
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 8;
return strlen(p_inout);
case DCH_day:
INVALID_FOR_INTERVAL;
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
*inout = pg_tolower((unsigned char) *inout);
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 8;
return strlen(p_inout);
case DCH_DY:
INVALID_FOR_INTERVAL;
strcpy(inout, days[tm->tm_wday]);
inout = str_toupper(inout);
return 2;
str_toupper(inout);
return 3; /* truncate */
case DCH_Dy:
INVALID_FOR_INTERVAL;
strcpy(inout, days[tm->tm_wday]);
return 2;
return 3; /* truncate */
case DCH_dy:
INVALID_FOR_INTERVAL;
strcpy(inout, days[tm->tm_wday]);
*inout = pg_tolower((unsigned char) *inout);
return 2;
return 3; /* truncate */
case DCH_DDD:
if (is_to_char)
......@@ -2284,23 +2276,19 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 3, tm->tm_yday);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 2;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->ddd);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%03d", &tmfc->ddd);
return 2 + SKIP_THth(suf);
return 3 + SKIP_THth(suf);
}
}
break;
......@@ -2310,41 +2298,35 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mday);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->dd);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->dd);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
case DCH_D:
INVALID_FOR_INTERVAL;
if (is_to_char)
{
sprintf(inout, "%d", tm->tm_wday + 1);
if (S_THth(suf))
{
str_numth(p_inout, inout, S_TH_TYPE(suf));
return 2;
}
return 0;
return strlen(p_inout);
}
else
{
sscanf(inout, "%1d", &tmfc->d);
return 0 + SKIP_THth(suf);
return 1 + SKIP_THth(suf);
}
break;
case DCH_WW:
......@@ -2354,23 +2336,19 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
(tm->tm_yday - 1) / 7 + 1);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->ww);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->ww);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
......@@ -2381,22 +2359,19 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf))
return strlen(p_inout) - 1;
else
return 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->iw);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->iw);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
......@@ -2407,53 +2382,49 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
return -1;
sprintf(inout, "%d", (tm->tm_mon - 1) / 3 + 1);
if (S_THth(suf))
{
str_numth(p_inout, inout, S_TH_TYPE(suf));
return 2;
}
return 0;
return strlen(p_inout);
}
else
{
sscanf(inout, "%1d", &tmfc->q);
return 0 + SKIP_THth(suf);
return 1 + SKIP_THth(suf);
}
break;
case DCH_CC:
if (is_to_char)
{
i = tm->tm_year / 100 + 1;
i = tm->tm_year / 100 + ((is_interval) ? 0 : 1);
if (i <= 99 && i >= -99)
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, i);
else
sprintf(inout, "%d", i);
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout) - 1;
return strlen(p_inout);
}
else
{
if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->cc);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->cc);
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
}
break;
case DCH_Y_YYY:
if (is_to_char)
{
i = YEAR_ABS(tm->tm_year) / 1000;
sprintf(inout, "%d,%03d", i, YEAR_ABS(tm->tm_year) - (i * 1000));
i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
sprintf(inout, "%d,%03d", i, ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout) - 1;
return strlen(p_inout);
}
else
{
......@@ -2462,7 +2433,7 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sscanf(inout, "%d,%03d", &cc, &tmfc->year);
tmfc->year += (cc * 1000);
tmfc->yysz = 4;
return strdigits_len(inout) + 3 + SKIP_THth(suf);
return strdigits_len(inout) + 4 + SKIP_THth(suf);
}
break;
case DCH_YYYY:
......@@ -2473,22 +2444,22 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%0*d",
S_FM(suf) ? 0 : 4,
arg == DCH_YYYY ?
YEAR_ABS(tm->tm_year) :
YEAR_ABS(date2isoyear(
ADJUST_YEAR(tm->tm_year, is_interval) :
ADJUST_YEAR(date2isoyear(
tm->tm_year,
tm->tm_mon,
tm->tm_mday)));
tm->tm_mday), is_interval));
else
sprintf(inout, "%d",
arg == DCH_YYYY ?
YEAR_ABS(tm->tm_year) :
YEAR_ABS(date2isoyear(
ADJUST_YEAR(tm->tm_year, is_interval) :
ADJUST_YEAR(date2isoyear(
tm->tm_year,
tm->tm_mon,
tm->tm_mday)));
tm->tm_mday), is_interval));
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout) - 1;
return strlen(p_inout);
}
else
{
......@@ -2496,13 +2467,13 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
{
sscanf(inout, "%d", &tmfc->year);
tmfc->yysz = 4;
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
else
{
sscanf(inout, "%04d", &tmfc->year);
tmfc->yysz = 4;
return 3 + SKIP_THth(suf);
return 4 + SKIP_THth(suf);
}
}
break;
......@@ -2512,18 +2483,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
{
snprintf(buff, sizeof(buff), "%03d",
arg == DCH_YYY ?
YEAR_ABS(tm->tm_year) :
YEAR_ABS(date2isoyear(tm->tm_year,
tm->tm_mon, tm->tm_mday)));
ADJUST_YEAR(tm->tm_year, is_interval) :
ADJUST_YEAR(date2isoyear(tm->tm_year,
tm->tm_mon, tm->tm_mday),
is_interval));
i = strlen(buff);
strcpy(inout, buff + (i - 3));
if (S_THth(suf))
{
str_numth(p_inout, inout, S_TH_TYPE(suf));
return 4;
}
return 2;
return strlen(p_inout);
}
else
{
......@@ -2538,7 +2506,7 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
else
tmfc->year += 2000;
tmfc->yysz = 3;
return 2 + SKIP_THth(suf);
return 3 + SKIP_THth(suf);
}
break;
case DCH_YY:
......@@ -2547,18 +2515,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
{
snprintf(buff, sizeof(buff), "%02d",
arg == DCH_YY ?
YEAR_ABS(tm->tm_year) :
YEAR_ABS(date2isoyear(tm->tm_year,
tm->tm_mon, tm->tm_mday)));
ADJUST_YEAR(tm->tm_year, is_interval) :
ADJUST_YEAR(date2isoyear(tm->tm_year,
tm->tm_mon, tm->tm_mday),
is_interval));
i = strlen(buff);
strcpy(inout, buff + (i - 2));
if (S_THth(suf))
{
str_numth(p_inout, inout, S_TH_TYPE(suf));
return 3;
}
return 1;
return strlen(p_inout);
}
else
{
......@@ -2573,7 +2538,7 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
else
tmfc->year += 1900;
tmfc->yysz = 2;
return 1 + SKIP_THth(suf);
return 2 + SKIP_THth(suf);
}
break;
case DCH_Y:
......@@ -2582,18 +2547,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
{
snprintf(buff, sizeof(buff), "%1d",
arg == DCH_Y ?
YEAR_ABS(tm->tm_year) :
YEAR_ABS(date2isoyear(tm->tm_year,
tm->tm_mon, tm->tm_mday)));
ADJUST_YEAR(tm->tm_year, is_interval) :
ADJUST_YEAR(date2isoyear(tm->tm_year,
tm->tm_mon, tm->tm_mday),
is_interval));
i = strlen(buff);
strcpy(inout, buff + (i - 1));
if (S_THth(suf))
{
str_numth(p_inout, inout, S_TH_TYPE(suf));
return 2;
}
return 0;
return strlen(p_inout);
}
else
{
......@@ -2604,7 +2566,7 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
*/
tmfc->year += 2000;
tmfc->yysz = 1;
return 0 + SKIP_THth(suf);
return 1 + SKIP_THth(suf);
}
break;
case DCH_RM:
......@@ -2614,20 +2576,16 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
return -1;
sprintf(inout, "%*s", S_FM(suf) ? 0 : -4,
rm_months_upper[12 - tm->tm_mon]);
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 3;
return strlen(p_inout);
}
else
{
tmfc->mm = 12 - seq_search(inout, rm_months_upper, ALL_UPPER, FULL_SIZ, &len);
CHECK_SEQ_SEARCH(len, "RM");
if (S_FM(suf))
return len - 1;
return len;
else
return 3;
return 4;
}
break;
case DCH_rm:
......@@ -2637,20 +2595,16 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
return -1;
sprintf(inout, "%*s", S_FM(suf) ? 0 : -4,
rm_months_lower[12 - tm->tm_mon]);
if (S_FM(suf))
return strlen(p_inout) - 1;
else
return 3;
return strlen(p_inout);
}
else
{
tmfc->mm = 12 - seq_search(inout, rm_months_lower, ALL_LOWER, FULL_SIZ, &len);
CHECK_SEQ_SEARCH(len, "rm");
if (S_FM(suf))
return len - 1;
return len;
else
return 3;
return 4;
}
break;
case DCH_W:
......@@ -2658,16 +2612,13 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
{
sprintf(inout, "%d", (tm->tm_mday - 1) / 7 + 1);
if (S_THth(suf))
{
str_numth(p_inout, inout, S_TH_TYPE(suf));
return 2;
}
return 0;
return strlen(p_inout);
}
else
{
sscanf(inout, "%1d", &tmfc->w);
return 0 + SKIP_THth(suf);
return 1 + SKIP_THth(suf);
}
break;
case DCH_J:
......@@ -2676,12 +2627,12 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, FormatNode *node, void
sprintf(inout, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout) - 1;
return strlen(p_inout);
}
else
{
sscanf(inout, "%d", &tmfc->j);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
return strdigits_len(inout) + SKIP_THth(suf);
}
break;
}
......@@ -2725,7 +2676,6 @@ DCH_cache_getnew(char *str)
/* old->format fill parser */
old->age = (++DCHCounter);
return old;
}
else
{
......@@ -2774,7 +2724,7 @@ DCH_cache_search(char *str)
}
static text *
datetime_to_char_body(TmToChar *tmtc, text *fmt)
datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval)
{
FormatNode *format;
struct pg_tm *tm = NULL;
......@@ -2812,7 +2762,6 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt)
DCH_suff, DCH_index, DCH_TYPE, NULL);
(format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */
}
else
{
......@@ -2825,7 +2774,6 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt)
if ((ent = DCH_cache_search(fmt_str)) == NULL)
{
ent = DCH_cache_getnew(fmt_str);
/*
......@@ -2845,7 +2793,7 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt)
format = ent->format;
}
DCH_processor(format, result, true, (void *) tmtc);
DCH_processor(format, result, true, is_interval, (void *) tmtc);
if (!incache)
pfree(format);
......@@ -2900,7 +2848,7 @@ timestamp_to_char(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (!(res = datetime_to_char_body(&tmtc, fmt)))
if (!(res = datetime_to_char_body(&tmtc, fmt, false)))
PG_RETURN_NULL();
PG_RETURN_TEXT_P(res);
......@@ -2925,7 +2873,7 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
if (!(res = datetime_to_char_body(&tmtc, fmt)))
if (!(res = datetime_to_char_body(&tmtc, fmt, false)))
PG_RETURN_NULL();
PG_RETURN_TEXT_P(res);
......@@ -2952,7 +2900,7 @@ interval_to_char(PG_FUNCTION_ARGS)
if (interval2tm(*it, tmtcTm(&tmtc), &tmtcFsec(&tmtc)) != 0)
PG_RETURN_NULL();
if (!(res = datetime_to_char_body(&tmtc, fmt)))
if (!(res = datetime_to_char_body(&tmtc, fmt, true)))
PG_RETURN_NULL();
PG_RETURN_TEXT_P(res);
......@@ -3099,7 +3047,7 @@ do_to_timestamp(text *date_txt, text *fmt,
memcpy(date_str, VARDATA(date_txt), date_len);
*(date_str + date_len) = '\0';
DCH_processor(format, date_str, false, (void *) &tmfc);
DCH_processor(format, date_str, false, false, (void *) &tmfc);
pfree(date_str);
pfree(fmt_str);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment