#include "fmgr.h"
Go to the source code of this file.
Functions | |
char * | str_tolower (const char *buff, size_t nbytes, Oid collid) |
char * | str_toupper (const char *buff, size_t nbytes, Oid collid) |
char * | str_initcap (const char *buff, size_t nbytes, Oid collid) |
char * | asc_tolower (const char *buff, size_t nbytes) |
char * | asc_toupper (const char *buff, size_t nbytes) |
char * | asc_initcap (const char *buff, size_t nbytes) |
Datum | timestamp_to_char (PG_FUNCTION_ARGS) |
Datum | timestamptz_to_char (PG_FUNCTION_ARGS) |
Datum | interval_to_char (PG_FUNCTION_ARGS) |
Datum | to_timestamp (PG_FUNCTION_ARGS) |
Datum | to_date (PG_FUNCTION_ARGS) |
Datum | numeric_to_number (PG_FUNCTION_ARGS) |
Datum | numeric_to_char (PG_FUNCTION_ARGS) |
Datum | int4_to_char (PG_FUNCTION_ARGS) |
Datum | int8_to_char (PG_FUNCTION_ARGS) |
Datum | float4_to_char (PG_FUNCTION_ARGS) |
Datum | float8_to_char (PG_FUNCTION_ARGS) |
char* asc_initcap | ( | const char * | buff, | |
size_t | nbytes | |||
) |
Definition at line 1916 of file formatting.c.
References pg_ascii_tolower(), pg_ascii_toupper(), and pnstrdup().
Referenced by str_initcap().
{ 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_ascii_tolower((unsigned char) *p); else *p = c = pg_ascii_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; }
char* asc_tolower | ( | const char * | buff, | |
size_t | nbytes | |||
) |
Definition at line 1870 of file formatting.c.
References pg_ascii_tolower(), and pnstrdup().
Referenced by asc_tolower_z(), and str_tolower().
{ char *result; char *p; if (!buff) return NULL; result = pnstrdup(buff, nbytes); for (p = result; *p; p++) *p = pg_ascii_tolower((unsigned char) *p); return result; }
char* asc_toupper | ( | const char * | buff, | |
size_t | nbytes | |||
) |
Definition at line 1893 of file formatting.c.
References pg_ascii_toupper(), and pnstrdup().
Referenced by asc_toupper_z(), and str_toupper().
{ char *result; char *p; if (!buff) return NULL; result = pnstrdup(buff, nbytes); for (p = result; *p; p++) *p = pg_ascii_toupper((unsigned char) *p); return result; }
Datum float4_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5273 of file formatting.c.
References fill_str(), format, int_to_roman(), IS_EEEE, is_infinite(), IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, MAXFLOATWIDTH, NUMDesc::multi, palloc(), PG_GETARG_FLOAT4, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, rint(), sign, snprintf(), val, and value.
{ float4 value = PG_GETARG_FLOAT4(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum, *p; NUM_TOCHAR_prepare; if (IS_ROMAN(&Num)) numstr = orgnum = int_to_roman((int) rint(value)); else if (IS_EEEE(&Num)) { numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); if (isnan(value) || is_infinite(value)) { /* * Allow 6 characters for the leading sign, the decimal point, * "e", the exponent's sign and two exponent digits. */ numstr = (char *) palloc(Num.pre + Num.post + 7); fill_str(numstr, '#', Num.pre + Num.post + 6); *numstr = ' '; *(numstr + Num.pre + 1) = '.'; } else { snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ if (*orgnum == '+') *orgnum = ' '; len = strlen(orgnum); numstr = orgnum; } } else { float4 val = value; if (IS_MULTI(&Num)) { float multi = pow((double) 10, (double) Num.multi); val = value * multi; Num.pre += Num.multi; } orgnum = (char *) palloc(MAXFLOATWIDTH + 1); snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val)); len = strlen(orgnum); if (Num.pre > len) plen = Num.pre - len; if (len >= FLT_DIG) Num.post = 0; else if (Num.post + len > FLT_DIG) Num.post = FLT_DIG - len; snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val); if (*orgnum == '-') { /* < 0 */ sign = '-'; numstr = orgnum + 1; } else { sign = '+'; numstr = orgnum; } if ((p = strchr(numstr, '.'))) len = p - numstr; else len = strlen(numstr); if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum float8_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5377 of file formatting.c.
References fill_str(), format, int_to_roman(), IS_EEEE, is_infinite(), IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, NUMDesc::multi, palloc(), PG_GETARG_FLOAT8, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, rint(), sign, snprintf(), val, and value.
{ float8 value = PG_GETARG_FLOAT8(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum, *p; NUM_TOCHAR_prepare; if (IS_ROMAN(&Num)) numstr = orgnum = int_to_roman((int) rint(value)); else if (IS_EEEE(&Num)) { numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); if (isnan(value) || is_infinite(value)) { /* * Allow 6 characters for the leading sign, the decimal point, * "e", the exponent's sign and two exponent digits. */ numstr = (char *) palloc(Num.pre + Num.post + 7); fill_str(numstr, '#', Num.pre + Num.post + 6); *numstr = ' '; *(numstr + Num.pre + 1) = '.'; } else { snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ if (*orgnum == '+') *orgnum = ' '; len = strlen(orgnum); numstr = orgnum; } } else { float8 val = value; if (IS_MULTI(&Num)) { double multi = pow((double) 10, (double) Num.multi); val = value * multi; Num.pre += Num.multi; } orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val)); if (Num.pre > len) plen = Num.pre - len; if (len >= DBL_DIG) Num.post = 0; else if (Num.post + len > DBL_DIG) Num.post = DBL_DIG - len; snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val); if (*orgnum == '-') { /* < 0 */ sign = '-'; numstr = orgnum + 1; } else { sign = '+'; numstr = orgnum; } if ((p = strchr(numstr, '.'))) len = p - numstr; else len = strlen(numstr); if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum int4_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5075 of file formatting.c.
References DatumGetCString, DirectFunctionCall1, fill_str(), format, Int32GetDatum, int4out(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, NUMDesc::multi, palloc(), PG_GETARG_INT32, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, snprintf(), val, and value.
{ int32 value = PG_GETARG_INT32(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum; NUM_TOCHAR_prepare; /* * On DateType depend part (int32) */ if (IS_ROMAN(&Num)) numstr = orgnum = int_to_roman(value); else if (IS_EEEE(&Num)) { /* we can do it easily because float8 won't lose any precision */ float8 val = (float8) value; orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val); /* * Swap a leading positive sign for a space. */ if (*orgnum == '+') *orgnum = ' '; len = strlen(orgnum); numstr = orgnum; } else { if (IS_MULTI(&Num)) { orgnum = DatumGetCString(DirectFunctionCall1(int4out, Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi))))); Num.pre += Num.multi; } else { orgnum = DatumGetCString(DirectFunctionCall1(int4out, Int32GetDatum(value))); } if (*orgnum == '-') { sign = '-'; orgnum++; } else sign = '+'; len = strlen(orgnum); if (Num.post) { numstr = (char *) palloc(len + Num.post + 2); strcpy(numstr, orgnum); *(numstr + len) = '.'; memset(numstr + len + 1, '0', Num.post); *(numstr + len + Num.post + 1) = '\0'; } else numstr = orgnum; if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum int8_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5166 of file formatting.c.
References DatumGetCString, DatumGetInt32, DatumGetInt64, DatumGetNumeric, DirectFunctionCall1, DirectFunctionCall2, dtoi8(), fill_str(), Float8GetDatum(), format, Int64GetDatum(), int84(), int8_numeric(), int8mul(), int8out(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, numeric_out_sci(), palloc(), PG_GETARG_INT64, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, val, and value.
{ int64 value = PG_GETARG_INT64(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum; NUM_TOCHAR_prepare; /* * On DateType depend part (int32) */ if (IS_ROMAN(&Num)) { /* Currently don't support int8 conversion to roman... */ numstr = orgnum = int_to_roman(DatumGetInt32( DirectFunctionCall1(int84, Int64GetDatum(value)))); } else if (IS_EEEE(&Num)) { /* to avoid loss of precision, must go via numeric not float8 */ Numeric val; val = DatumGetNumeric(DirectFunctionCall1(int8_numeric, Int64GetDatum(value))); orgnum = numeric_out_sci(val, Num.post); /* * numeric_out_sci() does not emit a sign for positive numbers. We * need to add a space in this case so that positive and negative * numbers are aligned. We don't have to worry about NaN here. */ if (*orgnum != '-') { numstr = (char *) palloc(strlen(orgnum) + 2); *numstr = ' '; strcpy(numstr + 1, orgnum); len = strlen(numstr); } else { numstr = orgnum; len = strlen(orgnum); } } else { if (IS_MULTI(&Num)) { double multi = pow((double) 10, (double) Num.multi); value = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(value), DirectFunctionCall1(dtoi8, Float8GetDatum(multi)))); Num.pre += Num.multi; } orgnum = DatumGetCString(DirectFunctionCall1(int8out, Int64GetDatum(value))); if (*orgnum == '-') { sign = '-'; orgnum++; } else sign = '+'; len = strlen(orgnum); if (Num.post) { numstr = (char *) palloc(len + Num.post + 2); strcpy(numstr, orgnum); *(numstr + len) = '.'; memset(numstr + len + 1, '0', Num.post); *(numstr + len + Num.post + 1) = '\0'; } else numstr = orgnum; if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum interval_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3326 of file formatting.c.
References datetime_to_char_body(), DAYS_PER_MONTH, interval2tm(), MONTHS_PER_YEAR, PG_GET_COLLATION, PG_GETARG_INTERVAL_P, PG_GETARG_TEXT_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, VARHDRSZ, VARSIZE, and ZERO_tmtc.
{ Interval *it = PG_GETARG_INTERVAL_P(0); 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, 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_GET_COLLATION()))) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); }
Datum numeric_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 4952 of file formatting.c.
References DatumGetCString, DatumGetInt32, DatumGetNumeric, DirectFunctionCall1, DirectFunctionCall2, fill_str(), format, Int32GetDatum, int4_numeric(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, numeric_int4(), numeric_mul(), numeric_out(), numeric_out_sci(), numeric_power(), numeric_round(), NumericGetDatum, palloc(), PG_GETARG_NUMERIC, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, val, and value.
{ Numeric value = PG_GETARG_NUMERIC(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum, *p; Numeric x; NUM_TOCHAR_prepare; /* * On DateType depend part (numeric) */ if (IS_ROMAN(&Num)) { x = DatumGetNumeric(DirectFunctionCall2(numeric_round, NumericGetDatum(value), Int32GetDatum(0))); numstr = orgnum = int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(x)))); } else if (IS_EEEE(&Num)) { orgnum = numeric_out_sci(value, Num.post); /* * numeric_out_sci() does not emit a sign for positive numbers. We * need to add a space in this case so that positive and negative * numbers are aligned. We also have to do the right thing for NaN. */ if (strcmp(orgnum, "NaN") == 0) { /* * Allow 6 characters for the leading sign, the decimal point, * "e", the exponent's sign and two exponent digits. */ numstr = (char *) palloc(Num.pre + Num.post + 7); fill_str(numstr, '#', Num.pre + Num.post + 6); *numstr = ' '; *(numstr + Num.pre + 1) = '.'; } else if (*orgnum != '-') { numstr = (char *) palloc(strlen(orgnum) + 2); *numstr = ' '; strcpy(numstr + 1, orgnum); len = strlen(numstr); } else { numstr = orgnum; len = strlen(orgnum); } } else { Numeric val = value; if (IS_MULTI(&Num)) { Numeric a = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(10))); Numeric b = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(Num.multi))); x = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(a), NumericGetDatum(b))); val = DatumGetNumeric(DirectFunctionCall2(numeric_mul, NumericGetDatum(value), NumericGetDatum(x))); Num.pre += Num.multi; } x = DatumGetNumeric(DirectFunctionCall2(numeric_round, NumericGetDatum(val), Int32GetDatum(Num.post))); orgnum = DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(x))); if (*orgnum == '-') { sign = '-'; numstr = orgnum + 1; } else { sign = '+'; numstr = orgnum; } if ((p = strchr(numstr, '.'))) len = p - numstr; else len = strlen(numstr); if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum numeric_to_number | ( | PG_FUNCTION_ARGS | ) |
Definition at line 4908 of file formatting.c.
References CStringGetDatum, DirectFunctionCall3, format, Int32GetDatum, InvalidOid, Max, NUM_cache(), NUM_MAX_ITEM_SIZ, NUM_processor(), numeric_in(), ObjectIdGetDatum, palloc(), pfree(), PG_GET_COLLATION, PG_GETARG_TEXT_P, PG_RETURN_NULL, NUMDesc::post, NUMDesc::pre, scale, value, VARDATA, VARHDRSZ, and VARSIZE.
{ text *value = PG_GETARG_TEXT_P(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; Datum result; FormatNode *format; char *numstr; bool shouldFree; int len = 0; int scale, precision; len = VARSIZE(fmt) - VARHDRSZ; if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ) PG_RETURN_NULL(); format = NUM_cache(len, &Num, fmt, &shouldFree); numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1); NUM_processor(format, &Num, VARDATA(value), numstr, VARSIZE(value) - VARHDRSZ, 0, false, PG_GET_COLLATION()); scale = Num.post; precision = Max(0, Num.pre) + scale; if (shouldFree) pfree(format); result = DirectFunctionCall3(numeric_in, CStringGetDatum(numstr), ObjectIdGetDatum(InvalidOid),
char* str_initcap | ( | const char * | buff, | |
size_t | nbytes, | |||
Oid | collid | |||
) |
Definition at line 1725 of file formatting.c.
References asc_initcap(), DEFAULT_COLLATION_OID, ereport, errcode(), errhint(), errmsg(), ERROR, isalnum_l, iswalnum_l, lc_ctype_is_c(), OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_tolower(), pg_toupper(), pnstrdup(), tolower_l, toupper_l, towlower_l, and towupper_l.
Referenced by initcap(), and str_initcap_z().
{ char *result; int wasalnum = false; if (!buff) return NULL; /* C/POSIX collations use this path regardless of database encoding */ if (lc_ctype_is_c(collid)) { result = asc_initcap(buff, nbytes); } #ifdef USE_WIDE_UPPER_LOWER else if (pg_database_encoding_max_length() > 1) { pg_locale_t mylocale = 0; wchar_t *workspace; size_t curr_char; size_t result_size; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for initcap() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } mylocale = pg_newlocale_from_collation(collid); } /* Overflow paranoia */ if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T if (mylocale) { if (wasalnum) workspace[curr_char] = towlower_l(workspace[curr_char], mylocale); else workspace[curr_char] = towupper_l(workspace[curr_char], mylocale); wasalnum = iswalnum_l(workspace[curr_char], mylocale); } else #endif { if (wasalnum) workspace[curr_char] = towlower(workspace[curr_char]); else workspace[curr_char] = towupper(workspace[curr_char]); wasalnum = iswalnum(workspace[curr_char]); } } /* Make result large enough; case change might change number of bytes */ result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); wchar2char(result, workspace, result_size, mylocale); pfree(workspace); } #endif /* USE_WIDE_UPPER_LOWER */ else { #ifdef HAVE_LOCALE_T pg_locale_t mylocale = 0; #endif char *p; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for initcap() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } #ifdef HAVE_LOCALE_T mylocale = pg_newlocale_from_collation(collid); #endif } result = pnstrdup(buff, nbytes); /* * Note: we assume that toupper_l()/tolower_l() will not be so broken * as to need guard tests. When using the default collation, we apply * the traditional Postgres behavior that forces ASCII-style treatment * of I/i, but in non-default collations you get exactly what the * collation says. */ for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T if (mylocale) { if (wasalnum) *p = tolower_l((unsigned char) *p, mylocale); else *p = toupper_l((unsigned char) *p, mylocale); wasalnum = isalnum_l((unsigned char) *p, mylocale); } else #endif { if (wasalnum) *p = pg_tolower((unsigned char) *p); else *p = pg_toupper((unsigned char) *p); wasalnum = isalnum((unsigned char) *p); } } } return result; }
char* str_tolower | ( | const char * | buff, | |
size_t | nbytes, | |||
Oid | collid | |||
) |
Definition at line 1485 of file formatting.c.
References asc_tolower(), DEFAULT_COLLATION_OID, ereport, errcode(), errhint(), errmsg(), ERROR, lc_ctype_is_c(), OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_tolower(), pnstrdup(), tolower_l, and towlower_l.
Referenced by citext_eq(), citext_hash(), citext_ne(), citextcmp(), lower(), ltree_strncasecmp(), and str_tolower_z().
{ char *result; if (!buff) return NULL; /* C/POSIX collations use this path regardless of database encoding */ if (lc_ctype_is_c(collid)) { result = asc_tolower(buff, nbytes); } #ifdef USE_WIDE_UPPER_LOWER else if (pg_database_encoding_max_length() > 1) { pg_locale_t mylocale = 0; wchar_t *workspace; size_t curr_char; size_t result_size; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for lower() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } mylocale = pg_newlocale_from_collation(collid); } /* Overflow paranoia */ if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T if (mylocale) workspace[curr_char] = towlower_l(workspace[curr_char], mylocale); else #endif workspace[curr_char] = towlower(workspace[curr_char]); } /* Make result large enough; case change might change number of bytes */ result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); wchar2char(result, workspace, result_size, mylocale); pfree(workspace); } #endif /* USE_WIDE_UPPER_LOWER */ else { #ifdef HAVE_LOCALE_T pg_locale_t mylocale = 0; #endif char *p; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for lower() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } #ifdef HAVE_LOCALE_T mylocale = pg_newlocale_from_collation(collid); #endif } result = pnstrdup(buff, nbytes); /* * Note: we assume that tolower_l() will not be so broken as to need * an isupper_l() guard test. When using the default collation, we * apply the traditional Postgres behavior that forces ASCII-style * treatment of I/i, but in non-default collations you get exactly * what the collation says. */ for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T if (mylocale) *p = tolower_l((unsigned char) *p, mylocale); else #endif *p = pg_tolower((unsigned char) *p); } } return result; }
char* str_toupper | ( | const char * | buff, | |
size_t | nbytes, | |||
Oid | collid | |||
) |
Definition at line 1605 of file formatting.c.
References asc_toupper(), DEFAULT_COLLATION_OID, ereport, errcode(), errhint(), errmsg(), ERROR, lc_ctype_is_c(), OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_toupper(), pnstrdup(), toupper_l, and towupper_l.
Referenced by str_toupper_z(), and upper().
{ char *result; if (!buff) return NULL; /* C/POSIX collations use this path regardless of database encoding */ if (lc_ctype_is_c(collid)) { result = asc_toupper(buff, nbytes); } #ifdef USE_WIDE_UPPER_LOWER else if (pg_database_encoding_max_length() > 1) { pg_locale_t mylocale = 0; wchar_t *workspace; size_t curr_char; size_t result_size; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for upper() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } mylocale = pg_newlocale_from_collation(collid); } /* Overflow paranoia */ if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T if (mylocale) workspace[curr_char] = towupper_l(workspace[curr_char], mylocale); else #endif workspace[curr_char] = towupper(workspace[curr_char]); } /* Make result large enough; case change might change number of bytes */ result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); wchar2char(result, workspace, result_size, mylocale); pfree(workspace); } #endif /* USE_WIDE_UPPER_LOWER */ else { #ifdef HAVE_LOCALE_T pg_locale_t mylocale = 0; #endif char *p; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for upper() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } #ifdef HAVE_LOCALE_T mylocale = pg_newlocale_from_collation(collid); #endif } result = pnstrdup(buff, nbytes); /* * Note: we assume that toupper_l() will not be so broken as to need * an islower_l() guard test. When using the default collation, we * apply the traditional Postgres behavior that forces ASCII-style * treatment of I/i, but in non-default collations you get exactly * what the collation says. */ for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T if (mylocale) *p = toupper_l((unsigned char) *p, mylocale); else #endif *p = pg_toupper((unsigned char) *p); } } return result; }
Datum timestamp_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3258 of file formatting.c.
References date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, NULL, PG_GET_COLLATION, PG_GETARG_TEXT_P, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, VARHDRSZ, VARSIZE, and ZERO_tmtc.
{ Timestamp dt = PG_GETARG_TIMESTAMP(0); 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, 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_GET_COLLATION()))) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); }
Datum timestamptz_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3289 of file formatting.c.
References date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, NULL, PG_GET_COLLATION, PG_GETARG_TEXT_P, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, tmtcTzn, VARHDRSZ, VARSIZE, and ZERO_tmtc.
{ TimestampTz dt = PG_GETARG_TIMESTAMP(0); text *fmt = PG_GETARG_TEXT_P(1), *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, 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_GET_COLLATION()))) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); }
Datum to_date | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3387 of file formatting.c.
References date2j(), do_to_timestamp(), ereport, errcode(), errmsg(), ERROR, IS_VALID_JULIAN, PG_GETARG_TEXT_P, PG_RETURN_DATEADT, text_to_cstring(), pg_tm::tm_mday, pg_tm::tm_mon, and pg_tm::tm_year.
{ text *date_txt = PG_GETARG_TEXT_P(0); text *fmt = PG_GETARG_TEXT_P(1); DateADT result; struct pg_tm tm; fsec_t fsec; do_to_timestamp(date_txt, fmt, &tm, &fsec); if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range: \"%s\"", text_to_cstring(date_txt)))); result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE; PG_RETURN_DATEADT(result); }
Datum to_timestamp | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3360 of file formatting.c.
References DetermineTimeZoneOffset(), do_to_timestamp(), ereport, errcode(), errmsg(), ERROR, PG_GETARG_TEXT_P, PG_RETURN_TIMESTAMP, session_timezone, and tm2timestamp().
{ text *date_txt = PG_GETARG_TEXT_P(0); text *fmt = PG_GETARG_TEXT_P(1); Timestamp result; int tz; struct pg_tm tm; fsec_t fsec; do_to_timestamp(date_txt, fmt, &tm, &fsec); tz = DetermineTimeZoneOffset(&tm, session_timezone); if (tm2timestamp(&tm, fsec, &tz, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMP(result); }