예제 #1
0
파일: cash.c 프로젝트: AnLingm/gpdb
/* cashsmaller()
 * Return smaller of two cash values.
 */
Datum
cashsmaller(PG_FUNCTION_ARGS)
{
	Cash		c1 = PG_GETARG_CASH(0);
	Cash		c2 = PG_GETARG_CASH(1);
	Cash		result;

	result = (c1 < c2) ? c1 : c2;

	PG_RETURN_CASH(result);
}
예제 #2
0
파일: cash.c 프로젝트: AnLingm/gpdb
/* cash_mi()
 * Subtract two cash values.
 */
Datum
cash_mi(PG_FUNCTION_ARGS)
{
	Cash		c1 = PG_GETARG_CASH(0);
	Cash		c2 = PG_GETARG_CASH(1);
	Cash		result;

	result = c1 - c2;

	PG_RETURN_CASH(result);
}
예제 #3
0
파일: cash.c 프로젝트: yangineer/cscd43-1
Datum
cash_cmp(PG_FUNCTION_ARGS)
{
    Cash		c1 = PG_GETARG_CASH(0);
    Cash		c2 = PG_GETARG_CASH(1);

    if (c1 > c2)
        PG_RETURN_INT32(1);
    else if (c1 == c2)
        PG_RETURN_INT32(0);
    else
        PG_RETURN_INT32(-1);
}
예제 #4
0
파일: cash.c 프로젝트: AmiGanguli/postgres
/* cash_div_cash()
 * Divide cash by cash, returning float8.
 */
Datum
cash_div_cash(PG_FUNCTION_ARGS)
{
	Cash		dividend = PG_GETARG_CASH(0);
	Cash		divisor = PG_GETARG_CASH(1);
	float8		quotient;

	if (divisor == 0)
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));

	quotient = (float8) dividend / (float8) divisor;
	PG_RETURN_FLOAT8(quotient);
}
예제 #5
0
파일: cash.c 프로젝트: AmiGanguli/postgres
/* cash_numeric()
 * Convert cash to numeric.
 */
Datum
cash_numeric(PG_FUNCTION_ARGS)
{
	Cash		money = PG_GETARG_CASH(0);
	Numeric		result;
	int			fpoint;
	int64		scale;
	int			i;
	Datum		amount;
	Datum		numeric_scale;
	Datum		quotient;
	struct lconv *lconvert = PGLC_localeconv();

	/* see comments about frac_digits in cash_in() */
	fpoint = lconvert->frac_digits;
	if (fpoint < 0 || fpoint > 10)
		fpoint = 2;

	/* compute required scale factor */
	scale = 1;
	for (i = 0; i < fpoint; i++)
		scale *= 10;

	/* form the result as money / scale */
	amount = DirectFunctionCall1(int8_numeric, Int64GetDatum(money));
	numeric_scale = DirectFunctionCall1(int8_numeric, Int64GetDatum(scale));
	quotient = DirectFunctionCall2(numeric_div, amount, numeric_scale);

	/* forcibly round to exactly the intended number of digits */
	result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
												 quotient,
												 Int32GetDatum(fpoint)));

	PG_RETURN_NUMERIC(result);
}
예제 #6
0
Datum
gpupreagg_psum_money(PG_FUNCTION_ARGS)
{
	Assert(PG_NARGS() == 1);
	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();
	PG_RETURN_CASH(PG_GETARG_CASH(0));
}
예제 #7
0
파일: cash.c 프로젝트: AmiGanguli/postgres
/* flt8_mul_cash()
 * Multiply float8 by cash.
 */
Datum
flt8_mul_cash(PG_FUNCTION_ARGS)
{
	float8		f = PG_GETARG_FLOAT8(0);
	Cash		c = PG_GETARG_CASH(1);
	Cash		result;

	result = rint(f * c);
	PG_RETURN_CASH(result);
}
예제 #8
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/*
 *		cash_send			- converts cash to binary format
 */
Datum
cash_send(PG_FUNCTION_ARGS)
{
    Cash		arg1 = PG_GETARG_CASH(0);
    StringInfoData buf;

    pq_begintypsend(&buf);
    pq_sendint(&buf, arg1, sizeof(Cash));
    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
예제 #9
0
Datum
cash_dist(PG_FUNCTION_ARGS)
{
	Cash		a = PG_GETARG_CASH(0);
	Cash		b = PG_GETARG_CASH(1);
	Cash		r;
	Cash		ra;

	r = a - b;
	ra = Abs(r);

	/* Overflow check. */
	if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("money out of range")));

	PG_RETURN_CASH(ra);
}
예제 #10
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* cash_mul_int2()
 * Multiply cash by int2.
 */
Datum
cash_mul_int2(PG_FUNCTION_ARGS)
{
    Cash		c = PG_GETARG_CASH(0);
    int16		s = PG_GETARG_INT16(1);
    Cash		result;

    result = c * s;
    PG_RETURN_CASH(result);
}
예제 #11
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* int2_mul_cash()
 * Multiply int2 by cash.
 */
Datum
int2_mul_cash(PG_FUNCTION_ARGS)
{
    int16		s = PG_GETARG_INT16(0);
    Cash		c = PG_GETARG_CASH(1);
    Cash		result;

    result = s * c;
    PG_RETURN_CASH(result);
}
예제 #12
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* cash_mul_int4()
 * Multiply cash by int4.
 */
Datum
cash_mul_int4(PG_FUNCTION_ARGS)
{
    Cash		c = PG_GETARG_CASH(0);
    int32		i = PG_GETARG_INT32(1);
    Cash		result;

    result = c * i;
    PG_RETURN_CASH(result);
}
예제 #13
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* int4_mul_cash()
 * Multiply int4 by cash.
 */
Datum
int4_mul_cash(PG_FUNCTION_ARGS)
{
    int32		i = PG_GETARG_INT32(0);
    Cash		c = PG_GETARG_CASH(1);
    Cash		result;

    result = i * c;
    PG_RETURN_CASH(result);
}
예제 #14
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* flt4_mul_cash()
 * Multiply float4 by cash.
 */
Datum
flt4_mul_cash(PG_FUNCTION_ARGS)
{
    float4		f = PG_GETARG_FLOAT4(0);
    Cash		c = PG_GETARG_CASH(1);
    Cash		result;

    result = f * c;
    PG_RETURN_CASH(result);
}
예제 #15
0
파일: cash.c 프로젝트: AmiGanguli/postgres
/* cash_mul_flt8()
 * Multiply cash by float8.
 */
Datum
cash_mul_flt8(PG_FUNCTION_ARGS)
{
	Cash		c = PG_GETARG_CASH(0);
	float8		f = PG_GETARG_FLOAT8(1);
	Cash		result;

	result = rint(c * f);
	PG_RETURN_CASH(result);
}
예제 #16
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* cash_mul_flt4()
 * Multiply cash by float4.
 */
Datum
cash_mul_flt4(PG_FUNCTION_ARGS)
{
    Cash		c = PG_GETARG_CASH(0);
    float4		f = PG_GETARG_FLOAT4(1);
    Cash		result;

    result = c * f;
    PG_RETURN_CASH(result);
}
예제 #17
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* cash_div_int2()
 * Divide cash by int2.
 *
 * XXX Don't know if rounding or truncating is correct behavior.
 * Round for now. - tgl 97/04/15
 */
Datum
cash_div_int2(PG_FUNCTION_ARGS)
{
    Cash		c = PG_GETARG_CASH(0);
    int16		s = PG_GETARG_INT16(1);
    Cash		result;

    if (s == 0)
        ereport(ERROR,
                (errcode(ERRCODE_DIVISION_BY_ZERO),
                 errmsg("division by zero")));

    result = rint(c / s);
    PG_RETURN_CASH(result);
}
예제 #18
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* cash_div_flt4()
 * Divide cash by float4.
 *
 * XXX Don't know if rounding or truncating is correct behavior.
 * Round for now. - tgl 97/04/15
 */
Datum
cash_div_flt4(PG_FUNCTION_ARGS)
{
    Cash		c = PG_GETARG_CASH(0);
    float4		f = PG_GETARG_FLOAT4(1);
    Cash		result;

    if (f == 0.0)
        ereport(ERROR,
                (errcode(ERRCODE_DIVISION_BY_ZERO),
                 errmsg("division by zero")));

    result = rint(c / f);
    PG_RETURN_CASH(result);
}
예제 #19
0
파일: cash.c 프로젝트: AmiGanguli/postgres
/* cash_div_int4()
 * Divide cash by 4-byte integer.
 *
 */
Datum
cash_div_int4(PG_FUNCTION_ARGS)
{
	Cash		c = PG_GETARG_CASH(0);
	int32		i = PG_GETARG_INT32(1);
	Cash		result;

	if (i == 0)
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));

	result = c / i;

	PG_RETURN_CASH(result);
}
예제 #20
0
Datum
gbt_cash_distance(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	Cash		query = PG_GETARG_CASH(1);

	/* Oid		subtype = PG_GETARG_OID(3); */
	cashKEY    *kkk = (cashKEY *) DatumGetPointer(entry->key);
	GBT_NUMKEY_R key;

	key.lower = (GBT_NUMKEY *) &kkk->lower;
	key.upper = (GBT_NUMKEY *) &kkk->upper;

	PG_RETURN_FLOAT8(
			gbt_num_distance(&key, (void *) &query, GIST_LEAF(entry), &tinfo)
		);
}
예제 #21
0
Datum
gbt_cash_consistent(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	Cash		query = PG_GETARG_CASH(1);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

	/* Oid		subtype = PG_GETARG_OID(3); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
	cashKEY    *kkk = (cashKEY *) DatumGetPointer(entry->key);
	GBT_NUMKEY_R key;

	/* All cases served by this function are exact */
	*recheck = false;

	key.lower = (GBT_NUMKEY *) &kkk->lower;
	key.upper = (GBT_NUMKEY *) &kkk->upper;

	PG_RETURN_BOOL(
				   gbt_num_consistent(&key, (void *) &query, &strategy, GIST_LEAF(entry), &tinfo)
		);
}
예제 #22
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* cash_words()
 * This converts a int4 as well but to a representation using words
 * Obviously way North American centric - sorry
 */
Datum
cash_words(PG_FUNCTION_ARGS)
{
    Cash		value = PG_GETARG_CASH(0);
    unsigned int val;
    char		buf[256];
    char	   *p = buf;
    Cash		m0;
    Cash		m1;
    Cash		m2;
    Cash		m3;
    text	   *result;

    /* work with positive numbers */
    if (value < 0)
    {
        value = -value;
        strcpy(buf, "minus ");
        p += 6;
    }
    else
        buf[0] = '\0';

    /* Now treat as unsigned, to avoid trouble at INT_MIN */
    val = (unsigned int) value;

    m0 = val % 100;				/* cents */
    m1 = (val / 100) % 1000;	/* hundreds */
    m2 = (val / 100000) % 1000; /* thousands */
    m3 = val / 100000000 % 1000;	/* millions */

    if (m3)
    {
        strcat(buf, num_word(m3));
        strcat(buf, " million ");
    }

    if (m2)
    {
        strcat(buf, num_word(m2));
        strcat(buf, " thousand ");
    }

    if (m1)
        strcat(buf, num_word(m1));

    if (!*p)
        strcat(buf, "zero");

    strcat(buf, (val / 100) == 1 ? " dollar and " : " dollars and ");
    strcat(buf, num_word(m0));
    strcat(buf, m0 == 1 ? " cent" : " cents");

    /* capitalize output */
    buf[0] = toupper((unsigned char) buf[0]);

    /* make a text type for output */
    result = (text *) palloc(strlen(buf) + VARHDRSZ);
    VARATT_SIZEP(result) = strlen(buf) + VARHDRSZ;
    memcpy(VARDATA(result), buf, strlen(buf));

    PG_RETURN_TEXT_P(result);
}
예제 #23
0
파일: cash.c 프로젝트: yangineer/cscd43-1
/* cash_out()
 * Function to convert cash to a dollars and cents representation.
 * XXX HACK This code appears to assume US conventions for
 *	positive-valued amounts. - tgl 97/04/14
 */
