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