Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
74a40190
Commit
74a40190
authored
Jan 03, 2007
by
D'Arcy J.M. Cain
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Widen the money type to 64 bits.
parent
d30d8f3a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
176 additions
and
111 deletions
+176
-111
src/backend/utils/adt/cash.c
src/backend/utils/adt/cash.c
+164
-102
src/include/catalog/pg_type.h
src/include/catalog/pg_type.h
+3
-3
src/include/utils/cash.h
src/include/utils/cash.h
+9
-6
No files found.
src/backend/utils/adt/cash.c
View file @
74a40190
/*
* cash.c
* Written by D'Arcy J.M. Cain
* darcy@druid.net
* http://www.druid.net/darcy/
*
* Functions to allow input and output of money normally but store
* and handle it as
int4
s
* and handle it as
64 bit int
s
*
* A slightly modified version of this file and a discussion of the
* workings can be found in the book "Software Solutions in C" by
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7 except that
* this version handles 64 bit numbers and so can hold values up to
* $92,233,720,368,547,758.07.
*
* $PostgreSQL: pgsql/src/backend/utils/adt/cash.c,v 1.6
8 2006/07/14 14:52:23 momjian
Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/cash.c,v 1.6
9 2007/01/03 01:19:50 darcy
Exp $
*/
#include "postgres.h"
...
...
@@ -23,17 +27,12 @@
#include "utils/cash.h"
#include "utils/pg_locale.h"
static
const
char
*
num_word
(
Cash
value
);
/* when we go to 64 bit values we will have to modify this */
#define CASH_BUFSZ 24
#define CASH_BUFSZ 36
#define TERMINATOR (CASH_BUFSZ - 1)
#define LAST_PAREN (TERMINATOR - 1)
#define LAST_DIGIT (LAST_PAREN - 1)
/*
* Cash is a pass-by-ref SQL type, so we must pass and return pointers.
* These macros and support routine hide the pass-by-refness.
...
...
@@ -41,6 +40,65 @@ static const char *num_word(Cash value);
#define PG_GETARG_CASH(n) (* ((Cash *) PG_GETARG_POINTER(n)))
#define PG_RETURN_CASH(x) return CashGetDatum(x)
/*************************************************************************
* Private routines
************************************************************************/
static
const
char
*
num_word
(
Cash
value
)
{
static
char
buf
[
128
];
static
const
char
*
small
[]
=
{
"zero"
,
"one"
,
"two"
,
"three"
,
"four"
,
"five"
,
"six"
,
"seven"
,
"eight"
,
"nine"
,
"ten"
,
"eleven"
,
"twelve"
,
"thirteen"
,
"fourteen"
,
"fifteen"
,
"sixteen"
,
"seventeen"
,
"eighteen"
,
"nineteen"
,
"twenty"
,
"thirty"
,
"forty"
,
"fifty"
,
"sixty"
,
"seventy"
,
"eighty"
,
"ninety"
};
const
char
**
big
=
small
+
18
;
int
tu
=
value
%
100
;
/* deal with the simple cases first */
if
(
value
<=
20
)
return
small
[
value
];
/* is it an even multiple of 100? */
if
(
!
tu
)
{
sprintf
(
buf
,
"%s hundred"
,
small
[
value
/
100
]);
return
buf
;
}
/* more than 99? */
if
(
value
>
99
)
{
/* is it an even multiple of 10 other than 10? */
if
(
value
%
10
==
0
&&
tu
>
10
)
sprintf
(
buf
,
"%s hundred %s"
,
small
[
value
/
100
],
big
[
tu
/
10
]);
else
if
(
tu
<
20
)
sprintf
(
buf
,
"%s hundred and %s"
,
small
[
value
/
100
],
small
[
tu
]);
else
sprintf
(
buf
,
"%s hundred %s %s"
,
small
[
value
/
100
],
big
[
tu
/
10
],
small
[
tu
%
10
]);
}
else
{
/* is it an even multiple of 10 other than 10? */
if
(
value
%
10
==
0
&&
tu
>
10
)
sprintf
(
buf
,
"%s"
,
big
[
tu
/
10
]);
else
if
(
tu
<
20
)
sprintf
(
buf
,
"%s"
,
small
[
tu
]);
else
sprintf
(
buf
,
"%s %s"
,
big
[
tu
/
10
],
small
[
tu
%
10
]);
}
return
buf
;
}
/* num_word() */
static
Datum
CashGetDatum
(
Cash
value
)
{
...
...
@@ -56,12 +114,6 @@ CashGetDatum(Cash value)
* Format is [$]###[,]###[.##]
* Examples: 123.45 $123.45 $123,456.78
*
* This is currently implemented as a 32-bit integer.
* XXX HACK It looks as though some of the symbols for
* monetary values returned by localeconv() can be multiple
* bytes/characters. This code assumes one byte only. - tgl 97/04/14
* XXX UNHACK Allow the currency symbol to be multibyte.
* - thomas 1998-03-01
*/
Datum
cash_in
(
PG_FUNCTION_ARGS
)
...
...
@@ -74,11 +126,11 @@ cash_in(PG_FUNCTION_ARGS)
int
seen_dot
=
0
;
const
char
*
s
=
str
;
int
fpoint
;
char
*
csymbol
;
char
dsymbol
,
ssymbol
,
psymbol
,
*
nsymbol
;
psymbol
;
const
char
*
nsymbol
,
*
csymbol
;
struct
lconv
*
lconvert
=
PGLC_localeconv
();
...
...
@@ -120,6 +172,7 @@ cash_in(PG_FUNCTION_ARGS)
/* a leading minus or paren signifies a negative number */
/* again, better heuristics needed */
/* XXX - doesn't properly check for balanced parens - djmc */
if
(
strncmp
(
s
,
nsymbol
,
strlen
(
nsymbol
))
==
0
)
{
sgn
=
-
1
;
...
...
@@ -152,7 +205,7 @@ cash_in(PG_FUNCTION_ARGS)
for
(;;
s
++
)
{
/* we look for digits as int
4
as we have less */
/* we look for digits as int
8
as we have less */
/* than the required number of decimal places */
if
(
isdigit
((
unsigned
char
)
*
s
)
&&
dec
<
fpoint
)
{
...
...
@@ -161,14 +214,14 @@ cash_in(PG_FUNCTION_ARGS)
if
(
seen_dot
)
dec
++
;
/* decimal point? then start counting fractions... */
}
/* decimal point? then start counting fractions... */
else
if
(
*
s
==
dsymbol
&&
!
seen_dot
)
{
seen_dot
=
1
;
/* "thousands" separator? then skip... */
}
/* "thousands" separator? then skip... */
else
if
(
*
s
==
ssymbol
)
{
...
...
@@ -187,7 +240,9 @@ cash_in(PG_FUNCTION_ARGS)
}
}
while
(
isspace
((
unsigned
char
)
*
s
)
||
*
s
==
'0'
||
*
s
==
')'
)
/* should only be trailing digits followed by whitespace or closing paren */
while
(
isdigit
(
*
s
))
s
++
;
while
(
isspace
((
unsigned
char
)
*
s
)
||
*
s
==
')'
)
s
++
;
if
(
*
s
!=
'\0'
)
...
...
@@ -223,9 +278,9 @@ cash_out(PG_FUNCTION_ARGS)
int
points
,
mon_group
;
char
comma
;
char
*
csymbol
,
dsymbol
,
const
char
*
csymbol
,
*
nsymbol
;
char
dsymbol
;
char
convention
;
struct
lconv
*
lconvert
=
PGLC_localeconv
();
...
...
@@ -276,8 +331,8 @@ cash_out(PG_FUNCTION_ARGS)
else
if
(
comma
&&
count
%
(
mon_group
+
1
)
==
comma_position
)
buf
[
count
--
]
=
comma
;
buf
[
count
--
]
=
((
u
nsigned
int
)
value
%
10
)
+
'0'
;
value
=
((
u
nsigned
int
)
value
)
/
10
;
buf
[
count
--
]
=
((
u
int64
)
value
%
10
)
+
'0'
;
value
=
((
u
int64
)
value
)
/
10
;
}
strncpy
((
buf
+
count
-
strlen
(
csymbol
)
+
1
),
csymbol
,
strlen
(
csymbol
));
...
...
@@ -470,9 +525,6 @@ flt8_mul_cash(PG_FUNCTION_ARGS)
/* cash_div_flt8()
* Divide cash by float8.
*
* XXX Don't know if rounding or truncating is correct behavior.
* Round for now. - tgl 97/04/15
*/
Datum
cash_div_flt8
(
PG_FUNCTION_ARGS
)
...
...
@@ -490,6 +542,7 @@ cash_div_flt8(PG_FUNCTION_ARGS)
PG_RETURN_CASH
(
result
);
}
/* cash_mul_flt4()
* Multiply cash by float4.
*/
...
...
@@ -523,8 +576,6 @@ flt4_mul_cash(PG_FUNCTION_ARGS)
/* 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
)
...
...
@@ -543,6 +594,56 @@ cash_div_flt4(PG_FUNCTION_ARGS)
}
/* cash_mul_int8()
* Multiply cash by int8.
*/
Datum
cash_mul_int8
(
PG_FUNCTION_ARGS
)
{
Cash
c
=
PG_GETARG_CASH
(
0
);
int64
i
=
PG_GETARG_INT64
(
1
);
Cash
result
;
result
=
c
*
i
;
PG_RETURN_CASH
(
result
);
}
/* int8_mul_cash()
* Multiply int8 by cash.
*/
Datum
int8_mul_cash
(
PG_FUNCTION_ARGS
)
{
int64
i
=
PG_GETARG_INT64
(
0
);
Cash
c
=
PG_GETARG_CASH
(
1
);
Cash
result
;
result
=
i
*
c
;
PG_RETURN_CASH
(
result
);
}
/* cash_div_int8()
* Divide cash by 8-byte integer.
*/
Datum
cash_div_int8
(
PG_FUNCTION_ARGS
)
{
Cash
c
=
PG_GETARG_CASH
(
0
);
int64
i
=
PG_GETARG_INT64
(
1
);
Cash
result
;
if
(
i
==
0
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DIVISION_BY_ZERO
),
errmsg
(
"division by zero"
)));
result
=
rint
(
c
/
i
);
PG_RETURN_CASH
(
result
);
}
/* cash_mul_int4()
* Multiply cash by int4.
*/
...
...
@@ -550,7 +651,7 @@ Datum
cash_mul_int4
(
PG_FUNCTION_ARGS
)
{
Cash
c
=
PG_GETARG_CASH
(
0
);
int
32
i
=
PG_GETARG_INT32
(
1
);
int
64
i
=
PG_GETARG_INT64
(
1
);
Cash
result
;
result
=
c
*
i
;
...
...
@@ -576,14 +677,12 @@ int4_mul_cash(PG_FUNCTION_ARGS)
/* cash_div_int4()
* Divide cash by 4-byte integer.
*
* XXX Don't know if rounding or truncating is correct behavior.
* Round for now. - tgl 97/04/15
*/
Datum
cash_div_int4
(
PG_FUNCTION_ARGS
)
{
Cash
c
=
PG_GETARG_CASH
(
0
);
int
32
i
=
PG_GETARG_INT32
(
1
);
int
64
i
=
PG_GETARG_INT64
(
1
);
Cash
result
;
if
(
i
==
0
)
...
...
@@ -628,8 +727,6 @@ int2_mul_cash(PG_FUNCTION_ARGS)
/* 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
)
...
...
@@ -677,7 +774,6 @@ cashsmaller(PG_FUNCTION_ARGS)
PG_RETURN_CASH
(
result
);
}
/* cash_words()
* This converts a int4 as well but to a representation using words
* Obviously way North American centric - sorry
...
...
@@ -686,13 +782,16 @@ Datum
cash_words
(
PG_FUNCTION_ARGS
)
{
Cash
value
=
PG_GETARG_CASH
(
0
);
u
nsigned
int
val
;
u
int64
val
;
char
buf
[
256
];
char
*
p
=
buf
;
Cash
m0
;
Cash
m1
;
Cash
m2
;
Cash
m3
;
Cash
m4
;
Cash
m5
;
Cash
m6
;
text
*
result
;
/* work with positive numbers */
...
...
@@ -706,12 +805,33 @@ cash_words(PG_FUNCTION_ARGS)
buf
[
0
]
=
'\0'
;
/* Now treat as unsigned, to avoid trouble at INT_MIN */
val
=
(
u
nsigned
int
)
value
;
val
=
(
u
int64
)
value
;
m0
=
val
%
100
;
/* cents */
m1
=
(
val
/
100
)
%
1000
;
/* hundreds */
m2
=
(
val
/
100000
)
%
1000
;
/* thousands */
m3
=
val
/
100000000
%
1000
;
/* millions */
m0
=
val
%
100ll
;
/* cents */
m1
=
(
val
/
100ll
)
%
1000
;
/* hundreds */
m2
=
(
val
/
100000ll
)
%
1000
;
/* thousands */
m3
=
val
/
100000000ll
%
1000
;
/* millions */
m4
=
val
/
100000000000ll
%
1000
;
/* billions */
m5
=
val
/
100000000000000ll
%
1000
;
/* trillions */
m6
=
val
/
100000000000000000ll
%
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
)
{
...
...
@@ -745,61 +865,3 @@ cash_words(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P
(
result
);
}
/*************************************************************************
* Private routines
************************************************************************/
static
const
char
*
num_word
(
Cash
value
)
{
static
char
buf
[
128
];
static
const
char
*
small
[]
=
{
"zero"
,
"one"
,
"two"
,
"three"
,
"four"
,
"five"
,
"six"
,
"seven"
,
"eight"
,
"nine"
,
"ten"
,
"eleven"
,
"twelve"
,
"thirteen"
,
"fourteen"
,
"fifteen"
,
"sixteen"
,
"seventeen"
,
"eighteen"
,
"nineteen"
,
"twenty"
,
"thirty"
,
"forty"
,
"fifty"
,
"sixty"
,
"seventy"
,
"eighty"
,
"ninety"
};
const
char
**
big
=
small
+
18
;
int
tu
=
value
%
100
;
/* deal with the simple cases first */
if
(
value
<=
20
)
return
small
[
value
];
/* is it an even multiple of 100? */
if
(
!
tu
)
{
sprintf
(
buf
,
"%s hundred"
,
small
[
value
/
100
]);
return
buf
;
}
/* more than 99? */
if
(
value
>
99
)
{
/* is it an even multiple of 10 other than 10? */
if
(
value
%
10
==
0
&&
tu
>
10
)
sprintf
(
buf
,
"%s hundred %s"
,
small
[
value
/
100
],
big
[
tu
/
10
]);
else
if
(
tu
<
20
)
sprintf
(
buf
,
"%s hundred and %s"
,
small
[
value
/
100
],
small
[
tu
]);
else
sprintf
(
buf
,
"%s hundred %s %s"
,
small
[
value
/
100
],
big
[
tu
/
10
],
small
[
tu
%
10
]);
}
else
{
/* is it an even multiple of 10 other than 10? */
if
(
value
%
10
==
0
&&
tu
>
10
)
sprintf
(
buf
,
"%s"
,
big
[
tu
/
10
]);
else
if
(
tu
<
20
)
sprintf
(
buf
,
"%s"
,
small
[
tu
]);
else
sprintf
(
buf
,
"%s %s"
,
big
[
tu
/
10
],
small
[
tu
%
10
]);
}
return
buf
;
}
/* num_word() */
src/include/catalog/pg_type.h
View file @
74a40190
...
...
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.17
6 2006/12/30 21:21:55 tgl
Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.17
7 2007/01/03 01:19:51 darcy
Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
...
...
@@ -388,10 +388,10 @@ DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b t \054 0 0 circle_in circl
DESCR
(
"geometric circle '(center,radius)'"
);
#define CIRCLEOID 718
DATA
(
insert
OID
=
719
(
_circle
PGNSP
PGUID
-
1
f
b
t
\
054
0
718
array_in
array_out
array_recv
array_send
-
-
-
d
x
f
0
-
1
0
_null_
_null_
));
DATA
(
insert
OID
=
790
(
money
PGNSP
PGUID
4
f
b
t
\
054
0
0
cash_in
cash_out
cash_recv
cash_send
-
-
-
i
p
f
0
-
1
0
_null_
_null_
));
DATA
(
insert
OID
=
790
(
money
PGNSP
PGUID
8
f
b
t
\
054
0
0
cash_in
cash_out
cash_recv
cash_send
-
-
-
d
p
f
0
-
1
0
_null_
_null_
));
DESCR
(
"monetary amounts, $d,ddd.cc"
);
#define CASHOID 790
DATA
(
insert
OID
=
791
(
_money
PGNSP
PGUID
-
1
f
b
t
\
054
0
790
array_in
array_out
array_recv
array_send
-
-
-
i
x
f
0
-
1
0
_null_
_null_
));
DATA
(
insert
OID
=
791
(
_money
PGNSP
PGUID
-
1
f
b
t
\
054
0
790
array_in
array_out
array_recv
array_send
-
-
-
d
x
f
0
-
1
0
_null_
_null_
));
/* OIDS 800 - 899 */
DATA
(
insert
OID
=
829
(
macaddr
PGNSP
PGUID
6
f
b
t
\
054
0
0
macaddr_in
macaddr_out
macaddr_recv
macaddr_send
-
-
-
i
p
f
0
-
1
0
_null_
_null_
));
...
...
src/include/utils/cash.h
View file @
74a40190
...
...
@@ -3,7 +3,7 @@
* Written by D'Arcy J.M. Cain
*
* Functions to allow input and output of money normally but store
* and handle it as
int4
.
* and handle it as
64 bit integer
.
*/
#ifndef CASH_H
...
...
@@ -11,8 +11,7 @@
#include "fmgr.h"
/* if we store this as 4 bytes, we better make it int, not long, bjm */
typedef
int32
Cash
;
typedef
int64
Cash
;
extern
Datum
cash_in
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_out
(
PG_FUNCTION_ARGS
);
...
...
@@ -31,16 +30,20 @@ extern Datum cash_pl(PG_FUNCTION_ARGS);
extern
Datum
cash_mi
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_mul_flt8
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_div_flt8
(
PG_FUNCTION_ARGS
);
extern
Datum
flt8_mul_cash
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_div_flt8
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_mul_flt4
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_div_flt4
(
PG_FUNCTION_ARGS
);
extern
Datum
flt4_mul_cash
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_div_flt4
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_mul_int8
(
PG_FUNCTION_ARGS
);
extern
Datum
int8_mul_cash
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_div_int8
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_mul_int4
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_div_int4
(
PG_FUNCTION_ARGS
);
extern
Datum
int4_mul_cash
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_div_int4
(
PG_FUNCTION_ARGS
);
extern
Datum
cash_mul_int2
(
PG_FUNCTION_ARGS
);
extern
Datum
int2_mul_cash
(
PG_FUNCTION_ARGS
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment