diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index c90f48d00a..74d89c6357 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -964,7 +964,6 @@ static const char *get_th(char *num, int type); static char *str_numth(char *dest, char *num, int type); static int adjust_partial_year_to_2020(int year); static int strspace_len(char *str); -static int strdigits_len(char *str); static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode); static void from_char_set_int(int *dest, const int value, const FormatNode *node); static int from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node); @@ -1976,9 +1975,19 @@ asc_toupper_z(const char *buff) /* ---------- * Skip TM / th in FROM_CHAR + * + * If S_THth is on, skip two chars, assuming there are two available * ---------- */ -#define SKIP_THth(_suf) (S_THth(_suf) ? 2 : 0) +#define SKIP_THth(ptr, _suf) \ + do { \ + if (S_THth(_suf)) \ + { \ + if (*(ptr)) (ptr)++; \ + if (*(ptr)) (ptr)++; \ + } \ + } while (0) + #ifdef DEBUG_TO_FROM_CHAR /* ----------- @@ -2086,23 +2095,6 @@ strspace_len(char *str) return len; } -static int -strdigits_len(char *str) -{ - char *p = str; - int len; - - len = strspace_len(str); - p += len; - - while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ) - { - len++; - p++; - } - return len; -} - /* * Set the date mode of a from-char conversion. * @@ -3007,19 +2999,19 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) case DCH_HH12: from_char_parse_int_len(&out->hh, &s, 2, n); out->clock = CLOCK_12_HOUR; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_HH24: from_char_parse_int_len(&out->hh, &s, 2, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_MI: from_char_parse_int(&out->mi, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_SS: from_char_parse_int(&out->ss, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_MS: /* millisecond */ len = from_char_parse_int_len(&out->ms, &s, 3, n); @@ -3030,7 +3022,7 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) out->ms *= len == 1 ? 100 : len == 2 ? 10 : 1; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_US: /* microsecond */ len = from_char_parse_int_len(&out->us, &s, 6, n); @@ -3041,11 +3033,11 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) len == 4 ? 100 : len == 5 ? 10 : 1; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_SSSS: from_char_parse_int(&out->ssss, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_tz: case DCH_TZ: @@ -3085,7 +3077,7 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) break; case DCH_MM: from_char_parse_int(&out->mm, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_DAY: case DCH_Day: @@ -3105,31 +3097,31 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) break; case DCH_DDD: from_char_parse_int(&out->ddd, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_IDDD: from_char_parse_int_len(&out->ddd, &s, 3, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_DD: from_char_parse_int(&out->dd, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_D: from_char_parse_int(&out->d, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_ID: from_char_parse_int_len(&out->d, &s, 1, n); /* Shift numbering to match Gregorian where Sunday = 1 */ if (++out->d > 7) out->d = 1; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_WW: case DCH_IW: from_char_parse_int(&out->ww, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_Q: @@ -3144,55 +3136,57 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) * isn't stored anywhere in 'out'. */ from_char_parse_int((int *) NULL, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_CC: from_char_parse_int(&out->cc, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_Y_YYY: { int matched, years, - millenia; + millenia, + nch; - matched = sscanf(s, "%d,%03d", &millenia, &years); - if (matched != 2) + matched = sscanf(s, "%d,%03d%n", &millenia, &years, &nch); + if (matched < 2) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid input string for \"Y,YYY\""))); years += (millenia * 1000); from_char_set_int(&out->year, years, n); out->yysz = 4; - s += strdigits_len(s) + 4 + SKIP_THth(n->suffix); + s += nch; + SKIP_THth(s, n->suffix); } break; case DCH_YYYY: case DCH_IYYY: from_char_parse_int(&out->year, &s, n); out->yysz = 4; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_YYY: case DCH_IYY: if (from_char_parse_int(&out->year, &s, n) < 4) out->year = adjust_partial_year_to_2020(out->year); out->yysz = 3; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_YY: case DCH_IY: if (from_char_parse_int(&out->year, &s, n) < 4) out->year = adjust_partial_year_to_2020(out->year); out->yysz = 2; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_Y: case DCH_I: if (from_char_parse_int(&out->year, &s, n) < 4) out->year = adjust_partial_year_to_2020(out->year); out->yysz = 1; - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_RM: from_char_seq_search(&value, &s, rm_months_upper, @@ -3206,11 +3200,11 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) break; case DCH_W: from_char_parse_int(&out->w, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; case DCH_J: from_char_parse_int(&out->j, &s, n); - s += SKIP_THth(n->suffix); + SKIP_THth(s, n->suffix); break; } }