summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/formatting.c138
-rw-r--r--src/include/utils/formatting.h4
2 files changed, 117 insertions, 25 deletions
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index cb99b86b23e..3b823fa78fb 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -1646,6 +1646,87 @@ str_initcap(const char *buff, size_t nbytes)
return result;
}
+/*
+ * ASCII-only lower function
+ *
+ * We pass the number of bytes so we can pass varlena and char*
+ * to this function. The result is a palloc'd, null-terminated string.
+ */
+char *
+asc_tolower(const char *buff, size_t nbytes)
+{
+ char *result;
+ char *p;
+
+ if (!buff)
+ return NULL;
+
+ result = pnstrdup(buff, nbytes);
+
+ for (p = result; *p; p++)
+ *p = pg_tolower((unsigned char) *p);
+
+ return result;
+}
+
+/*
+ * ASCII-only upper function
+ *
+ * We pass the number of bytes so we can pass varlena and char*
+ * to this function. The result is a palloc'd, null-terminated string.
+ */
+char *
+asc_toupper(const char *buff, size_t nbytes)
+{
+ char *result;
+ char *p;
+
+ if (!buff)
+ return NULL;
+
+ result = pnstrdup(buff, nbytes);
+
+ for (p = result; *p; p++)
+ *p = pg_toupper((unsigned char) *p);
+
+ return result;
+}
+
+/*
+ * ASCII-only initcap function
+ *
+ * We pass the number of bytes so we can pass varlena and char*
+ * to this function. The result is a palloc'd, null-terminated string.
+ */
+char *
+asc_initcap(const char *buff, size_t nbytes)
+{
+ char *result;
+ char *p;
+ int wasalnum = false;
+
+ if (!buff)
+ return NULL;
+
+ result = pnstrdup(buff, nbytes);
+
+ for (p = result; *p; p++)
+ {
+ char c;
+
+ if (wasalnum)
+ *p = c = pg_tolower((unsigned char) *p);
+ else
+ *p = c = pg_toupper((unsigned char) *p);
+ /* we don't trust isalnum() here */
+ wasalnum = ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9'));
+ }
+
+ return result;
+}
+
/* convenience routines for when the input is null-terminated */
static char *
@@ -1666,6 +1747,20 @@ str_initcap_z(const char *buff)
return str_initcap(buff, strlen(buff));
}
+static char *
+asc_tolower_z(const char *buff)
+{
+ return asc_tolower(buff, strlen(buff));
+}
+
+static char *
+asc_toupper_z(const char *buff)
+{
+ return asc_toupper(buff, strlen(buff));
+}
+
+/* asc_initcap_z is not currently needed */
+
/* ----------
* Skip TM / th in FROM_CHAR
@@ -2149,7 +2244,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
INVALID_FOR_INTERVAL;
if (tmtcTzn(in))
{
- char *p = str_tolower_z(tmtcTzn(in));
+ /* We assume here that timezone names aren't localized */
+ char *p = asc_tolower_z(tmtcTzn(in));
strcpy(s, p);
pfree(p);
@@ -2196,7 +2292,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1]));
else
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
- str_toupper_z(months_full[tm->tm_mon - 1]));
+ asc_toupper_z(months_full[tm->tm_mon - 1]));
s += strlen(s);
break;
case DCH_Month:
@@ -2206,7 +2302,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1]));
else
- sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, months_full[tm->tm_mon - 1]);
+ sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
+ months_full[tm->tm_mon - 1]);
s += strlen(s);
break;
case DCH_month:
@@ -2216,10 +2313,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1]));
else
- {
- sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, months_full[tm->tm_mon - 1]);
- *s = pg_tolower((unsigned char) *s);
- }
+ sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
+ asc_tolower_z(months_full[tm->tm_mon - 1]));
s += strlen(s);
break;
case DCH_MON:
@@ -2229,7 +2324,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1]));
else
- strcpy(s, str_toupper_z(months[tm->tm_mon - 1]));
+ strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
s += strlen(s);
break;
case DCH_Mon:
@@ -2249,10 +2344,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1]));
else
- {
- strcpy(s, months[tm->tm_mon - 1]);
- *s = pg_tolower((unsigned char) *s);
- }
+ strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
s += strlen(s);
break;
case DCH_MM:
@@ -2267,7 +2359,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday]));
else
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
- str_toupper_z(days[tm->tm_wday]));
+ asc_toupper_z(days[tm->tm_wday]));
s += strlen(s);
break;
case DCH_Day:
@@ -2275,7 +2367,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday]));
else
- sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, days[tm->tm_wday]);
+ sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
+ days[tm->tm_wday]);
s += strlen(s);
break;
case DCH_day:
@@ -2283,10 +2376,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday]));
else
- {
- sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, days[tm->tm_wday]);
- *s = pg_tolower((unsigned char) *s);
- }
+ sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
+ asc_tolower_z(days[tm->tm_wday]));
s += strlen(s);
break;
case DCH_DY:
@@ -2294,7 +2385,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday]));
else
- strcpy(s, str_toupper_z(days_short[tm->tm_wday]));
+ strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
s += strlen(s);
break;
case DCH_Dy:
@@ -2310,10 +2401,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
if (S_TM(n->suffix))
strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday]));
else
- {
- strcpy(s, days_short[tm->tm_wday]);
- *s = pg_tolower((unsigned char) *s);
- }
+ strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
s += strlen(s);
break;
case DCH_DDD:
@@ -4414,12 +4502,12 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
case NUM_rn:
if (IS_FILLMODE(Np->Num))
{
- strcpy(Np->inout_p, str_tolower_z(Np->number_p));
+ strcpy(Np->inout_p, asc_tolower_z(Np->number_p));
Np->inout_p += strlen(Np->inout_p) - 1;
}
else
{
- sprintf(Np->inout_p, "%15s", str_tolower_z(Np->number_p));
+ sprintf(Np->inout_p, "%15s", asc_tolower_z(Np->number_p));
Np->inout_p += strlen(Np->inout_p) - 1;
}
break;
diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h
index 006dbc8a28d..e0c9dda2a07 100644
--- a/src/include/utils/formatting.h
+++ b/src/include/utils/formatting.h
@@ -25,6 +25,10 @@ extern char *str_tolower(const char *buff, size_t nbytes);
extern char *str_toupper(const char *buff, size_t nbytes);
extern char *str_initcap(const char *buff, size_t nbytes);
+extern char *asc_tolower(const char *buff, size_t nbytes);
+extern char *asc_toupper(const char *buff, size_t nbytes);
+extern char *asc_initcap(const char *buff, size_t nbytes);
+
extern Datum timestamp_to_char(PG_FUNCTION_ARGS);
extern Datum timestamptz_to_char(PG_FUNCTION_ARGS);
extern Datum interval_to_char(PG_FUNCTION_ARGS);