Skip to content

Commit 5bf948d

Browse files
committed
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
1 parent 47c9803 commit 5bf948d

File tree

1 file changed

+44
-41
lines changed

1 file changed

+44
-41
lines changed

src/backend/utils/adt/cash.c

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@
3535
* Private routines
3636
************************************************************************/
3737

38-
static const char *
39-
num_word(Cash value)
38+
static void
39+
append_num_word(StringInfo buf, Cash value)
4040
{
41-
static char buf[128];
4241
static const char *const small[] = {
4342
"zero", "one", "two", "three", "four", "five", "six", "seven",
4443
"eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
@@ -50,41 +49,42 @@ num_word(Cash value)
5049

5150
/* deal with the simple cases first */
5251
if (value <= 20)
53-
return small[value];
52+
{
53+
appendStringInfoString(buf, small[value]);
54+
return;
55+
}
5456

5557
/* is it an even multiple of 100? */
5658
if (!tu)
5759
{
58-
sprintf(buf, "%s hundred", small[value / 100]);
59-
return buf;
60+
appendStringInfo(buf, "%s hundred", small[value / 100]);
61+
return;
6062
}
6163

6264
/* more than 99? */
6365
if (value > 99)
6466
{
6567
/* is it an even multiple of 10 other than 10? */
6668
if (value % 10 == 0 && tu > 10)
67-
sprintf(buf, "%s hundred %s",
68-
small[value / 100], big[tu / 10]);
69+
appendStringInfo(buf, "%s hundred %s",
70+
small[value / 100], big[tu / 10]);
6971
else if (tu < 20)
70-
sprintf(buf, "%s hundred and %s",
71-
small[value / 100], small[tu]);
72+
appendStringInfo(buf, "%s hundred and %s",
73+
small[value / 100], small[tu]);
7274
else
73-
sprintf(buf, "%s hundred %s %s",
74-
small[value / 100], big[tu / 10], small[tu % 10]);
75+
appendStringInfo(buf, "%s hundred %s %s",
76+
small[value / 100], big[tu / 10], small[tu % 10]);
7577
}
7678
else
7779
{
7880
/* is it an even multiple of 10 other than 10? */
7981
if (value % 10 == 0 && tu > 10)
80-
sprintf(buf, "%s", big[tu / 10]);
82+
appendStringInfoString(buf, big[tu / 10]);
8183
else if (tu < 20)
82-
sprintf(buf, "%s", small[tu]);
84+
appendStringInfoString(buf, small[tu]);
8385
else
84-
sprintf(buf, "%s %s", big[tu / 10], small[tu % 10]);
86+
appendStringInfo(buf, "%s %s", big[tu / 10], small[tu % 10]);
8587
}
86-
87-
return buf;
8888
} /* num_word() */
8989

9090
static inline Cash
@@ -960,8 +960,9 @@ cash_words(PG_FUNCTION_ARGS)
960960
{
961961
Cash value = PG_GETARG_CASH(0);
962962
uint64 val;
963-
char buf[256];
964-
char *p = buf;
963+
StringInfoData buf;
964+
text *res;
965+
Cash dollars;
965966
Cash m0;
966967
Cash m1;
967968
Cash m2;
@@ -970,19 +971,19 @@ cash_words(PG_FUNCTION_ARGS)
970971
Cash m5;
971972
Cash m6;
972973

974+
initStringInfo(&buf);
975+
973976
/* work with positive numbers */
974977
if (value < 0)
975978
{
976979
value = -value;
977-
strcpy(buf, "minus ");
978-
p += 6;
980+
appendStringInfoString(&buf, "minus ");
979981
}
980-
else
981-
buf[0] = '\0';
982982

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

986+
dollars = val / INT64CONST(100);
986987
m0 = val % INT64CONST(100); /* cents */
987988
m1 = (val / INT64CONST(100)) % 1000; /* hundreds */
988989
m2 = (val / INT64CONST(100000)) % 1000; /* thousands */
@@ -993,49 +994,51 @@ cash_words(PG_FUNCTION_ARGS)
993994

994995
if (m6)
995996
{
996-
strcat(buf, num_word(m6));
997-
strcat(buf, " quadrillion ");
997+
append_num_word(&buf, m6);
998+
appendStringInfoString(&buf, " quadrillion ");
998999
}
9991000

10001001
if (m5)
10011002
{
1002-
strcat(buf, num_word(m5));
1003-
strcat(buf, " trillion ");
1003+
append_num_word(&buf, m5);
1004+
appendStringInfoString(&buf, " trillion ");
10041005
}
10051006

10061007
if (m4)
10071008
{
1008-
strcat(buf, num_word(m4));
1009-
strcat(buf, " billion ");
1009+
append_num_word(&buf, m4);
1010+
appendStringInfoString(&buf, " billion ");
10101011
}
10111012

10121013
if (m3)
10131014
{
1014-
strcat(buf, num_word(m3));
1015-
strcat(buf, " million ");
1015+
append_num_word(&buf, m3);
1016+
appendStringInfoString(&buf, " million ");
10161017
}
10171018

10181019
if (m2)
10191020
{
1020-
strcat(buf, num_word(m2));
1021-
strcat(buf, " thousand ");
1021+
append_num_word(&buf, m2);
1022+
appendStringInfoString(&buf, " thousand ");
10221023
}
10231024

10241025
if (m1)
1025-
strcat(buf, num_word(m1));
1026+
append_num_word(&buf, m1);
10261027

1027-
if (!*p)
1028-
strcat(buf, "zero");
1028+
if (dollars == 0)
1029+
appendStringInfoString(&buf, "zero");
10291030

1030-
strcat(buf, (val / 100) == 1 ? " dollar and " : " dollars and ");
1031-
strcat(buf, num_word(m0));
1032-
strcat(buf, m0 == 1 ? " cent" : " cents");
1031+
appendStringInfoString(&buf, dollars == 1 ? " dollar and " : " dollars and ");
1032+
append_num_word(&buf, m0);
1033+
appendStringInfoString(&buf, m0 == 1 ? " cent" : " cents");
10331034

10341035
/* capitalize output */
1035-
buf[0] = pg_toupper((unsigned char) buf[0]);
1036+
buf.data[0] = pg_toupper((unsigned char) buf.data[0]);
10361037

10371038
/* return as text datum */
1038-
PG_RETURN_TEXT_P(cstring_to_text(buf));
1039+
res = cstring_to_text_with_len(buf.data, buf.len);
1040+
pfree(buf.data);
1041+
PG_RETURN_TEXT_P(res);
10391042
}
10401043

10411044

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy