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/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/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 new file mode 100755 index 00000000000..6ced7b75d5e --- /dev/null +++ b/contrib/fixeddecimal/Makefile @@ -0,0 +1,62 @@ +MODULE_big = fixeddecimal +OBJS = fixeddecimal.o + +EXTENSION = fixeddecimal + +DATA = fixeddecimal--1.0.0--1.1.0.sql +DATA_built = fixeddecimal--1.1.0.sql + +REGRESS_OPTS = --inputdir=test --outputdir=test --load-extension=fixeddecimal + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) + +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/README.md b/contrib/fixeddecimal/README.md new file mode 100755 index 00000000000..8199dc6e707 --- /dev/null +++ b/contrib/fixeddecimal/README.md @@ -0,0 +1,162 @@ +FIXEDDECIMAL +============ + +Works with PostgreSQL 9.5 or higher. +The latest test was executed on version 12. + +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. + +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 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 +-------------------------------------------------------- + +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 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 +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 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 +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 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: + +``` +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, since 1.129 is immediately rounded to 1.12 on input. + +``` +test=# select '1000'::fixeddecimal * '1.129'::fixeddecimal; + ?column? +---------- + 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; +``` + +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 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.0.0_base.sql b/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql new file mode 100755 index 00000000000..d23e59ae970 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--1.0.0_base.sql @@ -0,0 +1,528 @@ + +------------------ +-- 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. +); + +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. +-- + +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); + +-- +-- 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 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.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--aggs.sql b/contrib/fixeddecimal/fixeddecimal--aggs.sql new file mode 100644 index 00000000000..a24a869129c --- /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; + +CREATE FUNCTION fixeddecimal_avg(INTERNAL) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE; + +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--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--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--xlaggs.sql b/contrib/fixeddecimal/fixeddecimal--xlaggs.sql new file mode 100644 index 00000000000..57fa07d1e42 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal--xlaggs.sql @@ -0,0 +1,57 @@ + +-- Aggregate Support + + +CREATE FUNCTION fixeddecimalaggstatecombine(FIXEDDECIMALAGGSTATE, FIXEDDECIMALAGGSTATE) +RETURNS FIXEDDECIMALAGGSTATE +AS 'fixeddecimal', 'fixeddecimalaggstatecombine' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_avg_accum(FIXEDDECIMALAGGSTATE, FIXEDDECIMAL) +RETURNS FIXEDDECIMALAGGSTATE +AS 'fixeddecimal', 'fixeddecimal_avg_accum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_sum(FIXEDDECIMALAGGSTATE) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_sum' +LANGUAGE C IMMUTABLE; + +CREATE FUNCTION fixeddecimal_avg(FIXEDDECIMALAGGSTATE) +RETURNS FIXEDDECIMAL +AS 'fixeddecimal', 'fixeddecimal_avg' +LANGUAGE C IMMUTABLE; + +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 = FIXEDDECIMALAGGSTATE +); + +CREATE AGGREGATE avg(FIXEDDECIMAL) ( + SFUNC = fixeddecimal_avg_accum, + CFUNC = fixeddecimalaggstatecombine, + CTYPE = FIXEDDECIMALAGGSTATE, + FINALFUNC = fixeddecimal_avg, + STYPE = FIXEDDECIMALAGGSTATE +); + + diff --git a/contrib/fixeddecimal/fixeddecimal.c b/contrib/fixeddecimal/fixeddecimal.c new file mode 100755 index 00000000000..27e97325a96 --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal.c @@ -0,0 +1,2372 @@ +/*------------------------------------------------------------------------- + * + * 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 +#include +#include + +#include "funcapi.h" +#include "libpq/pqformat.h" +#include "access/hash.h" +#include "common/int.h" +#include "utils/array.h" +#include "utils/builtins.h" + +#include "utils/int8.h" + +#include "utils/numeric.h" + +#define FIXEDDECIMAL_INT64STRLEN 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_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 + * 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 */ + +#ifndef HAVE_BUILTIN_OVERFLOW +#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) +#endif /* HAVE_BUILTIN_OVERFLOW */ + +/* Compiler must have a working 128 int type */ +typedef __int128 int128; + +#ifdef PG_MODULE_MAGIC +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); + +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(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); +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(fixeddecimal); +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(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); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatecombine); +PG_FUNCTION_INFO_V1(fixeddecimalaggstateserialize); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatedeserialize); + +PG_FUNCTION_INFO_V1(fixeddecimalaggstatein); +PG_FUNCTION_INFO_V1(fixeddecimalaggstateout); +PG_FUNCTION_INFO_V1(fixeddecimalaggstatesend); +PG_FUNCTION_INFO_V1(fixeddecimalaggstaterecv); + + +/* 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 + ** + ***********************************************************************/ + +/*---------------------------------------------------------- + * 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; +} + +/* + * 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. + */ +static int64 +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. + */ + + /* 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'); + + vprecision++; + 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'); + + vprecision++; + 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; + vscale++; + } + + /* + * Eat into any excess precision digits. + * XXX These are ignored, should we error instead? + */ + while (isdigit((unsigned char) *ptr)) + ptr++, vscale++; + } + + /* 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))); + + *precision = vprecision; + *scale = vscale; + + 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); + 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() + */ +Datum +fixeddecimalout(PG_FUNCTION_ARGS) +{ + int64 val = PG_GETARG_INT64(0); + char buf[FIXEDDECIMAL_INT64STRLEN + 1]; + char *end = fixeddecimal2str(val, buf); + PG_RETURN_CSTRING(pnstrdup(buf, end - buf)); +} + +/* + * 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); +} + +/* 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) +{ + int64 val = PG_GETARG_INT64(0); + Datum result; + + result = hash_any((unsigned char *) &val, sizeof(int64)); + PG_RETURN_DATUM(result); +} + +/*---------------------------------------------------------- + * Arithmetic operators on fixeddecimal. + *---------------------------------------------------------*/ + +Datum +fixeddecimalum(PG_FUNCTION_ARGS) +{ + int64 arg = PG_GETARG_INT64(0); + int64 result; + + if (pg_sub_s64_overflow(0, arg, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + 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; + + if (pg_add_s64_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64(result); +} + +Datum +fixeddecimalmi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + if (pg_sub_s64_overflow(arg1, arg2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + PG_RETURN_INT64(result); +} + +Datum +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 + * 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 +fixeddecimaldiv(PG_FUNCTION_ARGS) +{ + int64 dividend = PG_GETARG_INT64(0); + int64 divisor = PG_GETARG_INT64(1); + int128 result; + + 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"))); + + /* + * 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() + * 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. + *---------------------------------------------------------*/ + +/* + * 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; + + /* 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); +} + +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); +} + + +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 = DirectFunctionCall3(fixeddecimalin, CStringGetDatum(tmp), 0, -1); + + pfree(tmp); + + PG_RETURN_DATUM(result); +} + + +/* Aggregate Support */ + +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) +{ + if (state->N++ > 0) + { + int64 result; + + if (pg_add_s64_overflow(state->sumX, newval, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("fixeddecimal out of range"))); + + state->sumX = result; + } + else + state->sumX = newval; +} + +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); +} + + +/* + * 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 *) palloc(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[FIXEDDECIMAL_INT64STRLEN + 1 + FIXEDDECIMAL_INT64STRLEN + 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 +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"); + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + 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"); + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + 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) +{ + 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); + + collectstate = PG_ARGISNULL(0) ? NULL : (FixedDecimalAggState *) + PG_GETARG_POINTER(0); + + 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) + { + MemoryContextSwitchTo(old_context); + 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); +} diff --git a/contrib/fixeddecimal/fixeddecimal.control b/contrib/fixeddecimal/fixeddecimal.control new file mode 100755 index 00000000000..cab29c7d9ee --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimal.control @@ -0,0 +1,4 @@ +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/fixeddecimalaggstate.sql b/contrib/fixeddecimal/fixeddecimalaggstate.sql new file mode 100644 index 00000000000..9e814777b5b --- /dev/null +++ b/contrib/fixeddecimal/fixeddecimalaggstate.sql @@ -0,0 +1,41 @@ +-------------------------- +-- 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, + PASSEDBYVALUE +); + diff --git a/contrib/fixeddecimal/test/expected/aggregate.out b/contrib/fixeddecimal/test/expected/aggregate.out new file mode 100755 index 00000000000..e88269e79c9 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/aggregate.out @@ -0,0 +1,34 @@ +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 +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/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/brin.out b/contrib/fixeddecimal/test/expected/brin.out new file mode 100644 index 00000000000..56b30e86c07 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/brin.out @@ -0,0 +1,25 @@ +-- 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 +--------------------------------------------------------------- + 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 +----------+------------------------------------------------------------------ + 10000.00 | 0000000000000000000000000000000000000000000000000000000000000000 +(1 row) + +DROP TABLE fixdec; +RESET enable_seqscan; diff --git a/contrib/fixeddecimal/test/expected/cast.out b/contrib/fixeddecimal/test/expected/cast.out new file mode 100755 index 00000000000..b230ed59787 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/cast.out @@ -0,0 +1,48 @@ +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/expected/comparison.out b/contrib/fixeddecimal/test/expected/comparison.out new file mode 100755 index 00000000000..9ba9abe9ae5 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/comparison.out @@ -0,0 +1,310 @@ +-- 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/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/expected/index.out b/contrib/fixeddecimal/test/expected/index.out new file mode 100644 index 00000000000..5b5eb073c51 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/index.out @@ -0,0 +1,105 @@ +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); +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: 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 +--------------------------------------- + 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 +----+--------- + 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 +------------------------------------------ + 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 +----+------- + 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; +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 +--------------------------------------------------------- + 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 +----+------- + 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/expected/overflow.out b/contrib/fixeddecimal/test/expected/overflow.out new file mode 100755 index 00000000000..74222eaf467 --- /dev/null +++ b/contrib/fixeddecimal/test/expected/overflow.out @@ -0,0 +1,124 @@ +-- 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)); +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. +INSERT INTO fixdec VALUES(1.23); -- Pass +DROP TABLE fixdec; 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 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/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/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 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; 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; diff --git a/contrib/fixeddecimal/test/sql/index.sql b/contrib/fixeddecimal/test/sql/index.sql new file mode 100644 index 00000000000..3782593fb8c --- /dev/null +++ b/contrib/fixeddecimal/test/sql/index.sql @@ -0,0 +1,50 @@ +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); + +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; + +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; diff --git a/contrib/fixeddecimal/test/sql/overflow.sql b/contrib/fixeddecimal/test/sql/overflow.sql new file mode 100755 index 00000000000..06408cda2b9 --- /dev/null +++ b/contrib/fixeddecimal/test/sql/overflow.sql @@ -0,0 +1,79 @@ +-- 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; + +-- 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; + +-- 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; + +-- 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); + +-- 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; 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/** +