Datum
cash_out(PG_FUNCTION_ARGS)
{
    Cash		value = PG_GETARG_CASH(0);
    char	   *result;
    char		buf[CASH_BUFSZ];
    int			minus = 0;
    int			count = LAST_DIGIT;
    int			point_pos;
    int			comma_position = 0;
    int			points,
                mon_group;
    char		comma;
    char	   *csymbol,
               dsymbol,
               *nsymbol;
    char		convention;

    struct lconv *lconvert = PGLC_localeconv();

    /* see comments about frac_digits in cash_in() */
    points = lconvert->frac_digits;
    if (points < 0 || points > 10)
        points = 2;				/* best guess in this case, I think */

    /*
     * As with frac_digits, must apply a range check to mon_grouping to
     * avoid being fooled by variant CHAR_MAX values.
     */
    mon_group = *lconvert->mon_grouping;
    if (mon_group <= 0 || mon_group > 6)
        mon_group = 3;

    comma = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
    convention = lconvert->n_sign_posn;
    dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
    csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
    nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");

    point_pos = LAST_DIGIT - points;

    /* allow more than three decimal points and separate them */
    if (comma)
    {
        point_pos -= (points - 1) / mon_group;
        comma_position = point_pos % (mon_group + 1);
    }

    /* we work with positive amounts and add the minus sign at the end */
    if (value < 0)
    {
        minus = 1;
        value = -value;
    }

    /* allow for trailing negative strings */
    MemSet(buf, ' ', CASH_BUFSZ);
    buf[TERMINATOR] = buf[LAST_PAREN] = '\0';

    while (value || count > (point_pos - 2))
    {
        if (points && count == point_pos)
            buf[count--] = dsymbol;
        else if (comma && count % (mon_group + 1) == comma_position)
            buf[count--] = comma;

        buf[count--] = ((unsigned int) value % 10) + '0';
        value = ((unsigned int) value) / 10;
    }

    strncpy((buf + count - strlen(csymbol) + 1), csymbol, strlen(csymbol));
    count -= strlen(csymbol) - 1;

    if (buf[LAST_DIGIT] == ',')
        buf[LAST_DIGIT] = buf[LAST_PAREN];

    /* see if we need to signify negative amount */
    if (minus)
    {
        if (!PointerIsValid(result = palloc(CASH_BUFSZ + 2 - count + strlen(nsymbol))))
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));

        /* Position code of 0 means use parens */
        if (convention == 0)
            sprintf(result, "(%s)", buf + count);
        else if (convention == 2)
            sprintf(result, "%s%s", buf + count, nsymbol);
        else
            sprintf(result, "%s%s", nsymbol, buf + count);
    }
    else
    {
        if (!PointerIsValid(result = palloc(CASH_BUFSZ + 2 - count)))
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));

        strcpy(result, buf + count);
    }

    PG_RETURN_CSTRING(result);
}
예제 #24
0
/* cash_out()
 * Function to convert cash to a dollars and cents representation.
 * XXX HACK This code appears to assume US conventions for
 *	positive-valued amounts. - tgl 97/04/14
 */
Datum
cash_out(PG_FUNCTION_ARGS)
{
	Cash		value = PG_GETARG_CASH(0);
	char	   *result;
	char		buf[CASH_BUFSZ];
	int			minus = 0;
	int			count = LAST_DIGIT;
	int			point_pos;
	int			ssymbol_position = 0;
	int			points,
				mon_group;
	char		ssymbol;
	const char *csymbol,
			   *nsymbol;
	char		dsymbol;
	char		convention;
	struct lconv *lconvert = PGLC_localeconv();

	/* see comments about frac_digits in cash_in() */
	points = lconvert->frac_digits;
	if (points < 0 || points > 10)
		points = 2;				/* best guess in this case, I think */

	/*
	 * As with frac_digits, must apply a range check to mon_grouping to avoid
	 * being fooled by variant CHAR_MAX values.
	 */
	mon_group = *lconvert->mon_grouping;
	if (mon_group <= 0 || mon_group > 6)
		mon_group = 3;

	convention = lconvert->n_sign_posn;
	dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
	if (*lconvert->mon_thousands_sep != '\0')
		ssymbol = *lconvert->mon_thousands_sep;
	else
		/* ssymbol should not equal dsymbol */
		ssymbol = (dsymbol != ',') ? ',' : '.';
	csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
	nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");

	point_pos = LAST_DIGIT - points;

	point_pos -= (points - 1) / mon_group;
	ssymbol_position = point_pos % (mon_group + 1);

	/* we work with positive amounts and add the minus sign at the end */
	if (value < 0)
	{
		minus = 1;
		value = -value;
	}

	/* allow for trailing negative strings */
	MemSet(buf, ' ', CASH_BUFSZ);
	buf[TERMINATOR] = buf[LAST_PAREN] = '\0';

	while (value || count > (point_pos - 2))
	{
		if (points && count == point_pos)
			buf[count--] = dsymbol;
		else if (ssymbol && count % (mon_group + 1) == ssymbol_position)
			buf[count--] = ssymbol;

		buf[count--] = ((uint64) value % 10) + '0';
		value = ((uint64) value) / 10;
	}

	strncpy((buf + count - strlen(csymbol) + 1), csymbol, strlen(csymbol));
	count -= strlen(csymbol) - 1;

	/*
	 * If points == 0 and the number of digits % mon_group == 0, the code
	 * above adds a trailing ssymbol on the far right, so remove it.
	 */
	if (buf[LAST_DIGIT] == ssymbol)
		buf[LAST_DIGIT] = '\0';

	/* see if we need to signify negative amount */
	if (minus)
	{
		result = palloc(CASH_BUFSZ + 2 - count + strlen(nsymbol));

		/* Position code of 0 means use parens */
		if (convention == 0)
			sprintf(result, "(%s)", buf + count);
		else if (convention == 2)
			sprintf(result, "%s%s", buf + count, nsymbol);
		else
			sprintf(result, "%s%s", nsymbol, buf + count);
	}
	else
	{
		result = palloc(CASH_BUFSZ + 2 - count);
		strcpy(result, buf + count);
	}

	PG_RETURN_CSTRING(result);
}
예제 #25
0
파일: cash.c 프로젝트: AmiGanguli/postgres
/* cash_words()
 * This converts an int4 as well but to a representation using words
 * Obviously way North American centric - sorry
 */
Datum
cash_words(PG_FUNCTION_ARGS)
{
	Cash		value = PG_GETARG_CASH(0);
	uint64		val;
	char		buf[256];
	char	   *p = buf;
	Cash		m0;
	Cash		m1;
	Cash		m2;
	Cash		m3;
	Cash		m4;
	Cash		m5;
	Cash		m6;

	/* work with positive numbers */
	if (value < 0)
	{
		value = -value;
		strcpy(buf, "minus ");
		p += 6;
	}
	else
		buf[0] = '\0';

	/* Now treat as unsigned, to avoid trouble at INT_MIN */
	val = (uint64) value;

	m0 = val % INT64CONST(100); /* cents */
	m1 = (val / INT64CONST(100)) % 1000;	/* hundreds */
	m2 = (val / INT64CONST(100000)) % 1000; /* thousands */
	m3 = (val / INT64CONST(100000000)) % 1000;	/* millions */
	m4 = (val / INT64CONST(100000000000)) % 1000;	/* billions */
	m5 = (val / INT64CONST(100000000000000)) % 1000;	/* trillions */
	m6 = (val / INT64CONST(100000000000000000)) % 1000; /* quadrillions */

	if (m6)
	{
		strcat(buf, num_word(m6));
		strcat(buf, " quadrillion ");
	}

	if (m5)
	{
		strcat(buf, num_word(m5));
		strcat(buf, " trillion ");
	}

	if (m4)
	{
		strcat(buf, num_word(m4));
		strcat(buf, " billion ");
	}

	if (m3)
	{
		strcat(buf, num_word(m3));
		strcat(buf, " million ");
	}

	if (m2)
	{
		strcat(buf, num_word(m2));
		strcat(buf, " thousand ");
	}

	if (m1)
		strcat(buf, num_word(m1));

	if (!*p)
		strcat(buf, "zero");

	strcat(buf, (val / 100) == 1 ? " dollar and " : " dollars and ");
	strcat(buf, num_word(m0));
	strcat(buf, m0 == 1 ? " cent" : " cents");

	/* capitalize output */
	buf[0] = pg_toupper((unsigned char) buf[0]);

	/* return as text datum */
	PG_RETURN_TEXT_P(cstring_to_text(buf));
}
예제 #26
0
파일: cash.c 프로젝트: GisKook/Gis
/* cash_out()
 * Function to convert cash to a dollars and cents representation, using
 * the lc_monetary locale's formatting.
 */
Datum
cash_out(PG_FUNCTION_ARGS)
{
	Cash		value = PG_GETARG_CASH(0);
	char	   *result;
	char		buf[128];
	char	   *bufptr;
	bool		minus = false;
	int			digit_pos;
	int			points,
				mon_group;
	char		dsymbol;
	const char *ssymbol,
			   *csymbol,
			   *nsymbol;
	char		convention;
	struct lconv *lconvert = PGLC_localeconv();

	/* see comments about frac_digits in cash_in() */
	points = lconvert->frac_digits;
	if (points < 0 || points > 10)
		points = 2;				/* best guess in this case, I think */

	/*
	 * As with frac_digits, must apply a range check to mon_grouping to avoid
	 * being fooled by variant CHAR_MAX values.
	 */
	mon_group = *lconvert->mon_grouping;
	if (mon_group <= 0 || mon_group > 6)
		mon_group = 3;

	convention = lconvert->n_sign_posn;

	/* we restrict dsymbol to be a single byte, but not the other symbols */
	if (*lconvert->mon_decimal_point != '\0' &&
		lconvert->mon_decimal_point[1] == '\0')
		dsymbol = *lconvert->mon_decimal_point;
	else
		dsymbol = '.';
	if (*lconvert->mon_thousands_sep != '\0')
		ssymbol = lconvert->mon_thousands_sep;
	else						/* ssymbol should not equal dsymbol */
		ssymbol = (dsymbol != ',') ? "," : ".";
	csymbol = (*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$";
	nsymbol = (*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-";

	/* we work with positive amounts and add the minus sign at the end */
	if (value < 0)
	{
		minus = true;
		value = -value;
	}

	/* we build the result string right-to-left in buf[] */
	bufptr = buf + sizeof(buf) - 1;
	*bufptr = '\0';

	/*
	 * Generate digits till there are no non-zero digits left and we emitted
	 * at least one to the left of the decimal point.  digit_pos is the
	 * current digit position, with zero as the digit just left of the decimal
	 * point, increasing to the right.
	 */
	digit_pos = points;
	do
	{
		if (points && digit_pos == 0)
		{
			/* insert decimal point */
			*(--bufptr) = dsymbol;
		}
		else if (digit_pos < points && (digit_pos % mon_group) == 0)
		{
			/* insert thousands sep */
			bufptr -= strlen(ssymbol);
			memcpy(bufptr, ssymbol, strlen(ssymbol));
		}

		*(--bufptr) = ((uint64) value % 10) + '0';
		value = ((uint64) value) / 10;
		digit_pos--;
	} while (value || digit_pos >= 0);

	/* prepend csymbol */
	bufptr -= strlen(csymbol);
	memcpy(bufptr, csymbol, strlen(csymbol));

	/* see if we need to signify negative amount */
	if (minus)
	{
		result = palloc(strlen(bufptr) + strlen(nsymbol) + 3);

		/* Position code of 0 means use parens */
		if (convention == 0)
			sprintf(result, "(%s)", bufptr);
		else if (convention == 2)
			sprintf(result, "%s%s", bufptr, nsymbol);
		else
			sprintf(result, "%s%s", nsymbol, bufptr);
	}
	else
	{
		/* just emit what we have */
		result = pstrdup(bufptr);
	}

	PG_RETURN_CSTRING(result);
}
예제 #27
0
파일: cash.c 프로젝트: AmiGanguli/postgres
/* cash_out()
 * Function to convert cash to a dollars and cents representation, using
 * the lc_monetary locale's formatting.
 */
Datum
cash_out(PG_FUNCTION_ARGS)
{
	Cash		value = PG_GETARG_CASH(0);
	char	   *result;
	char		buf[128];
	char	   *bufptr;
	int			digit_pos;
	int			points,
				mon_group;
	char		dsymbol;
	const char *ssymbol,
			   *csymbol,
			   *signsymbol;
	char		sign_posn,
				cs_precedes,
				sep_by_space;
	struct lconv *lconvert = PGLC_localeconv();

	/* see comments about frac_digits in cash_in() */
	points = lconvert->frac_digits;
	if (points < 0 || points > 10)
		points = 2;				/* best guess in this case, I think */

	/*
	 * As with frac_digits, must apply a range check to mon_grouping to avoid
	 * being fooled by variant CHAR_MAX values.
	 */
	mon_group = *lconvert->mon_grouping;
	if (mon_group <= 0 || mon_group > 6)
		mon_group = 3;

	/* we restrict dsymbol to be a single byte, but not the other symbols */
	if (*lconvert->mon_decimal_point != '\0' &&
		lconvert->mon_decimal_point[1] == '\0')
		dsymbol = *lconvert->mon_decimal_point;
	else
		dsymbol = '.';
	if (*lconvert->mon_thousands_sep != '\0')
		ssymbol = lconvert->mon_thousands_sep;
	else						/* ssymbol should not equal dsymbol */
		ssymbol = (dsymbol != ',') ? "," : ".";
	csymbol = (*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$";

	if (value < 0)
	{
		/* make the amount positive for digit-reconstruction loop */
		value = -value;
		/* set up formatting data */
		signsymbol = (*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-";
		sign_posn = lconvert->n_sign_posn;
		cs_precedes = lconvert->n_cs_precedes;
		sep_by_space = lconvert->n_sep_by_space;
	}
	else
	{
		signsymbol = lconvert->positive_sign;
		sign_posn = lconvert->p_sign_posn;
		cs_precedes = lconvert->p_cs_precedes;
		sep_by_space = lconvert->p_sep_by_space;
	}

	/* we build the digits+decimal-point+sep string right-to-left in buf[] */
	bufptr = buf + sizeof(buf) - 1;
	*bufptr = '\0';

	/*
	 * Generate digits till there are no non-zero digits left and we emitted
	 * at least one to the left of the decimal point.  digit_pos is the
	 * current digit position, with zero as the digit just left of the decimal
	 * point, increasing to the right.
	 */
	digit_pos = points;
	do
	{
		if (points && digit_pos == 0)
		{
			/* insert decimal point, but not if value cannot be fractional */
			*(--bufptr) = dsymbol;
		}
		else if (digit_pos < 0 && (digit_pos % mon_group) == 0)
		{
			/* insert thousands sep, but only to left of radix point */
			bufptr -= strlen(ssymbol);
			memcpy(bufptr, ssymbol, strlen(ssymbol));
		}

		*(--bufptr) = ((uint64) value % 10) + '0';
		value = ((uint64) value) / 10;
		digit_pos--;
	} while (value || digit_pos >= 0);

	/*----------
	 * Now, attach currency symbol and sign symbol in the correct order.
	 *
	 * The POSIX spec defines these values controlling this code:
	 *
	 * p/n_sign_posn:
	 *	0	Parentheses enclose the quantity and the currency_symbol.
	 *	1	The sign string precedes the quantity and the currency_symbol.
	 *	2	The sign string succeeds the quantity and the currency_symbol.
	 *	3	The sign string precedes the currency_symbol.
	 *	4	The sign string succeeds the currency_symbol.
	 *
	 * p/n_cs_precedes: 0 means currency symbol after value, else before it.
	 *
	 * p/n_sep_by_space:
	 *	0	No <space> separates the currency symbol and value.
	 *	1	If the currency symbol and sign string are adjacent, a <space>
	 *		separates them from the value; otherwise, a <space> separates
	 *		the currency symbol from the value.
	 *	2	If the currency symbol and sign string are adjacent, a <space>
	 *		separates them; otherwise, a <space> separates the sign string
	 *		from the value.
	 *----------
	 */
	switch (sign_posn)
	{
		case 0:
			if (cs_precedes)
				result = psprintf("(%s%s%s)",
								  csymbol,
								  (sep_by_space == 1) ? " " : "",
								  bufptr);
			else
				result = psprintf("(%s%s%s)",
								  bufptr,
								  (sep_by_space == 1) ? " " : "",
								  csymbol);
			break;
		case 1:
		default:
			if (cs_precedes)
				result = psprintf("%s%s%s%s%s",
								  signsymbol,
								  (sep_by_space == 2) ? " " : "",
								  csymbol,
								  (sep_by_space == 1) ? " " : "",
								  bufptr);
			else
				result = psprintf("%s%s%s%s%s",
								  signsymbol,
								  (sep_by_space == 2) ? " " : "",
								  bufptr,
								  (sep_by_space == 1) ? " " : "",
								  csymbol);
			break;
		case 2:
			if (cs_precedes)
				result = psprintf("%s%s%s%s%s",
								  csymbol,
								  (sep_by_space == 1) ? " " : "",
								  bufptr,
								  (sep_by_space == 2) ? " " : "",
								  signsymbol);
			else
				result = psprintf("%s%s%s%s%s",
								  bufptr,
								  (sep_by_space == 1) ? " " : "",
								  csymbol,
								  (sep_by_space == 2) ? " " : "",
								  signsymbol);
			break;
		case 3:
			if (cs_precedes)
				result = psprintf("%s%s%s%s%s",
								  signsymbol,
								  (sep_by_space == 2) ? " " : "",
								  csymbol,
								  (sep_by_space == 1) ? " " : "",
								  bufptr);
			else
				result = psprintf("%s%s%s%s%s",
								  bufptr,
								  (sep_by_space == 1) ? " " : "",
								  signsymbol,
								  (sep_by_space == 2) ? " " : "",
								  csymbol);
			break;
		case 4:
			if (cs_precedes)
				result = psprintf("%s%s%s%s%s",
								  csymbol,
								  (sep_by_space == 2) ? " " : "",
								  signsymbol,
								  (sep_by_space == 1) ? " " : "",
								  bufptr);
			else
				result = psprintf("%s%s%s%s%s",
								  bufptr,
								  (sep_by_space == 1) ? " " : "",
								  csymbol,
								  (sep_by_space == 2) ? " " : "",
								  signsymbol);
			break;
	}

	PG_RETURN_CSTRING(result);
}