Replace static bufs with a StringInfo in cash_words()
For clarity. The code was correct, and the buffer was large enough, but string manipulation with no bounds checking is scary. This incurs an extra palloc+pfree to every call, but in quick performance testing, it doesn't seem to be significant. Reviewed-by: Robert Haas Discussion: https://www.postgresql.org/message-id/7f86e06a-98c5-4ce3-8ec9-3885c8de0358@iki.fi
This commit is contained in:
parent
47c98035c6
commit
5bf948d564
@ -35,10 +35,9 @@
|
|||||||
* Private routines
|
* Private routines
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
static const char *
|
static void
|
||||||
num_word(Cash value)
|
append_num_word(StringInfo buf, Cash value)
|
||||||
{
|
{
|
||||||
static char buf[128];
|
|
||||||
static const char *const small[] = {
|
static const char *const small[] = {
|
||||||
"zero", "one", "two", "three", "four", "five", "six", "seven",
|
"zero", "one", "two", "three", "four", "five", "six", "seven",
|
||||||
"eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
|
"eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
|
||||||
@ -50,13 +49,16 @@ num_word(Cash value)
|
|||||||
|
|
||||||
/* deal with the simple cases first */
|
/* deal with the simple cases first */
|
||||||
if (value <= 20)
|
if (value <= 20)
|
||||||
return small[value];
|
{
|
||||||
|
appendStringInfoString(buf, small[value]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* is it an even multiple of 100? */
|
/* is it an even multiple of 100? */
|
||||||
if (!tu)
|
if (!tu)
|
||||||
{
|
{
|
||||||
sprintf(buf, "%s hundred", small[value / 100]);
|
appendStringInfo(buf, "%s hundred", small[value / 100]);
|
||||||
return buf;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* more than 99? */
|
/* more than 99? */
|
||||||
@ -64,27 +66,25 @@ num_word(Cash value)
|
|||||||
{
|
{
|
||||||
/* is it an even multiple of 10 other than 10? */
|
/* is it an even multiple of 10 other than 10? */
|
||||||
if (value % 10 == 0 && tu > 10)
|
if (value % 10 == 0 && tu > 10)
|
||||||
sprintf(buf, "%s hundred %s",
|
appendStringInfo(buf, "%s hundred %s",
|
||||||
small[value / 100], big[tu / 10]);
|
small[value / 100], big[tu / 10]);
|
||||||
else if (tu < 20)
|
else if (tu < 20)
|
||||||
sprintf(buf, "%s hundred and %s",
|
appendStringInfo(buf, "%s hundred and %s",
|
||||||
small[value / 100], small[tu]);
|
small[value / 100], small[tu]);
|
||||||
else
|
else
|
||||||
sprintf(buf, "%s hundred %s %s",
|
appendStringInfo(buf, "%s hundred %s %s",
|
||||||
small[value / 100], big[tu / 10], small[tu % 10]);
|
small[value / 100], big[tu / 10], small[tu % 10]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* is it an even multiple of 10 other than 10? */
|
/* is it an even multiple of 10 other than 10? */
|
||||||
if (value % 10 == 0 && tu > 10)
|
if (value % 10 == 0 && tu > 10)
|
||||||
sprintf(buf, "%s", big[tu / 10]);
|
appendStringInfoString(buf, big[tu / 10]);
|
||||||
else if (tu < 20)
|
else if (tu < 20)
|
||||||
sprintf(buf, "%s", small[tu]);
|
appendStringInfoString(buf, small[tu]);
|
||||||
else
|
else
|
||||||
sprintf(buf, "%s %s", big[tu / 10], small[tu % 10]);
|
appendStringInfo(buf, "%s %s", big[tu / 10], small[tu % 10]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
|
||||||
} /* num_word() */
|
} /* num_word() */
|
||||||
|
|
||||||
static inline Cash
|
static inline Cash
|
||||||
@ -960,8 +960,9 @@ cash_words(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Cash value = PG_GETARG_CASH(0);
|
Cash value = PG_GETARG_CASH(0);
|
||||||
uint64 val;
|
uint64 val;
|
||||||
char buf[256];
|
StringInfoData buf;
|
||||||
char *p = buf;
|
text *res;
|
||||||
|
Cash dollars;
|
||||||
Cash m0;
|
Cash m0;
|
||||||
Cash m1;
|
Cash m1;
|
||||||
Cash m2;
|
Cash m2;
|
||||||
@ -970,19 +971,19 @@ cash_words(PG_FUNCTION_ARGS)
|
|||||||
Cash m5;
|
Cash m5;
|
||||||
Cash m6;
|
Cash m6;
|
||||||
|
|
||||||
|
initStringInfo(&buf);
|
||||||
|
|
||||||
/* work with positive numbers */
|
/* work with positive numbers */
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
{
|
{
|
||||||
value = -value;
|
value = -value;
|
||||||
strcpy(buf, "minus ");
|
appendStringInfoString(&buf, "minus ");
|
||||||
p += 6;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
buf[0] = '\0';
|
|
||||||
|
|
||||||
/* Now treat as unsigned, to avoid trouble at INT_MIN */
|
/* Now treat as unsigned, to avoid trouble at INT_MIN */
|
||||||
val = (uint64) value;
|
val = (uint64) value;
|
||||||
|
|
||||||
|
dollars = val / INT64CONST(100);
|
||||||
m0 = val % INT64CONST(100); /* cents */
|
m0 = val % INT64CONST(100); /* cents */
|
||||||
m1 = (val / INT64CONST(100)) % 1000; /* hundreds */
|
m1 = (val / INT64CONST(100)) % 1000; /* hundreds */
|
||||||
m2 = (val / INT64CONST(100000)) % 1000; /* thousands */
|
m2 = (val / INT64CONST(100000)) % 1000; /* thousands */
|
||||||
@ -993,49 +994,51 @@ cash_words(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
if (m6)
|
if (m6)
|
||||||
{
|
{
|
||||||
strcat(buf, num_word(m6));
|
append_num_word(&buf, m6);
|
||||||
strcat(buf, " quadrillion ");
|
appendStringInfoString(&buf, " quadrillion ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m5)
|
if (m5)
|
||||||
{
|
{
|
||||||
strcat(buf, num_word(m5));
|
append_num_word(&buf, m5);
|
||||||
strcat(buf, " trillion ");
|
appendStringInfoString(&buf, " trillion ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m4)
|
if (m4)
|
||||||
{
|
{
|
||||||
strcat(buf, num_word(m4));
|
append_num_word(&buf, m4);
|
||||||
strcat(buf, " billion ");
|
appendStringInfoString(&buf, " billion ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m3)
|
if (m3)
|
||||||
{
|
{
|
||||||
strcat(buf, num_word(m3));
|
append_num_word(&buf, m3);
|
||||||
strcat(buf, " million ");
|
appendStringInfoString(&buf, " million ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m2)
|
if (m2)
|
||||||
{
|
{
|
||||||
strcat(buf, num_word(m2));
|
append_num_word(&buf, m2);
|
||||||
strcat(buf, " thousand ");
|
appendStringInfoString(&buf, " thousand ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m1)
|
if (m1)
|
||||||
strcat(buf, num_word(m1));
|
append_num_word(&buf, m1);
|
||||||
|
|
||||||
if (!*p)
|
if (dollars == 0)
|
||||||
strcat(buf, "zero");
|
appendStringInfoString(&buf, "zero");
|
||||||
|
|
||||||
strcat(buf, (val / 100) == 1 ? " dollar and " : " dollars and ");
|
appendStringInfoString(&buf, dollars == 1 ? " dollar and " : " dollars and ");
|
||||||
strcat(buf, num_word(m0));
|
append_num_word(&buf, m0);
|
||||||
strcat(buf, m0 == 1 ? " cent" : " cents");
|
appendStringInfoString(&buf, m0 == 1 ? " cent" : " cents");
|
||||||
|
|
||||||
/* capitalize output */
|
/* capitalize output */
|
||||||
buf[0] = pg_toupper((unsigned char) buf[0]);
|
buf.data[0] = pg_toupper((unsigned char) buf.data[0]);
|
||||||
|
|
||||||
/* return as text datum */
|
/* return as text datum */
|
||||||
PG_RETURN_TEXT_P(cstring_to_text(buf));
|
res = cstring_to_text_with_len(buf.data, buf.len);
|
||||||
|
pfree(buf.data);
|
||||||
|
PG_RETURN_TEXT_P(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user