2424#include "access/hash.h"
2525#include "utils/array.h"
2626#include "utils/builtins.h"
27+
28+ #ifdef PGXC
29+ #include "utils/int8.h"
30+ #endif /* PGXC */
31+
2732#include "utils/numeric.h"
2833
2934#define MAXINT8LEN 25
4247 */
4348#define FIXEDDECIMAL_SCALE 2
4449
50+ /* Sanity checks */
51+ #if FIXEDDECIMAL_SCALE == 0
52+ #error "FIXEDDECIMAL_SCALE cannot be zero. Just use a BIGINT if that's what you really want"
53+ #endif
54+
55+ #if FIXEDDECIMAL_SCALE > 19
56+ #error "FIXEDDECIMAL_SCALE cannot be greater than 19"
57+ #endif
58+
4559/*
4660 * This is bounded by the maximum and minimum values of int64.
4761 * 9223372036854775807 is 19 decimal digits long, but we we can only represent
@@ -118,6 +132,14 @@ PG_FUNCTION_INFO_V1(fixeddecimal_avg_accum);
118132PG_FUNCTION_INFO_V1 (fixeddecimal_avg );
119133PG_FUNCTION_INFO_V1 (fixeddecimal_sum );
120134
135+ #ifdef PGXC
136+ PG_FUNCTION_INFO_V1 (fixeddecimalaggstatein );
137+ PG_FUNCTION_INFO_V1 (fixeddecimalaggstateout );
138+ PG_FUNCTION_INFO_V1 (fixeddecimalaggstatesend );
139+ PG_FUNCTION_INFO_V1 (fixeddecimalaggstaterecv );
140+ PG_FUNCTION_INFO_V1 (fixeddecimalaggstatecombine );
141+ #endif /* PGXC */
142+
121143/* Aggregate Internal State */
122144typedef struct FixedDecimalAggState
123145{
@@ -286,6 +308,36 @@ pg_int64tostr_zeropad(char *str, int64 value, int64 padding)
286308 return end ;
287309}
288310
311+ /*
312+ * fixeddecimal2str
313+ * Prints the fixeddecimal 'val' to buffer as a string.
314+ * Returns a pointer to the end of the written string.
315+ */
316+ static char *
317+ fixeddecimal2str (int64 val , char * buffer )
318+ {
319+ char * ptr = buffer ;
320+ int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER ;
321+ int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER ;
322+
323+ if (val < 0 )
324+ {
325+ fractionalpart = - fractionalpart ;
326+
327+ /*
328+ * Handle special case for negative numbers where the intergral part
329+ * is zero. pg_int64tostr() won't prefix with "-0" in this case, so
330+ * we'll do it manually
331+ */
332+ if (integralpart == 0 )
333+ * ptr ++ = '-' ;
334+ }
335+ ptr = pg_int64tostr (ptr , integralpart );
336+ * ptr ++ = '.' ;
337+ ptr = pg_int64tostr_zeropad (ptr , fractionalpart , FIXEDDECIMAL_SCALE );
338+ return ptr ;
339+ }
340+
289341/*
290342 * scanfixeddecimal --- try to parse a string into a fixeddecimal.
291343 */
@@ -583,28 +635,8 @@ fixeddecimalout(PG_FUNCTION_ARGS)
583635{
584636 int64 val = PG_GETARG_INT64 (0 );
585637 char buf [MAXINT8LEN + 1 ];
586- char * ptr = & buf [0 ];
587- int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER ;
588- int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER ;
589-
590-
591- if (val < 0 )
592- {
593- fractionalpart = - fractionalpart ;
594-
595- /*
596- * Handle special case for negative numbers where the intergral part
597- * is zero. pg_int64tostr() won't prefix with "-0" in this case, so
598- * we'll do it manually
599- */
600- if (integralpart == 0 )
601- * ptr ++ = '-' ;
602- }
603- ptr = pg_int64tostr (ptr , integralpart );
604- * ptr ++ = '.' ;
605- ptr = pg_int64tostr_zeropad (ptr , fractionalpart , FIXEDDECIMAL_SCALE );
606-
607- PG_RETURN_CSTRING (pnstrdup (buf , ptr - & buf [0 ]));
638+ char * end = fixeddecimal2str (val , buf );
639+ PG_RETURN_CSTRING (pnstrdup (buf , end - buf ));
608640}
609641
610642/*
@@ -1684,6 +1716,7 @@ fixeddecimal_avg(PG_FUNCTION_ARGS)
16841716 PG_RETURN_INT64 (state -> sumX / state -> N );
16851717}
16861718
1719+
16871720Datum
16881721fixeddecimal_sum (PG_FUNCTION_ARGS )
16891722{
@@ -1697,3 +1730,94 @@ fixeddecimal_sum(PG_FUNCTION_ARGS)
16971730
16981731 PG_RETURN_INT64 (state -> sumX );
16991732}
1733+
1734+
1735+ #ifdef PGXC
1736+
1737+ /*
1738+ * Input / Output / Send / Receive functions for aggrgate states
1739+ * Currently for XL only
1740+ */
1741+
1742+ Datum
1743+ fixeddecimalaggstatein (PG_FUNCTION_ARGS )
1744+ {
1745+ char * str = pstrdup (PG_GETARG_CSTRING (0 ));
1746+ FixedDecimalAggState * state ;
1747+ char * token ;
1748+
1749+ state = (FixedDecimalAggState * ) palloc0 (sizeof (FixedDecimalAggState ));
1750+
1751+ token = strtok (str , ":" );
1752+ state -> sumX = DatumGetInt64 (DirectFunctionCall3 (fixeddecimalin , CStringGetDatum (token ), 0 , -1 ));
1753+ token = strtok (NULL , ":" );
1754+ state -> N = DatumGetInt64 (DirectFunctionCall1 (int8in , CStringGetDatum (token )));
1755+ pfree (str );
1756+
1757+ PG_RETURN_POINTER (state );
1758+ }
1759+
1760+
1761+ /*
1762+ * fixeddecimalaggstateout()
1763+ */
1764+ Datum
1765+ fixeddecimalaggstateout (PG_FUNCTION_ARGS )
1766+ {
1767+ FixedDecimalAggState * state = (FixedDecimalAggState * ) PG_GETARG_POINTER (0 );
1768+ char buf [MAXINT8LEN + 1 + MAXINT8LEN + 1 ];
1769+ char * p ;
1770+
1771+ p = fixeddecimal2str (state -> sumX , buf );
1772+ * p ++ = ':' ;
1773+ p = pg_int64tostr (p , state -> N );
1774+ PG_RETURN_CSTRING (pnstrdup (buf , p - buf ));
1775+ }
1776+
1777+ /*
1778+ * fixeddecimalaggstaterecv
1779+ */
1780+ Datum
1781+ fixeddecimalaggstaterecv (PG_FUNCTION_ARGS )
1782+ {
1783+ StringInfo buf = (StringInfo ) PG_GETARG_POINTER (0 );
1784+ FixedDecimalAggState * state ;
1785+ state = (FixedDecimalAggState * ) palloc (sizeof (FixedDecimalAggState ));
1786+
1787+ state -> sumX = pq_getmsgint (buf , sizeof (int64 ));
1788+ state -> N = pq_getmsgint (buf , sizeof (int64 ));
1789+
1790+ PG_RETURN_POINTER (state );
1791+ }
1792+
1793+ /*
1794+ * fixeddecimalaggstatesend
1795+ */
1796+ Datum
1797+ fixeddecimalaggstatesend (PG_FUNCTION_ARGS )
1798+ {
1799+ FixedDecimalAggState * state = (FixedDecimalAggState * ) PG_GETARG_POINTER (0 );
1800+ StringInfoData buf ;
1801+
1802+ pq_begintypsend (& buf );
1803+
1804+ pq_sendint (& buf , state -> sumX , sizeof (int64 ));
1805+ pq_sendint (& buf , state -> N , sizeof (int64 ));
1806+
1807+ PG_RETURN_BYTEA_P (pq_endtypsend (& buf ));
1808+ }
1809+
1810+ Datum
1811+ fixeddecimalaggstatecombine (PG_FUNCTION_ARGS )
1812+ {
1813+ FixedDecimalAggState * state1 = (FixedDecimalAggState * ) PG_GETARG_POINTER (0 );
1814+ FixedDecimalAggState * state2 = (FixedDecimalAggState * ) PG_GETARG_POINTER (1 );
1815+ FixedDecimalAggState * newstate = palloc (sizeof (FixedDecimalAggState ));
1816+
1817+ newstate -> sumX = DatumGetInt64 (DirectFunctionCall2 (fixeddecimalpl , Int64GetDatum (state1 -> sumX ), Int64GetDatum (state2 -> sumX )));
1818+ newstate -> N = DatumGetInt64 (DirectFunctionCall2 (int8pl , Int64GetDatum (state1 -> N ), Int64GetDatum (state2 -> N )));
1819+
1820+ PG_RETURN_POINTER (newstate );
1821+ }
1822+
1823+ #endif /* PGXC */
0 commit comments