From f6ecfba79d1ccd1c323e381e056220493419ac36 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 17:51:04 +1200 Subject: [PATCH 01/32] Initial workings of a fixeddecimal type --- contrib/fixeddecimal/Makefile | 21 + contrib/fixeddecimal/fixeddecimal--1.0.0.sql | 523 ++++++ contrib/fixeddecimal/fixeddecimal.c | 1444 +++++++++++++++++ contrib/fixeddecimal/fixeddecimal.control | 4 + .../fixeddecimal/test/expected/overflow.out | 63 + .../fixeddecimal/test/results/overflow.out | 67 + 6 files changed, 2122 insertions(+) create mode 100755 contrib/fixeddecimal/Makefile create mode 100755 contrib/fixeddecimal/fixeddecimal--1.0.0.sql create mode 100755 contrib/fixeddecimal/fixeddecimal.c create mode 100755 contrib/fixeddecimal/fixeddecimal.control create mode 100755 contrib/fixeddecimal/test/expected/overflow.out create mode 100755 contrib/fixeddecimal/test/results/overflow.out diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile new file mode 100755 index 00000000000..48477f6ceec --- /dev/null +++ b/contrib/fixeddecimal/Makefile @@ -0,0 +1,21 @@ +MODULE_big = fixeddecimal +OBJS = fixeddecimal.o + +EXTENSION = fixeddecimal +DATA = fixeddecimal--1.0.0.sql +MODULES = fixeddecimal + +CFLAGS=`pg_config --includedir-server` + +TESTS = $(wildcard test/sql/*.sql) +REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS)) +REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=fixeddecimal --temp-instance=. + +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) + +fixeddecimal.so: fixeddecimal.o + +fixeddecimal.o: fixeddecimal.c + diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql new file mode 100755 index 00000000000..e33c90314b4 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql @@ -0,0 +1,523 @@ + +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE FIXEDDECIMAL; + +CREATE FUNCTION fixeddecimalin(cstring) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'fixeddecimal', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalrecv' +LANGUAGE C STABLE STRICT; + +CREATE FUNCTION fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'fixeddecimal', 'fixeddecimalsend' +LANGUAGE C STABLE STRICT; + +CREATE TYPE FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = false, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +CREATE FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalum(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION abs(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +-- +-- Operators. +-- + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR - ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +CREATE FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + + +CREATE FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +-- +-- Cross type operators with int2 +-- + +CREATE FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +CREATE FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR + ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +-- +-- Casts +-- + +CREATE FUNCTION int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'fixeddecimal', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'fixeddecimal', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +-- Aggregate Support + + +CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_sum(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_avg(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE STRICT; + +CREATE AGGREGATE min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + STYPE = FIXEDDECIMAL, + SORTOP = < +); + +CREATE AGGREGATE max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + STYPE = FIXEDDECIMAL, + SORTOP = > +); + +CREATE AGGREGATE sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL +); \ No newline at end of file diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c new file mode 100755 index 00000000000..8d7a1bef3b4 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -0,0 +1,1444 @@ + +#include "postgres.h" + +#include +#include +#include + +#include "funcapi.h" +#include "libpq/pqformat.h" +#include "utils/builtins.h" + + +#define MAXINT8LEN 25 + +/* + * The scale which the number is actually stored. + * For example: 100 will allow 2 decimal places of precision + * This must always be a '1' followed by a number of '0's. + */ +#define FIXEDDECIMAL_MULTIPLIER 100LL + +/* + * Number of decimal places to store. + * This number should be the number of decimal digits that it takes to + * represent FIXEDDECIMAL_MULTIPLIER - 1 + */ +#define FIXEDDECIMAL_PRECISION 2 + +/* Define this if your compiler has _builtin_add_overflow() */ +#define HAVE_BUILTIN_OVERFLOW + +#ifndef HAVE_BUILTIN_OVERFLOW +#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) +#endif /* HAVE_BUILTIN_OVERFLOW */ + +#ifdef PG_MODULE_MAGIC +PG_MODULE_MAGIC; +#endif + +PG_FUNCTION_INFO_V1(fixeddecimalin); +PG_FUNCTION_INFO_V1(fixeddecimalout); +PG_FUNCTION_INFO_V1(fixeddecimalrecv); +PG_FUNCTION_INFO_V1(fixeddecimalsend); +PG_FUNCTION_INFO_V1(fixeddecimaleq); +PG_FUNCTION_INFO_V1(fixeddecimalne); +PG_FUNCTION_INFO_V1(fixeddecimallt); +PG_FUNCTION_INFO_V1(fixeddecimalgt); +PG_FUNCTION_INFO_V1(fixeddecimalle); +PG_FUNCTION_INFO_V1(fixeddecimalge); +PG_FUNCTION_INFO_V1(fixeddecimal_cmp); +PG_FUNCTION_INFO_V1(fixeddecimalum); +PG_FUNCTION_INFO_V1(fixeddecimalup); +PG_FUNCTION_INFO_V1(fixeddecimalpl); +PG_FUNCTION_INFO_V1(fixeddecimalmi); +PG_FUNCTION_INFO_V1(fixeddecimalmul); +PG_FUNCTION_INFO_V1(fixeddecimaldiv); +PG_FUNCTION_INFO_V1(fixeddecimalabs); +PG_FUNCTION_INFO_V1(fixeddecimallarger); +PG_FUNCTION_INFO_V1(fixeddecimalsmaller); +PG_FUNCTION_INFO_V1(fixeddecimalint4pl); +PG_FUNCTION_INFO_V1(fixeddecimalint4mi); +PG_FUNCTION_INFO_V1(fixeddecimalint4mul); +PG_FUNCTION_INFO_V1(fixeddecimalint4div); +PG_FUNCTION_INFO_V1(int4fixeddecimalpl); +PG_FUNCTION_INFO_V1(int4fixeddecimalmi); +PG_FUNCTION_INFO_V1(int4fixeddecimalmul); +PG_FUNCTION_INFO_V1(int4fixeddecimaldiv); +PG_FUNCTION_INFO_V1(fixeddecimalint2pl); +PG_FUNCTION_INFO_V1(fixeddecimalint2mi); +PG_FUNCTION_INFO_V1(fixeddecimalint2mul); +PG_FUNCTION_INFO_V1(fixeddecimalint2div); +PG_FUNCTION_INFO_V1(int2fixeddecimalpl); +PG_FUNCTION_INFO_V1(int2fixeddecimalmi); +PG_FUNCTION_INFO_V1(int2fixeddecimalmul); +PG_FUNCTION_INFO_V1(int2fixeddecimaldiv); +PG_FUNCTION_INFO_V1(int4fixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimalint4); +PG_FUNCTION_INFO_V1(int2fixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimalint2); +PG_FUNCTION_INFO_V1(fixeddecimaltod); +PG_FUNCTION_INFO_V1(dtofixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimaltof); +PG_FUNCTION_INFO_V1(ftofixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimal_avg_accum); +PG_FUNCTION_INFO_V1(fixeddecimal_avg); +PG_FUNCTION_INFO_V1(fixeddecimal_sum); + +/*********************************************************************** + ** + ** Routines for fixeddecimal + ** + ***********************************************************************/ + +/*---------------------------------------------------------- + * Formatting and conversion routines. + *---------------------------------------------------------*/ + + /* + * pg_int64tostr + * Converts 'value' into a decimal string representation of the number. + * + * Caller must ensure that 'str' points to enough memory to hold the result + * (at least 21 bytes, counting a leading sign and trailing NUL). + * Return value is a pointer to the new NUL terminated end of string. + */ +static char * +pg_int64tostr(char *str, int64 value) +{ + char *start; + char *end; + + /* + * Handle negative numbers in a special way. We can't just append a '-' + * prefix and reverse the sign as on two's complement machines negative + * numbers can be 1 further from 0 than positive numbers, we do it this way + * so we properly handle the smallest possible value. + */ + if (value < 0) + { + *str++ = '-'; + + /* mark the position we must reverse the string from. */ + start = str; + + /* Compute the result string backwards. */ + do + { + int64 remainder; + int64 oldval = value; + + value /= 10; + remainder = oldval - value * 10; + *str++ = '0' + -remainder; + } while (value != 0); + } + else + { + /* mark the position we must reverse the string from. */ + start = str; + do + { + int64 remainder; + int64 oldval = value; + + value /= 10; + remainder = oldval - value * 10; + *str++ = '0' + remainder; + } while (value != 0); + } + + /* Add trailing NUL byte, and back up 'str' to the last character. */ + end = str; + *str-- = '\0'; + + /* Reverse string. */ + while (start < str) + { + char swap = *start; + *start++ = *str; + *str-- = swap; + } + return end; +} + +/* + * pg_int64tostr_zeropad + * Converts 'value' into a decimal string representation of the number. + * 'padding' specifies the minimum width of the number. Any extra space + * is filled up by prefixing the number with zeros. The return value is a + * pointer to the NUL terminated end of the string. + * + * Note: Callers should ensure that 'padding' is above zero. + * Note: This function is optimized for the case where the number is not too + * big to fit inside of the specified padding. + * Note: Caller must ensure that 'str' points to enough memory to hold the + result (at least 21 bytes, counting a leading sign and trailing NUL, + or padding + 1 bytes, whichever is larger). + */ +static char * +pg_int64tostr_zeropad(char *str, int64 value, int64 padding) +{ + char *start = str; + char *end = &str[padding]; + int64 num = value; + + Assert(padding > 0); + + /* + * Handle negative numbers in a special way. We can't just append a '-' + * prefix and reverse the sign as on two's complement machines negative + * numbers can be 1 further from 0 than positive numbers, we do it this way + * so we properly handle the smallest possible value. + */ + if (num < 0) + { + *start++ = '-'; + padding--; + + /* + * Build the number starting at the end. Here remainder will be a + * negative number, we must reverse this sign on this before adding + * '0' in order to get the correct ASCII digit + */ + while (padding--) + { + int64 remainder; + int64 oldval = num; + + num /= 10; + remainder = oldval - num * 10; + start[padding] = '0' + -remainder; + } + } + else + { + /* build the number starting at the end */ + while (padding--) + { + int64 remainder; + int64 oldval = num; + + num /= 10; + remainder = oldval - num * 10; + start[padding] = '0' + remainder; + } + } + + /* + * If padding was not high enough to fit this number then num won't have + * been divided down to zero. We'd better have another go, this time we + * know there won't be any zero padding required so we can just enlist the + * help of pg_int64tostr() + */ + if (num != 0) + return pg_int64tostr(str, value); + + *end = '\0'; + return end; +} + +/* + * scanfixeddecimal --- try to parse a string into a fixeddecimal. + */ +static int64 +scanfixeddecimal(const char *str) +{ + const char *ptr = str; + int64 integralpart = 0; + int64 fractionalpart = 0; + bool negative; + /* + * Do our own scan, rather than relying on sscanf which might be broken + * for long long. + */ + + /* skip leading spaces */ + while (isspace((unsigned char) *ptr)) + ptr++; + + /* handle sign */ + if (*ptr == '-') + { + negative = true; + ptr++; + + while (isdigit((unsigned char) *ptr)) + { + int64 tmp = integralpart * 10 - (*ptr++ - '0'); + + if ((tmp / 10) != integralpart) /* underflow? */ + { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + } + integralpart = tmp; + } + } + else + { + negative = false; + + if (*ptr == '+') + ptr++; + + while (isdigit((unsigned char) *ptr)) + { + int64 tmp = integralpart * 10 + (*ptr++ - '0'); + + if ((tmp / 10) != integralpart) /* overflow? */ + { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + } + integralpart = tmp; + } + } + + /* process the part after the decimal point */ + if (*ptr == '.') + { + int64 multiplier = FIXEDDECIMAL_MULTIPLIER; + ptr++; + + while (isdigit((unsigned char) *ptr) && multiplier > 1) + { + multiplier /= 10; + fractionalpart += (*ptr++ - '0') * multiplier; + } + + /* + * Eat into any excess precision digits. + * XXX These are ignored, should we error instead? + */ + while (isdigit((unsigned char) *ptr)) + ptr++; + } + + /* consume any remaining space chars */ + while (isspace((unsigned char) *ptr)) + ptr++; + + if (*ptr != '\0') + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", str))); + + if (negative) + { + + int64 value; + +#ifdef HAVE_BUILTIN_OVERFLOW + int64 multiplier = FIXEDDECIMAL_MULTIPLIER; + if (__builtin_mul_overflow(integralpart, multiplier, &value)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + + if (__builtin_sub_overflow(value, fractionalpart, &value)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + return value; + +#else + value = integralpart * FIXEDDECIMAL_MULTIPLIER; + if (value != 0 && (!SAMESIGN(value, integralpart) || + !SAMESIGN(value - fractionalpart, value) || + !SAMESIGN(value - fractionalpart, value))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + + return value - fractionalpart; +#endif /* HAVE_BUILTIN_OVERFLOW */ + + } + else + { + int64 value; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(integralpart, FIXEDDECIMAL_MULTIPLIER, &value)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + + if (__builtin_add_overflow(value, fractionalpart, &value)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + return value; +#else + value = integralpart * FIXEDDECIMAL_MULTIPLIER; + if (value != 0 && (!SAMESIGN(value, integralpart) || + !SAMESIGN(value - fractionalpart, value) || + !SAMESIGN(value + fractionalpart, value))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); + + return value + fractionalpart; +#endif /* HAVE_BUILTIN_OVERFLOW */ + + } +} + +/* fixeddecimalin() + */ +Datum +fixeddecimalin(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + int64 result = scanfixeddecimal(str); + PG_RETURN_INT64(result); +} + + +/* fixeddecimalout() + */ +Datum +fixeddecimalout(PG_FUNCTION_ARGS) +{ + int64 val = PG_GETARG_INT64(0); + char buf[MAXINT8LEN + 1]; + char *ptr = &buf[0]; + int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER; + int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER; + + if (val < 0) + { + fractionalpart = -fractionalpart; + + /* + * Handle special case for negative numbers where the intergral part + * is zero. pg_int64tostr() won't prefix with "-0" in this case, so + * we'll do it manually + */ + if (integralpart == 0) + *ptr++ = '-'; + } + ptr = pg_int64tostr(ptr, integralpart); + *ptr++ = '.'; + ptr = pg_int64tostr_zeropad(ptr, fractionalpart, FIXEDDECIMAL_PRECISION); + + PG_RETURN_CSTRING(pnstrdup(buf, ptr - &buf[0])); +} + +/* + * fixeddecimalrecv - converts external binary format to int8 + */ +Datum +fixeddecimalrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + + PG_RETURN_INT64(pq_getmsgint64(buf)); +} + +/* + * fixeddecimalsend - converts int8 to binary format + */ +Datum +fixeddecimalsend(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendint64(&buf, arg1); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + + +/*---------------------------------------------------------- + * Relational operators for fixeddecimals, including cross-data-type comparisons. + *---------------------------------------------------------*/ + +Datum +fixeddecimaleq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +fixeddecimalne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +fixeddecimallt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +fixeddecimalgt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +fixeddecimalle(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +fixeddecimalge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT64(1); + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + + +/*---------------------------------------------------------- + * Arithmetic operators on fixeddecimal. + *---------------------------------------------------------*/ + +Datum +fixeddecimalum(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + int64 zero = 0; + + if (__builtin_sub_overflow(zero, arg, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = -arg; + /* overflow check (needed for INT64_MIN) */ + if (arg != 0 && SAMESIGN(result, arg)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalup(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + + PG_RETURN_INT64(arg); +} + +Datum +fixeddecimalpl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalmul(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_INT64(0) / (float8) FIXEDDECIMAL_MULTIPLIER; + float8 arg2 = PG_GETARG_INT64(1) / (float8) FIXEDDECIMAL_MULTIPLIER; + float8 result; + + result = arg1 * arg2; + PG_RETURN_FLOAT8(result); +} + +Datum +fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int64 dividend = PG_GETARG_INT64(0); + int64 divisor = PG_GETARG_INT64(1); + float8 quotient; + + if (divisor == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* ensure compiler realizes we mustn't reach the division (gcc bug) */ + PG_RETURN_NULL(); + } + + if (divisor == 0) + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + + quotient = (float8) dividend / (float8) divisor; + PG_RETURN_FLOAT8(quotient); +} + +/* fixeddecimalabs() + * Absolute value + */ +Datum +fixeddecimalabs(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 result; + + result = (arg1 < 0) ? -arg1 : arg1; + /* overflow check (needed for INT64_MIN) */ + if (result < 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + PG_RETURN_INT64(result); +} + + +Datum +fixeddecimallarger(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = ((arg1 > arg2) ? arg1 : arg2); + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalsmaller(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = ((arg1 < arg2) ? arg1 : arg2); + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint4pl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 adder = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(arg1, adder, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 + adder; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, adder) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint4mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 subtractor = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(arg1, subtractor, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 - subtractor; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, subtractor) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint4mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 * arg2; + + /* + * Overflow check. We basically check to see if result / arg1 gives arg2 + * again. There is one case where this fails: arg1 = 0 (which cannot + * overflow). + * + * Since the division is likely much more expensive than the actual + * multiplication, we'd like to skip it where possible. The best bang for + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) && + result / arg1 != arg2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint4div(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int32 arg2 = PG_GETARG_INT32(1); + int64 result; + + if (arg2 == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* ensure compiler realizes we mustn't reach the division (gcc bug) */ + PG_RETURN_NULL(); + } + + /* + * INT64_MIN / -1 is problematic, since the result can't be represented on + * a two's-complement machine. Some machines produce INT64_MIN, some + * produce zero, some throw an exception. We can dodge the problem by + * recognizing that division by -1 is the same as negation. + */ + if (arg2 == -1) + { +#ifdef HAVE_BUILTIN_OVERFLOW + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = -arg1; + /* overflow check (needed for INT64_MIN) */ + if (arg1 != 0 && SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); + } + + /* No overflow is possible */ + + result = arg1 / arg2; + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimalpl(PG_FUNCTION_ARGS) +{ + int64 adder = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(adder, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = adder + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(adder, arg2) && !SAMESIGN(result, adder)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 subtractor = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(subtractor, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = subtractor - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(subtractor, arg2) && !SAMESIGN(result, subtractor)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimalmul(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 * arg2; + + /* + * Overflow check. We basically check to see if result / arg2 gives arg1 + * again. There is one case where this fails: arg2 = 0 (which cannot + * overflow). + * + * Since the division is likely much more expensive than the actual + * multiplication, we'd like to skip it where possible. The best bang for + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg2 != (int64) ((int32) arg2) && + result / arg2 != arg1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int4fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + float8 arg2 = (float8) PG_GETARG_INT64(1) / (float8) FIXEDDECIMAL_MULTIPLIER; + + if (arg2 == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* ensure compiler realizes we mustn't reach the division (gcc bug) */ + PG_RETURN_NULL(); + } + + /* No overflow is possible */ + PG_RETURN_FLOAT8((float8) arg1 / arg2); +} + +Datum +fixeddecimalint2pl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 adder = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(arg1, adder, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 + adder; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, adder) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint2mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 subtractor = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(arg1, subtractor, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 - subtractor; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, subtractor) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint2mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = arg1 * arg2; + + /* + * Overflow check. We basically check to see if result / arg1 gives arg2 + * again. There is one case where this fails: arg1 = 0 (which cannot + * overflow). + * + * Since the division is likely much more expensive than the actual + * multiplication, we'd like to skip it where possible. The best bang for + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg1 != (int64) ((int32) arg1) && + result / arg1 != arg2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalint2div(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; + + if (arg2 == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* ensure compiler realizes we mustn't reach the division (gcc bug) */ + PG_RETURN_NULL(); + } + + /* + * INT64_MIN / -1 is problematic, since the result can't be represented on + * a two's-complement machine. Some machines produce INT64_MIN, some + * produce zero, some throw an exception. We can dodge the problem by + * recognizing that division by -1 is the same as negation. + */ + if (arg2 == -1) + { +#ifdef HAVE_BUILTIN_OVERFLOW + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = -arg1; + /* overflow check (needed for INT64_MIN) */ + if (arg1 != 0 && SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); + } + + /* No overflow is possible */ + + result = arg1 / arg2; + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimalpl(PG_FUNCTION_ARGS) +{ + int64 adder = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(adder, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = adder + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(adder, arg2) && !SAMESIGN(result, adder)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 subtractor = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_sub_overflow(subtractor, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = subtractor - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(subtractor, arg2) && !SAMESIGN(result, subtractor)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimalmul(PG_FUNCTION_ARGS) +{ + int64 multiplier = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_mul_overflow(multiplier, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#else + result = multiplier * arg2; + + /* + * Overflow check. We basically check to see if result / arg2 gives + * multiplier again. There is one case where this fails: arg2 = 0 (which + * cannot overflow). + * + * Since the division is likely much more expensive than the actual + * multiplication, we'd like to skip it where possible. The best bang for + * the buck seems to be to check whether both inputs are in the int32 + * range; if so, no overflow is possible. + */ + if (arg2 != (int64) ((int32) arg2) && + result / arg2 != multiplier) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); +#endif /* HAVE_BUILTIN_OVERFLOW */ + + PG_RETURN_INT64(result); +} + +Datum +int2fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + float8 arg2 = PG_GETARG_INT64(1) / (float8) FIXEDDECIMAL_MULTIPLIER; + + if (arg2 == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* ensure compiler realizes we mustn't reach the division (gcc bug) */ + PG_RETURN_NULL(); + } + + /* No overflow is possible */ + PG_RETURN_INT64((float8) arg1 / arg2); +} + +/*---------------------------------------------------------- + * Conversion operators. + *---------------------------------------------------------*/ + +Datum +int4fixeddecimal(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT32(0); + + PG_RETURN_INT64(arg * FIXEDDECIMAL_MULTIPLIER); +} + +Datum +fixeddecimalint4(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0) / FIXEDDECIMAL_MULTIPLIER; + + if ((int32) arg != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + PG_RETURN_INT32((int32) arg); +} + +Datum +int2fixeddecimal(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT16(0); + + PG_RETURN_INT64(arg * FIXEDDECIMAL_MULTIPLIER); +} + +Datum +fixeddecimalint2(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0) / FIXEDDECIMAL_MULTIPLIER; + + if ((int16) arg != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("smallint out of range"))); + + PG_RETURN_INT16((int16) arg); +} + +Datum +fixeddecimaltod(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + float8 result; + + result = (float8) arg / FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_FLOAT8(result); +} + +/* dtofixeddecimal() + * Convert float8 to fixeddecimal + */ +Datum +dtofixeddecimal(PG_FUNCTION_ARGS) +{ + float8 arg = PG_GETARG_FLOAT8(0) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + + /* Round arg to nearest integer (but it's still in float form) */ + arg = rint(arg); + + /* + * Does it fit in an int64? Avoid assuming that we have handy constants + * defined for the range boundaries, instead test for overflow by + * reverse-conversion. + */ + result = (int64) arg; + + if ((float8) result != arg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimaltof(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + float4 result; + + result = (float4) arg / FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_FLOAT4(result); +} + +/* ftofixeddecimal() + * Convert float4 to fixeddecimal. + */ +Datum +ftofixeddecimal(PG_FUNCTION_ARGS) +{ + float4 arg = PG_GETARG_FLOAT4(0) * FIXEDDECIMAL_MULTIPLIER; + int64 result; + float8 darg; + + /* Round arg to nearest integer (but it's still in float form) */ + darg = rint(arg); + + /* + * Does it fit in an int64? Avoid assuming that we have handy constants + * defined for the range boundaries, instead test for overflow by + * reverse-conversion. + */ + result = (int64) darg; + + if ((float8) result != darg) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64(result); +} + +/* Aggregate Support */ + +typedef struct FixedDecimalAggState +{ + MemoryContext agg_context; /* context we're calculating in */ + int64 N; /* count of processed numbers */ + int64 sumX; /* sum of processed numbers */ +} FixedDecimalAggState; + +static FixedDecimalAggState * +makeFixedDecimalAggState(FunctionCallInfo fcinfo) +{ + FixedDecimalAggState *state; + MemoryContext agg_context; + MemoryContext old_context; + + if (!AggCheckCallContext(fcinfo, &agg_context)) + elog(ERROR, "aggregate function called in non-aggregate context"); + + old_context = MemoryContextSwitchTo(agg_context); + + state = (FixedDecimalAggState *) palloc0(sizeof(FixedDecimalAggState)); + state->agg_context = agg_context; + + MemoryContextSwitchTo(old_context); + + return state; +} + +/* + * Accumulate a new input value for fixeddecimal aggregate functions. + */ +static void +fixeddecimal_accum(FixedDecimalAggState *state, int64 newval) +{ +#ifdef HAVE_BUILTIN_OVERFLOW + if (__builtin_add_overflow(state->sumX, newval, &state->sumX)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + state->N++; +#else + if (state->N++ > 0) + { + int64 result = state->sumX + newval; + + if (SAMESIGN(state->sumX, newval) && !SAMESIGN(result, state->sumX)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + state->sumX = result; + } + else + state->sumX = newval; +#endif /* HAVE_BUILTIN_OVERFLOW */ +} + +Datum +fixeddecimal_avg_accum(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + /* Create the state data on the first call */ + if (state == NULL) + state = makeFixedDecimalAggState(fcinfo); + + if (!PG_ARGISNULL(1)) + fixeddecimal_accum(state, PG_GETARG_INT64(1)); + + PG_RETURN_POINTER(state); +} + +Datum +fixeddecimal_avg(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + /* If there were no non-null inputs, return NULL */ + if (state == NULL || state->N == 0) + PG_RETURN_NULL(); + + PG_RETURN_INT64(state->sumX / state->N); +} + +Datum +fixeddecimal_sum(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + /* If there were no non-null inputs, return NULL */ + if (state == NULL || state->N == 0) + PG_RETURN_NULL(); + + PG_RETURN_INT64(state->sumX); +} diff --git a/contrib/fixeddecimal/fixeddecimal.control b/contrib/fixeddecimal/fixeddecimal.control new file mode 100755 index 00000000000..318593a184c --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal.control @@ -0,0 +1,4 @@ +comment = 'fixeddecimal' +default_version = '1.0.0' +relocatable = false +module_pathname = '$libdir/fixeddecimal' diff --git a/contrib/fixeddecimal/test/expected/overflow.out b/contrib/fixeddecimal/test/expected/overflow.out new file mode 100755 index 00000000000..b2db167bbb0 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/overflow.out @@ -0,0 +1,63 @@ +-- Ensure the expected extreme values can be represented +SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07'::fixeddecimal as maxvalue; + minvalue | maxvalue +-----------------------+---------------------- + -92233720368547758.08 | 92233720368547758.07 +(1 row) + + +SELECT '-92233720368547758.09'::fixeddecimal; +ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal +LINE 1: SELECT '-92233720368547758.09'::fixeddecimal; + ^ + +SELECT '92233720368547758.08'::fixeddecimal; +ERROR: value "92233720368547758.08" is out of range for type fixeddecimal +LINE 1: SELECT '92233720368547758.08'::fixeddecimal; + ^ + +SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; +ERROR: fixeddecimal out of range + +SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; +ERROR: fixeddecimal out of range + +-- Ensure limits of int2 can be represented +SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; + int2 | int2 +-------+-------- + 32767 | -32768 +(1 row) + + +-- Ensure overflow of int2 is detected +SELECT '32768'::fixeddecimal::int2; +ERROR: smallint out of range + +-- Ensure underflow of int2 is detected +SELECT '-32769'::fixeddecimal::int2; +ERROR: smallint out of range + +-- Ensure limits of int4 can be represented +SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; + int4 | int4 +------------+------------- + 2147483647 | -2147483648 +(1 row) + + +-- Ensure overflow of int4 is detected +SELECT '2147483648'::fixeddecimal::int4; +ERROR: integer out of range + +-- Ensure underflow of int4 is detected +SELECT '-2147483649'::fixeddecimal::int4; +ERROR: integer out of range + +-- Ensure overflow is detected +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); +ERROR: fixeddecimal out of range + +-- Ensure underflow is detected +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); +ERROR: fixeddecimal out of range diff --git a/contrib/fixeddecimal/test/results/overflow.out b/contrib/fixeddecimal/test/results/overflow.out new file mode 100755 index 00000000000..6d78434d656 --- /dev/null +++ b/contrib/fixeddecimal/test/results/overflow.out @@ -0,0 +1,67 @@ +-- Ensure the expected extreme values can be represented +SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07'::fixeddecimal as maxvalue; + minvalue | maxvalue +-----------------------+---------------------- + -92233720368547758.08 | 92233720368547758.07 +(1 row) + + +SELECT '-92233720368547758.09'::fixeddecimal; + fixeddecimal +---------------------- + 92233720368547758.07 +(1 row) + + +SELECT '92233720368547758.08'::fixeddecimal; + fixeddecimal +----------------------- + -92233720368547758.08 +(1 row) + + +SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; +ERROR: fixeddecimal out of range + +SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; +ERROR: fixeddecimal out of range + +-- Ensure limits of int2 can be represented +SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; + int2 | int2 +-------+-------- + 32767 | -32768 +(1 row) + + +-- Ensure overflow of int2 is detected +SELECT '32768'::fixeddecimal::int2; +ERROR: smallint out of range + +-- Ensure underflow of int2 is detected +SELECT '-32769'::fixeddecimal::int2; +ERROR: smallint out of range + +-- Ensure limits of int4 can be represented +SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; + int4 | int4 +------------+------------- + 2147483647 | -2147483648 +(1 row) + + +-- Ensure overflow of int4 is detected +SELECT '2147483648'::fixeddecimal::int4; +ERROR: integer out of range + +-- Ensure underflow of int4 is detected +SELECT '-2147483649'::fixeddecimal::int4; +ERROR: integer out of range + +-- Ensure overflow is detected +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); +ERROR: fixeddecimal out of range + +-- Ensure underflow is detected +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); +ERROR: fixeddecimal out of range From 4beaa0a75864ef9019fd17c4d012e7bfdbba794c Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 17:52:15 +1200 Subject: [PATCH 02/32] Remove the deadly temp-instance=. --- contrib/fixeddecimal/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index 48477f6ceec..815165fc065 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -9,7 +9,7 @@ CFLAGS=`pg_config --includedir-server` TESTS = $(wildcard test/sql/*.sql) REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS)) -REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=fixeddecimal --temp-instance=. +REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=fixeddecimal PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) From 1c78f9d359f20dc57f69c85aea2607f03fabbbef Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 17:57:30 +1200 Subject: [PATCH 03/32] Add missing overflow.sql --- contrib/fixeddecimal/test/sql/overflow.sql | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 contrib/fixeddecimal/test/sql/overflow.sql diff --git a/contrib/fixeddecimal/test/sql/overflow.sql b/contrib/fixeddecimal/test/sql/overflow.sql new file mode 100755 index 00000000000..cb8e9506f9d --- /dev/null +++ b/contrib/fixeddecimal/test/sql/overflow.sql @@ -0,0 +1,34 @@ +-- Ensure the expected extreme values can be represented +SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07'::fixeddecimal as maxvalue; + +SELECT '-92233720368547758.09'::fixeddecimal; + +SELECT '92233720368547758.08'::fixeddecimal; + +SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; + +SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; + +-- Ensure limits of int2 can be represented +SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; + +-- Ensure overflow of int2 is detected +SELECT '32768'::fixeddecimal::int2; + +-- Ensure underflow of int2 is detected +SELECT '-32769'::fixeddecimal::int2; + +-- Ensure limits of int4 can be represented +SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; + +-- Ensure overflow of int4 is detected +SELECT '2147483648'::fixeddecimal::int4; + +-- Ensure underflow of int4 is detected +SELECT '-2147483649'::fixeddecimal::int4; + +-- Ensure overflow is detected +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); + +-- Ensure underflow is detected +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); From fcfbf3082301dfcbdfb9c65a2fd1eeaa692ca358 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 18:09:59 +1200 Subject: [PATCH 04/32] Fixed regression test expected results --- contrib/fixeddecimal/test/results/overflow.out | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/contrib/fixeddecimal/test/results/overflow.out b/contrib/fixeddecimal/test/results/overflow.out index 6d78434d656..b2db167bbb0 100755 --- a/contrib/fixeddecimal/test/results/overflow.out +++ b/contrib/fixeddecimal/test/results/overflow.out @@ -7,18 +7,14 @@ SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07': SELECT '-92233720368547758.09'::fixeddecimal; - fixeddecimal ----------------------- - 92233720368547758.07 -(1 row) - +ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal +LINE 1: SELECT '-92233720368547758.09'::fixeddecimal; + ^ SELECT '92233720368547758.08'::fixeddecimal; - fixeddecimal ------------------------ - -92233720368547758.08 -(1 row) - +ERROR: value "92233720368547758.08" is out of range for type fixeddecimal +LINE 1: SELECT '92233720368547758.08'::fixeddecimal; + ^ SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; ERROR: fixeddecimal out of range From 9763af3f2db4646bd3e76ff88aa65cdf9a7bcc02 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 18:23:35 +1200 Subject: [PATCH 05/32] Add regression test for comparision operators --- .../fixeddecimal/test/expected/comparison.out | 368 ++++++++++++++++++ .../fixeddecimal/test/results/comparison.out | 368 ++++++++++++++++++ contrib/fixeddecimal/test/sql/comparison.sql | 118 ++++++ 3 files changed, 854 insertions(+) create mode 100755 contrib/fixeddecimal/test/expected/comparison.out create mode 100644 contrib/fixeddecimal/test/results/comparison.out create mode 100755 contrib/fixeddecimal/test/sql/comparison.sql diff --git a/contrib/fixeddecimal/test/expected/comparison.out b/contrib/fixeddecimal/test/expected/comparison.out new file mode 100755 index 00000000000..ece8a21344b --- /dev/null +++ b/contrib/fixeddecimal/test/expected/comparison.out @@ -0,0 +1,368 @@ +-- True comparisons + +SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +-- Compare to int4 + +SELECT '123'::INT < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT = '123.00'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL < '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL = '123'::INT; + ?column? +---------- + t +(1 row) + + +-- Compare to int2 + +SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +-- False comparisons +SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +-- Compare to int4 + +SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL < '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL > '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; + ?column? +---------- + f +(1 row) + + +-- Compare to int2 + +SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; + ?column? +---------- + f +(1 row) + diff --git a/contrib/fixeddecimal/test/results/comparison.out b/contrib/fixeddecimal/test/results/comparison.out new file mode 100644 index 00000000000..ece8a21344b --- /dev/null +++ b/contrib/fixeddecimal/test/results/comparison.out @@ -0,0 +1,368 @@ +-- True comparisons + +SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +-- Compare to int4 + +SELECT '123'::INT < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::INT = '123.00'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL < '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; + ?column? +---------- + t +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL = '123'::INT; + ?column? +---------- + t +(1 row) + + +-- Compare to int2 + +SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; + ?column? +---------- + t +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; + ?column? +---------- + t +(1 row) + + +-- False comparisons +SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +-- Compare to int4 + +SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL < '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL > '123'::INT; + ?column? +---------- + f +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; + ?column? +---------- + f +(1 row) + + +-- Compare to int2 + +SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; + ?column? +---------- + f +(1 row) + + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; + ?column? +---------- + f +(1 row) + + +SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; + ?column? +---------- + f +(1 row) + diff --git a/contrib/fixeddecimal/test/sql/comparison.sql b/contrib/fixeddecimal/test/sql/comparison.sql new file mode 100755 index 00000000000..ed3e6ad0c2f --- /dev/null +++ b/contrib/fixeddecimal/test/sql/comparison.sql @@ -0,0 +1,118 @@ +-- True comparisons + +SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; + +SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; + +-- Compare to int4 + +SELECT '123'::INT < '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT > '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT = '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::INT; + +SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL < '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; + +SELECT '123.00'::FIXEDDECIMAL = '123'::INT; + +-- Compare to int2 + +SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; + +SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; + +SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; + +-- False comparisons +SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; + +SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; + +SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; + +-- Compare to int4 + +SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT > '123.01'::FIXEDDECIMAL; + +SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT < '122.99'::FIXEDDECIMAL; + +SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; + +SELECT '123.01'::FIXEDDECIMAL < '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; + +SELECT '122.99'::FIXEDDECIMAL > '123'::INT; + +SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; + +-- Compare to int2 + +SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; + +SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; + +-- Compare to int4 reversed + +SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; + +SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; + +SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; + +SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; From a871ebbf4ee383b38f0fda713f60640c4accab60 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 18:30:16 +1200 Subject: [PATCH 06/32] Add regression tests for casts --- contrib/fixeddecimal/test/expected/cast.out | 57 +++++++++++++++++++++ contrib/fixeddecimal/test/results/cast.out | 57 +++++++++++++++++++++ contrib/fixeddecimal/test/sql/cast.sql | 23 +++++++++ 3 files changed, 137 insertions(+) create mode 100755 contrib/fixeddecimal/test/expected/cast.out create mode 100644 contrib/fixeddecimal/test/results/cast.out create mode 100755 contrib/fixeddecimal/test/sql/cast.sql diff --git a/contrib/fixeddecimal/test/expected/cast.out b/contrib/fixeddecimal/test/expected/cast.out new file mode 100755 index 00000000000..65004ed16d9 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/cast.out @@ -0,0 +1,57 @@ +SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); + int4 +------------ + 2147483647 +(1 row) + + +-- Ensure overflow is detected +SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); +ERROR: integer out of range + +SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); + int4 +------------- + -2147483648 +(1 row) + + +-- Ensure underflow is detected +SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); +ERROR: integer out of range + +SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); + int2 +------- + 32767 +(1 row) + + +-- Ensure overflow is detected +SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); +ERROR: smallint out of range + +SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); + int2 +-------- + -32768 +(1 row) + + +-- Ensure underflow is detected +SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); +ERROR: smallint out of range + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); + float8 +------------ + 1234321.23 +(1 row) + + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); + float8 +------------ + 1234321.23 +(1 row) + diff --git a/contrib/fixeddecimal/test/results/cast.out b/contrib/fixeddecimal/test/results/cast.out new file mode 100644 index 00000000000..65004ed16d9 --- /dev/null +++ b/contrib/fixeddecimal/test/results/cast.out @@ -0,0 +1,57 @@ +SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); + int4 +------------ + 2147483647 +(1 row) + + +-- Ensure overflow is detected +SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); +ERROR: integer out of range + +SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); + int4 +------------- + -2147483648 +(1 row) + + +-- Ensure underflow is detected +SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); +ERROR: integer out of range + +SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); + int2 +------- + 32767 +(1 row) + + +-- Ensure overflow is detected +SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); +ERROR: smallint out of range + +SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); + int2 +-------- + -32768 +(1 row) + + +-- Ensure underflow is detected +SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); +ERROR: smallint out of range + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); + float8 +------------ + 1234321.23 +(1 row) + + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); + float8 +------------ + 1234321.23 +(1 row) + diff --git a/contrib/fixeddecimal/test/sql/cast.sql b/contrib/fixeddecimal/test/sql/cast.sql new file mode 100755 index 00000000000..3b7b1c8bbc6 --- /dev/null +++ b/contrib/fixeddecimal/test/sql/cast.sql @@ -0,0 +1,23 @@ +SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); + +-- Ensure overflow is detected +SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); + +SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); + +-- Ensure underflow is detected +SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); + +SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); + +-- Ensure overflow is detected +SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); + +SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); + +-- Ensure underflow is detected +SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); + +SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); \ No newline at end of file From 3757de0ed5105099afdf91700683e3145e343e15 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 18:48:48 +1200 Subject: [PATCH 07/32] Add aggregate regression test and fix problem with EOLs --- .../fixeddecimal/test/expected/aggregate.out | 33 +++++++++++ .../fixeddecimal/test/results/aggregate.out | 33 +++++++++++ contrib/fixeddecimal/test/results/cast.out | 9 --- .../fixeddecimal/test/results/comparison.out | 58 ------------------- .../fixeddecimal/test/results/overflow.out | 12 ---- contrib/fixeddecimal/test/sql/aggregate.sql | 21 +++++++ 6 files changed, 87 insertions(+), 79 deletions(-) create mode 100755 contrib/fixeddecimal/test/expected/aggregate.out create mode 100644 contrib/fixeddecimal/test/results/aggregate.out create mode 100755 contrib/fixeddecimal/test/sql/aggregate.sql diff --git a/contrib/fixeddecimal/test/expected/aggregate.out b/contrib/fixeddecimal/test/expected/aggregate.out new file mode 100755 index 00000000000..934c51b9b13 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/aggregate.out @@ -0,0 +1,33 @@ +CREATE TABLE fixed_decimal(a FIXEDDECIMAL NOT NULL); +INSERT INTO fixed_decimal VALUES('92233720368547758.07'),('0.01'),('-92233720368547758.08'),('-0.01'); +SELECT SUM(a) FROM fixed_decimal WHERE a > 0; +ERROR: fixeddecimal out of range +SELECT SUM(a) FROM fixed_decimal WHERE a < 0; +ERROR: fixeddecimal out of range +TRUNCATE TABLE fixed_decimal; +INSERT INTO fixed_decimal VALUES('11.11'),('22.22'),('33.33'); +SELECT SUM(a) FROM fixed_decimal; + sum +------- + 66.66 +(1 row) + +SELECT MAX(a) FROM fixed_decimal; + max +------- + 33.33 +(1 row) + +SELECT MIN(a) FROM fixed_decimal; + min +------- + 11.11 +(1 row) + +SELECT AVG(a) FROM fixed_decimal; + avg +------- + 22.22 +(1 row) + +DROP TABLE fixed_decimal; diff --git a/contrib/fixeddecimal/test/results/aggregate.out b/contrib/fixeddecimal/test/results/aggregate.out new file mode 100644 index 00000000000..934c51b9b13 --- /dev/null +++ b/contrib/fixeddecimal/test/results/aggregate.out @@ -0,0 +1,33 @@ +CREATE TABLE fixed_decimal(a FIXEDDECIMAL NOT NULL); +INSERT INTO fixed_decimal VALUES('92233720368547758.07'),('0.01'),('-92233720368547758.08'),('-0.01'); +SELECT SUM(a) FROM fixed_decimal WHERE a > 0; +ERROR: fixeddecimal out of range +SELECT SUM(a) FROM fixed_decimal WHERE a < 0; +ERROR: fixeddecimal out of range +TRUNCATE TABLE fixed_decimal; +INSERT INTO fixed_decimal VALUES('11.11'),('22.22'),('33.33'); +SELECT SUM(a) FROM fixed_decimal; + sum +------- + 66.66 +(1 row) + +SELECT MAX(a) FROM fixed_decimal; + max +------- + 33.33 +(1 row) + +SELECT MIN(a) FROM fixed_decimal; + min +------- + 11.11 +(1 row) + +SELECT AVG(a) FROM fixed_decimal; + avg +------- + 22.22 +(1 row) + +DROP TABLE fixed_decimal; diff --git a/contrib/fixeddecimal/test/results/cast.out b/contrib/fixeddecimal/test/results/cast.out index 65004ed16d9..b230ed59787 100644 --- a/contrib/fixeddecimal/test/results/cast.out +++ b/contrib/fixeddecimal/test/results/cast.out @@ -4,51 +4,42 @@ SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); 2147483647 (1 row) - -- Ensure overflow is detected SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); ERROR: integer out of range - SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); int4 ------------- -2147483648 (1 row) - -- Ensure underflow is detected SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); ERROR: integer out of range - SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); int2 ------- 32767 (1 row) - -- Ensure overflow is detected SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); ERROR: smallint out of range - SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); int2 -------- -32768 (1 row) - -- Ensure underflow is detected SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); ERROR: smallint out of range - SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); float8 ------------ 1234321.23 (1 row) - SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); float8 ------------ diff --git a/contrib/fixeddecimal/test/results/comparison.out b/contrib/fixeddecimal/test/results/comparison.out index ece8a21344b..9ba9abe9ae5 100644 --- a/contrib/fixeddecimal/test/results/comparison.out +++ b/contrib/fixeddecimal/test/results/comparison.out @@ -1,188 +1,158 @@ -- True comparisons - SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; ?column? ---------- t (1 row) - -- Compare to int4 - SELECT '123'::INT < '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT > '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT = '123.00'::FIXEDDECIMAL; ?column? ---------- t (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL > '123'::INT; ?column? ---------- t (1 row) - SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL < '123'::INT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; ?column? ---------- t (1 row) - SELECT '123.00'::FIXEDDECIMAL = '123'::INT; ?column? ---------- t (1 row) - -- Compare to int2 - SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; ?column? ---------- t (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; ?column? ---------- t (1 row) - -- False comparisons SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; ?column? @@ -190,176 +160,148 @@ SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; f (1 row) - SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; ?column? ---------- f (1 row) - -- Compare to int4 - SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT > '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT < '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; ?column? ---------- f (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; ?column? ---------- f (1 row) - SELECT '123.01'::FIXEDDECIMAL < '123'::INT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL > '123'::INT; ?column? ---------- f (1 row) - SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; ?column? ---------- f (1 row) - -- Compare to int2 - SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; ?column? ---------- f (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; ?column? ---------- diff --git a/contrib/fixeddecimal/test/results/overflow.out b/contrib/fixeddecimal/test/results/overflow.out index b2db167bbb0..963f1a0d7b8 100755 --- a/contrib/fixeddecimal/test/results/overflow.out +++ b/contrib/fixeddecimal/test/results/overflow.out @@ -5,23 +5,18 @@ SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07': -92233720368547758.08 | 92233720368547758.07 (1 row) - SELECT '-92233720368547758.09'::fixeddecimal; ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal LINE 1: SELECT '-92233720368547758.09'::fixeddecimal; ^ - SELECT '92233720368547758.08'::fixeddecimal; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal LINE 1: SELECT '92233720368547758.08'::fixeddecimal; ^ - SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; ERROR: fixeddecimal out of range - SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; ERROR: fixeddecimal out of range - -- Ensure limits of int2 can be represented SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; int2 | int2 @@ -29,15 +24,12 @@ SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; 32767 | -32768 (1 row) - -- Ensure overflow of int2 is detected SELECT '32768'::fixeddecimal::int2; ERROR: smallint out of range - -- Ensure underflow of int2 is detected SELECT '-32769'::fixeddecimal::int2; ERROR: smallint out of range - -- Ensure limits of int4 can be represented SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; int4 | int4 @@ -45,19 +37,15 @@ SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; 2147483647 | -2147483648 (1 row) - -- Ensure overflow of int4 is detected SELECT '2147483648'::fixeddecimal::int4; ERROR: integer out of range - -- Ensure underflow of int4 is detected SELECT '-2147483649'::fixeddecimal::int4; ERROR: integer out of range - -- Ensure overflow is detected SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); ERROR: fixeddecimal out of range - -- Ensure underflow is detected SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); ERROR: fixeddecimal out of range diff --git a/contrib/fixeddecimal/test/sql/aggregate.sql b/contrib/fixeddecimal/test/sql/aggregate.sql new file mode 100755 index 00000000000..6c00a7205aa --- /dev/null +++ b/contrib/fixeddecimal/test/sql/aggregate.sql @@ -0,0 +1,21 @@ +CREATE TABLE fixed_decimal(a FIXEDDECIMAL NOT NULL); + +INSERT INTO fixed_decimal VALUES('92233720368547758.07'),('0.01'),('-92233720368547758.08'),('-0.01'); + +SELECT SUM(a) FROM fixed_decimal WHERE a > 0; + +SELECT SUM(a) FROM fixed_decimal WHERE a < 0; + +TRUNCATE TABLE fixed_decimal; + +INSERT INTO fixed_decimal VALUES('11.11'),('22.22'),('33.33'); + +SELECT SUM(a) FROM fixed_decimal; + +SELECT MAX(a) FROM fixed_decimal; + +SELECT MIN(a) FROM fixed_decimal; + +SELECT AVG(a) FROM fixed_decimal; + +DROP TABLE fixed_decimal; \ No newline at end of file From 363f3be39f45a61ea20dfc309cd1aa39c7debcf6 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 31 Aug 2015 18:54:59 +1200 Subject: [PATCH 08/32] Fix more problems with windows EOLs --- contrib/fixeddecimal/test/expected/cast.out | 9 --- .../fixeddecimal/test/expected/comparison.out | 58 ------------------- .../fixeddecimal/test/expected/overflow.out | 12 ---- 3 files changed, 79 deletions(-) diff --git a/contrib/fixeddecimal/test/expected/cast.out b/contrib/fixeddecimal/test/expected/cast.out index 65004ed16d9..b230ed59787 100755 --- a/contrib/fixeddecimal/test/expected/cast.out +++ b/contrib/fixeddecimal/test/expected/cast.out @@ -4,51 +4,42 @@ SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); 2147483647 (1 row) - -- Ensure overflow is detected SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); ERROR: integer out of range - SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); int4 ------------- -2147483648 (1 row) - -- Ensure underflow is detected SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); ERROR: integer out of range - SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); int2 ------- 32767 (1 row) - -- Ensure overflow is detected SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); ERROR: smallint out of range - SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); int2 -------- -32768 (1 row) - -- Ensure underflow is detected SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); ERROR: smallint out of range - SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); float8 ------------ 1234321.23 (1 row) - SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); float8 ------------ diff --git a/contrib/fixeddecimal/test/expected/comparison.out b/contrib/fixeddecimal/test/expected/comparison.out index ece8a21344b..9ba9abe9ae5 100755 --- a/contrib/fixeddecimal/test/expected/comparison.out +++ b/contrib/fixeddecimal/test/expected/comparison.out @@ -1,188 +1,158 @@ -- True comparisons - SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; ?column? ---------- t (1 row) - -- Compare to int4 - SELECT '123'::INT < '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT > '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::INT = '123.00'::FIXEDDECIMAL; ?column? ---------- t (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL > '123'::INT; ?column? ---------- t (1 row) - SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL < '123'::INT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; ?column? ---------- t (1 row) - SELECT '123.00'::FIXEDDECIMAL = '123'::INT; ?column? ---------- t (1 row) - -- Compare to int2 - SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; ?column? ---------- t (1 row) - SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; ?column? ---------- t (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; ?column? ---------- t (1 row) - SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; ?column? ---------- t (1 row) - -- False comparisons SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; ?column? @@ -190,176 +160,148 @@ SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; f (1 row) - SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; ?column? ---------- f (1 row) - -- Compare to int4 - SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT > '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT < '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; ?column? ---------- f (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; ?column? ---------- f (1 row) - SELECT '123.01'::FIXEDDECIMAL < '123'::INT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL > '123'::INT; ?column? ---------- f (1 row) - SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; ?column? ---------- f (1 row) - -- Compare to int2 - SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; ?column? ---------- f (1 row) - SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; ?column? ---------- f (1 row) - -- Compare to int4 reversed - SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; ?column? ---------- f (1 row) - SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; ?column? ---------- diff --git a/contrib/fixeddecimal/test/expected/overflow.out b/contrib/fixeddecimal/test/expected/overflow.out index b2db167bbb0..963f1a0d7b8 100755 --- a/contrib/fixeddecimal/test/expected/overflow.out +++ b/contrib/fixeddecimal/test/expected/overflow.out @@ -5,23 +5,18 @@ SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07': -92233720368547758.08 | 92233720368547758.07 (1 row) - SELECT '-92233720368547758.09'::fixeddecimal; ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal LINE 1: SELECT '-92233720368547758.09'::fixeddecimal; ^ - SELECT '92233720368547758.08'::fixeddecimal; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal LINE 1: SELECT '92233720368547758.08'::fixeddecimal; ^ - SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; ERROR: fixeddecimal out of range - SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; ERROR: fixeddecimal out of range - -- Ensure limits of int2 can be represented SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; int2 | int2 @@ -29,15 +24,12 @@ SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; 32767 | -32768 (1 row) - -- Ensure overflow of int2 is detected SELECT '32768'::fixeddecimal::int2; ERROR: smallint out of range - -- Ensure underflow of int2 is detected SELECT '-32769'::fixeddecimal::int2; ERROR: smallint out of range - -- Ensure limits of int4 can be represented SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; int4 | int4 @@ -45,19 +37,15 @@ SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; 2147483647 | -2147483648 (1 row) - -- Ensure overflow of int4 is detected SELECT '2147483648'::fixeddecimal::int4; ERROR: integer out of range - -- Ensure underflow of int4 is detected SELECT '-2147483649'::fixeddecimal::int4; ERROR: integer out of range - -- Ensure overflow is detected SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); ERROR: fixeddecimal out of range - -- Ensure underflow is detected SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); ERROR: fixeddecimal out of range From c7a0431ecb5d28df8f1fc4f72a21cbf087771c08 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 4 Sep 2015 14:34:04 +1200 Subject: [PATCH 09/32] Change multiply and divide to use int128 as an intermediate number --- contrib/fixeddecimal/fixeddecimal--1.0.0.sql | 4 +- contrib/fixeddecimal/fixeddecimal.c | 44 +++++++++++++++---- .../fixeddecimal/test/expected/overflow.out | 20 +++++++++ .../fixeddecimal/test/results/overflow.out | 20 +++++++++ contrib/fixeddecimal/test/sql/overflow.sql | 12 +++++ 5 files changed, 89 insertions(+), 11 deletions(-) diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql index e33c90314b4..18d5adc5113 100755 --- a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql @@ -85,12 +85,12 @@ AS 'fixeddecimal', 'fixeddecimalmi' LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) -RETURNS DOUBLE PRECISION +RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimalmul' LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) -RETURNS DOUBLE PRECISION +RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimaldiv' LANGUAGE C IMMUTABLE STRICT; diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index 8d7a1bef3b4..9aa90c96023 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -27,12 +27,17 @@ #define FIXEDDECIMAL_PRECISION 2 /* Define this if your compiler has _builtin_add_overflow() */ -#define HAVE_BUILTIN_OVERFLOW +/* #define HAVE_BUILTIN_OVERFLOW */ #ifndef HAVE_BUILTIN_OVERFLOW #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) #endif /* HAVE_BUILTIN_OVERFLOW */ +/* 128bit int is required for multiply and divide */ +#ifndef HAVE_INT128 +#error "A working 128bit int type is required for fixed decimal" +#endif /* HAVE_INT128 */ + #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif @@ -632,12 +637,23 @@ fixeddecimalmi(PG_FUNCTION_ARGS) Datum fixeddecimalmul(PG_FUNCTION_ARGS) { - float8 arg1 = PG_GETARG_INT64(0) / (float8) FIXEDDECIMAL_MULTIPLIER; - float8 arg2 = PG_GETARG_INT64(1) / (float8) FIXEDDECIMAL_MULTIPLIER; - float8 result; + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int128 result; - result = arg1 * arg2; - PG_RETURN_FLOAT8(result); + /* We need to promote this to 128bit as we may overflow int64 here. + * Remember that arg2 is the number multiplied by + * FIXEDDECIMAL_MULTIPLIER, we must divide the result by this to get + * the correct result. + */ + result = (int128) arg1 * arg2 / FIXEDDECIMAL_MULTIPLIER; + + if (result != ((int64) result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64((int64) result); } Datum @@ -645,7 +661,7 @@ fixeddecimaldiv(PG_FUNCTION_ARGS) { int64 dividend = PG_GETARG_INT64(0); int64 divisor = PG_GETARG_INT64(1); - float8 quotient; + int128 result; if (divisor == 0) { @@ -661,8 +677,18 @@ fixeddecimaldiv(PG_FUNCTION_ARGS) (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); - quotient = (float8) dividend / (float8) divisor; - PG_RETURN_FLOAT8(quotient); + /* + * this can't overflow, but we can end up with a number that's too big for + * int64 + */ + result = (int128) dividend * FIXEDDECIMAL_MULTIPLIER / divisor; + + if (result != ((int64) result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64((int64) result); } /* fixeddecimalabs() diff --git a/contrib/fixeddecimal/test/expected/overflow.out b/contrib/fixeddecimal/test/expected/overflow.out index 963f1a0d7b8..2bca2d890ac 100755 --- a/contrib/fixeddecimal/test/expected/overflow.out +++ b/contrib/fixeddecimal/test/expected/overflow.out @@ -17,6 +17,26 @@ SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; ERROR: fixeddecimal out of range SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; ERROR: fixeddecimal out of range +-- Should not overflow +SELECT '46116860184273879.03'::fixeddecimal * '2.00'::fixeddecimal; + ?column? +---------------------- + 92233720368547758.06 +(1 row) + +-- Ensure this overflows +SELECT '46116860184273879.04'::fixeddecimal * '2.00'::fixeddecimal; +ERROR: fixeddecimal out of range +-- Should not overflow +SELECT '46116860184273879.03'::fixeddecimal / '0.50'::fixeddecimal; + ?column? +---------------------- + 92233720368547758.06 +(1 row) + +-- Ensure this overflows +SELECT '46116860184273879.04'::fixeddecimal / '0.50'::fixeddecimal; +ERROR: fixeddecimal out of range -- Ensure limits of int2 can be represented SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; int2 | int2 diff --git a/contrib/fixeddecimal/test/results/overflow.out b/contrib/fixeddecimal/test/results/overflow.out index 963f1a0d7b8..2bca2d890ac 100755 --- a/contrib/fixeddecimal/test/results/overflow.out +++ b/contrib/fixeddecimal/test/results/overflow.out @@ -17,6 +17,26 @@ SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; ERROR: fixeddecimal out of range SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; ERROR: fixeddecimal out of range +-- Should not overflow +SELECT '46116860184273879.03'::fixeddecimal * '2.00'::fixeddecimal; + ?column? +---------------------- + 92233720368547758.06 +(1 row) + +-- Ensure this overflows +SELECT '46116860184273879.04'::fixeddecimal * '2.00'::fixeddecimal; +ERROR: fixeddecimal out of range +-- Should not overflow +SELECT '46116860184273879.03'::fixeddecimal / '0.50'::fixeddecimal; + ?column? +---------------------- + 92233720368547758.06 +(1 row) + +-- Ensure this overflows +SELECT '46116860184273879.04'::fixeddecimal / '0.50'::fixeddecimal; +ERROR: fixeddecimal out of range -- Ensure limits of int2 can be represented SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; int2 | int2 diff --git a/contrib/fixeddecimal/test/sql/overflow.sql b/contrib/fixeddecimal/test/sql/overflow.sql index cb8e9506f9d..b8e247957c1 100755 --- a/contrib/fixeddecimal/test/sql/overflow.sql +++ b/contrib/fixeddecimal/test/sql/overflow.sql @@ -9,6 +9,18 @@ SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; +-- Should not overflow +SELECT '46116860184273879.03'::fixeddecimal * '2.00'::fixeddecimal; + +-- Ensure this overflows +SELECT '46116860184273879.04'::fixeddecimal * '2.00'::fixeddecimal; + +-- Should not overflow +SELECT '46116860184273879.03'::fixeddecimal / '0.50'::fixeddecimal; + +-- Ensure this overflows +SELECT '46116860184273879.04'::fixeddecimal / '0.50'::fixeddecimal; + -- Ensure limits of int2 can be represented SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; From 678049e3aab533133a01d6cc05d0e5b80410a880 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 4 Sep 2015 15:52:08 +1200 Subject: [PATCH 10/32] Add casts to and from numeric --- contrib/fixeddecimal/fixeddecimal--1.0.0.sql | 17 +++++++ contrib/fixeddecimal/fixeddecimal.c | 47 ++++++++++++++++++- .../fixeddecimal/test/expected/overflow.out | 22 +++++++++ .../fixeddecimal/test/results/overflow.out | 22 +++++++++ contrib/fixeddecimal/test/sql/overflow.sql | 14 ++++++ 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql index 18d5adc5113..02e1329e734 100755 --- a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql @@ -456,6 +456,17 @@ RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'ftofixeddecimal' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'fixeddecimal', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + + CREATE CAST (INT4 AS FIXEDDECIMAL) WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; @@ -480,6 +491,12 @@ CREATE CAST (FIXEDDECIMAL AS REAL) CREATE CAST (REAL AS FIXEDDECIMAL) WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS ASSIGNMENT; + -- Aggregate Support diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index 9aa90c96023..d01934fa4ea 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -8,7 +8,7 @@ #include "funcapi.h" #include "libpq/pqformat.h" #include "utils/builtins.h" - +#include "utils/numeric.h" #define MAXINT8LEN 25 @@ -86,6 +86,8 @@ PG_FUNCTION_INFO_V1(fixeddecimaltod); PG_FUNCTION_INFO_V1(dtofixeddecimal); PG_FUNCTION_INFO_V1(fixeddecimaltof); PG_FUNCTION_INFO_V1(ftofixeddecimal); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric); PG_FUNCTION_INFO_V1(fixeddecimal_avg_accum); PG_FUNCTION_INFO_V1(fixeddecimal_avg); PG_FUNCTION_INFO_V1(fixeddecimal_sum); @@ -422,6 +424,7 @@ fixeddecimalout(PG_FUNCTION_ARGS) int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER; int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER; + if (val < 0) { fractionalpart = -fractionalpart; @@ -1125,7 +1128,6 @@ fixeddecimalint2div(PG_FUNCTION_ARGS) } /* No overflow is possible */ - result = arg1 / arg2; PG_RETURN_INT64(result); @@ -1366,6 +1368,47 @@ ftofixeddecimal(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } + +Datum +fixeddecimal_numeric(PG_FUNCTION_ARGS) +{ + int64 num = PG_GETARG_INT64(0); + char *tmp; + Datum result; + + tmp = DatumGetCString(DirectFunctionCall1(fixeddecimalout, + Int64GetDatum(num))); + + result = DirectFunctionCall3(numeric_in, CStringGetDatum(tmp), 0, -1); + + pfree(tmp); + + PG_RETURN_DATUM(result); +} + +Datum +numeric_fixeddecimal(PG_FUNCTION_ARGS) +{ + Numeric num = PG_GETARG_NUMERIC(0); + char *tmp; + Datum result; + + if (numeric_is_nan(num)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot convert NaN to fixeddecimal"))); + + tmp = DatumGetCString(DirectFunctionCall1(numeric_out, + NumericGetDatum(num))); + + result = DirectFunctionCall1(fixeddecimalin, CStringGetDatum(tmp)); + + pfree(tmp); + + PG_RETURN_DATUM(result); +} + + /* Aggregate Support */ typedef struct FixedDecimalAggState diff --git a/contrib/fixeddecimal/test/expected/overflow.out b/contrib/fixeddecimal/test/expected/overflow.out index 2bca2d890ac..be99e33069d 100755 --- a/contrib/fixeddecimal/test/expected/overflow.out +++ b/contrib/fixeddecimal/test/expected/overflow.out @@ -13,6 +13,28 @@ SELECT '92233720368547758.08'::fixeddecimal; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal LINE 1: SELECT '92233720368547758.08'::fixeddecimal; ^ +-- Ensure casts from numeric to fixeddecimal work +SELECT '92233720368547758.07'::numeric::fixeddecimal; + fixeddecimal +---------------------- + 92233720368547758.07 +(1 row) + +-- The literal below must be quoted as the parser seems to read the literal as +-- a positive number first and then us the - unary operator to make it negaive. +-- This would overflow without the quotes as this number cannot be represented +-- in a positive fixeddecimal. +SELECT '-92233720368547758.08'::numeric::fixeddecimal; + fixeddecimal +----------------------- + -92233720368547758.08 +(1 row) + +-- Ensure casts from numeric to fixed decimal detect overflow +SELECT '92233720368547758.08'::numeric::fixeddecimal; +ERROR: value "92233720368547758.08" is out of range for type fixeddecimal +SELECT '-92233720368547758.09'::numeric::fixeddecimal; +ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; ERROR: fixeddecimal out of range SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; diff --git a/contrib/fixeddecimal/test/results/overflow.out b/contrib/fixeddecimal/test/results/overflow.out index 2bca2d890ac..be99e33069d 100755 --- a/contrib/fixeddecimal/test/results/overflow.out +++ b/contrib/fixeddecimal/test/results/overflow.out @@ -13,6 +13,28 @@ SELECT '92233720368547758.08'::fixeddecimal; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal LINE 1: SELECT '92233720368547758.08'::fixeddecimal; ^ +-- Ensure casts from numeric to fixeddecimal work +SELECT '92233720368547758.07'::numeric::fixeddecimal; + fixeddecimal +---------------------- + 92233720368547758.07 +(1 row) + +-- The literal below must be quoted as the parser seems to read the literal as +-- a positive number first and then us the - unary operator to make it negaive. +-- This would overflow without the quotes as this number cannot be represented +-- in a positive fixeddecimal. +SELECT '-92233720368547758.08'::numeric::fixeddecimal; + fixeddecimal +----------------------- + -92233720368547758.08 +(1 row) + +-- Ensure casts from numeric to fixed decimal detect overflow +SELECT '92233720368547758.08'::numeric::fixeddecimal; +ERROR: value "92233720368547758.08" is out of range for type fixeddecimal +SELECT '-92233720368547758.09'::numeric::fixeddecimal; +ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; ERROR: fixeddecimal out of range SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; diff --git a/contrib/fixeddecimal/test/sql/overflow.sql b/contrib/fixeddecimal/test/sql/overflow.sql index b8e247957c1..e73b64e8a8e 100755 --- a/contrib/fixeddecimal/test/sql/overflow.sql +++ b/contrib/fixeddecimal/test/sql/overflow.sql @@ -5,6 +5,20 @@ SELECT '-92233720368547758.09'::fixeddecimal; SELECT '92233720368547758.08'::fixeddecimal; +-- Ensure casts from numeric to fixeddecimal work +SELECT '92233720368547758.07'::numeric::fixeddecimal; + +-- The literal below must be quoted as the parser seems to read the literal as +-- a positive number first and then us the - unary operator to make it negaive. +-- This would overflow without the quotes as this number cannot be represented +-- in a positive fixeddecimal. +SELECT '-92233720368547758.08'::numeric::fixeddecimal; + +-- Ensure casts from numeric to fixed decimal detect overflow +SELECT '92233720368547758.08'::numeric::fixeddecimal; + +SELECT '-92233720368547758.09'::numeric::fixeddecimal; + SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; From 93dd2e4067cb37a8fab6cad84179997167b24fd7 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 10 Sep 2015 23:41:47 +1200 Subject: [PATCH 11/32] Add README file --- contrib/fixeddecimal/README | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100755 contrib/fixeddecimal/README diff --git a/contrib/fixeddecimal/README b/contrib/fixeddecimal/README new file mode 100755 index 00000000000..dcfca10da6f --- /dev/null +++ b/contrib/fixeddecimal/README @@ -0,0 +1,70 @@ +FIXEDDECIMAL +============ + +FixedDecimal is a fixed precision decimal type which internally uses a 64bit +integer type for its underlying storage. This makes fixeddecimal very fast when +compared to PostgreSQL's NUMERIC type. Although fixeddecimal is unable to store +the same range of numbers that NUMERIC is able to. + +As of today the precision of this type is "hard-coded" at compile time using +the FIXEDDECIMAL_PRECISION and FIXEDDECIMAL_MULTIPLIER pre-processor constants +in fixeddecimal.c. + +By default the precision of fixeddecimal is 2 decimal digits after the decimal +point. This allows fixeddecimal to store a maximum value of 92233720368547758.07 +and a minimum value of -92233720368547758.08. These numbers may look familiar, +as if you remove the decimal point the numbers represent the same limits as a +64 bit integer type on a two's complement machine. + +Internally fixeddecimal stores the value as an integer where the actual value +stored is the fixeddecimal value * FIXEDDECIMAL_MULTIPLIER. By default this is +100, so a value of 1.00 will actually be stored as 100. It should also be noted +that all arithmetic on fixeddecimals uses integer arithmetic on the actual +stored integer value. This means that division truncates rather than rounds. + +For example: + +test=# select '2.00'::fixeddecimal / '3.00'::fixeddecimal; + ?column? +---------- + 0.66 +(1 row) + +Where the same calculation done in PostgreSQL's NUMERIC type would result in a +number which ends with a '7' due to the infinity of 6's being rounded up to 7. + +It should also be noted that multiplication and division using fixeddecimal +requires the use of a 128bit integer type. The reason for this is due to the +internal integer storage and also from danger of overflow. + +If we imagine the following calculation in fixeddecimal: 2 * 2.5. Internally +this would be 200 * 250 (With a FIXEDDECIMAL_MULTIPLIER of 100). The result of +this is 50000, so we must now divide the number by FIXEDDECIMAL_MULTIPLIER in +order to obtain the expected internal value of 500. Such calculations may cause +a fixednumeric to overflow unnecessarily, so in order to avoid this problem +all division and multiplication uses a 128bit integer type. Addition and +subtraction do not suffer from the same problem. + +It should also be noted that excess precision is ignored by fixeddecimal. +With a FIXEDDECIMAL_PRECISION of 2, any value after the 2nd digit following +the decimal point is completely ignored rather than rounded. The following +example demonstrates this: + +test=# select '1.239'::fixeddecimal; + fixeddecimal +-------------- + 1.23 +(1 row) + +It is especially important to remember that this truncation also occurs during +arithmetic. Notice in the following example the result is 1120 rather than +1129: + +test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; + ?column? +---------- + 1120.00 +(1 row) + + + From 23df8d2444397322d88118e26e09d0eee9fee86b Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 17 Sep 2015 01:33:51 +1200 Subject: [PATCH 12/32] Various changes to fixeddecimal 1. Added typmod enforcement for fixednumeric. 2. Added hash index support. 3. Added missing copywrite notice 4. Added tests for indexes --- contrib/fixeddecimal/fixeddecimal--1.0.0.sql | 38 ++- contrib/fixeddecimal/fixeddecimal.c | 229 ++++++++++++++++-- contrib/fixeddecimal/test/expected/index.out | 91 +++++++ .../fixeddecimal/test/expected/overflow.out | 76 ++++-- contrib/fixeddecimal/test/results/index.out | 91 +++++++ .../fixeddecimal/test/results/overflow.out | 76 ++++-- contrib/fixeddecimal/test/sql/index.sql | 48 ++++ contrib/fixeddecimal/test/sql/overflow.sql | 61 +++-- 8 files changed, 616 insertions(+), 94 deletions(-) create mode 100644 contrib/fixeddecimal/test/expected/index.out create mode 100644 contrib/fixeddecimal/test/results/index.out create mode 100644 contrib/fixeddecimal/test/sql/index.sql diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql index 02e1329e734..4c90efe8cb9 100755 --- a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql @@ -5,7 +5,7 @@ CREATE TYPE FIXEDDECIMAL; -CREATE FUNCTION fixeddecimalin(cstring) +CREATE FUNCTION fixeddecimalin(cstring, oid, int4) RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimalin' LANGUAGE C IMMUTABLE STRICT; @@ -18,18 +18,31 @@ LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION fixeddecimalrecv(internal) RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimalrecv' -LANGUAGE C STABLE STRICT; +LANGUAGE C IMMUTABLE STRICT; CREATE FUNCTION fixeddecimalsend(FIXEDDECIMAL) RETURNS bytea AS 'fixeddecimal', 'fixeddecimalsend' -LANGUAGE C STABLE STRICT; +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'fixeddecimal', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT; + CREATE TYPE FIXEDDECIMAL ( INPUT = fixeddecimalin, OUTPUT = fixeddecimalout, RECEIVE = fixeddecimalrecv, SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, INTERNALLENGTH = 8, ALIGNMENT = 'double', STORAGE = plain, @@ -114,6 +127,11 @@ RETURNS INT4 AS 'fixeddecimal', 'fixeddecimal_cmp' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT; + -- -- Operators. -- @@ -219,6 +237,11 @@ DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + -- -- Cross type operators with int4 -- @@ -416,6 +439,11 @@ CREATE OPERATOR / ( -- Casts -- +CREATE FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + CREATE FUNCTION int4fixeddecimal(INT4) RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'int4fixeddecimal' @@ -466,6 +494,8 @@ RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'numeric_fixeddecimal' LANGUAGE C IMMUTABLE STRICT; +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; CREATE CAST (INT4 AS FIXEDDECIMAL) WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; @@ -478,7 +508,7 @@ CREATE CAST (INT2 AS FIXEDDECIMAL) CREATE CAST (FIXEDDECIMAL AS INT2) WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; - + CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index d01934fa4ea..743cdf4f50d 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -1,4 +1,18 @@ - +/*------------------------------------------------------------------------- + * + * fixeddecimal.c + * Fixed Decimal numeric type extension + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * + * IDENTIFICATION + * fixeddecimal.c + * + * The research leading to these results has received funding from the European + * Union’s Seventh Framework Programme (FP7/2007-2015) under grant agreement + * n° 318633 + *------------------------------------------------------------------------- + */ #include "postgres.h" #include @@ -7,6 +21,7 @@ #include "funcapi.h" #include "libpq/pqformat.h" +#include "utils/array.h" #include "utils/builtins.h" #include "utils/numeric.h" @@ -16,7 +31,7 @@ * The scale which the number is actually stored. * For example: 100 will allow 2 decimal places of precision * This must always be a '1' followed by a number of '0's. - */ + */ #define FIXEDDECIMAL_MULTIPLIER 100LL /* @@ -24,7 +39,15 @@ * This number should be the number of decimal digits that it takes to * represent FIXEDDECIMAL_MULTIPLIER - 1 */ -#define FIXEDDECIMAL_PRECISION 2 +#define FIXEDDECIMAL_SCALE 2 + +/* + * This is bounded by the maximum and minimum values of int64. + * 9223372036854775807 is 19 decimal digits long, but we we can only represent + * this number / FIXEDDECIMAL_MULTIPLIER, so we must subtract + * FIXEDDECIMAL_SCALE + */ +#define FIXEDDECIMAL_MAX_PRECISION 19 - FIXEDDECIMAL_SCALE /* Define this if your compiler has _builtin_add_overflow() */ /* #define HAVE_BUILTIN_OVERFLOW */ @@ -43,6 +66,8 @@ PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1(fixeddecimalin); +PG_FUNCTION_INFO_V1(fixeddecimaltypmodin); +PG_FUNCTION_INFO_V1(fixeddecimaltypmodout); PG_FUNCTION_INFO_V1(fixeddecimalout); PG_FUNCTION_INFO_V1(fixeddecimalrecv); PG_FUNCTION_INFO_V1(fixeddecimalsend); @@ -53,6 +78,7 @@ PG_FUNCTION_INFO_V1(fixeddecimalgt); PG_FUNCTION_INFO_V1(fixeddecimalle); PG_FUNCTION_INFO_V1(fixeddecimalge); PG_FUNCTION_INFO_V1(fixeddecimal_cmp); +PG_FUNCTION_INFO_V1(fixeddecimal_hash); PG_FUNCTION_INFO_V1(fixeddecimalum); PG_FUNCTION_INFO_V1(fixeddecimalup); PG_FUNCTION_INFO_V1(fixeddecimalpl); @@ -66,6 +92,7 @@ PG_FUNCTION_INFO_V1(fixeddecimalint4pl); PG_FUNCTION_INFO_V1(fixeddecimalint4mi); PG_FUNCTION_INFO_V1(fixeddecimalint4mul); PG_FUNCTION_INFO_V1(fixeddecimalint4div); +PG_FUNCTION_INFO_V1(fixeddecimal); PG_FUNCTION_INFO_V1(int4fixeddecimalpl); PG_FUNCTION_INFO_V1(int4fixeddecimalmi); PG_FUNCTION_INFO_V1(int4fixeddecimalmul); @@ -92,6 +119,21 @@ PG_FUNCTION_INFO_V1(fixeddecimal_avg_accum); PG_FUNCTION_INFO_V1(fixeddecimal_avg); PG_FUNCTION_INFO_V1(fixeddecimal_sum); +/* Aggregate Internal State */ +typedef struct FixedDecimalAggState +{ + MemoryContext agg_context; /* context we're calculating in */ + int64 N; /* count of processed numbers */ + int64 sumX; /* sum of processed numbers */ +} FixedDecimalAggState; + +static char *pg_int64tostr(char *str, int64 value); +static char *pg_int64tostr_zeropad(char *str, int64 value, int64 padding); +static void apply_typmod(int64 value, int32 typmod, int precision, int scale); +static int64 scanfixeddecimal(const char *str, int *precision, int *scale); +static FixedDecimalAggState *makeFixedDecimalAggState(FunctionCallInfo fcinfo); +static void fixeddecimal_accum(FixedDecimalAggState *state, int64 newval); + /*********************************************************************** ** ** Routines for fixeddecimal @@ -249,12 +291,15 @@ pg_int64tostr_zeropad(char *str, int64 value, int64 padding) * scanfixeddecimal --- try to parse a string into a fixeddecimal. */ static int64 -scanfixeddecimal(const char *str) +scanfixeddecimal(const char *str, int *precision, int *scale) { const char *ptr = str; int64 integralpart = 0; int64 fractionalpart = 0; bool negative; + int vprecision = 0; + int vscale = 0; + /* * Do our own scan, rather than relying on sscanf which might be broken * for long long. @@ -274,6 +319,7 @@ scanfixeddecimal(const char *str) { int64 tmp = integralpart * 10 - (*ptr++ - '0'); + vprecision++; if ((tmp / 10) != integralpart) /* underflow? */ { ereport(ERROR, @@ -287,7 +333,7 @@ scanfixeddecimal(const char *str) else { negative = false; - + if (*ptr == '+') ptr++; @@ -295,6 +341,7 @@ scanfixeddecimal(const char *str) { int64 tmp = integralpart * 10 + (*ptr++ - '0'); + vprecision++; if ((tmp / 10) != integralpart) /* overflow? */ { ereport(ERROR, @@ -311,11 +358,12 @@ scanfixeddecimal(const char *str) { int64 multiplier = FIXEDDECIMAL_MULTIPLIER; ptr++; - + while (isdigit((unsigned char) *ptr) && multiplier > 1) { multiplier /= 10; fractionalpart += (*ptr++ - '0') * multiplier; + vscale++; } /* @@ -323,7 +371,7 @@ scanfixeddecimal(const char *str) * XXX These are ignored, should we error instead? */ while (isdigit((unsigned char) *ptr)) - ptr++; + ptr++, vscale++; } /* consume any remaining space chars */ @@ -335,6 +383,9 @@ scanfixeddecimal(const char *str) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%s\" is out of range for type fixeddecimal", str))); + *precision = vprecision; + *scale = vscale; + if (negative) { @@ -402,18 +453,131 @@ scanfixeddecimal(const char *str) } } -/* fixeddecimalin() +/* + * fixeddecimalin() */ Datum fixeddecimalin(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); - int64 result = scanfixeddecimal(str); + int32 typmod = PG_GETARG_INT32(2); + int precision; + int scale; + int64 result = scanfixeddecimal(str, &precision, &scale); + + apply_typmod(result, typmod, precision, scale); + PG_RETURN_INT64(result); } +static void +apply_typmod(int64 value, int32 typmod, int precision, int scale) +{ + int precisionlimit; + int scalelimit; + int maxdigits; + + /* Do nothing if we have a default typmod (-1) */ + if (typmod < (int32) (VARHDRSZ)) + return; + + typmod -= VARHDRSZ; + precisionlimit = (typmod >> 16) & 0xffff; + scalelimit = typmod & 0xffff; + maxdigits = precisionlimit - scalelimit; + + if (scale > scalelimit) + + if (scale != FIXEDDECIMAL_SCALE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("FIXEDDECIMAL scale must be %d", + FIXEDDECIMAL_SCALE))); + + if (precision > maxdigits) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("FIXEDDECIMAL field overflow"), + errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.", + precision, scale, + /* Display 10^0 as 1 */ + maxdigits ? "10^" : "", + maxdigits ? maxdigits : 1 + ))); + +} + +Datum +fixeddecimaltypmodin(PG_FUNCTION_ARGS) +{ + ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); + int32 *tl; + int n; + int32 typmod; + + tl = ArrayGetIntegerTypmods(ta, &n); + + if (n == 2) + { + /* + * we demand that the precision is at least the scale, since later we + * enforce that the scale is exactly FIXEDDECIMAL_SCALE + */ + if (tl[0] < FIXEDDECIMAL_SCALE || tl[0] > FIXEDDECIMAL_MAX_PRECISION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("FIXEDDECIMAL precision %d must be between %d and %d", + tl[0], FIXEDDECIMAL_SCALE, FIXEDDECIMAL_MAX_PRECISION))); + + if (tl[1] != FIXEDDECIMAL_SCALE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("FIXEDDECIMAL scale must be %d", + FIXEDDECIMAL_SCALE))); + + typmod = ((tl[0] << 16) | tl[1]) + VARHDRSZ; + } + else if (n == 1) + { + if (tl[0] < FIXEDDECIMAL_SCALE || tl[0] > FIXEDDECIMAL_MAX_PRECISION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("FIXEDDECIMAL precision %d must be between %d and %d", + tl[0], FIXEDDECIMAL_SCALE, FIXEDDECIMAL_MAX_PRECISION))); + + /* scale defaults to FIXEDDECIMAL_SCALE */ + typmod = ((tl[0] << 16) | FIXEDDECIMAL_SCALE) + VARHDRSZ; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid FIXEDDECIMAL type modifier"))); + typmod = 0; /* keep compiler quiet */ + } + + PG_RETURN_INT32(typmod); +} + +Datum +fixeddecimaltypmodout(PG_FUNCTION_ARGS) +{ + int32 typmod = PG_GETARG_INT32(0); + char *res = (char *) palloc(64); + + if (typmod >= 0) + snprintf(res, 64, "(%d,%d)", + ((typmod - VARHDRSZ) >> 16) & 0xffff, + (typmod - VARHDRSZ) & 0xffff); + else + *res = '\0'; + + PG_RETURN_CSTRING(res); +} + -/* fixeddecimalout() +/* + * fixeddecimalout() */ Datum fixeddecimalout(PG_FUNCTION_ARGS) @@ -428,7 +592,7 @@ fixeddecimalout(PG_FUNCTION_ARGS) if (val < 0) { fractionalpart = -fractionalpart; - + /* * Handle special case for negative numbers where the intergral part * is zero. pg_int64tostr() won't prefix with "-0" in this case, so @@ -439,7 +603,7 @@ fixeddecimalout(PG_FUNCTION_ARGS) } ptr = pg_int64tostr(ptr, integralpart); *ptr++ = '.'; - ptr = pg_int64tostr_zeropad(ptr, fractionalpart, FIXEDDECIMAL_PRECISION); + ptr = pg_int64tostr_zeropad(ptr, fractionalpart, FIXEDDECIMAL_SCALE); PG_RETURN_CSTRING(pnstrdup(buf, ptr - &buf[0])); } @@ -533,7 +697,7 @@ fixeddecimal_cmp(PG_FUNCTION_ARGS) { int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - + if (val1 == val2) PG_RETURN_INT32(0); else if (val1 < val2) @@ -542,6 +706,15 @@ fixeddecimal_cmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(1); } +Datum +fixeddecimal_hash(PG_FUNCTION_ARGS) +{ + int64 val = PG_GETARG_INT64(0); + Datum result; + + result = hash_any(&val, sizeof(int64)); + PG_RETURN_DATUM(result); +} /*---------------------------------------------------------- * Arithmetic operators on fixeddecimal. @@ -555,7 +728,7 @@ fixeddecimalum(PG_FUNCTION_ARGS) #ifdef HAVE_BUILTIN_OVERFLOW int64 zero = 0; - + if (__builtin_sub_overflow(zero, arg, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), @@ -643,7 +816,7 @@ fixeddecimalmul(PG_FUNCTION_ARGS) int64 arg1 = PG_GETARG_INT64(0); int64 arg2 = PG_GETARG_INT64(1); int128 result; - + /* We need to promote this to 128bit as we may overflow int64 here. * Remember that arg2 is the number multiplied by * FIXEDDECIMAL_MULTIPLIER, we must divide the result by this to get @@ -1249,6 +1422,23 @@ int2fixeddecimaldiv(PG_FUNCTION_ARGS) * Conversion operators. *---------------------------------------------------------*/ +/* + * fixeddecimal serves as casting function for fixeddecimal to fixeddecimal. + * The only serves to generate an error if the fixedecimal is too big for the + * specified typmod. + */ +Datum +fixeddecimal(PG_FUNCTION_ARGS) +{ + int64 num = PG_GETARG_INT64(0); + int32 typmod = PG_GETARG_INT32(1); + Datum result; + + result = DirectFunctionCall1(fixeddecimalout, num); + result = DirectFunctionCall3(fixeddecimalin, result, 0, typmod); + PG_RETURN_INT64(num); +} + Datum int4fixeddecimal(PG_FUNCTION_ARGS) { @@ -1401,7 +1591,7 @@ numeric_fixeddecimal(PG_FUNCTION_ARGS) tmp = DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(num))); - result = DirectFunctionCall1(fixeddecimalin, CStringGetDatum(tmp)); + result = DirectFunctionCall3(fixeddecimalin, CStringGetDatum(tmp), 0, -1); pfree(tmp); @@ -1411,13 +1601,6 @@ numeric_fixeddecimal(PG_FUNCTION_ARGS) /* Aggregate Support */ -typedef struct FixedDecimalAggState -{ - MemoryContext agg_context; /* context we're calculating in */ - int64 N; /* count of processed numbers */ - int64 sumX; /* sum of processed numbers */ -} FixedDecimalAggState; - static FixedDecimalAggState * makeFixedDecimalAggState(FunctionCallInfo fcinfo) { diff --git a/contrib/fixeddecimal/test/expected/index.out b/contrib/fixeddecimal/test/expected/index.out new file mode 100644 index 00000000000..332fe7e9f33 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/index.out @@ -0,0 +1,91 @@ +CREATE TABLE fixdec (id INT PRIMARY KEY, d FIXEDDECIMAL(5,2)); +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); +-- Should fail +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); +ERROR: could not create unique index "fixdec_d_idx" +DETAIL: Key (d)=(123.45) is duplicated. +DELETE FROM fixdec WHERE id = 9; +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); +SET enable_seqscan = off; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + QUERY PLAN +----------------------------------------- + Index Scan using fixdec_d_idx on fixdec +(1 row) + +SELECT * FROM fixdec ORDER BY d; + id | d +----+--------- + 1 | -123.45 + 2 | -123.00 + 3 | -12.34 + 4 | -1.34 + 5 | 0.12 + 6 | 1.23 + 7 | 12.34 + 8 | 123.45 +(8 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------- + Index Scan using fixdec_d_idx on fixdec + Index Cond: (d = '12.34'::fixeddecimal) +(2 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP INDEX fixdec_d_idx; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +WARNING: hash indexes are not WAL-logged and their use is discouraged +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------- + Index Scan using fixdec_d_idx on fixdec + Index Cond: (d = '12.34'::fixeddecimal) +(2 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +SET enable_seqscan = on; +DROP TABLE fixdec; diff --git a/contrib/fixeddecimal/test/expected/overflow.out b/contrib/fixeddecimal/test/expected/overflow.out index be99e33069d..ee0010080d4 100755 --- a/contrib/fixeddecimal/test/expected/overflow.out +++ b/contrib/fixeddecimal/test/expected/overflow.out @@ -1,20 +1,20 @@ -- Ensure the expected extreme values can be represented -SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07'::fixeddecimal as maxvalue; +SELECT '-92233720368547758.08'::FIXEDDECIMAL as minvalue,'92233720368547758.07'::FIXEDDECIMAL as maxvalue; minvalue | maxvalue -----------------------+---------------------- -92233720368547758.08 | 92233720368547758.07 (1 row) -SELECT '-92233720368547758.09'::fixeddecimal; +SELECT '-92233720368547758.09'::FIXEDDECIMAL; ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal -LINE 1: SELECT '-92233720368547758.09'::fixeddecimal; +LINE 1: SELECT '-92233720368547758.09'::FIXEDDECIMAL; ^ -SELECT '92233720368547758.08'::fixeddecimal; +SELECT '92233720368547758.08'::FIXEDDECIMAL; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal -LINE 1: SELECT '92233720368547758.08'::fixeddecimal; +LINE 1: SELECT '92233720368547758.08'::FIXEDDECIMAL; ^ -- Ensure casts from numeric to fixeddecimal work -SELECT '92233720368547758.07'::numeric::fixeddecimal; +SELECT '92233720368547758.07'::numeric::FIXEDDECIMAL; fixeddecimal ---------------------- 92233720368547758.07 @@ -24,70 +24,100 @@ SELECT '92233720368547758.07'::numeric::fixeddecimal; -- a positive number first and then us the - unary operator to make it negaive. -- This would overflow without the quotes as this number cannot be represented -- in a positive fixeddecimal. -SELECT '-92233720368547758.08'::numeric::fixeddecimal; +SELECT '-92233720368547758.08'::numeric::FIXEDDECIMAL; fixeddecimal ----------------------- -92233720368547758.08 (1 row) -- Ensure casts from numeric to fixed decimal detect overflow -SELECT '92233720368547758.08'::numeric::fixeddecimal; +SELECT '92233720368547758.08'::numeric::FIXEDDECIMAL; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal -SELECT '-92233720368547758.09'::numeric::fixeddecimal; +SELECT '-92233720368547758.09'::numeric::FIXEDDECIMAL; ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal -SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; +SELECT '-92233720368547758.08'::FIXEDDECIMAL - '0.01'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; +SELECT '92233720368547758.07'::FIXEDDECIMAL + '0.01'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -- Should not overflow -SELECT '46116860184273879.03'::fixeddecimal * '2.00'::fixeddecimal; +SELECT '46116860184273879.03'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; ?column? ---------------------- 92233720368547758.06 (1 row) -- Ensure this overflows -SELECT '46116860184273879.04'::fixeddecimal * '2.00'::fixeddecimal; +SELECT '46116860184273879.04'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -- Should not overflow -SELECT '46116860184273879.03'::fixeddecimal / '0.50'::fixeddecimal; +SELECT '46116860184273879.03'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; ?column? ---------------------- 92233720368547758.06 (1 row) -- Ensure this overflows -SELECT '46116860184273879.04'::fixeddecimal / '0.50'::fixeddecimal; +SELECT '46116860184273879.04'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -- Ensure limits of int2 can be represented -SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; +SELECT '32767'::FIXEDDECIMAL::INT2,'-32768'::FIXEDDECIMAL::INT2; int2 | int2 -------+-------- 32767 | -32768 (1 row) -- Ensure overflow of int2 is detected -SELECT '32768'::fixeddecimal::int2; +SELECT '32768'::FIXEDDECIMAL::INT2; ERROR: smallint out of range -- Ensure underflow of int2 is detected -SELECT '-32769'::fixeddecimal::int2; +SELECT '-32769'::FIXEDDECIMAL::INT2; ERROR: smallint out of range -- Ensure limits of int4 can be represented -SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; +SELECT '2147483647'::FIXEDDECIMAL::INT4,'-2147483648'::FIXEDDECIMAL::INT4; int4 | int4 ------------+------------- 2147483647 | -2147483648 (1 row) -- Ensure overflow of int4 is detected -SELECT '2147483648'::fixeddecimal::int4; +SELECT '2147483648'::FIXEDDECIMAL::INT4; ERROR: integer out of range -- Ensure underflow of int4 is detected -SELECT '-2147483649'::fixeddecimal::int4; +SELECT '-2147483649'::FIXEDDECIMAL::INT4; ERROR: integer out of range -- Ensure overflow is detected -SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::FIXEDDECIMAL),('0.01'::FIXEDDECIMAL)) a(a); ERROR: fixeddecimal out of range -- Ensure underflow is detected -SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::FIXEDDECIMAL),('-0.01'::FIXEDDECIMAL)) a(a); ERROR: fixeddecimal out of range +-- Test typmods +SELECT 12345.33::FIXEDDECIMAL(3,2); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^1. +SELECT 12345.33::FIXEDDECIMAL(5,2); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^3. +-- scale of 2 should be enforced. +SELECT 12345.44::FIXEDDECIMAL(7,0); +ERROR: FIXEDDECIMAL scale must be 2 +LINE 1: SELECT 12345.44::FIXEDDECIMAL(7,0); + ^ +-- should work. +SELECT 12345.33::FIXEDDECIMAL(7,2); + fixeddecimal +-------------- + 12345.33 +(1 row) + +-- error, precision limit should be 17 +SELECT 12345.33::FIXEDDECIMAL(18,2); +ERROR: FIXEDDECIMAL precision 18 must be between 2 and 17 +LINE 1: SELECT 12345.33::FIXEDDECIMAL(18,2); + ^ +CREATE TABLE fixdec (d FIXEDDECIMAL(3,2)); +INSERT INTO fixdec VALUES(12.34); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 2, scale 2 must round to an absolute value less than 10^1. +INSERT INTO fixdec VALUES(1.23); -- Pass +DROP TABLE fixdec; diff --git a/contrib/fixeddecimal/test/results/index.out b/contrib/fixeddecimal/test/results/index.out new file mode 100644 index 00000000000..332fe7e9f33 --- /dev/null +++ b/contrib/fixeddecimal/test/results/index.out @@ -0,0 +1,91 @@ +CREATE TABLE fixdec (id INT PRIMARY KEY, d FIXEDDECIMAL(5,2)); +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); +-- Should fail +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); +ERROR: could not create unique index "fixdec_d_idx" +DETAIL: Key (d)=(123.45) is duplicated. +DELETE FROM fixdec WHERE id = 9; +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); +SET enable_seqscan = off; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + QUERY PLAN +----------------------------------------- + Index Scan using fixdec_d_idx on fixdec +(1 row) + +SELECT * FROM fixdec ORDER BY d; + id | d +----+--------- + 1 | -123.45 + 2 | -123.00 + 3 | -12.34 + 4 | -1.34 + 5 | 0.12 + 6 | 1.23 + 7 | 12.34 + 8 | 123.45 +(8 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------- + Index Scan using fixdec_d_idx on fixdec + Index Cond: (d = '12.34'::fixeddecimal) +(2 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP INDEX fixdec_d_idx; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +WARNING: hash indexes are not WAL-logged and their use is discouraged +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------- + Index Scan using fixdec_d_idx on fixdec + Index Cond: (d = '12.34'::fixeddecimal) +(2 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +SET enable_seqscan = on; +DROP TABLE fixdec; diff --git a/contrib/fixeddecimal/test/results/overflow.out b/contrib/fixeddecimal/test/results/overflow.out index be99e33069d..ee0010080d4 100755 --- a/contrib/fixeddecimal/test/results/overflow.out +++ b/contrib/fixeddecimal/test/results/overflow.out @@ -1,20 +1,20 @@ -- Ensure the expected extreme values can be represented -SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07'::fixeddecimal as maxvalue; +SELECT '-92233720368547758.08'::FIXEDDECIMAL as minvalue,'92233720368547758.07'::FIXEDDECIMAL as maxvalue; minvalue | maxvalue -----------------------+---------------------- -92233720368547758.08 | 92233720368547758.07 (1 row) -SELECT '-92233720368547758.09'::fixeddecimal; +SELECT '-92233720368547758.09'::FIXEDDECIMAL; ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal -LINE 1: SELECT '-92233720368547758.09'::fixeddecimal; +LINE 1: SELECT '-92233720368547758.09'::FIXEDDECIMAL; ^ -SELECT '92233720368547758.08'::fixeddecimal; +SELECT '92233720368547758.08'::FIXEDDECIMAL; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal -LINE 1: SELECT '92233720368547758.08'::fixeddecimal; +LINE 1: SELECT '92233720368547758.08'::FIXEDDECIMAL; ^ -- Ensure casts from numeric to fixeddecimal work -SELECT '92233720368547758.07'::numeric::fixeddecimal; +SELECT '92233720368547758.07'::numeric::FIXEDDECIMAL; fixeddecimal ---------------------- 92233720368547758.07 @@ -24,70 +24,100 @@ SELECT '92233720368547758.07'::numeric::fixeddecimal; -- a positive number first and then us the - unary operator to make it negaive. -- This would overflow without the quotes as this number cannot be represented -- in a positive fixeddecimal. -SELECT '-92233720368547758.08'::numeric::fixeddecimal; +SELECT '-92233720368547758.08'::numeric::FIXEDDECIMAL; fixeddecimal ----------------------- -92233720368547758.08 (1 row) -- Ensure casts from numeric to fixed decimal detect overflow -SELECT '92233720368547758.08'::numeric::fixeddecimal; +SELECT '92233720368547758.08'::numeric::FIXEDDECIMAL; ERROR: value "92233720368547758.08" is out of range for type fixeddecimal -SELECT '-92233720368547758.09'::numeric::fixeddecimal; +SELECT '-92233720368547758.09'::numeric::FIXEDDECIMAL; ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal -SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; +SELECT '-92233720368547758.08'::FIXEDDECIMAL - '0.01'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; +SELECT '92233720368547758.07'::FIXEDDECIMAL + '0.01'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -- Should not overflow -SELECT '46116860184273879.03'::fixeddecimal * '2.00'::fixeddecimal; +SELECT '46116860184273879.03'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; ?column? ---------------------- 92233720368547758.06 (1 row) -- Ensure this overflows -SELECT '46116860184273879.04'::fixeddecimal * '2.00'::fixeddecimal; +SELECT '46116860184273879.04'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -- Should not overflow -SELECT '46116860184273879.03'::fixeddecimal / '0.50'::fixeddecimal; +SELECT '46116860184273879.03'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; ?column? ---------------------- 92233720368547758.06 (1 row) -- Ensure this overflows -SELECT '46116860184273879.04'::fixeddecimal / '0.50'::fixeddecimal; +SELECT '46116860184273879.04'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; ERROR: fixeddecimal out of range -- Ensure limits of int2 can be represented -SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; +SELECT '32767'::FIXEDDECIMAL::INT2,'-32768'::FIXEDDECIMAL::INT2; int2 | int2 -------+-------- 32767 | -32768 (1 row) -- Ensure overflow of int2 is detected -SELECT '32768'::fixeddecimal::int2; +SELECT '32768'::FIXEDDECIMAL::INT2; ERROR: smallint out of range -- Ensure underflow of int2 is detected -SELECT '-32769'::fixeddecimal::int2; +SELECT '-32769'::FIXEDDECIMAL::INT2; ERROR: smallint out of range -- Ensure limits of int4 can be represented -SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; +SELECT '2147483647'::FIXEDDECIMAL::INT4,'-2147483648'::FIXEDDECIMAL::INT4; int4 | int4 ------------+------------- 2147483647 | -2147483648 (1 row) -- Ensure overflow of int4 is detected -SELECT '2147483648'::fixeddecimal::int4; +SELECT '2147483648'::FIXEDDECIMAL::INT4; ERROR: integer out of range -- Ensure underflow of int4 is detected -SELECT '-2147483649'::fixeddecimal::int4; +SELECT '-2147483649'::FIXEDDECIMAL::INT4; ERROR: integer out of range -- Ensure overflow is detected -SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::FIXEDDECIMAL),('0.01'::FIXEDDECIMAL)) a(a); ERROR: fixeddecimal out of range -- Ensure underflow is detected -SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::FIXEDDECIMAL),('-0.01'::FIXEDDECIMAL)) a(a); ERROR: fixeddecimal out of range +-- Test typmods +SELECT 12345.33::FIXEDDECIMAL(3,2); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^1. +SELECT 12345.33::FIXEDDECIMAL(5,2); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^3. +-- scale of 2 should be enforced. +SELECT 12345.44::FIXEDDECIMAL(7,0); +ERROR: FIXEDDECIMAL scale must be 2 +LINE 1: SELECT 12345.44::FIXEDDECIMAL(7,0); + ^ +-- should work. +SELECT 12345.33::FIXEDDECIMAL(7,2); + fixeddecimal +-------------- + 12345.33 +(1 row) + +-- error, precision limit should be 17 +SELECT 12345.33::FIXEDDECIMAL(18,2); +ERROR: FIXEDDECIMAL precision 18 must be between 2 and 17 +LINE 1: SELECT 12345.33::FIXEDDECIMAL(18,2); + ^ +CREATE TABLE fixdec (d FIXEDDECIMAL(3,2)); +INSERT INTO fixdec VALUES(12.34); -- Fail +ERROR: FIXEDDECIMAL field overflow +DETAIL: A field with precision 2, scale 2 must round to an absolute value less than 10^1. +INSERT INTO fixdec VALUES(1.23); -- Pass +DROP TABLE fixdec; diff --git a/contrib/fixeddecimal/test/sql/index.sql b/contrib/fixeddecimal/test/sql/index.sql new file mode 100644 index 00000000000..a9b2950e525 --- /dev/null +++ b/contrib/fixeddecimal/test/sql/index.sql @@ -0,0 +1,48 @@ +CREATE TABLE fixdec (id INT PRIMARY KEY, d FIXEDDECIMAL(5,2)); + +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); + +-- Should fail +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); + +DELETE FROM fixdec WHERE id = 9; + +CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); + +SET enable_seqscan = off; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + +SELECT * FROM fixdec ORDER BY d; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +DROP INDEX fixdec_d_idx; + +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +SET enable_seqscan = on; + +DROP TABLE fixdec; \ No newline at end of file diff --git a/contrib/fixeddecimal/test/sql/overflow.sql b/contrib/fixeddecimal/test/sql/overflow.sql index e73b64e8a8e..06408cda2b9 100755 --- a/contrib/fixeddecimal/test/sql/overflow.sql +++ b/contrib/fixeddecimal/test/sql/overflow.sql @@ -1,60 +1,79 @@ -- Ensure the expected extreme values can be represented -SELECT '-92233720368547758.08'::fixeddecimal as minvalue,'92233720368547758.07'::fixeddecimal as maxvalue; +SELECT '-92233720368547758.08'::FIXEDDECIMAL as minvalue,'92233720368547758.07'::FIXEDDECIMAL as maxvalue; -SELECT '-92233720368547758.09'::fixeddecimal; +SELECT '-92233720368547758.09'::FIXEDDECIMAL; -SELECT '92233720368547758.08'::fixeddecimal; +SELECT '92233720368547758.08'::FIXEDDECIMAL; -- Ensure casts from numeric to fixeddecimal work -SELECT '92233720368547758.07'::numeric::fixeddecimal; +SELECT '92233720368547758.07'::numeric::FIXEDDECIMAL; -- The literal below must be quoted as the parser seems to read the literal as -- a positive number first and then us the - unary operator to make it negaive. -- This would overflow without the quotes as this number cannot be represented -- in a positive fixeddecimal. -SELECT '-92233720368547758.08'::numeric::fixeddecimal; +SELECT '-92233720368547758.08'::numeric::FIXEDDECIMAL; -- Ensure casts from numeric to fixed decimal detect overflow -SELECT '92233720368547758.08'::numeric::fixeddecimal; +SELECT '92233720368547758.08'::numeric::FIXEDDECIMAL; -SELECT '-92233720368547758.09'::numeric::fixeddecimal; +SELECT '-92233720368547758.09'::numeric::FIXEDDECIMAL; -SELECT '-92233720368547758.08'::fixeddecimal - '0.01'::fixeddecimal; +SELECT '-92233720368547758.08'::FIXEDDECIMAL - '0.01'::FIXEDDECIMAL; -SELECT '92233720368547758.07'::fixeddecimal + '0.01'::fixeddecimal; +SELECT '92233720368547758.07'::FIXEDDECIMAL + '0.01'::FIXEDDECIMAL; -- Should not overflow -SELECT '46116860184273879.03'::fixeddecimal * '2.00'::fixeddecimal; +SELECT '46116860184273879.03'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; -- Ensure this overflows -SELECT '46116860184273879.04'::fixeddecimal * '2.00'::fixeddecimal; +SELECT '46116860184273879.04'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; -- Should not overflow -SELECT '46116860184273879.03'::fixeddecimal / '0.50'::fixeddecimal; +SELECT '46116860184273879.03'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; -- Ensure this overflows -SELECT '46116860184273879.04'::fixeddecimal / '0.50'::fixeddecimal; +SELECT '46116860184273879.04'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; -- Ensure limits of int2 can be represented -SELECT '32767'::fixeddecimal::int2,'-32768'::fixeddecimal::int2; +SELECT '32767'::FIXEDDECIMAL::INT2,'-32768'::FIXEDDECIMAL::INT2; -- Ensure overflow of int2 is detected -SELECT '32768'::fixeddecimal::int2; +SELECT '32768'::FIXEDDECIMAL::INT2; -- Ensure underflow of int2 is detected -SELECT '-32769'::fixeddecimal::int2; +SELECT '-32769'::FIXEDDECIMAL::INT2; -- Ensure limits of int4 can be represented -SELECT '2147483647'::fixeddecimal::int4,'-2147483648'::fixeddecimal::int4; +SELECT '2147483647'::FIXEDDECIMAL::INT4,'-2147483648'::FIXEDDECIMAL::INT4; -- Ensure overflow of int4 is detected -SELECT '2147483648'::fixeddecimal::int4; +SELECT '2147483648'::FIXEDDECIMAL::INT4; -- Ensure underflow of int4 is detected -SELECT '-2147483649'::fixeddecimal::int4; +SELECT '-2147483649'::FIXEDDECIMAL::INT4; -- Ensure overflow is detected -SELECT SUM(a) FROM (VALUES('92233720368547758.07'::fixeddecimal),('0.01'::fixeddecimal)) a(a); +SELECT SUM(a) FROM (VALUES('92233720368547758.07'::FIXEDDECIMAL),('0.01'::FIXEDDECIMAL)) a(a); -- Ensure underflow is detected -SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::fixeddecimal),('-0.01'::fixeddecimal)) a(a); +SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::FIXEDDECIMAL),('-0.01'::FIXEDDECIMAL)) a(a); + +-- Test typmods +SELECT 12345.33::FIXEDDECIMAL(3,2); -- Fail + +SELECT 12345.33::FIXEDDECIMAL(5,2); -- Fail + +-- scale of 2 should be enforced. +SELECT 12345.44::FIXEDDECIMAL(7,0); + +-- should work. +SELECT 12345.33::FIXEDDECIMAL(7,2); + +-- error, precision limit should be 17 +SELECT 12345.33::FIXEDDECIMAL(18,2); + +CREATE TABLE fixdec (d FIXEDDECIMAL(3,2)); +INSERT INTO fixdec VALUES(12.34); -- Fail +INSERT INTO fixdec VALUES(1.23); -- Pass +DROP TABLE fixdec; From 686d8d5e281a5ff3b0d949eddaf6b0163fb8e02b Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 17 Sep 2015 01:38:04 +1200 Subject: [PATCH 13/32] Add fastpath for fixeddecimal to fixeddecimal cast This cast only serves to check that the typmod is valid or the fixeddecimal. So we only need to bother doing this when the typmod is actually present, i.e, not -1. --- contrib/fixeddecimal/fixeddecimal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index 743cdf4f50d..fc22110a6ab 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -1434,8 +1434,12 @@ fixeddecimal(PG_FUNCTION_ARGS) int32 typmod = PG_GETARG_INT32(1); Datum result; - result = DirectFunctionCall1(fixeddecimalout, num); - result = DirectFunctionCall3(fixeddecimalin, result, 0, typmod); + /* no need to check typmod if it's -1 */ + if (typmod != -1) + { + result = DirectFunctionCall1(fixeddecimalout, num); + result = DirectFunctionCall3(fixeddecimalin, result, 0, typmod); + } PG_RETURN_INT64(num); } From e9f9e016737b53ba9f72ec5217dfdbbddaf49ea2 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 17 Sep 2015 14:40:13 +1200 Subject: [PATCH 14/32] Add support for BRIN indexes Also fixed small cast compiler warning in paramter to hash_any() --- contrib/fixeddecimal/fixeddecimal--1.0.0.sql | 13 ++++++++++++ contrib/fixeddecimal/fixeddecimal.c | 3 ++- contrib/fixeddecimal/test/expected/index.out | 22 +++++++++++++++++++- contrib/fixeddecimal/test/results/index.out | 22 +++++++++++++++++++- contrib/fixeddecimal/test/sql/index.sql | 17 +++++++++++++-- 5 files changed, 72 insertions(+), 5 deletions(-) diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql index 4c90efe8cb9..9605153b981 100755 --- a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0.sql @@ -242,6 +242,19 @@ DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +CREATE OPERATOR CLASS fixeddecimal_minmax_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING brin AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 brin_minmax_opcinfo(INTERNAL), + FUNCTION 2 brin_minmax_add_value(INTERNAL, INTERNAL, INTERNAL, INTERNAL), + FUNCTION 3 brin_minmax_consistent(INTERNAL, INTERNAL, INTERNAL), + FUNCTION 4 brin_minmax_union(INTERNAL, INTERNAL, INTERNAL); + -- -- Cross type operators with int4 -- diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index fc22110a6ab..c30344ca8ba 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -21,6 +21,7 @@ #include "funcapi.h" #include "libpq/pqformat.h" +#include "access/hash.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/numeric.h" @@ -712,7 +713,7 @@ fixeddecimal_hash(PG_FUNCTION_ARGS) int64 val = PG_GETARG_INT64(0); Datum result; - result = hash_any(&val, sizeof(int64)); + result = hash_any((unsigned char *) &val, sizeof(int64)); PG_RETURN_DATUM(result); } diff --git a/contrib/fixeddecimal/test/expected/index.out b/contrib/fixeddecimal/test/expected/index.out index 332fe7e9f33..b64e2724571 100644 --- a/contrib/fixeddecimal/test/expected/index.out +++ b/contrib/fixeddecimal/test/expected/index.out @@ -87,5 +87,25 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; 8 | 123.45 (1 row) -SET enable_seqscan = on; DROP TABLE fixdec; +-- Test BRIN indexes +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + QUERY PLAN +--------------------------------------------------- + Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) +(4 rows) + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + d | txt +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +SET enable_seqscan = on; diff --git a/contrib/fixeddecimal/test/results/index.out b/contrib/fixeddecimal/test/results/index.out index 332fe7e9f33..b64e2724571 100644 --- a/contrib/fixeddecimal/test/results/index.out +++ b/contrib/fixeddecimal/test/results/index.out @@ -87,5 +87,25 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; 8 | 123.45 (1 row) -SET enable_seqscan = on; DROP TABLE fixdec; +-- Test BRIN indexes +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + QUERY PLAN +--------------------------------------------------- + Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) +(4 rows) + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + d | txt +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +SET enable_seqscan = on; diff --git a/contrib/fixeddecimal/test/sql/index.sql b/contrib/fixeddecimal/test/sql/index.sql index a9b2950e525..25c04ee68fb 100644 --- a/contrib/fixeddecimal/test/sql/index.sql +++ b/contrib/fixeddecimal/test/sql/index.sql @@ -43,6 +43,19 @@ SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; -SET enable_seqscan = on; +DROP TABLE fixdec; + +-- Test BRIN indexes + +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); + +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); -DROP TABLE fixdec; \ No newline at end of file +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +SET enable_seqscan = on; From 33e8cb7f2f1a8549795243579912acb30bbaf60b Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 17 Sep 2015 16:03:31 +1200 Subject: [PATCH 15/32] Improve README file and format as .md --- contrib/fixeddecimal/README | 70 -------------------- contrib/fixeddecimal/README.md | 114 +++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 70 deletions(-) delete mode 100755 contrib/fixeddecimal/README create mode 100755 contrib/fixeddecimal/README.md diff --git a/contrib/fixeddecimal/README b/contrib/fixeddecimal/README deleted file mode 100755 index dcfca10da6f..00000000000 --- a/contrib/fixeddecimal/README +++ /dev/null @@ -1,70 +0,0 @@ -FIXEDDECIMAL -============ - -FixedDecimal is a fixed precision decimal type which internally uses a 64bit -integer type for its underlying storage. This makes fixeddecimal very fast when -compared to PostgreSQL's NUMERIC type. Although fixeddecimal is unable to store -the same range of numbers that NUMERIC is able to. - -As of today the precision of this type is "hard-coded" at compile time using -the FIXEDDECIMAL_PRECISION and FIXEDDECIMAL_MULTIPLIER pre-processor constants -in fixeddecimal.c. - -By default the precision of fixeddecimal is 2 decimal digits after the decimal -point. This allows fixeddecimal to store a maximum value of 92233720368547758.07 -and a minimum value of -92233720368547758.08. These numbers may look familiar, -as if you remove the decimal point the numbers represent the same limits as a -64 bit integer type on a two's complement machine. - -Internally fixeddecimal stores the value as an integer where the actual value -stored is the fixeddecimal value * FIXEDDECIMAL_MULTIPLIER. By default this is -100, so a value of 1.00 will actually be stored as 100. It should also be noted -that all arithmetic on fixeddecimals uses integer arithmetic on the actual -stored integer value. This means that division truncates rather than rounds. - -For example: - -test=# select '2.00'::fixeddecimal / '3.00'::fixeddecimal; - ?column? ----------- - 0.66 -(1 row) - -Where the same calculation done in PostgreSQL's NUMERIC type would result in a -number which ends with a '7' due to the infinity of 6's being rounded up to 7. - -It should also be noted that multiplication and division using fixeddecimal -requires the use of a 128bit integer type. The reason for this is due to the -internal integer storage and also from danger of overflow. - -If we imagine the following calculation in fixeddecimal: 2 * 2.5. Internally -this would be 200 * 250 (With a FIXEDDECIMAL_MULTIPLIER of 100). The result of -this is 50000, so we must now divide the number by FIXEDDECIMAL_MULTIPLIER in -order to obtain the expected internal value of 500. Such calculations may cause -a fixednumeric to overflow unnecessarily, so in order to avoid this problem -all division and multiplication uses a 128bit integer type. Addition and -subtraction do not suffer from the same problem. - -It should also be noted that excess precision is ignored by fixeddecimal. -With a FIXEDDECIMAL_PRECISION of 2, any value after the 2nd digit following -the decimal point is completely ignored rather than rounded. The following -example demonstrates this: - -test=# select '1.239'::fixeddecimal; - fixeddecimal --------------- - 1.23 -(1 row) - -It is especially important to remember that this truncation also occurs during -arithmetic. Notice in the following example the result is 1120 rather than -1129: - -test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; - ?column? ----------- - 1120.00 -(1 row) - - - diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md new file mode 100755 index 00000000000..b291c87706f --- /dev/null +++ b/contrib/fixeddecimal/README.md @@ -0,0 +1,114 @@ +FIXEDDECIMAL +============ + +Overview +-------- + +FixedDecimal is a fixed precision decimal type which provides a subset of the +features of PostgreSQL's builtin NUMERIC type, but with vastly increased +performance. Fixeddecimal is targeted to cases where performance and disk space +are a critical. + +Often there are data storage requirements where the built in REAL and +DOUBLE PRECISION types cannot be used due to the non-exact representation of +numbers, e.g where monetary values need to be stored. In many of these cases +NUMERIC is an almost perfect type, although with NUMERIC performance is no +match for the performance of REAL or DOUBLE PRCISION, as these use CPU native +processor types. FixedDecimal aims to offer performance advantages over NUMERIC +without the inprecise prepresentations that are apparent in REAL and DOUBLE +PRECISION, but it comes with some caveats... + +Behavioural differences between FIXEDDECIMAL and NUMERIC +-------------------------------------------------------- + +It should be noted that there are cases were FIXEDDECIMAL behaves differently +from NUMERIC. + +1. FIXEDDECIMAL has a much more limited range of values than NUMERIC. By + default this type can represent a maximum range of FIXEDDECIMAL(17,2), + although the underlying type is unable to represent the full range of + of the 17th significant digit. + +2. FIXEDDECIMAL always rounds towards zero. + +3. FIXEDDECIMAL does not support NaN. + +4. Any attempt to use a numerical scale other than the default fixed scale + will result in an error. e.g SELECT '123.223'::FIXEDDECIMAL(4,1) will fail + by default, as the default scale is 2, not 1. + +Internals +--------- + +FIXEDDECIMAL internally uses a 64bit integer type for its underlying storage. +This is what gives the type the performance advantage over NUMERIC, as most +calculations are performed as native processor operations rather than software +implementations as in the case with NUMERIC. + +FIXEDDECIMAL has a fixed scale value, which by default is 2. Internally numbers +are stores as the actual value multiplied by 100. e.g 50 would be stored as +5000, and 1.23 would be stored as 123. This internal representation allows very +fast addition and subtraction between two fixeddecimal types. Multiplication +between two fixeddecimal types is slighty more complex. If we wanted to +perform 2.00 * 3.00 in fixeddecimal, internally these numbers would be 200 and +300 respectively, so internally 200 * 300 becomes 60000, which must be divided +by 100 in order to obtain the correct internal result of 600, which of course +externally is 6.00. This method of multiplication is hazard to overflowing the +internal 64bit integer type, for this reason all multiplication and division is +performed using 128bit interger types. + +Internally, by default, FIXEDDECIMAL is limited to a maximum value of +92233720368547758.07 and a minimum value of -92233720368547758.08. If any of +these limits are exceeded the query will fail with an error. + +By default the scale of FIXEDDECIMAL is 2 decimal digits after the decimal +point. This value may be changed only by recompiling FIXEDDECIMAL from source, +which is done by altering the FIXEDDECIMAL_MULTIPLIER and FIXEDDECIMAL_SCALE +constants. If the FIXEDDECIMAL_SCALE was set to 4, then the +FIXEDDECIMAL_MULTIPLIER should be set to 10000. Doing this will mean that the +absolute limits of the type decrease to a range of -922337203685477.5808 to +922337203685477.5807. + +Caution +------- + +FIXEDDECIMAL is mainly intended as a fast and efficient data type which will +suit a limited set numerical data storage and retreaval needs. Complex +artimetic could be said to be one of fixeddecimal's limits. As stated above +division always rounds towards zero. Please observe the following example: + +> test=# select '2.00'::fixeddecimal / '3.00'::fixeddecimal; +> ?column? +> ---------- +> 0.66 +> (1 row) + +A workaround of this would be to perform all calculations in NUMERIC, and +ROUND() the result into the maximum scale of FIXEDDECIMAL: + +> test=# select round('2.00'::numeric / '3.00'::numeric, 2)::fixeddecimal; +> ?column? +> ---------- +> 0.67 +> (1 row) + +It should also be noted that excess precision is ignored by fixeddecimal. +With a FIXEDDECIMAL_PRECISION of 2, any value after the 2nd digit following +the decimal point is completely ignored rather than rounded. The following +example demonstrates this: + +> test=# select '1.239'::fixeddecimal; +> fixeddecimal +> -------------- +> 1.23 +> (1 row) + +It is especially important to remember that this truncation also occurs during +arithmetic. Notice in the following example the result is 1120 rather than +1129: + +> test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; +> ?column? +> ---------- +> 1120.00 +> (1 row) From 6e60e25e88208d2bab8705e8656ef2e092e14d14 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 17 Sep 2015 16:15:57 +1200 Subject: [PATCH 16/32] Fix .md formatting for examples --- contrib/fixeddecimal/README.md | 48 ++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md index b291c87706f..05fb679d604 100755 --- a/contrib/fixeddecimal/README.md +++ b/contrib/fixeddecimal/README.md @@ -77,38 +77,46 @@ suit a limited set numerical data storage and retreaval needs. Complex artimetic could be said to be one of fixeddecimal's limits. As stated above division always rounds towards zero. Please observe the following example: -> test=# select '2.00'::fixeddecimal / '3.00'::fixeddecimal; -> ?column? -> ---------- -> 0.66 -> (1 row) +``` +test=# select '2.00'::fixeddecimal / '3.00'::fixeddecimal; + ?column? +---------- + 0.66 +(1 row) +``` A workaround of this would be to perform all calculations in NUMERIC, and ROUND() the result into the maximum scale of FIXEDDECIMAL: -> test=# select round('2.00'::numeric / '3.00'::numeric, 2)::fixeddecimal; -> ?column? -> ---------- -> 0.67 -> (1 row) +``` +test=# select round('2.00'::numeric / '3.00'::numeric, 2)::fixeddecimal; + ?column? +---------- + 0.67 +(1 row) +``` It should also be noted that excess precision is ignored by fixeddecimal. With a FIXEDDECIMAL_PRECISION of 2, any value after the 2nd digit following the decimal point is completely ignored rather than rounded. The following example demonstrates this: -> test=# select '1.239'::fixeddecimal; -> fixeddecimal -> -------------- -> 1.23 -> (1 row) +``` +test=# select '1.239'::fixeddecimal; + fixeddecimal +-------------- + 1.23 +(1 row) +``` It is especially important to remember that this truncation also occurs during arithmetic. Notice in the following example the result is 1120 rather than 1129: -> test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; -> ?column? -> ---------- -> 1120.00 -> (1 row) +``` +test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; + ?column? +---------- + 1120.00 +(1 row) +``` From 12d87ddcb4be3f93ccda0414a5ad3962613d070e Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 17 Sep 2015 16:22:40 +1200 Subject: [PATCH 17/32] Fix various spelling mistakes in README.md --- contrib/fixeddecimal/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md index 05fb679d604..2e780e4b54f 100755 --- a/contrib/fixeddecimal/README.md +++ b/contrib/fixeddecimal/README.md @@ -11,12 +11,12 @@ are a critical. Often there are data storage requirements where the built in REAL and DOUBLE PRECISION types cannot be used due to the non-exact representation of -numbers, e.g where monetary values need to be stored. In many of these cases -NUMERIC is an almost perfect type, although with NUMERIC performance is no -match for the performance of REAL or DOUBLE PRCISION, as these use CPU native -processor types. FixedDecimal aims to offer performance advantages over NUMERIC -without the inprecise prepresentations that are apparent in REAL and DOUBLE -PRECISION, but it comes with some caveats... +numbers using these types, e.g. where monetary values need to be stored. In many +of these cases NUMERIC is an almost perfect type, although with NUMERIC +performance is no match for the performance of REAL or DOUBLE PRCISION, as +these use CPU native processor types. FixedDecimal aims to offer performance +advantages over NUMERIC without the imprecise representations that are +apparent in REAL and DOUBLE PRECISION, but it comes with some caveats... Behavioural differences between FIXEDDECIMAL and NUMERIC -------------------------------------------------------- @@ -34,7 +34,7 @@ from NUMERIC. 3. FIXEDDECIMAL does not support NaN. 4. Any attempt to use a numerical scale other than the default fixed scale - will result in an error. e.g SELECT '123.223'::FIXEDDECIMAL(4,1) will fail + will result in an error. e.g. SELECT '123.223'::FIXEDDECIMAL(4,1) will fail by default, as the default scale is 2, not 1. Internals @@ -46,16 +46,16 @@ calculations are performed as native processor operations rather than software implementations as in the case with NUMERIC. FIXEDDECIMAL has a fixed scale value, which by default is 2. Internally numbers -are stores as the actual value multiplied by 100. e.g 50 would be stored as +are stores as the actual value multiplied by 100. e.g. 50 would be stored as 5000, and 1.23 would be stored as 123. This internal representation allows very fast addition and subtraction between two fixeddecimal types. Multiplication -between two fixeddecimal types is slighty more complex. If we wanted to +between two fixeddecimal types is slightly more complex. If we wanted to perform 2.00 * 3.00 in fixeddecimal, internally these numbers would be 200 and 300 respectively, so internally 200 * 300 becomes 60000, which must be divided by 100 in order to obtain the correct internal result of 600, which of course externally is 6.00. This method of multiplication is hazard to overflowing the internal 64bit integer type, for this reason all multiplication and division is -performed using 128bit interger types. +performed using 128bit integer types. Internally, by default, FIXEDDECIMAL is limited to a maximum value of 92233720368547758.07 and a minimum value of -92233720368547758.08. If any of @@ -73,8 +73,8 @@ Caution ------- FIXEDDECIMAL is mainly intended as a fast and efficient data type which will -suit a limited set numerical data storage and retreaval needs. Complex -artimetic could be said to be one of fixeddecimal's limits. As stated above +suit a limited set numerical data storage and retrieval needs. Complex +arithmetic could be said to be one of fixeddecimal's limits. As stated above division always rounds towards zero. Please observe the following example: ``` From f4cb852cf7e0e5576bb874e6b913457e181c17ef Mon Sep 17 00:00:00 2001 From: David Rowley Date: Sat, 19 Sep 2015 23:35:23 +1200 Subject: [PATCH 18/32] Allow fixed decimal to work in earlier postgres versions The problem was that the .sql file for the extension created a BRIN op class. The solution to this was to move the CREATE OPERATOR CLASS for BRIN to another file and have the makefile dynamically build the .sql file for the extension based on which version of Postgres we're building for. For versions < 9.5 we don't include BRIN. This also required similar logic for the BRIN tests. To fix this I've moved the BRIN test to a separate file, which is now only tested in version >= 9.5 --- contrib/fixeddecimal/Makefile | 11 ++++++-- ...1.0.0.sql => fixeddecimal--1.0.0_base.sql} | 16 ++---------- contrib/fixeddecimal/fixeddecimal--brin.sql | 12 +++++++++ contrib/fixeddecimal/fixeddecimal.c | 6 ++--- contrib/fixeddecimal/test/expected/brin.out | 22 ++++++++++++++++ contrib/fixeddecimal/test/expected/index.out | 25 +++---------------- contrib/fixeddecimal/test/results/brin.out | 22 ++++++++++++++++ contrib/fixeddecimal/test/results/index.out | 25 +++---------------- contrib/fixeddecimal/test/sql/brin.sql | 14 +++++++++++ contrib/fixeddecimal/test/sql/index.sql | 17 +++---------- 10 files changed, 92 insertions(+), 78 deletions(-) rename contrib/fixeddecimal/{fixeddecimal--1.0.0.sql => fixeddecimal--1.0.0_base.sql} (95%) create mode 100644 contrib/fixeddecimal/fixeddecimal--brin.sql create mode 100644 contrib/fixeddecimal/test/expected/brin.out create mode 100644 contrib/fixeddecimal/test/results/brin.out create mode 100644 contrib/fixeddecimal/test/sql/brin.sql diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index 815165fc065..b83feafb5db 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -1,14 +1,21 @@ + + MODULE_big = fixeddecimal OBJS = fixeddecimal.o EXTENSION = fixeddecimal -DATA = fixeddecimal--1.0.0.sql +DATA = $(shell $(PG_CONFIG) --version | grep -qE " 9\.[5-9]| 10\.0" && \ + cat fixeddecimal--1.0.0_base.sql fixeddecimal--brin.sql > fixeddecimal--1.0.0.sql | echo fixeddecimal--1.0.0.sql || \ + cat fixeddecimal--1.0.0_base.sql > fixeddecimal--1.0.0.sql | echo fixeddecimal--1.0.0.sql) MODULES = fixeddecimal CFLAGS=`pg_config --includedir-server` TESTS = $(wildcard test/sql/*.sql) -REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS)) +REGRESS = $(shell $(PG_CONFIG) --version | grep -qE " 9\.[5-9]| 10\.0" && \ + echo aggregate brin cast comparison index overflow || \ + echo aggregate cast comparison index overflow) + REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=fixeddecimal PG_CONFIG = pg_config diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql similarity index 95% rename from contrib/fixeddecimal/fixeddecimal--1.0.0.sql rename to contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql index 9605153b981..a4551dafca0 100755 --- a/contrib/fixeddecimal/fixeddecimal--1.0.0.sql +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql @@ -242,19 +242,6 @@ DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); - -CREATE OPERATOR CLASS fixeddecimal_minmax_ops -DEFAULT FOR TYPE FIXEDDECIMAL USING brin AS - OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), - OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), - OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), - OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), - OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), - FUNCTION 1 brin_minmax_opcinfo(INTERNAL), - FUNCTION 2 brin_minmax_add_value(INTERNAL, INTERNAL, INTERNAL, INTERNAL), - FUNCTION 3 brin_minmax_consistent(INTERNAL, INTERNAL, INTERNAL), - FUNCTION 4 brin_minmax_union(INTERNAL, INTERNAL, INTERNAL); - -- -- Cross type operators with int4 -- @@ -580,4 +567,5 @@ CREATE AGGREGATE avg(FIXEDDECIMAL) ( SFUNC = fixeddecimal_avg_accum, FINALFUNC = fixeddecimal_avg, STYPE = INTERNAL -); \ No newline at end of file +); + diff --git a/contrib/fixeddecimal/fixeddecimal--brin.sql b/contrib/fixeddecimal/fixeddecimal--brin.sql new file mode 100644 index 00000000000..ce98da4be7d --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--brin.sql @@ -0,0 +1,12 @@ +CREATE OPERATOR CLASS fixeddecimal_minmax_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING brin AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 brin_minmax_opcinfo(INTERNAL), + FUNCTION 2 brin_minmax_add_value(INTERNAL, INTERNAL, INTERNAL, INTERNAL), + FUNCTION 3 brin_minmax_consistent(INTERNAL, INTERNAL, INTERNAL), + FUNCTION 4 brin_minmax_union(INTERNAL, INTERNAL, INTERNAL); + diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index c30344ca8ba..2dcd9720e85 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -57,10 +57,8 @@ #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) #endif /* HAVE_BUILTIN_OVERFLOW */ -/* 128bit int is required for multiply and divide */ -#ifndef HAVE_INT128 -#error "A working 128bit int type is required for fixed decimal" -#endif /* HAVE_INT128 */ +/* Compiler must have a working 128 int type */ +typedef __int128 int128; #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; diff --git a/contrib/fixeddecimal/test/expected/brin.out b/contrib/fixeddecimal/test/expected/brin.out new file mode 100644 index 00000000000..e3ecea1c12b --- /dev/null +++ b/contrib/fixeddecimal/test/expected/brin.out @@ -0,0 +1,22 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + QUERY PLAN +--------------------------------------------------- + Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) +(4 rows) + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + d | txt +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +RESET enable_seqscan; diff --git a/contrib/fixeddecimal/test/expected/index.out b/contrib/fixeddecimal/test/expected/index.out index b64e2724571..f02aaf91065 100644 --- a/contrib/fixeddecimal/test/expected/index.out +++ b/contrib/fixeddecimal/test/expected/index.out @@ -1,4 +1,4 @@ -CREATE TABLE fixdec (id INT PRIMARY KEY, d FIXEDDECIMAL(5,2)); +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); INSERT INTO fixdec (id,d) VALUES(1,-123.45); INSERT INTO fixdec (id,d) VALUES(2,-123); INSERT INTO fixdec (id,d) VALUES(3,-12.34); @@ -60,8 +60,9 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; (1 row) DROP INDEX fixdec_d_idx; +SET client_min_messages = ERROR; CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); -WARNING: hash indexes are not WAL-logged and their use is discouraged +RESET client_min_messages; EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; QUERY PLAN ------------------------------------------- @@ -87,25 +88,5 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; 8 | 123.45 (1 row) -DROP TABLE fixdec; --- Test BRIN indexes -CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); -INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); -CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); -EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - QUERY PLAN ---------------------------------------------------- - Bitmap Heap Scan on fixdec - Recheck Cond: (d > '9999.00'::fixeddecimal) - -> Bitmap Index Scan on fixdec_d_idx - Index Cond: (d > '9999.00'::fixeddecimal) -(4 rows) - -SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - d | txt -----------+------------------------------------------------------------------ - 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 -(1 row) - DROP TABLE fixdec; SET enable_seqscan = on; diff --git a/contrib/fixeddecimal/test/results/brin.out b/contrib/fixeddecimal/test/results/brin.out new file mode 100644 index 00000000000..e3ecea1c12b --- /dev/null +++ b/contrib/fixeddecimal/test/results/brin.out @@ -0,0 +1,22 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + QUERY PLAN +--------------------------------------------------- + Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) +(4 rows) + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + d | txt +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +RESET enable_seqscan; diff --git a/contrib/fixeddecimal/test/results/index.out b/contrib/fixeddecimal/test/results/index.out index b64e2724571..f02aaf91065 100644 --- a/contrib/fixeddecimal/test/results/index.out +++ b/contrib/fixeddecimal/test/results/index.out @@ -1,4 +1,4 @@ -CREATE TABLE fixdec (id INT PRIMARY KEY, d FIXEDDECIMAL(5,2)); +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); INSERT INTO fixdec (id,d) VALUES(1,-123.45); INSERT INTO fixdec (id,d) VALUES(2,-123); INSERT INTO fixdec (id,d) VALUES(3,-12.34); @@ -60,8 +60,9 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; (1 row) DROP INDEX fixdec_d_idx; +SET client_min_messages = ERROR; CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); -WARNING: hash indexes are not WAL-logged and their use is discouraged +RESET client_min_messages; EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; QUERY PLAN ------------------------------------------- @@ -87,25 +88,5 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; 8 | 123.45 (1 row) -DROP TABLE fixdec; --- Test BRIN indexes -CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); -INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); -CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); -EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - QUERY PLAN ---------------------------------------------------- - Bitmap Heap Scan on fixdec - Recheck Cond: (d > '9999.00'::fixeddecimal) - -> Bitmap Index Scan on fixdec_d_idx - Index Cond: (d > '9999.00'::fixeddecimal) -(4 rows) - -SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - d | txt -----------+------------------------------------------------------------------ - 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 -(1 row) - DROP TABLE fixdec; SET enable_seqscan = on; diff --git a/contrib/fixeddecimal/test/sql/brin.sql b/contrib/fixeddecimal/test/sql/brin.sql new file mode 100644 index 00000000000..802328517d5 --- /dev/null +++ b/contrib/fixeddecimal/test/sql/brin.sql @@ -0,0 +1,14 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); + +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +RESET enable_seqscan; diff --git a/contrib/fixeddecimal/test/sql/index.sql b/contrib/fixeddecimal/test/sql/index.sql index 25c04ee68fb..3782593fb8c 100644 --- a/contrib/fixeddecimal/test/sql/index.sql +++ b/contrib/fixeddecimal/test/sql/index.sql @@ -1,4 +1,4 @@ -CREATE TABLE fixdec (id INT PRIMARY KEY, d FIXEDDECIMAL(5,2)); +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); INSERT INTO fixdec (id,d) VALUES(1,-123.45); INSERT INTO fixdec (id,d) VALUES(2,-123); @@ -33,7 +33,9 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; DROP INDEX fixdec_d_idx; +SET client_min_messages = ERROR; CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +RESET client_min_messages; EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; @@ -45,17 +47,4 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; DROP TABLE fixdec; --- Test BRIN indexes - -CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); -INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); - -CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); - -EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - -SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - -DROP TABLE fixdec; - SET enable_seqscan = on; From 3ef9f06d22706abf3b1621e018fb50a7703e9bfe Mon Sep 17 00:00:00 2001 From: David Rowley Date: Sun, 20 Sep 2015 17:44:40 +1200 Subject: [PATCH 19/32] Add installation nodes to README.md --- contrib/fixeddecimal/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md index 2e780e4b54f..ded198b81f4 100755 --- a/contrib/fixeddecimal/README.md +++ b/contrib/fixeddecimal/README.md @@ -120,3 +120,26 @@ test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; 1120.00 (1 row) ``` + +Installation +------------ + +To install fixeddecimal you must build the extension from source code. + +First ensure that your PATH environment variable is setup to find the correct +PostgreSQL installation first. You can check this by typing running the +pg_config command and checking the paths listed. + +Once you are confident your PATH variable is set correctly + +``` +make +make install +make installcheck +``` + +From psql, in order to create the extension you must type: + +``` +CREATE EXTENSION fixeddecimal; +``` From 565c8620fdd7a42102da6ac6a32665e614e8de0f Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 2 Oct 2015 02:27:39 +1300 Subject: [PATCH 20/32] Add support for Postgres-XL This adds support for XL's concept of aggregate collect functions which allows the aggregate to be partially calculated on each node, and the agg state to be passed to another node to allow the final aggregation to take place. Also added sanity checks for bogus values of FIXEDDECIMAL_SCALE Also removed accidental commit of regression test actual result files. --- contrib/fixeddecimal/Makefile | 10 +- .../fixeddecimal/fixeddecimal--1.0.0_base.sql | 43 --- contrib/fixeddecimal/fixeddecimal--aggs.sql | 44 +++ contrib/fixeddecimal/fixeddecimal--xlaggs.sql | 57 ++++ contrib/fixeddecimal/fixeddecimal.c | 168 ++++++++-- contrib/fixeddecimal/fixeddecimalaggstate.sql | 40 +++ .../fixeddecimal/test/results/aggregate.out | 33 -- contrib/fixeddecimal/test/results/brin.out | 22 -- contrib/fixeddecimal/test/results/cast.out | 48 --- .../fixeddecimal/test/results/comparison.out | 310 ------------------ contrib/fixeddecimal/test/results/index.out | 92 ------ .../fixeddecimal/test/results/overflow.out | 123 ------- 12 files changed, 294 insertions(+), 696 deletions(-) create mode 100644 contrib/fixeddecimal/fixeddecimal--aggs.sql create mode 100644 contrib/fixeddecimal/fixeddecimal--xlaggs.sql create mode 100644 contrib/fixeddecimal/fixeddecimalaggstate.sql delete mode 100644 contrib/fixeddecimal/test/results/aggregate.out delete mode 100644 contrib/fixeddecimal/test/results/brin.out delete mode 100644 contrib/fixeddecimal/test/results/cast.out delete mode 100644 contrib/fixeddecimal/test/results/comparison.out delete mode 100644 contrib/fixeddecimal/test/results/index.out delete mode 100755 contrib/fixeddecimal/test/results/overflow.out diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index b83feafb5db..127d57df557 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -5,11 +5,15 @@ OBJS = fixeddecimal.o EXTENSION = fixeddecimal DATA = $(shell $(PG_CONFIG) --version | grep -qE " 9\.[5-9]| 10\.0" && \ - cat fixeddecimal--1.0.0_base.sql fixeddecimal--brin.sql > fixeddecimal--1.0.0.sql | echo fixeddecimal--1.0.0.sql || \ - cat fixeddecimal--1.0.0_base.sql > fixeddecimal--1.0.0.sql | echo fixeddecimal--1.0.0.sql) + cat fixeddecimal--1.0.0_base.sql fixeddecimal--brin.sql > fixeddecimal--1.0.0.tmp | echo fixeddecimal--1.0.0.tmp || \ + cat fixeddecimal--1.0.0_base.sql > fixeddecimal--1.0.0.tmp | echo fixeddecimal--1.0.0.tmp) \ + $(shell $(PG_CONFIG) --version | grep -qE "XL" && \ + cat fixeddecimalaggstate.sql fixeddecimal--1.0.0.tmp fixeddecimal--xlaggs.sql > fixeddecimal--1.0.0.sql | echo fixeddecimal--1.0.0.sql || \ + cat fixeddecimal--1.0.0.tmp > fixeddecimal--1.0.0.sql fixeddecimal--aggs.sql | echo fixeddecimal--1.0.0.sql) + MODULES = fixeddecimal -CFLAGS=`pg_config --includedir-server` +CFLAGS=`pg_config --includedir-server -UXCP` TESTS = $(wildcard test/sql/*.sql) REGRESS = $(shell $(PG_CONFIG) --version | grep -qE " 9\.[5-9]| 10\.0" && \ diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql index a4551dafca0..d23e59ae970 100755 --- a/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql @@ -526,46 +526,3 @@ CREATE CAST (FIXEDDECIMAL AS NUMERIC) CREATE CAST (NUMERIC AS FIXEDDECIMAL) WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS ASSIGNMENT; - --- Aggregate Support - - -CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) -RETURNS INTERNAL -AS 'fixeddecimal', 'fixeddecimal_avg_accum' -LANGUAGE C IMMUTABLE; - -CREATE FUNCTION fixeddecimal_sum(INTERNAL) -RETURNS FIXEDDECIMAL -AS 'fixeddecimal', 'fixeddecimal_sum' -LANGUAGE C IMMUTABLE STRICT; - -CREATE FUNCTION fixeddecimal_avg(INTERNAL) -RETURNS FIXEDDECIMAL -AS 'fixeddecimal', 'fixeddecimal_avg' -LANGUAGE C IMMUTABLE STRICT; - -CREATE AGGREGATE min(FIXEDDECIMAL) ( - SFUNC = fixeddecimalsmaller, - STYPE = FIXEDDECIMAL, - SORTOP = < -); - -CREATE AGGREGATE max(FIXEDDECIMAL) ( - SFUNC = fixeddecimallarger, - STYPE = FIXEDDECIMAL, - SORTOP = > -); - -CREATE AGGREGATE sum(FIXEDDECIMAL) ( - SFUNC = fixeddecimal_avg_accum, - FINALFUNC = fixeddecimal_sum, - STYPE = INTERNAL -); - -CREATE AGGREGATE avg(FIXEDDECIMAL) ( - SFUNC = fixeddecimal_avg_accum, - FINALFUNC = fixeddecimal_avg, - STYPE = INTERNAL -); - diff --git a/contrib/fixeddecimal/fixeddecimal--aggs.sql b/contrib/fixeddecimal/fixeddecimal--aggs.sql new file mode 100644 index 00000000000..2af7194184d --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--aggs.sql @@ -0,0 +1,44 @@ + +-- Aggregate Support + + +CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_sum(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_avg(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE STRICT; + +CREATE AGGREGATE min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + STYPE = FIXEDDECIMAL, + SORTOP = < +); + +CREATE AGGREGATE max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + STYPE = FIXEDDECIMAL, + SORTOP = > +); + +CREATE AGGREGATE sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL +); + + diff --git a/contrib/fixeddecimal/fixeddecimal--xlaggs.sql b/contrib/fixeddecimal/fixeddecimal--xlaggs.sql new file mode 100644 index 00000000000..3e68cd995ec --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--xlaggs.sql @@ -0,0 +1,57 @@ + +-- Aggregate Support + + +CREATE FUNCTION fixeddecimalaggstatecombine(FIXEDDECIMALAGGSTATE, INTERNAL) +RETURNS FIXEDDECIMALAGGSTATE +AS 'fixeddecimal', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_sum(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_avg(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE STRICT; + +CREATE AGGREGATE min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + CFUNC = fixeddecimalsmaller, + CTYPE = FIXEDDECIMAL, + STYPE = FIXEDDECIMAL, + SORTOP = < +); + +CREATE AGGREGATE max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + CFUNC = fixeddecimallarger, + CTYPE = FIXEDDECIMAL, + STYPE = FIXEDDECIMAL, + SORTOP = > +); + +CREATE AGGREGATE sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + CFUNC = fixeddecimalaggstatecombine, + CTYPE = FIXEDDECIMALAGGSTATE, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + CFUNC = fixeddecimalaggstatecombine, + CTYPE = FIXEDDECIMALAGGSTATE, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL +); + + diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index 2dcd9720e85..42d3754a24a 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -24,6 +24,11 @@ #include "access/hash.h" #include "utils/array.h" #include "utils/builtins.h" + +#ifdef PGXC +#include "utils/int8.h" +#endif /* PGXC */ + #include "utils/numeric.h" #define MAXINT8LEN 25 @@ -42,6 +47,15 @@ */ #define FIXEDDECIMAL_SCALE 2 +/* Sanity checks */ +#if FIXEDDECIMAL_SCALE == 0 +#error "FIXEDDECIMAL_SCALE cannot be zero. Just use a BIGINT if that's what you really want" +#endif + +#if FIXEDDECIMAL_SCALE > 19 +#error "FIXEDDECIMAL_SCALE cannot be greater than 19" +#endif + /* * This is bounded by the maximum and minimum values of int64. * 9223372036854775807 is 19 decimal digits long, but we we can only represent @@ -118,6 +132,14 @@ PG_FUNCTION_INFO_V1(fixeddecimal_avg_accum); PG_FUNCTION_INFO_V1(fixeddecimal_avg); PG_FUNCTION_INFO_V1(fixeddecimal_sum); +#ifdef PGXC +PG_FUNCTION_INFO_V1(fixeddecimalaggstatein); +PG_FUNCTION_INFO_V1(fixeddecimalaggstateout); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatesend); +PG_FUNCTION_INFO_V1(fixeddecimalaggstaterecv); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatecombine); +#endif /* PGXC */ + /* Aggregate Internal State */ typedef struct FixedDecimalAggState { @@ -286,6 +308,36 @@ pg_int64tostr_zeropad(char *str, int64 value, int64 padding) return end; } +/* + * fixeddecimal2str + * Prints the fixeddecimal 'val' to buffer as a string. + * Returns a pointer to the end of the written string. + */ +static char * +fixeddecimal2str(int64 val, char *buffer) +{ + char *ptr = buffer; + int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER; + int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER; + + if (val < 0) + { + fractionalpart = -fractionalpart; + + /* + * Handle special case for negative numbers where the intergral part + * is zero. pg_int64tostr() won't prefix with "-0" in this case, so + * we'll do it manually + */ + if (integralpart == 0) + *ptr++ = '-'; + } + ptr = pg_int64tostr(ptr, integralpart); + *ptr++ = '.'; + ptr = pg_int64tostr_zeropad(ptr, fractionalpart, FIXEDDECIMAL_SCALE); + return ptr; +} + /* * scanfixeddecimal --- try to parse a string into a fixeddecimal. */ @@ -583,28 +635,8 @@ fixeddecimalout(PG_FUNCTION_ARGS) { int64 val = PG_GETARG_INT64(0); char buf[MAXINT8LEN + 1]; - char *ptr = &buf[0]; - int64 integralpart = val / FIXEDDECIMAL_MULTIPLIER; - int64 fractionalpart = val % FIXEDDECIMAL_MULTIPLIER; - - - if (val < 0) - { - fractionalpart = -fractionalpart; - - /* - * Handle special case for negative numbers where the intergral part - * is zero. pg_int64tostr() won't prefix with "-0" in this case, so - * we'll do it manually - */ - if (integralpart == 0) - *ptr++ = '-'; - } - ptr = pg_int64tostr(ptr, integralpart); - *ptr++ = '.'; - ptr = pg_int64tostr_zeropad(ptr, fractionalpart, FIXEDDECIMAL_SCALE); - - PG_RETURN_CSTRING(pnstrdup(buf, ptr - &buf[0])); + char *end = fixeddecimal2str(val, buf); + PG_RETURN_CSTRING(pnstrdup(buf, end - buf)); } /* @@ -1684,6 +1716,7 @@ fixeddecimal_avg(PG_FUNCTION_ARGS) PG_RETURN_INT64(state->sumX / state->N); } + Datum fixeddecimal_sum(PG_FUNCTION_ARGS) { @@ -1697,3 +1730,94 @@ fixeddecimal_sum(PG_FUNCTION_ARGS) PG_RETURN_INT64(state->sumX); } + + +#ifdef PGXC + +/* + * Input / Output / Send / Receive functions for aggrgate states + * Currently for XL only + */ + +Datum +fixeddecimalaggstatein(PG_FUNCTION_ARGS) +{ + char *str = pstrdup(PG_GETARG_CSTRING(0)); + FixedDecimalAggState *state; + char *token; + + state = (FixedDecimalAggState *) palloc0(sizeof(FixedDecimalAggState)); + + token = strtok(str, ":"); + state->sumX = DatumGetInt64(DirectFunctionCall3(fixeddecimalin, CStringGetDatum(token), 0, -1)); + token = strtok(NULL, ":"); + state->N = DatumGetInt64(DirectFunctionCall1(int8in, CStringGetDatum(token))); + pfree(str); + + PG_RETURN_POINTER(state); +} + + +/* + * fixeddecimalaggstateout() + */ +Datum +fixeddecimalaggstateout(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); + char buf[MAXINT8LEN + 1 + MAXINT8LEN + 1]; + char *p; + + p = fixeddecimal2str(state->sumX, buf); + *p++ = ':'; + p = pg_int64tostr(p, state->N); + PG_RETURN_CSTRING(pnstrdup(buf, p - buf)); +} + +/* + * fixeddecimalaggstaterecv + */ +Datum +fixeddecimalaggstaterecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + FixedDecimalAggState *state; + state = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); + + state->sumX = pq_getmsgint(buf, sizeof(int64)); + state->N = pq_getmsgint(buf, sizeof(int64)); + + PG_RETURN_POINTER(state); +} + +/* + * fixeddecimalaggstatesend + */ +Datum +fixeddecimalaggstatesend(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); + StringInfoData buf; + + pq_begintypsend(&buf); + + pq_sendint(&buf, state->sumX, sizeof (int64)); + pq_sendint(&buf, state->N, sizeof (int64)); + + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + +Datum +fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state1 = (FixedDecimalAggState *) PG_GETARG_POINTER(0); + FixedDecimalAggState *state2 = (FixedDecimalAggState *) PG_GETARG_POINTER(1); + FixedDecimalAggState *newstate = palloc(sizeof(FixedDecimalAggState)); + + newstate->sumX = DatumGetInt64(DirectFunctionCall2(fixeddecimalpl, Int64GetDatum(state1->sumX), Int64GetDatum(state2->sumX))); + newstate->N = DatumGetInt64(DirectFunctionCall2(int8pl, Int64GetDatum(state1->N), Int64GetDatum(state2->N))); + + PG_RETURN_POINTER(newstate); +} + +#endif /* PGXC */ \ No newline at end of file diff --git a/contrib/fixeddecimal/fixeddecimalaggstate.sql b/contrib/fixeddecimal/fixeddecimalaggstate.sql new file mode 100644 index 00000000000..e40c81923ec --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimalaggstate.sql @@ -0,0 +1,40 @@ +-------------------------- +-- FIXEDDECIMALAGGSTATE -- +------------------------- + +CREATE TYPE FIXEDDECIMALAGGSTATE; + +CREATE FUNCTION fixeddecimalaggstatein(cstring, oid, int4) +RETURNS FIXEDDECIMALAGGSTATE +AS 'fixeddecimal', 'fixeddecimalaggstatein' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalaggstateout(fixeddecimalaggstate) +RETURNS cstring +AS 'fixeddecimal', 'fixeddecimalaggstateout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalaggstaterecv(internal) +RETURNS FIXEDDECIMALAGGSTATE +AS 'fixeddecimal', 'fixeddecimalaggstaterecv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalaggstatesend(FIXEDDECIMALAGGSTATE) +RETURNS bytea +AS 'fixeddecimal', 'fixeddecimalaggstatesend' +LANGUAGE C IMMUTABLE STRICT; + + +CREATE TYPE FIXEDDECIMALAGGSTATE ( + INPUT = fixeddecimalaggstatein, + OUTPUT = fixeddecimalaggstateout, + RECEIVE = fixeddecimalaggstaterecv, + SEND = fixeddecimalaggstatesend, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = false, + COLLATABLE = false +); + diff --git a/contrib/fixeddecimal/test/results/aggregate.out b/contrib/fixeddecimal/test/results/aggregate.out deleted file mode 100644 index 934c51b9b13..00000000000 --- a/contrib/fixeddecimal/test/results/aggregate.out +++ /dev/null @@ -1,33 +0,0 @@ -CREATE TABLE fixed_decimal(a FIXEDDECIMAL NOT NULL); -INSERT INTO fixed_decimal VALUES('92233720368547758.07'),('0.01'),('-92233720368547758.08'),('-0.01'); -SELECT SUM(a) FROM fixed_decimal WHERE a > 0; -ERROR: fixeddecimal out of range -SELECT SUM(a) FROM fixed_decimal WHERE a < 0; -ERROR: fixeddecimal out of range -TRUNCATE TABLE fixed_decimal; -INSERT INTO fixed_decimal VALUES('11.11'),('22.22'),('33.33'); -SELECT SUM(a) FROM fixed_decimal; - sum -------- - 66.66 -(1 row) - -SELECT MAX(a) FROM fixed_decimal; - max -------- - 33.33 -(1 row) - -SELECT MIN(a) FROM fixed_decimal; - min -------- - 11.11 -(1 row) - -SELECT AVG(a) FROM fixed_decimal; - avg -------- - 22.22 -(1 row) - -DROP TABLE fixed_decimal; diff --git a/contrib/fixeddecimal/test/results/brin.out b/contrib/fixeddecimal/test/results/brin.out deleted file mode 100644 index e3ecea1c12b..00000000000 --- a/contrib/fixeddecimal/test/results/brin.out +++ /dev/null @@ -1,22 +0,0 @@ --- Test BRIN indexes -SET enable_seqscan = off; -CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); -INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); -CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); -EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - QUERY PLAN ---------------------------------------------------- - Bitmap Heap Scan on fixdec - Recheck Cond: (d > '9999.00'::fixeddecimal) - -> Bitmap Index Scan on fixdec_d_idx - Index Cond: (d > '9999.00'::fixeddecimal) -(4 rows) - -SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - d | txt -----------+------------------------------------------------------------------ - 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 -(1 row) - -DROP TABLE fixdec; -RESET enable_seqscan; diff --git a/contrib/fixeddecimal/test/results/cast.out b/contrib/fixeddecimal/test/results/cast.out deleted file mode 100644 index b230ed59787..00000000000 --- a/contrib/fixeddecimal/test/results/cast.out +++ /dev/null @@ -1,48 +0,0 @@ -SELECT CAST('2147483647'::FIXEDDECIMAL AS INT); - int4 ------------- - 2147483647 -(1 row) - --- Ensure overflow is detected -SELECT CAST('2147483648'::FIXEDDECIMAL AS INT); -ERROR: integer out of range -SELECT CAST('-2147483648'::FIXEDDECIMAL AS INT); - int4 -------------- - -2147483648 -(1 row) - --- Ensure underflow is detected -SELECT CAST('-2147483649'::FIXEDDECIMAL AS INT); -ERROR: integer out of range -SELECT CAST('32767'::FIXEDDECIMAL AS SMALLINT); - int2 -------- - 32767 -(1 row) - --- Ensure overflow is detected -SELECT CAST('32768'::FIXEDDECIMAL AS SMALLINT); -ERROR: smallint out of range -SELECT CAST('-32768'::FIXEDDECIMAL AS SMALLINT); - int2 --------- - -32768 -(1 row) - --- Ensure underflow is detected -SELECT CAST('-32769'::FIXEDDECIMAL AS SMALLINT); -ERROR: smallint out of range -SELECT CAST('1234321.23'::FIXEDDECIMAL AS FLOAT); - float8 ------------- - 1234321.23 -(1 row) - -SELECT CAST('1234321.23'::FIXEDDECIMAL AS DOUBLE PRECISION); - float8 ------------- - 1234321.23 -(1 row) - diff --git a/contrib/fixeddecimal/test/results/comparison.out b/contrib/fixeddecimal/test/results/comparison.out deleted file mode 100644 index 9ba9abe9ae5..00000000000 --- a/contrib/fixeddecimal/test/results/comparison.out +++ /dev/null @@ -1,310 +0,0 @@ --- True comparisons -SELECT '123'::FIXEDDECIMAL < '123.01'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::FIXEDDECIMAL <= '123.01'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::FIXEDDECIMAL > '122.99'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::FIXEDDECIMAL >= '122.99'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123.00'::FIXEDDECIMAL = '123'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - --- Compare to int4 -SELECT '123'::INT < '123.01'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::INT <= '123.01'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::INT > '122.99'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::INT >= '122.99'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::INT = '123.00'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - --- Compare to int4 reversed -SELECT '123.01'::FIXEDDECIMAL > '123'::INT; - ?column? ----------- - t -(1 row) - -SELECT '123.01'::FIXEDDECIMAL >= '123'::INT; - ?column? ----------- - t -(1 row) - -SELECT '122.99'::FIXEDDECIMAL < '123'::INT; - ?column? ----------- - t -(1 row) - -SELECT '122.99'::FIXEDDECIMAL <= '123'::INT; - ?column? ----------- - t -(1 row) - -SELECT '123.00'::FIXEDDECIMAL = '123'::INT; - ?column? ----------- - t -(1 row) - --- Compare to int2 -SELECT '123'::SMALLINT < '123.01'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::SMALLINT <= '123.01'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::SMALLINT > '122.99'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::SMALLINT >= '122.99'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - -SELECT '123'::SMALLINT = '123.00'::FIXEDDECIMAL; - ?column? ----------- - t -(1 row) - --- Compare to int4 reversed -SELECT '123.01'::FIXEDDECIMAL > '123'::SMALLINT; - ?column? ----------- - t -(1 row) - -SELECT '123.01'::FIXEDDECIMAL >= '123'::SMALLINT; - ?column? ----------- - t -(1 row) - -SELECT '122.99'::FIXEDDECIMAL < '123'::SMALLINT; - ?column? ----------- - t -(1 row) - -SELECT '122.99'::FIXEDDECIMAL <= '123'::SMALLINT; - ?column? ----------- - t -(1 row) - -SELECT '123.00'::FIXEDDECIMAL = '123'::SMALLINT; - ?column? ----------- - t -(1 row) - --- False comparisons -SELECT '123'::FIXEDDECIMAL >= '123.01'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::FIXEDDECIMAL > '123.01'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::FIXEDDECIMAL <= '122.99'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::FIXEDDECIMAL < '122.99'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123.00'::FIXEDDECIMAL <> '123'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - --- Compare to int4 -SELECT '123'::INT >= '123.01'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::INT > '123.01'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::INT <= '122.99'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::INT < '122.99'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::INT <> '123.00'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - --- Compare to int4 reversed -SELECT '123.01'::FIXEDDECIMAL <= '123'::INT; - ?column? ----------- - f -(1 row) - -SELECT '123.01'::FIXEDDECIMAL < '123'::INT; - ?column? ----------- - f -(1 row) - -SELECT '122.99'::FIXEDDECIMAL >= '123'::INT; - ?column? ----------- - f -(1 row) - -SELECT '122.99'::FIXEDDECIMAL > '123'::INT; - ?column? ----------- - f -(1 row) - -SELECT '123.00'::FIXEDDECIMAL <> '123'::INT; - ?column? ----------- - f -(1 row) - --- Compare to int2 -SELECT '123'::SMALLINT >= '123.01'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::SMALLINT > '123.01'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::SMALLINT <= '122.99'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::SMALLINT < '122.99'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - -SELECT '123'::SMALLINT <> '123.00'::FIXEDDECIMAL; - ?column? ----------- - f -(1 row) - --- Compare to int4 reversed -SELECT '123.01'::FIXEDDECIMAL <= '123'::SMALLINT; - ?column? ----------- - f -(1 row) - -SELECT '123.01'::FIXEDDECIMAL < '123'::SMALLINT; - ?column? ----------- - f -(1 row) - -SELECT '122.99'::FIXEDDECIMAL >= '123'::SMALLINT; - ?column? ----------- - f -(1 row) - -SELECT '122.99'::FIXEDDECIMAL > '123'::SMALLINT; - ?column? ----------- - f -(1 row) - -SELECT '123.00'::FIXEDDECIMAL <> '123'::SMALLINT; - ?column? ----------- - f -(1 row) - diff --git a/contrib/fixeddecimal/test/results/index.out b/contrib/fixeddecimal/test/results/index.out deleted file mode 100644 index f02aaf91065..00000000000 --- a/contrib/fixeddecimal/test/results/index.out +++ /dev/null @@ -1,92 +0,0 @@ -CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); -INSERT INTO fixdec (id,d) VALUES(1,-123.45); -INSERT INTO fixdec (id,d) VALUES(2,-123); -INSERT INTO fixdec (id,d) VALUES(3,-12.34); -INSERT INTO fixdec (id,d) VALUES(4,-1.34); -INSERT INTO fixdec (id,d) VALUES(5, 0.12); -INSERT INTO fixdec (id,d) VALUES(6, 1.23); -INSERT INTO fixdec (id,d) VALUES(7, 12.34); -INSERT INTO fixdec (id,d) VALUES(8, 123.45); -INSERT INTO fixdec (id,d) VALUES(9, 123.456); --- Should fail -CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); -ERROR: could not create unique index "fixdec_d_idx" -DETAIL: Key (d)=(123.45) is duplicated. -DELETE FROM fixdec WHERE id = 9; -CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); -SET enable_seqscan = off; -EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; - QUERY PLAN ------------------------------------------ - Index Scan using fixdec_d_idx on fixdec -(1 row) - -SELECT * FROM fixdec ORDER BY d; - id | d -----+--------- - 1 | -123.45 - 2 | -123.00 - 3 | -12.34 - 4 | -1.34 - 5 | 0.12 - 6 | 1.23 - 7 | 12.34 - 8 | 123.45 -(8 rows) - -EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; - QUERY PLAN -------------------------------------------- - Index Scan using fixdec_d_idx on fixdec - Index Cond: (d = '12.34'::fixeddecimal) -(2 rows) - -SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; - id | d -----+------- - 7 | 12.34 -(1 row) - -SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; - id | d -----+-------- - 3 | -12.34 -(1 row) - -SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; - id | d -----+-------- - 8 | 123.45 -(1 row) - -DROP INDEX fixdec_d_idx; -SET client_min_messages = ERROR; -CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); -RESET client_min_messages; -EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; - QUERY PLAN -------------------------------------------- - Index Scan using fixdec_d_idx on fixdec - Index Cond: (d = '12.34'::fixeddecimal) -(2 rows) - -SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; - id | d -----+------- - 7 | 12.34 -(1 row) - -SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; - id | d -----+-------- - 3 | -12.34 -(1 row) - -SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; - id | d -----+-------- - 8 | 123.45 -(1 row) - -DROP TABLE fixdec; -SET enable_seqscan = on; diff --git a/contrib/fixeddecimal/test/results/overflow.out b/contrib/fixeddecimal/test/results/overflow.out deleted file mode 100755 index ee0010080d4..00000000000 --- a/contrib/fixeddecimal/test/results/overflow.out +++ /dev/null @@ -1,123 +0,0 @@ --- Ensure the expected extreme values can be represented -SELECT '-92233720368547758.08'::FIXEDDECIMAL as minvalue,'92233720368547758.07'::FIXEDDECIMAL as maxvalue; - minvalue | maxvalue ------------------------+---------------------- - -92233720368547758.08 | 92233720368547758.07 -(1 row) - -SELECT '-92233720368547758.09'::FIXEDDECIMAL; -ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal -LINE 1: SELECT '-92233720368547758.09'::FIXEDDECIMAL; - ^ -SELECT '92233720368547758.08'::FIXEDDECIMAL; -ERROR: value "92233720368547758.08" is out of range for type fixeddecimal -LINE 1: SELECT '92233720368547758.08'::FIXEDDECIMAL; - ^ --- Ensure casts from numeric to fixeddecimal work -SELECT '92233720368547758.07'::numeric::FIXEDDECIMAL; - fixeddecimal ----------------------- - 92233720368547758.07 -(1 row) - --- The literal below must be quoted as the parser seems to read the literal as --- a positive number first and then us the - unary operator to make it negaive. --- This would overflow without the quotes as this number cannot be represented --- in a positive fixeddecimal. -SELECT '-92233720368547758.08'::numeric::FIXEDDECIMAL; - fixeddecimal ------------------------ - -92233720368547758.08 -(1 row) - --- Ensure casts from numeric to fixed decimal detect overflow -SELECT '92233720368547758.08'::numeric::FIXEDDECIMAL; -ERROR: value "92233720368547758.08" is out of range for type fixeddecimal -SELECT '-92233720368547758.09'::numeric::FIXEDDECIMAL; -ERROR: value "-92233720368547758.09" is out of range for type fixeddecimal -SELECT '-92233720368547758.08'::FIXEDDECIMAL - '0.01'::FIXEDDECIMAL; -ERROR: fixeddecimal out of range -SELECT '92233720368547758.07'::FIXEDDECIMAL + '0.01'::FIXEDDECIMAL; -ERROR: fixeddecimal out of range --- Should not overflow -SELECT '46116860184273879.03'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; - ?column? ----------------------- - 92233720368547758.06 -(1 row) - --- Ensure this overflows -SELECT '46116860184273879.04'::FIXEDDECIMAL * '2.00'::FIXEDDECIMAL; -ERROR: fixeddecimal out of range --- Should not overflow -SELECT '46116860184273879.03'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; - ?column? ----------------------- - 92233720368547758.06 -(1 row) - --- Ensure this overflows -SELECT '46116860184273879.04'::FIXEDDECIMAL / '0.50'::FIXEDDECIMAL; -ERROR: fixeddecimal out of range --- Ensure limits of int2 can be represented -SELECT '32767'::FIXEDDECIMAL::INT2,'-32768'::FIXEDDECIMAL::INT2; - int2 | int2 --------+-------- - 32767 | -32768 -(1 row) - --- Ensure overflow of int2 is detected -SELECT '32768'::FIXEDDECIMAL::INT2; -ERROR: smallint out of range --- Ensure underflow of int2 is detected -SELECT '-32769'::FIXEDDECIMAL::INT2; -ERROR: smallint out of range --- Ensure limits of int4 can be represented -SELECT '2147483647'::FIXEDDECIMAL::INT4,'-2147483648'::FIXEDDECIMAL::INT4; - int4 | int4 -------------+------------- - 2147483647 | -2147483648 -(1 row) - --- Ensure overflow of int4 is detected -SELECT '2147483648'::FIXEDDECIMAL::INT4; -ERROR: integer out of range --- Ensure underflow of int4 is detected -SELECT '-2147483649'::FIXEDDECIMAL::INT4; -ERROR: integer out of range --- Ensure overflow is detected -SELECT SUM(a) FROM (VALUES('92233720368547758.07'::FIXEDDECIMAL),('0.01'::FIXEDDECIMAL)) a(a); -ERROR: fixeddecimal out of range --- Ensure underflow is detected -SELECT SUM(a) FROM (VALUES('-92233720368547758.08'::FIXEDDECIMAL),('-0.01'::FIXEDDECIMAL)) a(a); -ERROR: fixeddecimal out of range --- Test typmods -SELECT 12345.33::FIXEDDECIMAL(3,2); -- Fail -ERROR: FIXEDDECIMAL field overflow -DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^1. -SELECT 12345.33::FIXEDDECIMAL(5,2); -- Fail -ERROR: FIXEDDECIMAL field overflow -DETAIL: A field with precision 5, scale 2 must round to an absolute value less than 10^3. --- scale of 2 should be enforced. -SELECT 12345.44::FIXEDDECIMAL(7,0); -ERROR: FIXEDDECIMAL scale must be 2 -LINE 1: SELECT 12345.44::FIXEDDECIMAL(7,0); - ^ --- should work. -SELECT 12345.33::FIXEDDECIMAL(7,2); - fixeddecimal --------------- - 12345.33 -(1 row) - --- error, precision limit should be 17 -SELECT 12345.33::FIXEDDECIMAL(18,2); -ERROR: FIXEDDECIMAL precision 18 must be between 2 and 17 -LINE 1: SELECT 12345.33::FIXEDDECIMAL(18,2); - ^ -CREATE TABLE fixdec (d FIXEDDECIMAL(3,2)); -INSERT INTO fixdec VALUES(12.34); -- Fail -ERROR: FIXEDDECIMAL field overflow -DETAIL: A field with precision 2, scale 2 must round to an absolute value less than 10^1. -INSERT INTO fixdec VALUES(1.23); -- Pass -DROP TABLE fixdec; From 8aba3d0a5fd73efc80945d02f4cc657d98c63391 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 2 Oct 2015 23:23:33 +1300 Subject: [PATCH 21/32] Remove incorrect STRICT properties from aggregate final functions --- contrib/fixeddecimal/fixeddecimal--aggs.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/fixeddecimal/fixeddecimal--aggs.sql b/contrib/fixeddecimal/fixeddecimal--aggs.sql index 2af7194184d..a24a869129c 100644 --- a/contrib/fixeddecimal/fixeddecimal--aggs.sql +++ b/contrib/fixeddecimal/fixeddecimal--aggs.sql @@ -10,12 +10,12 @@ LANGUAGE C IMMUTABLE; CREATE FUNCTION fixeddecimal_sum(INTERNAL) RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimal_sum' -LANGUAGE C IMMUTABLE STRICT; +LANGUAGE C IMMUTABLE; CREATE FUNCTION fixeddecimal_avg(INTERNAL) RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimal_avg' -LANGUAGE C IMMUTABLE STRICT; +LANGUAGE C IMMUTABLE; CREATE AGGREGATE min(FIXEDDECIMAL) ( SFUNC = fixeddecimalsmaller, From 48cd864fcc578fd8be639f350c67023ea1deaeee Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 2 Oct 2015 23:27:18 +1300 Subject: [PATCH 22/32] Various fixes for aggregates for Postgres-XL Patch by Pavan Deolasee --- contrib/fixeddecimal/fixeddecimal--xlaggs.sql | 18 ++++---- contrib/fixeddecimal/fixeddecimal.c | 44 +++++++++++++++---- contrib/fixeddecimal/fixeddecimalaggstate.sql | 3 +- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/contrib/fixeddecimal/fixeddecimal--xlaggs.sql b/contrib/fixeddecimal/fixeddecimal--xlaggs.sql index 3e68cd995ec..57fa07d1e42 100644 --- a/contrib/fixeddecimal/fixeddecimal--xlaggs.sql +++ b/contrib/fixeddecimal/fixeddecimal--xlaggs.sql @@ -2,25 +2,25 @@ -- Aggregate Support -CREATE FUNCTION fixeddecimalaggstatecombine(FIXEDDECIMALAGGSTATE, INTERNAL) +CREATE FUNCTION fixeddecimalaggstatecombine(FIXEDDECIMALAGGSTATE, FIXEDDECIMALAGGSTATE) RETURNS FIXEDDECIMALAGGSTATE AS 'fixeddecimal', 'fixeddecimalaggstatecombine' LANGUAGE C IMMUTABLE; -CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) -RETURNS INTERNAL +CREATE FUNCTION fixeddecimal_avg_accum(FIXEDDECIMALAGGSTATE, FIXEDDECIMAL) +RETURNS FIXEDDECIMALAGGSTATE AS 'fixeddecimal', 'fixeddecimal_avg_accum' LANGUAGE C IMMUTABLE; -CREATE FUNCTION fixeddecimal_sum(INTERNAL) +CREATE FUNCTION fixeddecimal_sum(FIXEDDECIMALAGGSTATE) RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimal_sum' -LANGUAGE C IMMUTABLE STRICT; +LANGUAGE C IMMUTABLE; -CREATE FUNCTION fixeddecimal_avg(INTERNAL) +CREATE FUNCTION fixeddecimal_avg(FIXEDDECIMALAGGSTATE) RETURNS FIXEDDECIMAL AS 'fixeddecimal', 'fixeddecimal_avg' -LANGUAGE C IMMUTABLE STRICT; +LANGUAGE C IMMUTABLE; CREATE AGGREGATE min(FIXEDDECIMAL) ( SFUNC = fixeddecimalsmaller, @@ -43,7 +43,7 @@ CREATE AGGREGATE sum(FIXEDDECIMAL) ( CFUNC = fixeddecimalaggstatecombine, CTYPE = FIXEDDECIMALAGGSTATE, FINALFUNC = fixeddecimal_sum, - STYPE = INTERNAL + STYPE = FIXEDDECIMALAGGSTATE ); CREATE AGGREGATE avg(FIXEDDECIMAL) ( @@ -51,7 +51,7 @@ CREATE AGGREGATE avg(FIXEDDECIMAL) ( CFUNC = fixeddecimalaggstatecombine, CTYPE = FIXEDDECIMALAGGSTATE, FINALFUNC = fixeddecimal_avg, - STYPE = INTERNAL + STYPE = FIXEDDECIMALAGGSTATE ); diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index 42d3754a24a..0813708c04b 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -1746,7 +1746,7 @@ fixeddecimalaggstatein(PG_FUNCTION_ARGS) FixedDecimalAggState *state; char *token; - state = (FixedDecimalAggState *) palloc0(sizeof(FixedDecimalAggState)); + state = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); token = strtok(str, ":"); state->sumX = DatumGetInt64(DirectFunctionCall3(fixeddecimalin, CStringGetDatum(token), 0, -1)); @@ -1771,6 +1771,7 @@ fixeddecimalaggstateout(PG_FUNCTION_ARGS) p = fixeddecimal2str(state->sumX, buf); *p++ = ':'; p = pg_int64tostr(p, state->N); + PG_RETURN_CSTRING(pnstrdup(buf, p - buf)); } @@ -1810,14 +1811,41 @@ fixeddecimalaggstatesend(PG_FUNCTION_ARGS) Datum fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) { - FixedDecimalAggState *state1 = (FixedDecimalAggState *) PG_GETARG_POINTER(0); - FixedDecimalAggState *state2 = (FixedDecimalAggState *) PG_GETARG_POINTER(1); - FixedDecimalAggState *newstate = palloc(sizeof(FixedDecimalAggState)); + FixedDecimalAggState *collectstate; + FixedDecimalAggState *transstate; + MemoryContext agg_context; + MemoryContext old_context; + + if (!AggCheckCallContext(fcinfo, &agg_context)) + elog(ERROR, "aggregate function called in non-aggregate context"); + + old_context = MemoryContextSwitchTo(agg_context); - newstate->sumX = DatumGetInt64(DirectFunctionCall2(fixeddecimalpl, Int64GetDatum(state1->sumX), Int64GetDatum(state2->sumX))); - newstate->N = DatumGetInt64(DirectFunctionCall2(int8pl, Int64GetDatum(state1->N), Int64GetDatum(state2->N))); + collectstate = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) + PG_GETARG_POINTER(0); - PG_RETURN_POINTER(newstate); + if (collectstate == NULL) + { + collectstate = (FixedDecimalAggState *) palloc(sizeof + (FixedDecimalAggState)); + collectstate->sumX = 0; + collectstate->N = 0; + } + + transstate = PG_ARGISNULL(1) ? NULL : (FixedDecimalAggState *) + PG_GETARG_POINTER(1); + + if (transstate == NULL) + PG_RETURN_POINTER(collectstate); + + collectstate->sumX = DatumGetInt64(DirectFunctionCall2(fixeddecimalpl, + Int64GetDatum(collectstate->sumX), Int64GetDatum(transstate->sumX))); + collectstate->N = DatumGetInt64(DirectFunctionCall2(int8pl, + Int64GetDatum(collectstate->N), Int64GetDatum(transstate->N))); + + MemoryContextSwitchTo(old_context); + + PG_RETURN_POINTER(collectstate); } -#endif /* PGXC */ \ No newline at end of file +#endif /* PGXC */ diff --git a/contrib/fixeddecimal/fixeddecimalaggstate.sql b/contrib/fixeddecimal/fixeddecimalaggstate.sql index e40c81923ec..9e814777b5b 100644 --- a/contrib/fixeddecimal/fixeddecimalaggstate.sql +++ b/contrib/fixeddecimal/fixeddecimalaggstate.sql @@ -35,6 +35,7 @@ CREATE TYPE FIXEDDECIMALAGGSTATE ( STORAGE = plain, CATEGORY = 'N', PREFERRED = false, - COLLATABLE = false + COLLATABLE = false, + PASSEDBYVALUE ); From 344f928ee02bbb857520d5970a248beb14adc3c3 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 2 Oct 2015 23:51:36 +1300 Subject: [PATCH 23/32] Create Postgres-XL specific regression tests This change adds logic to the Makefile to detect when running on Postgres-XL and run XL specific tests for this case. --- contrib/fixeddecimal/Makefile | 27 +++--- .../fixeddecimal/test/expected/brin-xl.out | 23 +++++ .../fixeddecimal/test/expected/index-xl.out | 95 +++++++++++++++++++ contrib/fixeddecimal/test/sql/brin-xl.sql | 14 +++ contrib/fixeddecimal/test/sql/index-xl.sql | 47 +++++++++ 5 files changed, 192 insertions(+), 14 deletions(-) create mode 100644 contrib/fixeddecimal/test/expected/brin-xl.out create mode 100644 contrib/fixeddecimal/test/expected/index-xl.out create mode 100644 contrib/fixeddecimal/test/sql/brin-xl.sql create mode 100644 contrib/fixeddecimal/test/sql/index-xl.sql diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index 127d57df557..bcfb751dbc5 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -1,24 +1,24 @@ - - MODULE_big = fixeddecimal OBJS = fixeddecimal.o EXTENSION = fixeddecimal -DATA = $(shell $(PG_CONFIG) --version | grep -qE " 9\.[5-9]| 10\.0" && \ - cat fixeddecimal--1.0.0_base.sql fixeddecimal--brin.sql > fixeddecimal--1.0.0.tmp | echo fixeddecimal--1.0.0.tmp || \ - cat fixeddecimal--1.0.0_base.sql > fixeddecimal--1.0.0.tmp | echo fixeddecimal--1.0.0.tmp) \ - $(shell $(PG_CONFIG) --version | grep -qE "XL" && \ - cat fixeddecimalaggstate.sql fixeddecimal--1.0.0.tmp fixeddecimal--xlaggs.sql > fixeddecimal--1.0.0.sql | echo fixeddecimal--1.0.0.sql || \ - cat fixeddecimal--1.0.0.tmp > fixeddecimal--1.0.0.sql fixeddecimal--aggs.sql | echo fixeddecimal--1.0.0.sql) +AGGSTATESQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimalaggstate.sql) +AGGFUNCSSQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimal--xlaggs.sql || echo fixeddecimal--aggs.sql) +BRINSQL := $(shell pg_config --version | grep -qE "9\.[5-9]| 10\.0" && echo fixeddecimal--brin.sql) +SQLFILES := $(shell cat $(AGGSTATESQL) fixeddecimal--1.0.0_base.sql $(AGGFUNCSSQL) $(BRINSQL) > fixeddecimal--1.0.0.sql) + +DATA = fixeddecimal--1.0.0.sql MODULES = fixeddecimal -CFLAGS=`pg_config --includedir-server -UXCP` +CFLAGS =`pg_config --includedir-server -UXCP` -TESTS = $(wildcard test/sql/*.sql) -REGRESS = $(shell $(PG_CONFIG) --version | grep -qE " 9\.[5-9]| 10\.0" && \ - echo aggregate brin cast comparison index overflow || \ - echo aggregate cast comparison index overflow) +TESTS = $(wildcard test/sql/*.sql) + +REGRESS_BRIN := $(shell pg_config --version | grep -qE "XL 9\.[5-9]| 10\.0" && echo brin-xl) +REGRESS_BRIN += $(shell pg_config --version | grep -E "9\.[5-9]| 10\.0" | grep -qEv "XL" && echo brin) +REGRESS_VERSION_SPECIFIC := $(shell pg_config --version | grep -qE "XL" && echo index-xl || echo index) +REGRESS = $(shell echo aggregate cast comparison overflow $(REGRESS_BRIN) $(REGRESS_VERSION_SPECIFIC)) REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=fixeddecimal @@ -29,4 +29,3 @@ include $(PGXS) fixeddecimal.so: fixeddecimal.o fixeddecimal.o: fixeddecimal.c - diff --git a/contrib/fixeddecimal/test/expected/brin-xl.out b/contrib/fixeddecimal/test/expected/brin-xl.out new file mode 100644 index 00000000000..a66f7cf515e --- /dev/null +++ b/contrib/fixeddecimal/test/expected/brin-xl.out @@ -0,0 +1,23 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + QUERY PLAN +--------------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) +(5 rows) + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + d | txt +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +RESET enable_seqscan; diff --git a/contrib/fixeddecimal/test/expected/index-xl.out b/contrib/fixeddecimal/test/expected/index-xl.out new file mode 100644 index 00000000000..43c34566432 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/index-xl.out @@ -0,0 +1,95 @@ +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); +CREATE INDEX fixdec_d_idx ON fixdec (d); +DELETE FROM fixdec WHERE id = 9; +SET enable_seqscan = off; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + QUERY PLAN +----------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Index Scan using fixdec_d_idx on fixdec +(2 rows) + +SELECT * FROM fixdec ORDER BY d; + id | d +----+--------- + 1 | -123.45 + 2 | -123.00 + 3 | -12.34 + 4 | -1.34 + 5 | 0.12 + 6 | 1.23 + 7 | 12.34 + 8 | 123.45 +(8 rows) + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Bitmap Heap Scan on fixdec + Recheck Cond: (d = '12.34'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d = '12.34'::fixeddecimal) +(5 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP INDEX fixdec_d_idx; +SET client_min_messages = ERROR; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +RESET client_min_messages; +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + QUERY PLAN +------------------------------------------------------- + Remote Subquery Scan on all (datanode_1,datanode_2) + -> Bitmap Heap Scan on fixdec + Recheck Cond: (d = '12.34'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d = '12.34'::fixeddecimal) +(5 rows) + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + id | d +----+------- + 7 | 12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + id | d +----+-------- + 3 | -12.34 +(1 row) + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + id | d +----+-------- + 8 | 123.45 +(1 row) + +DROP TABLE fixdec; +SET enable_seqscan = on; diff --git a/contrib/fixeddecimal/test/sql/brin-xl.sql b/contrib/fixeddecimal/test/sql/brin-xl.sql new file mode 100644 index 00000000000..802328517d5 --- /dev/null +++ b/contrib/fixeddecimal/test/sql/brin-xl.sql @@ -0,0 +1,14 @@ +-- Test BRIN indexes +SET enable_seqscan = off; +CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); + +CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +RESET enable_seqscan; diff --git a/contrib/fixeddecimal/test/sql/index-xl.sql b/contrib/fixeddecimal/test/sql/index-xl.sql new file mode 100644 index 00000000000..c963ba1f888 --- /dev/null +++ b/contrib/fixeddecimal/test/sql/index-xl.sql @@ -0,0 +1,47 @@ +CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); + +INSERT INTO fixdec (id,d) VALUES(1,-123.45); +INSERT INTO fixdec (id,d) VALUES(2,-123); +INSERT INTO fixdec (id,d) VALUES(3,-12.34); +INSERT INTO fixdec (id,d) VALUES(4,-1.34); +INSERT INTO fixdec (id,d) VALUES(5, 0.12); +INSERT INTO fixdec (id,d) VALUES(6, 1.23); +INSERT INTO fixdec (id,d) VALUES(7, 12.34); +INSERT INTO fixdec (id,d) VALUES(8, 123.45); +INSERT INTO fixdec (id,d) VALUES(9, 123.456); + +CREATE INDEX fixdec_d_idx ON fixdec (d); + +DELETE FROM fixdec WHERE id = 9; + +SET enable_seqscan = off; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; + +SELECT * FROM fixdec ORDER BY d; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +DROP INDEX fixdec_d_idx; + +SET client_min_messages = ERROR; +CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); +RESET client_min_messages; + +EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '-12.34'::FIXEDDECIMAL; + +SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; + +DROP TABLE fixdec; + +SET enable_seqscan = on; From 1945c49dfdbc2bfa93f591277732bf56f6a7f23c Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 9 Oct 2015 00:57:05 +1300 Subject: [PATCH 24/32] Remove unused CFLAGS in Makefile --- contrib/fixeddecimal/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index bcfb751dbc5..cf93160761d 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -11,8 +11,6 @@ DATA = fixeddecimal--1.0.0.sql MODULES = fixeddecimal -CFLAGS =`pg_config --includedir-server -UXCP` - TESTS = $(wildcard test/sql/*.sql) REGRESS_BRIN := $(shell pg_config --version | grep -qE "XL 9\.[5-9]| 10\.0" && echo brin-xl) From 19baef0124316beafd5269e55a8cecb643c35c39 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Fri, 9 Oct 2015 00:58:52 +1300 Subject: [PATCH 25/32] Re-add CFLAGS. This time without the bogus -UXCP --- contrib/fixeddecimal/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index cf93160761d..be3c424743d 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -11,6 +11,8 @@ DATA = fixeddecimal--1.0.0.sql MODULES = fixeddecimal +CFLAGS =`pg_config --includedir-server` + TESTS = $(wildcard test/sql/*.sql) REGRESS_BRIN := $(shell pg_config --version | grep -qE "XL 9\.[5-9]| 10\.0" && echo brin-xl) From 425de05456f12f868f6bc479ffd1c38b8577e74a Mon Sep 17 00:00:00 2001 From: Simon Riggs Date: Wed, 23 Dec 2015 18:08:07 +0000 Subject: [PATCH 26/32] Final wording prior to release Added credits, comments and legal wording prior to release --- contrib/fixeddecimal/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md index ded198b81f4..0546608f054 100755 --- a/contrib/fixeddecimal/README.md +++ b/contrib/fixeddecimal/README.md @@ -1,6 +1,8 @@ FIXEDDECIMAL ============ +Works with PostgreSQL 9.5 and Postgres-XL 9.5 + Overview -------- @@ -143,3 +145,12 @@ From psql, in order to create the extension you must type: ``` CREATE EXTENSION fixeddecimal; ``` + +Credits +------- + +fixeddecimal is open source using The PostgreSQL Licence, copyright is novated to the PostgreSQL Global Development Group. + +Source code developed by 2ndQuadrant, as part of the AXLE project (http://axleproject.eu) which received funding from the European Union’s Seventh Framework Programme (FP7/2007-2015) under grant agreement n° 318633 + +Lead Developer - David Rowley From 2eb7c43589c9d50b499c94013523cad0e46f25f5 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Sat, 25 Jun 2016 01:16:33 +1200 Subject: [PATCH 27/32] Add parallel aggregate support Also add various functions to allow cross type operators to save having to cast lesser types up to fixeddecimal. Please note that the upgrade script to upgrade from 1.0.0 to 1.1.0 is currently only for 9.6 and beyond. If you're running XL or 9.5 or less this script will need to be altered. --- contrib/fixeddecimal/Makefile | 15 +- .../fixeddecimal--1.0.0--1.1.0.sql | 800 +++++++++++ .../fixeddecimal/fixeddecimal--1.1.0_base.sql | 1194 +++++++++++++++++ .../fixeddecimal--1.1.0_base_parallel.sql | 1194 +++++++++++++++++ .../fixeddecimal--parallelaggs.sql | 70 + contrib/fixeddecimal/fixeddecimal.c | 575 +++++++- contrib/fixeddecimal/fixeddecimal.control | 2 +- 7 files changed, 3836 insertions(+), 14 deletions(-) create mode 100644 contrib/fixeddecimal/fixeddecimal--1.0.0--1.1.0.sql create mode 100755 contrib/fixeddecimal/fixeddecimal--1.1.0_base.sql create mode 100755 contrib/fixeddecimal/fixeddecimal--1.1.0_base_parallel.sql create mode 100644 contrib/fixeddecimal/fixeddecimal--parallelaggs.sql diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index be3c424743d..0f7972079fc 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -3,11 +3,18 @@ OBJS = fixeddecimal.o EXTENSION = fixeddecimal AGGSTATESQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimalaggstate.sql) -AGGFUNCSSQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimal--xlaggs.sql || echo fixeddecimal--aggs.sql) -BRINSQL := $(shell pg_config --version | grep -qE "9\.[5-9]| 10\.0" && echo fixeddecimal--brin.sql) -SQLFILES := $(shell cat $(AGGSTATESQL) fixeddecimal--1.0.0_base.sql $(AGGFUNCSSQL) $(BRINSQL) > fixeddecimal--1.0.0.sql) +AGGFUNCSSQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimal--xlaggs.sql) -DATA = fixeddecimal--1.0.0.sql +AGGFUNCSSQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]" && echo fixeddecimal--parallelaggs.sql || echo fixeddecimal--aggs.sql) + +BRINSQL := $(shell pg_config --version | grep -qE "9\.[5-9]| 10\.[0-9]" && echo fixeddecimal--brin.sql) + +# 9.6 was the dawn of parallel query, so we'll use the parallel enabled .sql file from then on. +BASESQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]" && echo fixeddecimal--1.1.0_base_parallel.sql || echo fixeddecimal--1.1.0_base.sql) + +SQLFILES := $(shell cat $(AGGSTATESQL) $(BASESQL) $(AGGFUNCSSQL) $(BRINSQL) > fixeddecimal--1.1.0.sql) + +DATA = fixeddecimal--1.1.0.sql fixeddecimal--1.0.0--1.1.0.sql MODULES = fixeddecimal diff --git a/contrib/fixeddecimal/fixeddecimal--1.0.0--1.1.0.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0--1.1.0.sql new file mode 100644 index 00000000000..98b8337c357 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0--1.1.0.sql @@ -0,0 +1,800 @@ +CREATE FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; +CREATE OPERATOR = ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT4, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT; +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT2, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + + +-- 9.6+ Parallel function changes. +ALTER FUNCTION fixeddecimalin(cstring, oid, int4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalout(fixeddecimal) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalrecv(internal) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalsend(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltypmodin(_cstring) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltypmodout(INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalum(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION abs(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_hash(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) PARALLEL SAFE; +ALTER FUNCTION int4fixeddecimal(INT4) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint4(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION int2fixeddecimal(INT2) PARALLEL SAFE; +ALTER FUNCTION fixeddecimalint2(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltod(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION dtofixeddecimal(DOUBLE PRECISION) PARALLEL SAFE; +ALTER FUNCTION fixeddecimaltof(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION ftofixeddecimal(REAL) PARALLEL SAFE; +ALTER FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) PARALLEL SAFE; +ALTER FUNCTION numeric_fixeddecimal(NUMERIC) PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstatecombine(INTERNAL, INTERNAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstateserialize(INTERNAL) +RETURNS BYTEA +AS 'fixeddecimal', 'fixeddecimalaggstateserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstatedeserialize(BYTEA, INTERNAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimalaggstatedeserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'min(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'max(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'sum(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_proc SET proparallel = 's' +WHERE oid = 'avg(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimalsmaller' +WHERE aggfnoid = 'min(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimallarger' +WHERE aggfnoid = 'max(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimalaggstatecombine', + aggserialfn = 'fixeddecimalaggstateserialize', + aggdeserialfn = 'fixeddecimalaggstatedeserialize' +WHERE aggfnoid = 'sum(FIXEDDECIMAL)'::pg_catalog.regprocedure; + +UPDATE pg_aggregate SET aggcombinefn = 'fixeddecimalaggstatecombine', + aggserialfn = 'fixeddecimalaggstateserialize', + aggdeserialfn = 'fixeddecimalaggstatedeserialize' +WHERE aggfnoid = 'avg(FIXEDDECIMAL)'::pg_catalog.regprocedure; diff --git a/contrib/fixeddecimal/fixeddecimal--1.1.0_base.sql b/contrib/fixeddecimal/fixeddecimal--1.1.0_base.sql new file mode 100755 index 00000000000..012bfb3ed85 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--1.1.0_base.sql @@ -0,0 +1,1194 @@ + +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE FIXEDDECIMAL; + +CREATE FUNCTION fixeddecimalin(cstring, oid, int4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'fixeddecimal', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalrecv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'fixeddecimal', 'fixeddecimalsend' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'fixeddecimal', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT; + + +CREATE TYPE FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = false, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalum(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION abs(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT; + +-- +-- Operators. +-- + +-- FIXEDDECIMAL op FIXEDDECIMAL +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR - ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT4, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int2 +-- +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR = ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT2, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Casts +-- + +CREATE FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'fixeddecimal', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'fixeddecimal', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'fixeddecimal', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS ASSIGNMENT; diff --git a/contrib/fixeddecimal/fixeddecimal--1.1.0_base_parallel.sql b/contrib/fixeddecimal/fixeddecimal--1.1.0_base_parallel.sql new file mode 100755 index 00000000000..fc420ef00c9 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--1.1.0_base_parallel.sql @@ -0,0 +1,1194 @@ + +------------------ +-- FIXEDDECIMAL -- +------------------ + +CREATE TYPE FIXEDDECIMAL; + +CREATE FUNCTION fixeddecimalin(cstring, oid, int4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalout(fixeddecimal) +RETURNS cstring +AS 'fixeddecimal', 'fixeddecimalout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalrecv(internal) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalrecv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalsend(FIXEDDECIMAL) +RETURNS bytea +AS 'fixeddecimal', 'fixeddecimalsend' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltypmodin(_cstring) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimaltypmodin' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltypmodout(INT4) +RETURNS cstring +AS 'fixeddecimal', 'fixeddecimaltypmodout' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE TYPE FIXEDDECIMAL ( + INPUT = fixeddecimalin, + OUTPUT = fixeddecimalout, + RECEIVE = fixeddecimalrecv, + SEND = fixeddecimalsend, + TYPMOD_IN = fixeddecimaltypmodin, + TYPMOD_OUT = fixeddecimaltypmodout, + INTERNALLENGTH = 8, + ALIGNMENT = 'double', + STORAGE = plain, + CATEGORY = 'N', + PREFERRED = false, + COLLATABLE = false, + PASSEDBYVALUE -- But not always.. XXX fix that. +); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimaleq(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimaleq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalne(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimallt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimallt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalle(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalle' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalgt(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalgt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalge(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimalge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalum(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalum' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalpl(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalmi(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalmul(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaldiv(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION abs(FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalabs' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimallarger(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimallarger' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalsmaller(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalsmaller' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_hash(FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_hash' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- +-- Operators. +-- + +-- FIXEDDECIMAL op FIXEDDECIMAL +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimaleq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimalne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimallt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimalle, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimalge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimalgt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalmi +); + +CREATE OPERATOR - ( + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimalum +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = fixeddecimaldiv +); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 2 <= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 3 = (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 4 >= (FIXEDDECIMAL, FIXEDDECIMAL), + OPERATOR 5 > (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_cmp(FIXEDDECIMAL, FIXEDDECIMAL); + +CREATE OPERATOR CLASS fixeddecimal_ops +DEFAULT FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- FIXEDDECIMAL, NUMERIC +CREATE FUNCTION fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_numeric_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'numeric_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_eq(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_ne(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_lt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_le(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_gt(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric_ge(FIXEDDECIMAL, NUMERIC) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_numeric_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_numeric_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_numeric_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_numeric_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_numeric_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_numeric_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = NUMERIC, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_numeric_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, NUMERIC), + OPERATOR 2 <= (FIXEDDECIMAL, NUMERIC), + OPERATOR 3 = (FIXEDDECIMAL, NUMERIC), + OPERATOR 4 >= (FIXEDDECIMAL, NUMERIC), + OPERATOR 5 > (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_numeric_cmp(FIXEDDECIMAL, NUMERIC); + +CREATE OPERATOR CLASS fixeddecimal_numeric_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, NUMERIC), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- NUMERIC, FIXEDDECIMAL +CREATE FUNCTION numeric_fixeddecimal_eq(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_ne(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_lt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_le(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_gt(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal_ge(NUMERIC, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'numeric_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = numeric_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = numeric_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = numeric_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = numeric_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = numeric_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = NUMERIC, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = numeric_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 2 <= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 3 = (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 4 >= (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + OPERATOR 5 > (NUMERIC, FIXEDDECIMAL) FOR SEARCH, + FUNCTION 1 numeric_fixeddecimal_cmp(NUMERIC, FIXEDDECIMAL); + +CREATE OPERATOR CLASS numeric_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (NUMERIC, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int4 +-- + +-- FIXEDDECIMAL, INT4 +CREATE FUNCTION fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_int4_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_eq(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_ne(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_lt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_le(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_gt(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int4_ge(FIXEDDECIMAL, INT4) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int4_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4pl(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4mi(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4mul(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4div(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint4div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int4_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int4_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int4_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int4_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int4_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int4_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint4pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint4mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT4, + PROCEDURE = fixeddecimalint4div +); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT4), + OPERATOR 2 <= (FIXEDDECIMAL, INT4), + OPERATOR 3 = (FIXEDDECIMAL, INT4), + OPERATOR 4 >= (FIXEDDECIMAL, INT4), + OPERATOR 5 > (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_int4_cmp(FIXEDDECIMAL, INT4); + +CREATE OPERATOR CLASS fixeddecimal_int4_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT4), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT4, FIXEDDECIMAL +CREATE FUNCTION int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'int4_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_eq(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_ne(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_lt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_le(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_gt(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4_fixeddecimal_ge(INT4, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int4_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimalpl(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimalmi(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimalmul(INT4, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimaldiv(INT4, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'int4fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int4_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int4_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int4_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int4_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int4_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int4_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int4fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int4fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT4, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int4fixeddecimaldiv +); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT4, FIXEDDECIMAL), + OPERATOR 2 <= (INT4, FIXEDDECIMAL), + OPERATOR 3 = (INT4, FIXEDDECIMAL), + OPERATOR 4 >= (INT4, FIXEDDECIMAL), + OPERATOR 5 > (INT4, FIXEDDECIMAL), + FUNCTION 1 int4_fixeddecimal_cmp(INT4, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int4_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT4, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Cross type operators with int2 +-- +-- FIXEDDECIMAL, INT2 +CREATE FUNCTION fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimal_int2_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_eq(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_ne(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_lt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_le(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_gt(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_int2_ge(FIXEDDECIMAL, INT2) +RETURNS bool +AS 'fixeddecimal', 'fixeddecimal_int2_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2pl(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2pl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2mi(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2mi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2mul(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2mul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2div(FIXEDDECIMAL, INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimalint2div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = fixeddecimal_int2_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = fixeddecimal_int2_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = fixeddecimal_int2_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = fixeddecimal_int2_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = fixeddecimal_int2_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = fixeddecimal_int2_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = +, + PROCEDURE = fixeddecimalint2pl +); + +CREATE OPERATOR - ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2mi +); + +CREATE OPERATOR * ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + COMMUTATOR = *, + PROCEDURE = fixeddecimalint2mul +); + +CREATE OPERATOR / ( + LEFTARG = FIXEDDECIMAL, + RIGHTARG = INT2, + PROCEDURE = fixeddecimalint2div +); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (FIXEDDECIMAL, INT2), + OPERATOR 2 <= (FIXEDDECIMAL, INT2), + OPERATOR 3 = (FIXEDDECIMAL, INT2), + OPERATOR 4 >= (FIXEDDECIMAL, INT2), + OPERATOR 5 > (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_int2_cmp(FIXEDDECIMAL, INT2); + +CREATE OPERATOR CLASS fixeddecimal_int2_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (FIXEDDECIMAL, INT2), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- INT2, FIXEDDECIMAL +CREATE FUNCTION int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'int2_fixeddecimal_cmp' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_eq(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_eq' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_ne(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_ne' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_lt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_lt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_le(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_le' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_gt(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_gt' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2_fixeddecimal_ge(INT2, FIXEDDECIMAL) +RETURNS bool +AS 'fixeddecimal', 'int2_fixeddecimal_ge' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimalpl(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalpl' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimalmi(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalmi' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimalmul(INT2, FIXEDDECIMAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimalmul' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimaldiv(INT2, FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'int2fixeddecimaldiv' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OPERATOR = ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = =, + NEGATOR = <>, + PROCEDURE = int2_fixeddecimal_eq, + RESTRICT = eqsel, + JOIN = eqjoinsel, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = =, + COMMUTATOR = <>, + PROCEDURE = int2_fixeddecimal_ne, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >=, + COMMUTATOR = >, + PROCEDURE = int2_fixeddecimal_lt, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = >, + COMMUTATOR = >=, + PROCEDURE = int2_fixeddecimal_le, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <, + COMMUTATOR = <=, + PROCEDURE = int2_fixeddecimal_ge, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + NEGATOR = <=, + COMMUTATOR = <, + PROCEDURE = int2_fixeddecimal_gt, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR + ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = +, + PROCEDURE = int2fixeddecimalpl +); + +CREATE OPERATOR - ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimalmi +); + +CREATE OPERATOR * ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + COMMUTATOR = *, + PROCEDURE = int2fixeddecimalmul +); + +CREATE OPERATOR / ( + LEFTARG = INT2, + RIGHTARG = FIXEDDECIMAL, + PROCEDURE = int2fixeddecimaldiv +); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING btree AS + OPERATOR 1 < (INT2, FIXEDDECIMAL), + OPERATOR 2 <= (INT2, FIXEDDECIMAL), + OPERATOR 3 = (INT2, FIXEDDECIMAL), + OPERATOR 4 >= (INT2, FIXEDDECIMAL), + OPERATOR 5 > (INT2, FIXEDDECIMAL), + FUNCTION 1 int2_fixeddecimal_cmp(INT2, FIXEDDECIMAL); + +CREATE OPERATOR CLASS int2_fixeddecimal_ops +FOR TYPE FIXEDDECIMAL USING hash AS + OPERATOR 1 = (INT2, FIXEDDECIMAL), + FUNCTION 1 fixeddecimal_hash(FIXEDDECIMAL); + +-- +-- Casts +-- + +CREATE FUNCTION fixeddecimal(FIXEDDECIMAL, INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int4fixeddecimal(INT4) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int4fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint4(FIXEDDECIMAL) +RETURNS INT4 +AS 'fixeddecimal', 'fixeddecimalint4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION int2fixeddecimal(INT2) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'int2fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalint2(FIXEDDECIMAL) +RETURNS INT2 +AS 'fixeddecimal', 'fixeddecimalint2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltod(FIXEDDECIMAL) +RETURNS DOUBLE PRECISION +AS 'fixeddecimal', 'fixeddecimaltod' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION dtofixeddecimal(DOUBLE PRECISION) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'dtofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimaltof(FIXEDDECIMAL) +RETURNS REAL +AS 'fixeddecimal', 'fixeddecimaltof' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION ftofixeddecimal(REAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'ftofixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_numeric(FIXEDDECIMAL) +RETURNS NUMERIC +AS 'fixeddecimal', 'fixeddecimal_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION numeric_fixeddecimal(NUMERIC) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'numeric_fixeddecimal' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE CAST (FIXEDDECIMAL AS FIXEDDECIMAL) + WITH FUNCTION fixeddecimal (FIXEDDECIMAL, INT4) AS ASSIGNMENT; + +CREATE CAST (INT4 AS FIXEDDECIMAL) + WITH FUNCTION int4fixeddecimal (INT4) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT4) + WITH FUNCTION fixeddecimalint4 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (INT2 AS FIXEDDECIMAL) + WITH FUNCTION int2fixeddecimal (INT2) AS IMPLICIT; + +CREATE CAST (FIXEDDECIMAL AS INT2) + WITH FUNCTION fixeddecimalint2 (FIXEDDECIMAL) AS ASSIGNMENT; + +CREATE CAST (FIXEDDECIMAL AS DOUBLE PRECISION) + WITH FUNCTION fixeddecimaltod (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (DOUBLE PRECISION AS FIXEDDECIMAL) + WITH FUNCTION dtofixeddecimal (DOUBLE PRECISION) AS ASSIGNMENT; -- XXX? or Implicit? + +CREATE CAST (FIXEDDECIMAL AS REAL) + WITH FUNCTION fixeddecimaltof (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (REAL AS FIXEDDECIMAL) + WITH FUNCTION ftofixeddecimal (REAL) AS ASSIGNMENT; -- XXX or Implicit? + +CREATE CAST (FIXEDDECIMAL AS NUMERIC) + WITH FUNCTION fixeddecimal_numeric (FIXEDDECIMAL) AS IMPLICIT; + +CREATE CAST (NUMERIC AS FIXEDDECIMAL) + WITH FUNCTION numeric_fixeddecimal (NUMERIC) AS ASSIGNMENT; diff --git a/contrib/fixeddecimal/fixeddecimal--parallelaggs.sql b/contrib/fixeddecimal/fixeddecimal--parallelaggs.sql new file mode 100644 index 00000000000..956793dee22 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--parallelaggs.sql @@ -0,0 +1,70 @@ + +-- Aggregate Support + +CREATE FUNCTION fixeddecimalaggstatecombine(INTERNAL, INTERNAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstateserialize(INTERNAL) +RETURNS BYTEA +AS 'fixeddecimal', 'fixeddecimalaggstateserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimalaggstatedeserialize(BYTEA, INTERNAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimalaggstatedeserialize' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_avg_accum(INTERNAL, FIXEDDECIMAL) +RETURNS INTERNAL +AS 'fixeddecimal', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_sum(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION fixeddecimal_avg(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE AGGREGATE min(FIXEDDECIMAL) ( + SFUNC = fixeddecimalsmaller, + STYPE = FIXEDDECIMAL, + SORTOP = <, + COMBINEFUNC = fixeddecimalsmaller, + PARALLEL = SAFE +); + +CREATE AGGREGATE max(FIXEDDECIMAL) ( + SFUNC = fixeddecimallarger, + STYPE = FIXEDDECIMAL, + SORTOP = >, + COMBINEFUNC = fixeddecimallarger, + PARALLEL = SAFE +); + +CREATE AGGREGATE sum(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_sum, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + FINALFUNC = fixeddecimal_avg, + STYPE = INTERNAL, + COMBINEFUNC = fixeddecimalaggstatecombine, + SERIALFUNC = fixeddecimalaggstateserialize, + DESERIALFUNC = fixeddecimalaggstatedeserialize, + PARALLEL = SAFE +); + + diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index 0813708c04b..f02caacfc88 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -25,9 +25,7 @@ #include "utils/array.h" #include "utils/builtins.h" -#ifdef PGXC #include "utils/int8.h" -#endif /* PGXC */ #include "utils/numeric.h" @@ -84,6 +82,7 @@ PG_FUNCTION_INFO_V1(fixeddecimaltypmodout); PG_FUNCTION_INFO_V1(fixeddecimalout); PG_FUNCTION_INFO_V1(fixeddecimalrecv); PG_FUNCTION_INFO_V1(fixeddecimalsend); + PG_FUNCTION_INFO_V1(fixeddecimaleq); PG_FUNCTION_INFO_V1(fixeddecimalne); PG_FUNCTION_INFO_V1(fixeddecimallt); @@ -91,6 +90,53 @@ PG_FUNCTION_INFO_V1(fixeddecimalgt); PG_FUNCTION_INFO_V1(fixeddecimalle); PG_FUNCTION_INFO_V1(fixeddecimalge); PG_FUNCTION_INFO_V1(fixeddecimal_cmp); + +PG_FUNCTION_INFO_V1(fixeddecimal_int2_eq); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_ne); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_lt); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_gt); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_le); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_ge); +PG_FUNCTION_INFO_V1(fixeddecimal_int2_cmp); + +PG_FUNCTION_INFO_V1(int2_fixeddecimal_eq); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_ne); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_lt); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_gt); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_le); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_ge); +PG_FUNCTION_INFO_V1(int2_fixeddecimal_cmp); + +PG_FUNCTION_INFO_V1(fixeddecimal_int4_eq); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_ne); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_lt); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_gt); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_le); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_ge); +PG_FUNCTION_INFO_V1(fixeddecimal_int4_cmp); + +PG_FUNCTION_INFO_V1(int4_fixeddecimal_eq); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_ne); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_lt); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_gt); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_le); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_ge); +PG_FUNCTION_INFO_V1(int4_fixeddecimal_cmp); + +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_cmp); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_eq); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_ne); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_lt); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_gt); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_le); +PG_FUNCTION_INFO_V1(fixeddecimal_numeric_ge); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_cmp); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_eq); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_ne); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_lt); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_gt); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_le); +PG_FUNCTION_INFO_V1(numeric_fixeddecimal_ge); PG_FUNCTION_INFO_V1(fixeddecimal_hash); PG_FUNCTION_INFO_V1(fixeddecimalum); PG_FUNCTION_INFO_V1(fixeddecimalup); @@ -131,14 +177,15 @@ PG_FUNCTION_INFO_V1(fixeddecimal_numeric); PG_FUNCTION_INFO_V1(fixeddecimal_avg_accum); PG_FUNCTION_INFO_V1(fixeddecimal_avg); PG_FUNCTION_INFO_V1(fixeddecimal_sum); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatecombine); +PG_FUNCTION_INFO_V1(fixeddecimalaggstateserialize); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatedeserialize); -#ifdef PGXC PG_FUNCTION_INFO_V1(fixeddecimalaggstatein); PG_FUNCTION_INFO_V1(fixeddecimalaggstateout); PG_FUNCTION_INFO_V1(fixeddecimalaggstatesend); PG_FUNCTION_INFO_V1(fixeddecimalaggstaterecv); -PG_FUNCTION_INFO_V1(fixeddecimalaggstatecombine); -#endif /* PGXC */ + /* Aggregate Internal State */ typedef struct FixedDecimalAggState @@ -737,6 +784,460 @@ fixeddecimal_cmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(1); } +/* int2, fixeddecimal */ +Datum +fixeddecimal_int2_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +fixeddecimal_int2_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +fixeddecimal_int2_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +fixeddecimal_int2_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +fixeddecimal_int2_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +fixeddecimal_int2_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +fixeddecimal_int2_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT16(1) * FIXEDDECIMAL_MULTIPLIER; + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +Datum +int2_fixeddecimal_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +int2_fixeddecimal_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +int2_fixeddecimal_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +int2_fixeddecimal_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +int2_fixeddecimal_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +int2_fixeddecimal_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +int2_fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT16(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +/* fixeddecimal, int4 */ +Datum +fixeddecimal_int4_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +fixeddecimal_int4_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +fixeddecimal_int4_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +fixeddecimal_int4_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +fixeddecimal_int4_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +fixeddecimal_int4_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +fixeddecimal_int4_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT64(0); + int64 val2 = PG_GETARG_INT32(1) * FIXEDDECIMAL_MULTIPLIER; + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +Datum +int4_fixeddecimal_eq(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 == val2); +} + +Datum +int4_fixeddecimal_ne(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 != val2); +} + +Datum +int4_fixeddecimal_lt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 < val2); +} + +Datum +int4_fixeddecimal_gt(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 > val2); +} + +Datum +int4_fixeddecimal_le(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 <= val2); +} + +Datum +int4_fixeddecimal_ge(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + PG_RETURN_BOOL(val1 >= val2); +} + +Datum +int4_fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + int64 val1 = PG_GETARG_INT32(0) * FIXEDDECIMAL_MULTIPLIER; + int64 val2 = PG_GETARG_INT64(1); + + if (val1 == val2) + PG_RETURN_INT32(0); + else if (val1 < val2) + PG_RETURN_INT32(-1); + else + PG_RETURN_INT32(1); +} + +Datum +fixeddecimal_numeric_cmp(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + Datum val2 = PG_GETARG_DATUM(1); + Datum val1; + + val1 = DirectFunctionCall1(fixeddecimal_numeric, Int64GetDatum(arg1)); + + PG_RETURN_INT32(DirectFunctionCall2(numeric_cmp, val1, val2)); +} + +Datum +fixeddecimal_numeric_eq(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result == 0); +} + +Datum +fixeddecimal_numeric_ne(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result != 0); +} + +Datum +fixeddecimal_numeric_lt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result < 0); +} + +Datum +fixeddecimal_numeric_gt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result > 0); +} + +Datum +fixeddecimal_numeric_le(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result <= 0); +} + +Datum +fixeddecimal_numeric_ge(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(fixeddecimal_numeric_cmp, val1, + val2)); + + PG_RETURN_BOOL(result >= 0); +} + +Datum +numeric_fixeddecimal_cmp(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + int64 arg2 = PG_GETARG_INT64(1); + Datum val2; + + val2 = DirectFunctionCall1(fixeddecimal_numeric, Int64GetDatum(arg2)); + + PG_RETURN_INT32(DirectFunctionCall2(numeric_cmp, val1, val2)); +} + +Datum +numeric_fixeddecimal_eq(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result == 0); +} + +Datum +numeric_fixeddecimal_ne(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result != 0); +} + +Datum +numeric_fixeddecimal_lt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result < 0); +} + +Datum +numeric_fixeddecimal_gt(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result > 0); +} + +Datum +numeric_fixeddecimal_le(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result <= 0); +} + +Datum +numeric_fixeddecimal_ge(PG_FUNCTION_ARGS) +{ + Datum val1 = PG_GETARG_DATUM(0); + Datum val2 = PG_GETARG_DATUM(1); + int32 result; + + result = DatumGetInt32(DirectFunctionCall2(numeric_fixeddecimal_cmp, val1, + val2)); + + PG_RETURN_BOOL(result >= 0); +} + Datum fixeddecimal_hash(PG_FUNCTION_ARGS) { @@ -1732,8 +2233,6 @@ fixeddecimal_sum(PG_FUNCTION_ARGS) } -#ifdef PGXC - /* * Input / Output / Send / Receive functions for aggrgate states * Currently for XL only @@ -1808,6 +2307,66 @@ fixeddecimalaggstatesend(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } +Datum +fixeddecimalaggstateserialize(PG_FUNCTION_ARGS) +{ + FixedDecimalAggState *state; + StringInfoData buf; + bytea *result; + + /* Ensure we disallow calling when not in aggregate context */ + if (!AggCheckCallContext(fcinfo, NULL)) + elog(ERROR, "aggregate function called in non-aggregate context"); + + state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); + + pq_begintypsend(&buf); + + /* N */ + pq_sendint64(&buf, state->N); + + /* sumX */ + pq_sendint64(&buf, state->sumX); + + result = pq_endtypsend(&buf); + + PG_RETURN_BYTEA_P(result); +} + +Datum +fixeddecimalaggstatedeserialize(PG_FUNCTION_ARGS) +{ + bytea *sstate; + FixedDecimalAggState *result; + StringInfoData buf; + + if (!AggCheckCallContext(fcinfo, NULL)) + elog(ERROR, "aggregate function called in non-aggregate context"); + + sstate = PG_GETARG_BYTEA_P(0); + + /* + * Copy the bytea into a StringInfo so that we can "receive" it using the + * standard recv-function infrastructure. + */ + initStringInfo(&buf); + appendBinaryStringInfo(&buf, VARDATA(sstate), VARSIZE(sstate) - VARHDRSZ); + + result = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); + + /* N */ + result->N = pq_getmsgint64(&buf); + + /* sumX */ + result->sumX = pq_getmsgint64(&buf); + + pq_getmsgend(&buf); + pfree(buf.data); + + PG_RETURN_POINTER(result); +} + + Datum fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) { @@ -1847,5 +2406,3 @@ fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) PG_RETURN_POINTER(collectstate); } - -#endif /* PGXC */ diff --git a/contrib/fixeddecimal/fixeddecimal.control b/contrib/fixeddecimal/fixeddecimal.control index 318593a184c..e9dd141f742 100755 --- a/contrib/fixeddecimal/fixeddecimal.control +++ b/contrib/fixeddecimal/fixeddecimal.control @@ -1,4 +1,4 @@ comment = 'fixeddecimal' -default_version = '1.0.0' +default_version = '1.1.0' relocatable = false module_pathname = '$libdir/fixeddecimal' From 9e5f5dd4506796b6ef7ec3dde151474918f4cfc6 Mon Sep 17 00:00:00 2001 From: Simon Riggs Date: Tue, 1 Oct 2019 10:10:03 +0100 Subject: [PATCH 28/32] Fix typo --- contrib/fixeddecimal/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md index 0546608f054..45ff30877e7 100755 --- a/contrib/fixeddecimal/README.md +++ b/contrib/fixeddecimal/README.md @@ -15,7 +15,7 @@ Often there are data storage requirements where the built in REAL and DOUBLE PRECISION types cannot be used due to the non-exact representation of numbers using these types, e.g. where monetary values need to be stored. In many of these cases NUMERIC is an almost perfect type, although with NUMERIC -performance is no match for the performance of REAL or DOUBLE PRCISION, as +performance is no match for the performance of REAL or DOUBLE PRECISION, as these use CPU native processor types. FixedDecimal aims to offer performance advantages over NUMERIC without the imprecise representations that are apparent in REAL and DOUBLE PRECISION, but it comes with some caveats... From eafd44f9c0c05847217c7f329fad42bba488b2f4 Mon Sep 17 00:00:00 2001 From: Simon Riggs Date: Tue, 1 Oct 2019 16:56:35 +0100 Subject: [PATCH 29/32] Update README.md Clarify explanations --- contrib/fixeddecimal/README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md index 45ff30877e7..7c1efcd048b 100755 --- a/contrib/fixeddecimal/README.md +++ b/contrib/fixeddecimal/README.md @@ -11,14 +11,18 @@ features of PostgreSQL's builtin NUMERIC type, but with vastly increased performance. Fixeddecimal is targeted to cases where performance and disk space are a critical. +Just use FIXEDDECIMAL(n, 2) rather than NUMERIC(n, 2) for n=3..17 + Often there are data storage requirements where the built in REAL and DOUBLE PRECISION types cannot be used due to the non-exact representation of numbers using these types, e.g. where monetary values need to be stored. In many of these cases NUMERIC is an almost perfect type, although with NUMERIC performance is no match for the performance of REAL or DOUBLE PRECISION, as -these use CPU native processor types. FixedDecimal aims to offer performance -advantages over NUMERIC without the imprecise representations that are -apparent in REAL and DOUBLE PRECISION, but it comes with some caveats... +these use CPU native processor types. + +FixedDecimal delivers performance advantages over NUMERIC with full precision for +addition and subtraction. Just as occurs with REAL and DOUBLE PRECISION, there +are some caveats for multiplication and division. Behavioural differences between FIXEDDECIMAL and NUMERIC -------------------------------------------------------- @@ -50,8 +54,9 @@ implementations as in the case with NUMERIC. FIXEDDECIMAL has a fixed scale value, which by default is 2. Internally numbers are stores as the actual value multiplied by 100. e.g. 50 would be stored as 5000, and 1.23 would be stored as 123. This internal representation allows very -fast addition and subtraction between two fixeddecimal types. Multiplication -between two fixeddecimal types is slightly more complex. If we wanted to +fast and accurate addition and subtraction between two fixeddecimal types. + +Multiplication between two fixeddecimal types is slightly more complex. If we perform 2.00 * 3.00 in fixeddecimal, internally these numbers would be 200 and 300 respectively, so internally 200 * 300 becomes 60000, which must be divided by 100 in order to obtain the correct internal result of 600, which of course @@ -113,7 +118,7 @@ test=# select '1.239'::fixeddecimal; It is especially important to remember that this truncation also occurs during arithmetic. Notice in the following example the result is 1120 rather than -1129: +1129, since 1.129 is immediately rounded to 1.12 on input. ``` test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; From d959bdfe1aa1259b186bb0c66646e5c58c842abe Mon Sep 17 00:00:00 2001 From: Florin Irion Date: Tue, 1 Oct 2019 16:38:54 +0200 Subject: [PATCH 30/32] Bump to version 12. Test for all versions from 9.5 to 12. Rework makefile Signed-off-by: Florin Irion --- contrib/fixeddecimal/Makefile | 38 +++++++++++++++++----------------- contrib/fixeddecimal/README.md | 3 ++- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index 0f7972079fc..76e7a045247 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -2,28 +2,16 @@ MODULE_big = fixeddecimal OBJS = fixeddecimal.o EXTENSION = fixeddecimal -AGGSTATESQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimalaggstate.sql) -AGGFUNCSSQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimal--xlaggs.sql) - -AGGFUNCSSQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]" && echo fixeddecimal--parallelaggs.sql || echo fixeddecimal--aggs.sql) - -BRINSQL := $(shell pg_config --version | grep -qE "9\.[5-9]| 10\.[0-9]" && echo fixeddecimal--brin.sql) - -# 9.6 was the dawn of parallel query, so we'll use the parallel enabled .sql file from then on. -BASESQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]" && echo fixeddecimal--1.1.0_base_parallel.sql || echo fixeddecimal--1.1.0_base.sql) - -SQLFILES := $(shell cat $(AGGSTATESQL) $(BASESQL) $(AGGFUNCSSQL) $(BRINSQL) > fixeddecimal--1.1.0.sql) - -DATA = fixeddecimal--1.1.0.sql fixeddecimal--1.0.0--1.1.0.sql -MODULES = fixeddecimal +DATA = fixeddecimal--1.0.0--1.1.0.sql +DATA_built = fixeddecimal--1.1.0.sql -CFLAGS =`pg_config --includedir-server` +CFLAGS = `pg_config --includedir-server` TESTS = $(wildcard test/sql/*.sql) -REGRESS_BRIN := $(shell pg_config --version | grep -qE "XL 9\.[5-9]| 10\.0" && echo brin-xl) -REGRESS_BRIN += $(shell pg_config --version | grep -E "9\.[5-9]| 10\.0" | grep -qEv "XL" && echo brin) +REGRESS_BRIN := $(shell pg_config --version | grep -qE "XL 9\.[5-9]| 10\.0| 11\.[0-9]| 12\.[0-9]" && echo brin-xl) +REGRESS_BRIN += $(shell pg_config --version | grep -E "9\.[5-9]| 10\.0| 11\.[0-9]| 12\.[0-9]" | grep -qEv "XL" && echo brin) REGRESS_VERSION_SPECIFIC := $(shell pg_config --version | grep -qE "XL" && echo index-xl || echo index) REGRESS = $(shell echo aggregate cast comparison overflow $(REGRESS_BRIN) $(REGRESS_VERSION_SPECIFIC)) @@ -33,6 +21,18 @@ PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) -fixeddecimal.so: fixeddecimal.o +AGGSTATESQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimalaggstate.sql) +AGGFUNCSSQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimal--xlaggs.sql) + +AGGFUNCSSQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--parallelaggs.sql || echo fixeddecimal--aggs.sql) + +BRINSQL := $(shell pg_config --version | grep -qE "9\.[5-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--brin.sql) + +# 9.6 was the dawn of parallel query, so we'll use the parallel enabled .sql file from then on. +BASESQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--1.1.0_base_parallel.sql || echo fixeddecimal--1.1.0_base.sql) + +OBJECTS := $(addprefix $(srcdir)/, $(AGGSTATESQL) $(BASESQL) $(AGGFUNCSSQL) $(BRINSQL)) + +fixeddecimal--1.1.0.sql: $(OBJECTS) + cat $^ > $@ -fixeddecimal.o: fixeddecimal.c diff --git a/contrib/fixeddecimal/README.md b/contrib/fixeddecimal/README.md index 7c1efcd048b..8199dc6e707 100755 --- a/contrib/fixeddecimal/README.md +++ b/contrib/fixeddecimal/README.md @@ -1,7 +1,8 @@ FIXEDDECIMAL ============ -Works with PostgreSQL 9.5 and Postgres-XL 9.5 +Works with PostgreSQL 9.5 or higher. +The latest test was executed on version 12. Overview -------- From eec01fe0c63a5a09bc598def32210e85a9543ca2 Mon Sep 17 00:00:00 2001 From: Dianjin Wang Date: Sat, 28 Feb 2026 10:58:59 +0800 Subject: [PATCH 31/32] contrib/fixeddecimal: add support for Cloudberry Add fixeddecimal to contrib recursive targets so it is built and tested with the rest of contrib modules. Rework contrib/fixeddecimal/Makefile to support both in-tree and PGXS builds: - use standard contrib in-tree includes (src/Makefile.global + contrib-global.mk) - keep USE_PGXS path for out-of-tree usage - remove hard dependency on pg_config for in-tree builds - fix generated SQL dependency path handling when srcdir is empty Fix fixeddecimal runtime issues seen in distributed aggregate execution: - avoid MAXINT8LEN macro conflict with core headers - switch int64 overflow checks to pg_add_s64_overflow/pg_sub_s64_overflow - harden aggregate state serialize/deserialize against NULL states - restore memory context before early return in aggregate combine Update fixeddecimal regression expected files for Cloudberry behavior (distribution-key NOTICEs, GPORCA plans, and distributed index semantics). With these changes, fixeddecimal builds, installs, and passes installcheck as a regular contrib extension in Cloudberry. --- .github/workflows/build-cloudberry-rocky8.yml | 1 + .github/workflows/build-cloudberry.yml | 1 + .github/workflows/build-deb-cloudberry.yml | 1 + contrib/Makefile | 3 +- contrib/fixeddecimal/Makefile | 66 +++++++++++------ contrib/fixeddecimal/fixeddecimal.c | 74 +++++-------------- contrib/fixeddecimal/fixeddecimal.control | 2 +- .../fixeddecimal/test/expected/aggregate.out | 1 + contrib/fixeddecimal/test/expected/brin.out | 17 +++-- contrib/fixeddecimal/test/expected/index.out | 45 +++++++---- .../fixeddecimal/test/expected/overflow.out | 1 + 11 files changed, 111 insertions(+), 101 deletions(-) diff --git a/.github/workflows/build-cloudberry-rocky8.yml b/.github/workflows/build-cloudberry-rocky8.yml index 2abf88060e3..ffe32d24bda 100644 --- a/.github/workflows/build-cloudberry-rocky8.yml +++ b/.github/workflows/build-cloudberry-rocky8.yml @@ -305,6 +305,7 @@ jobs: "contrib/formatter_fixedwidth:installcheck", "contrib/hstore:installcheck", "contrib/indexscan:installcheck", + "contrib/fixeddecimal:installcheck", "contrib/pg_trgm:installcheck", "contrib/indexscan:installcheck", "contrib/pgcrypto:installcheck", diff --git a/.github/workflows/build-cloudberry.yml b/.github/workflows/build-cloudberry.yml index ca75f7b42e7..96d2078923b 100644 --- a/.github/workflows/build-cloudberry.yml +++ b/.github/workflows/build-cloudberry.yml @@ -298,6 +298,7 @@ jobs: "contrib/formatter_fixedwidth:installcheck", "contrib/hstore:installcheck", "contrib/indexscan:installcheck", + "contrib/fixeddecimal:installcheck", "contrib/pg_trgm:installcheck", "contrib/indexscan:installcheck", "contrib/pgcrypto:installcheck", diff --git a/.github/workflows/build-deb-cloudberry.yml b/.github/workflows/build-deb-cloudberry.yml index 85d917b8ff0..e5f4058f06c 100644 --- a/.github/workflows/build-deb-cloudberry.yml +++ b/.github/workflows/build-deb-cloudberry.yml @@ -237,6 +237,7 @@ jobs: "contrib/formatter_fixedwidth:installcheck", "contrib/hstore:installcheck", "contrib/indexscan:installcheck", + "contrib/fixeddecimal:installcheck", "contrib/pg_trgm:installcheck", "contrib/indexscan:installcheck", "contrib/pgcrypto:installcheck", diff --git a/contrib/Makefile b/contrib/Makefile index b14600e3557..4fee6e3f49a 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -60,7 +60,8 @@ SUBDIRS += \ formatter \ formatter_fixedwidth \ extprotocol \ - indexscan + indexscan \ + fixeddecimal ifeq ($(with_ssl),openssl) SUBDIRS += sslinfo diff --git a/contrib/fixeddecimal/Makefile b/contrib/fixeddecimal/Makefile index 76e7a045247..6ced7b75d5e 100755 --- a/contrib/fixeddecimal/Makefile +++ b/contrib/fixeddecimal/Makefile @@ -6,33 +6,57 @@ EXTENSION = fixeddecimal DATA = fixeddecimal--1.0.0--1.1.0.sql DATA_built = fixeddecimal--1.1.0.sql -CFLAGS = `pg_config --includedir-server` - -TESTS = $(wildcard test/sql/*.sql) - -REGRESS_BRIN := $(shell pg_config --version | grep -qE "XL 9\.[5-9]| 10\.0| 11\.[0-9]| 12\.[0-9]" && echo brin-xl) -REGRESS_BRIN += $(shell pg_config --version | grep -E "9\.[5-9]| 10\.0| 11\.[0-9]| 12\.[0-9]" | grep -qEv "XL" && echo brin) -REGRESS_VERSION_SPECIFIC := $(shell pg_config --version | grep -qE "XL" && echo index-xl || echo index) -REGRESS = $(shell echo aggregate cast comparison overflow $(REGRESS_BRIN) $(REGRESS_VERSION_SPECIFIC)) - REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=fixeddecimal +ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) -include $(PGXS) - -AGGSTATESQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimalaggstate.sql) -AGGFUNCSSQL := $(shell pg_config --version | grep -qE "XL" && echo fixeddecimal--xlaggs.sql) -AGGFUNCSSQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--parallelaggs.sql || echo fixeddecimal--aggs.sql) - -BRINSQL := $(shell pg_config --version | grep -qE "9\.[5-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--brin.sql) - -# 9.6 was the dawn of parallel query, so we'll use the parallel enabled .sql file from then on. -BASESQL := $(shell pg_config --version | grep -qE "9\.[6-9]| 10\.[0-9]| 11\.[0-9]| 12\.[0-9]" && echo fixeddecimal--1.1.0_base_parallel.sql || echo fixeddecimal--1.1.0_base.sql) - -OBJECTS := $(addprefix $(srcdir)/, $(AGGSTATESQL) $(BASESQL) $(AGGFUNCSSQL) $(BRINSQL)) +PG_VERSION_STR := $(shell $(PG_CONFIG) --version) +ifeq (,$(findstring XL,$(PG_VERSION_STR))) +REGRESS_BRIN := brin +REGRESS_VERSION_SPECIFIC := index +AGGSTATESQL := +AGGFUNCSSQL := fixeddecimal--parallelaggs.sql +BRINSQL := fixeddecimal--brin.sql +BASESQL := fixeddecimal--1.1.0_base_parallel.sql +else +REGRESS_BRIN := brin-xl +REGRESS_VERSION_SPECIFIC := index-xl +AGGSTATESQL := fixeddecimalaggstate.sql +AGGFUNCSSQL := fixeddecimal--xlaggs.sql +BRINSQL := +BASESQL := fixeddecimal--1.1.0_base.sql +endif +else +subdir = contrib/fixeddecimal +top_builddir = ../.. + +# Cloudberry in-tree builds are non-XL and support parallel/BRIN paths. +REGRESS_BRIN := brin +REGRESS_VERSION_SPECIFIC := index +AGGSTATESQL := +AGGFUNCSSQL := fixeddecimal--parallelaggs.sql +BRINSQL := fixeddecimal--brin.sql +BASESQL := fixeddecimal--1.1.0_base_parallel.sql +endif + +REGRESS = aggregate cast comparison overflow $(REGRESS_BRIN) $(REGRESS_VERSION_SPECIFIC) + +ifeq ($(srcdir),) +FD_SRC_PREFIX := +else +FD_SRC_PREFIX := $(srcdir)/ +endif + +OBJECTS := $(addprefix $(FD_SRC_PREFIX), $(AGGSTATESQL) $(BASESQL) $(AGGFUNCSSQL) $(BRINSQL)) fixeddecimal--1.1.0.sql: $(OBJECTS) cat $^ > $@ +ifdef USE_PGXS +include $(PGXS) +else +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c index f02caacfc88..27e97325a96 100755 --- a/contrib/fixeddecimal/fixeddecimal.c +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -22,6 +22,7 @@ #include "funcapi.h" #include "libpq/pqformat.h" #include "access/hash.h" +#include "common/int.h" #include "utils/array.h" #include "utils/builtins.h" @@ -29,7 +30,7 @@ #include "utils/numeric.h" -#define MAXINT8LEN 25 +#define FIXEDDECIMAL_INT64STRLEN 25 /* * The scale which the number is actually stored. @@ -681,7 +682,7 @@ Datum fixeddecimalout(PG_FUNCTION_ARGS) { int64 val = PG_GETARG_INT64(0); - char buf[MAXINT8LEN + 1]; + char buf[FIXEDDECIMAL_INT64STRLEN + 1]; char *end = fixeddecimal2str(val, buf); PG_RETURN_CSTRING(pnstrdup(buf, end - buf)); } @@ -1258,21 +1259,11 @@ fixeddecimalum(PG_FUNCTION_ARGS) int64 arg = PG_GETARG_INT64(0); int64 result; -#ifdef HAVE_BUILTIN_OVERFLOW - int64 zero = 0; - - if (__builtin_sub_overflow(zero, arg, &result)) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("fixeddecimal out of range"))); -#else - result = -arg; - /* overflow check (needed for INT64_MIN) */ - if (arg != 0 && SAMESIGN(result, arg)) + if (pg_sub_s64_overflow(0, arg, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ + PG_RETURN_INT64(result); } @@ -1291,24 +1282,10 @@ fixeddecimalpl(PG_FUNCTION_ARGS) int64 arg2 = PG_GETARG_INT64(1); int64 result; -#ifdef HAVE_BUILTIN_OVERFLOW - if (__builtin_add_overflow(arg1, arg2, &result)) + if (pg_add_s64_overflow(arg1, arg2, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#else - result = arg1 + arg2; - - /* - * Overflow check. If the inputs are of different signs then their sum - * cannot overflow. If the inputs are of the same sign, their sum had - * better be that sign too. - */ - if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1320,24 +1297,10 @@ fixeddecimalmi(PG_FUNCTION_ARGS) int64 arg2 = PG_GETARG_INT64(1); int64 result; -#ifdef HAVE_BUILTIN_OVERFLOW - if (__builtin_sub_overflow(arg1, arg2, &result)) + if (pg_sub_s64_overflow(arg1, arg2, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#else - result = arg1 - arg2; - - /* - * Overflow check. If the inputs are of the same sign then their - * difference cannot overflow. If they are of different signs then the - * result should be of the same sign as the first input. - */ - if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2163,18 +2126,11 @@ makeFixedDecimalAggState(FunctionCallInfo fcinfo) static void fixeddecimal_accum(FixedDecimalAggState *state, int64 newval) { -#ifdef HAVE_BUILTIN_OVERFLOW - if (__builtin_add_overflow(state->sumX, newval, &state->sumX)) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("fixeddecimal out of range"))); - state->N++; -#else if (state->N++ > 0) { - int64 result = state->sumX + newval; + int64 result; - if (SAMESIGN(state->sumX, newval) && !SAMESIGN(result, state->sumX)) + if (pg_add_s64_overflow(state->sumX, newval, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); @@ -2183,7 +2139,6 @@ fixeddecimal_accum(FixedDecimalAggState *state, int64 newval) } else state->sumX = newval; -#endif /* HAVE_BUILTIN_OVERFLOW */ } Datum @@ -2264,7 +2219,7 @@ Datum fixeddecimalaggstateout(PG_FUNCTION_ARGS) { FixedDecimalAggState *state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); - char buf[MAXINT8LEN + 1 + MAXINT8LEN + 1]; + char buf[FIXEDDECIMAL_INT64STRLEN + 1 + FIXEDDECIMAL_INT64STRLEN + 1]; char *p; p = fixeddecimal2str(state->sumX, buf); @@ -2318,6 +2273,9 @@ fixeddecimalaggstateserialize(PG_FUNCTION_ARGS) if (!AggCheckCallContext(fcinfo, NULL)) elog(ERROR, "aggregate function called in non-aggregate context"); + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); pq_begintypsend(&buf); @@ -2343,6 +2301,9 @@ fixeddecimalaggstatedeserialize(PG_FUNCTION_ARGS) if (!AggCheckCallContext(fcinfo, NULL)) elog(ERROR, "aggregate function called in non-aggregate context"); + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + sstate = PG_GETARG_BYTEA_P(0); /* @@ -2395,7 +2356,10 @@ fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) PG_GETARG_POINTER(1); if (transstate == NULL) + { + MemoryContextSwitchTo(old_context); PG_RETURN_POINTER(collectstate); + } collectstate->sumX = DatumGetInt64(DirectFunctionCall2(fixeddecimalpl, Int64GetDatum(collectstate->sumX), Int64GetDatum(transstate->sumX))); diff --git a/contrib/fixeddecimal/fixeddecimal.control b/contrib/fixeddecimal/fixeddecimal.control index e9dd141f742..cab29c7d9ee 100755 --- a/contrib/fixeddecimal/fixeddecimal.control +++ b/contrib/fixeddecimal/fixeddecimal.control @@ -1,4 +1,4 @@ -comment = 'fixeddecimal' +comment = 'Exact fixed-point decimal type with operators, aggregates, and index support' default_version = '1.1.0' relocatable = false module_pathname = '$libdir/fixeddecimal' diff --git a/contrib/fixeddecimal/test/expected/aggregate.out b/contrib/fixeddecimal/test/expected/aggregate.out index 934c51b9b13..e88269e79c9 100755 --- a/contrib/fixeddecimal/test/expected/aggregate.out +++ b/contrib/fixeddecimal/test/expected/aggregate.out @@ -1,4 +1,5 @@ CREATE TABLE fixed_decimal(a FIXEDDECIMAL NOT NULL); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Apache Cloudberry data distribution key for this table. INSERT INTO fixed_decimal VALUES('92233720368547758.07'),('0.01'),('-92233720368547758.08'),('-0.01'); SELECT SUM(a) FROM fixed_decimal WHERE a > 0; ERROR: fixeddecimal out of range diff --git a/contrib/fixeddecimal/test/expected/brin.out b/contrib/fixeddecimal/test/expected/brin.out index e3ecea1c12b..56b30e86c07 100644 --- a/contrib/fixeddecimal/test/expected/brin.out +++ b/contrib/fixeddecimal/test/expected/brin.out @@ -1,16 +1,19 @@ -- Test BRIN indexes SET enable_seqscan = off; CREATE TABLE fixdec (d FIXEDDECIMAL, txt TEXT); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'd' as the Apache Cloudberry data distribution key for this table. INSERT INTO fixdec SELECT s.i,REPEAT('0',64) FROM generate_series(1,10000) s(i); CREATE INDEX fixdec_d_idx ON fixdec USING BRIN (d); EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; - QUERY PLAN ---------------------------------------------------- - Bitmap Heap Scan on fixdec - Recheck Cond: (d > '9999.00'::fixeddecimal) - -> Bitmap Index Scan on fixdec_d_idx - Index Cond: (d > '9999.00'::fixeddecimal) -(4 rows) + QUERY PLAN +--------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + -> Bitmap Heap Scan on fixdec + Recheck Cond: (d > '9999.00'::fixeddecimal) + -> Bitmap Index Scan on fixdec_d_idx + Index Cond: (d > '9999.00'::fixeddecimal) + Optimizer: GPORCA +(6 rows) SELECT * FROM fixdec WHERE d > '9999'::FIXEDDECIMAL; d | txt diff --git a/contrib/fixeddecimal/test/expected/index.out b/contrib/fixeddecimal/test/expected/index.out index f02aaf91065..5b5eb073c51 100644 --- a/contrib/fixeddecimal/test/expected/index.out +++ b/contrib/fixeddecimal/test/expected/index.out @@ -1,4 +1,5 @@ CREATE TABLE fixdec (id INT, d FIXEDDECIMAL(5,2)); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' as the Apache Cloudberry data distribution key for this table. INSERT INTO fixdec (id,d) VALUES(1,-123.45); INSERT INTO fixdec (id,d) VALUES(2,-123); INSERT INTO fixdec (id,d) VALUES(3,-12.34); @@ -10,16 +11,23 @@ INSERT INTO fixdec (id,d) VALUES(8, 123.45); INSERT INTO fixdec (id,d) VALUES(9, 123.456); -- Should fail CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); -ERROR: could not create unique index "fixdec_d_idx" -DETAIL: Key (d)=(123.45) is duplicated. +ERROR: UNIQUE index must contain all columns in the table's distribution key +DETAIL: Distribution key column "id" is not included in the constraint. DELETE FROM fixdec WHERE id = 9; CREATE UNIQUE INDEX fixdec_d_idx ON fixdec (d); +ERROR: UNIQUE index must contain all columns in the table's distribution key +DETAIL: Distribution key column "id" is not included in the constraint. SET enable_seqscan = off; EXPLAIN (COSTS OFF) SELECT * FROM fixdec ORDER BY d; - QUERY PLAN ------------------------------------------ - Index Scan using fixdec_d_idx on fixdec -(1 row) + QUERY PLAN +--------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Merge Key: d + -> Sort + Sort Key: d + -> Seq Scan on fixdec + Optimizer: GPORCA +(6 rows) SELECT * FROM fixdec ORDER BY d; id | d @@ -35,11 +43,13 @@ SELECT * FROM fixdec ORDER BY d; (8 rows) EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; - QUERY PLAN -------------------------------------------- - Index Scan using fixdec_d_idx on fixdec - Index Cond: (d = '12.34'::fixeddecimal) -(2 rows) + QUERY PLAN +------------------------------------------ + Gather Motion 3:1 (slice1; segments: 3) + -> Seq Scan on fixdec + Filter: (d = '12.34'::fixeddecimal) + Optimizer: GPORCA +(4 rows) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; id | d @@ -60,15 +70,18 @@ SELECT * FROM fixdec WHERE d = '123.45'::FIXEDDECIMAL; (1 row) DROP INDEX fixdec_d_idx; +ERROR: index "fixdec_d_idx" does not exist SET client_min_messages = ERROR; CREATE INDEX fixdec_d_idx ON fixdec USING hash (d); RESET client_min_messages; EXPLAIN (COSTS OFF) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; - QUERY PLAN -------------------------------------------- - Index Scan using fixdec_d_idx on fixdec - Index Cond: (d = '12.34'::fixeddecimal) -(2 rows) + QUERY PLAN +--------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + -> Index Scan using fixdec_d_idx on fixdec + Index Cond: (d = '12.34'::fixeddecimal) + Optimizer: GPORCA +(4 rows) SELECT * FROM fixdec WHERE d = '12.34'::FIXEDDECIMAL; id | d diff --git a/contrib/fixeddecimal/test/expected/overflow.out b/contrib/fixeddecimal/test/expected/overflow.out index ee0010080d4..74222eaf467 100755 --- a/contrib/fixeddecimal/test/expected/overflow.out +++ b/contrib/fixeddecimal/test/expected/overflow.out @@ -116,6 +116,7 @@ ERROR: FIXEDDECIMAL precision 18 must be between 2 and 17 LINE 1: SELECT 12345.33::FIXEDDECIMAL(18,2); ^ CREATE TABLE fixdec (d FIXEDDECIMAL(3,2)); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'd' as the Apache Cloudberry data distribution key for this table. INSERT INTO fixdec VALUES(12.34); -- Fail ERROR: FIXEDDECIMAL field overflow DETAIL: A field with precision 2, scale 2 must round to an absolute value less than 10^1. From 3bfd28ae6f5ff1a5da88f9d6ec8a5d74d3475cdf Mon Sep 17 00:00:00 2001 From: Dianjin Wang Date: Sat, 28 Feb 2026 14:56:07 +0800 Subject: [PATCH 32/32] ASF: add fixeddecimal license and RAT exclusions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add compliance metadata for the newly imported contrib/fixeddecimal extension. - Add fixeddecimal license notice entry under the "Apache Cloudberry includes codes from" section in LICENSE (PostgreSQL License, with a pointer to licenses/LICENSE-fixeddecimal.txt). - Add licenses/LICENSE-fixeddecimal.txt with fixeddecimal attribution and PostgreSQL license text. - Add Apache RAT exclusion for contrib/fixeddecimal/** in pom.xml, and place it in the Cloudberry-origin section (not the Greenplum section). This keeps license attribution and RAT classification aligned with fixeddecimal’s origin and repository organization. --- LICENSE | 6 ++++++ licenses/LICENSE-fixeddecimal.txt | 32 +++++++++++++++++++++++++++++++ pom.xml | 5 +++++ 3 files changed, 43 insertions(+) create mode 100644 licenses/LICENSE-fixeddecimal.txt diff --git a/LICENSE b/LICENSE index 28796e982e1..42372a5f4ae 100644 --- a/LICENSE +++ b/LICENSE @@ -338,6 +338,12 @@ Apache Cloudberry includes codes from see licenses/LICENSE-citusdata.txt +---------------------------- + PostgreSQL License + + contrib/fixeddecimal/* + see licenses/LICENSE-fixeddecimal.txt + ---------------------------- Apache License - Version 2.0 diff --git a/licenses/LICENSE-fixeddecimal.txt b/licenses/LICENSE-fixeddecimal.txt new file mode 100644 index 00000000000..cf07c705c80 --- /dev/null +++ b/licenses/LICENSE-fixeddecimal.txt @@ -0,0 +1,32 @@ +Copyright (c) 2015, PostgreSQL Global Development Group + +fixeddecimal is licensed under the PostgreSQL license, the same license +as PostgreSQL. It was originally developed by 2ndQuadrant and later +novated to the PostgreSQL Global Development Group. + +A copy of the PostgreSQL license is below: + +-------------- +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/pom.xml b/pom.xml index 75fdaf6619e..a74a36a7871 100644 --- a/pom.xml +++ b/pom.xml @@ -1272,6 +1272,11 @@ code or new licensing patterns. src/include/task/task_states.h src/include/task/job_metadata.h + + contrib/fixeddecimal/** +