Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

formatting.h File Reference

#include "fmgr.h"
Include dependency graph for formatting.h:
This graph shows which files directly or indirectly include this file:

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)

Function Documentation

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);
}