From 04a4821adef38155b7920ba9eb83c4c3c29156f8 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 1 Dec 2003 21:52:38 +0000 Subject: [PATCH] Attached is a patch implementing factorial(), returning numeric. Points to note: 1) arttype is numeric. I thought this was the best way of allowing arbitarily large factorials, even though factorial(2^63) is a large number. Happy to change to integers if this is overkill. 2) since we're accepting numeric arguments, the patch tests for floats. If a numeric is passed with non-zero decimal portion, an error is raised since (from memory) they are undefined. Gavin Sherry --- src/backend/utils/adt/int.c | 38 +------------- src/backend/utils/adt/int8.c | 22 +------- src/backend/utils/adt/numeric.c | 51 ++++++++++++++++++- src/include/catalog/pg_operator.h | 10 ++-- src/include/catalog/pg_proc.h | 17 ++----- src/include/utils/builtins.h | 5 +- src/include/utils/int8.h | 3 +- src/test/regress/expected/create_operator.out | 14 +++-- src/test/regress/sql/create_operator.sql | 14 +++-- 9 files changed, 74 insertions(+), 100 deletions(-) diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index 70e9971dd1..e23706582e 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.58 2003/11/29 19:51:58 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.59 2003/12/01 21:52:37 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -26,7 +26,7 @@ * intpl, intmi, int4mul, intdiv * * Arithmetic operators: - * intmod, int4fac + * intmod */ #include "postgres.h" @@ -849,40 +849,6 @@ int42mod(PG_FUNCTION_ARGS) PG_RETURN_INT32(arg1 % arg2); } -/* int[24]fac() - * Factorial - */ -Datum -int4fac(PG_FUNCTION_ARGS) -{ - int32 arg1 = PG_GETARG_INT32(0); - int32 result; - - if (arg1 == 0) - result = 1; - else if (arg1 < 0) - result = 0; - else - for (result = 1; arg1 > 0; --arg1) - result *= arg1; - PG_RETURN_INT32(result); -} - -Datum -int2fac(PG_FUNCTION_ARGS) -{ - int16 arg1 = PG_GETARG_INT16(0); - int32 result; - - if (arg1 == 0) - result = 1; - else if (arg1 < 0) - result = 0; - else - for (result = 1; arg1 > 0; --arg1) - result *= arg1; - PG_RETURN_INT32(result); -} /* int[24]abs() * Absolute value diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 616ceaaf9d..016330a053 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.49 2003/11/29 19:51:58 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.50 2003/12/01 21:52:37 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -561,26 +561,6 @@ int8mod(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } -/* int8fac() - * Factorial - */ -Datum -int8fac(PG_FUNCTION_ARGS) -{ - int64 arg1 = PG_GETARG_INT64(0); - int64 result; - int64 i; - - if (arg1 == 0) - result = 1; - else if (arg1 < 1) - result = 0; - else - for (i = arg1, result = 1; i > 0; --i) - result *= i; - - PG_RETURN_INT64(result); -} Datum int8inc(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index b2ffefa9da..7f16ee37a2 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -14,7 +14,7 @@ * Copyright (c) 1998-2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.68 2003/11/29 19:51:59 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.69 2003/12/01 21:52:37 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1288,6 +1288,55 @@ numeric_larger(PG_FUNCTION_ARGS) * ---------------------------------------------------------------------- */ +/* + * numeric_fac() + * Computer factorial + */ + +Datum +numeric_fac(PG_FUNCTION_ARGS) +{ + + int64 num = PG_GETARG_INT64(0); + NumericVar count; + NumericVar fact; + NumericVar zerovar; + NumericVar result; + Numeric res; + + if(num < 1) { + res = make_result(&const_one); + PG_RETURN_NUMERIC(res); + } + + + init_var(&fact); + init_var(&count); + init_var(&result); + init_var(&zerovar); + zero_var(&zerovar); + + int8_to_numericvar((int64)num, &result); + set_var_from_var(&const_one, &count); + + for(num = num - 1; num > 0; num--) { + set_var_from_var(&result,&count); + + int8_to_numericvar((int64)num,&fact); + + mul_var(&count, &fact, &result, count.dscale + fact.dscale); + } + + res = make_result(&count); + + free_var(&count); + free_var(&fact); + free_var(&result); + free_var(&zerovar); + + PG_RETURN_NUMERIC(res); +} + /* * numeric_sqrt() - diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 42f19d7687..f9ce05af2a 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.122 2003/11/29 22:40:58 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.123 2003/12/01 21:52:37 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -122,12 +122,12 @@ DATA(insert OID = 375 ( "||" PGNSP PGUID b f 2277 2277 2277 0 0 0 0 0 0 arra DATA(insert OID = 352 ( "=" PGNSP PGUID b t 28 28 16 352 0 0 0 0 0 xideq eqsel eqjoinsel )); DATA(insert OID = 353 ( "=" PGNSP PGUID b f 28 23 16 0 0 0 0 0 0 xideqint4 eqsel eqjoinsel )); +DATA(insert OID = 388 ( "!" PGNSP PGUID r f 20 0 1700 0 0 0 0 0 0 numeric_fac - - )); +DATA(insert OID = 389 ( "!!" PGNSP PGUID l f 0 20 1700 0 0 0 0 0 0 numeric_fac - - )); DATA(insert OID = 385 ( "=" PGNSP PGUID b t 29 29 16 385 0 0 0 0 0 cideq eqsel eqjoinsel )); DATA(insert OID = 386 ( "=" PGNSP PGUID b t 22 22 16 386 0 0 0 0 0 int2vectoreq eqsel eqjoinsel )); DATA(insert OID = 387 ( "=" PGNSP PGUID b f 27 27 16 387 0 0 0 0 0 tideq eqsel eqjoinsel )); #define TIDEqualOperator 387 -DATA(insert OID = 388 ( "!" PGNSP PGUID r f 20 0 20 0 0 0 0 0 0 int8fac - - )); -DATA(insert OID = 389 ( "!!" PGNSP PGUID l f 0 20 20 0 0 0 0 0 0 int8fac - - )); DATA(insert OID = 410 ( "=" PGNSP PGUID b t 20 20 16 410 411 412 412 412 413 int8eq eqsel eqjoinsel )); DATA(insert OID = 411 ( "<>" PGNSP PGUID b f 20 20 16 411 410 0 0 0 0 int8ne neqsel neqjoinsel )); @@ -176,8 +176,6 @@ DATA(insert OID = 511 ( "@" PGNSP PGUID b f 600 603 16 0 0 0 0 0 0 on_ DATA(insert OID = 512 ( "@" PGNSP PGUID b f 600 602 16 755 0 0 0 0 0 on_ppath - - )); DATA(insert OID = 513 ( "@@" PGNSP PGUID l f 0 603 600 0 0 0 0 0 0 box_center - - )); DATA(insert OID = 514 ( "*" PGNSP PGUID b f 23 23 23 514 0 0 0 0 0 int4mul - - )); -DATA(insert OID = 515 ( "!" PGNSP PGUID r f 23 0 23 0 0 0 0 0 0 int4fac - - )); -DATA(insert OID = 516 ( "!!" PGNSP PGUID l f 0 23 23 0 0 0 0 0 0 int4fac - - )); DATA(insert OID = 517 ( "<->" PGNSP PGUID b f 600 600 701 517 0 0 0 0 0 point_distance - - )); DATA(insert OID = 518 ( "<>" PGNSP PGUID b f 23 23 16 518 96 0 0 0 0 int4ne neqsel neqjoinsel )); DATA(insert OID = 519 ( "<>" PGNSP PGUID b f 21 21 16 519 94 0 0 0 0 int2ne neqsel neqjoinsel )); @@ -507,8 +505,6 @@ DATA(insert OID = 1133 ( ">" PGNSP PGUID b f 701 700 16 1122 1134 0 0 0 0 f DATA(insert OID = 1134 ( "<=" PGNSP PGUID b f 701 700 16 1125 1133 0 0 0 0 float84le scalarltsel scalarltjoinsel )); DATA(insert OID = 1135 ( ">=" PGNSP PGUID b f 701 700 16 1124 1132 0 0 0 0 float84ge scalargtsel scalargtjoinsel )); -DATA(insert OID = 1158 ( "!" PGNSP PGUID r f 21 0 23 0 0 0 0 0 0 int2fac - - )); -DATA(insert OID = 1175 ( "!!" PGNSP PGUID l f 0 21 23 0 0 0 0 0 0 int2fac - - )); /* LIKE hacks by Keith Parks. */ DATA(insert OID = 1207 ( "~~" PGNSP PGUID b f 19 25 16 0 1208 0 0 0 0 namelike likesel likejoinsel )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 5515a48d31..1ed5359ffb 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.316 2003/11/29 22:40:58 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.317 2003/12/01 21:52:37 momjian Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -208,8 +208,6 @@ DESCR("PostgreSQL version string"); /* OIDS 100 - 199 */ -DATA(insert OID = 100 ( int8fac PGNSP PGUID 12 f f t f i 1 20 "20" int8fac - _null_ )); -DESCR("factorial"); DATA(insert OID = 101 ( eqsel PGNSP PGUID 12 f f t f s 4 701 "2281 26 2281 23" eqsel - _null_ )); DESCR("restriction selectivity of = and related operators"); DATA(insert OID = 102 ( neqsel PGNSP PGUID 12 f f t f s 4 701 "2281 26 2281 23" neqsel - _null_ )); @@ -231,7 +229,7 @@ DATA(insert OID = 109 ( unknownin PGNSP PGUID 12 f f t f i 1 705 "2275" un DESCR("I/O"); DATA(insert OID = 110 ( unknownout PGNSP PGUID 12 f f t f i 1 2275 "705" unknownout - _null_ )); DESCR("I/O"); - +DATA(insert OID = 111 ( numeric_fac PGNSP PGUID 12 f f t f i 1 1700 "20" numeric_fac - _null_ )); DATA(insert OID = 112 ( text PGNSP PGUID 12 f f t f i 1 25 "23" int4_text - _null_ )); DESCR("convert int4 to text"); DATA(insert OID = 113 ( text PGNSP PGUID 12 f f t f i 1 25 "21" int2_text - _null_ )); @@ -294,8 +292,6 @@ DATA(insert OID = 140 ( areajoinsel PGNSP PGUID 12 f f t f s 4 701 "2281 26 DESCR("join selectivity for area-comparison operators"); DATA(insert OID = 141 ( int4mul PGNSP PGUID 12 f f t f i 2 23 "23 23" int4mul - _null_ )); DESCR("multiply"); -DATA(insert OID = 142 ( int4fac PGNSP PGUID 12 f f t f i 1 23 "23" int4fac - _null_ )); -DESCR("factorial"); DATA(insert OID = 144 ( int4ne PGNSP PGUID 12 f f t f i 2 16 "23 23" int4ne - _null_ )); DESCR("not equal"); DATA(insert OID = 145 ( int2ne PGNSP PGUID 12 f f t f i 2 16 "21 21" int2ne - _null_ )); @@ -571,9 +567,6 @@ DESCR("Current date and time - increments during transactions"); DATA(insert OID = 275 ( isfinite PGNSP PGUID 12 f f t f i 1 16 "702" abstime_finite - _null_ )); DESCR("finite abstime?"); -DATA(insert OID = 276 ( int2fac PGNSP PGUID 12 f f t f i 1 23 "21" int2fac - _null_ )); -DESCR("factorial"); - DATA(insert OID = 277 ( inter_sl PGNSP PGUID 12 f f t f i 2 16 "601 628" inter_sl - _null_ )); DESCR("intersect?"); DATA(insert OID = 278 ( inter_lb PGNSP PGUID 12 f f t f i 2 16 "628 603" inter_lb - _null_ )); @@ -1758,11 +1751,7 @@ DATA(insert OID = 1390 ( isfinite PGNSP PGUID 12 f f t f i 1 16 "1186" inte DESCR("finite interval?"); -DATA(insert OID = 1391 ( factorial PGNSP PGUID 12 f f t f i 1 23 "21" int2fac - _null_ )); -DESCR("factorial"); -DATA(insert OID = 1392 ( factorial PGNSP PGUID 12 f f t f i 1 23 "23" int4fac - _null_ )); -DESCR("factorial"); -DATA(insert OID = 1393 ( factorial PGNSP PGUID 12 f f t f i 1 20 "20" int8fac - _null_ )); +DATA(insert OID = 1376 ( factorial PGNSP PGUID 12 f f t f i 1 1700 "20" numeric_fac - _null_ )); DESCR("factorial"); DATA(insert OID = 1394 ( abs PGNSP PGUID 12 f f t f i 1 700 "700" float4abs - _null_ )); DESCR("absolute value"); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 92663c3e5c..c784f28afd 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.230 2003/11/29 22:41:15 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.231 2003/12/01 21:52:38 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -159,8 +159,6 @@ extern Datum int4mod(PG_FUNCTION_ARGS); extern Datum int2mod(PG_FUNCTION_ARGS); extern Datum int24mod(PG_FUNCTION_ARGS); extern Datum int42mod(PG_FUNCTION_ARGS); -extern Datum int4fac(PG_FUNCTION_ARGS); -extern Datum int2fac(PG_FUNCTION_ARGS); extern Datum int2larger(PG_FUNCTION_ARGS); extern Datum int2smaller(PG_FUNCTION_ARGS); extern Datum int4larger(PG_FUNCTION_ARGS); @@ -720,6 +718,7 @@ extern Datum numeric_mod(PG_FUNCTION_ARGS); extern Datum numeric_inc(PG_FUNCTION_ARGS); extern Datum numeric_smaller(PG_FUNCTION_ARGS); extern Datum numeric_larger(PG_FUNCTION_ARGS); +extern Datum numeric_fac(PG_FUNCTION_ARGS); extern Datum numeric_sqrt(PG_FUNCTION_ARGS); extern Datum numeric_exp(PG_FUNCTION_ARGS); extern Datum numeric_ln(PG_FUNCTION_ARGS); diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h index aad610eb9e..7fe9800b23 100644 --- a/src/include/utils/int8.h +++ b/src/include/utils/int8.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.39 2003/11/29 22:41:15 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.40 2003/12/01 21:52:38 momjian Exp $ * * NOTES * These data types are supported on all 64-bit architectures, and may @@ -72,7 +72,6 @@ extern Datum int8mi(PG_FUNCTION_ARGS); extern Datum int8mul(PG_FUNCTION_ARGS); extern Datum int8div(PG_FUNCTION_ARGS); extern Datum int8abs(PG_FUNCTION_ARGS); -extern Datum int8fac(PG_FUNCTION_ARGS); extern Datum int8mod(PG_FUNCTION_ARGS); extern Datum int8inc(PG_FUNCTION_ARGS); extern Datum int8larger(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/create_operator.out b/src/test/regress/expected/create_operator.out index 7685dbe802..df25f35ae7 100644 --- a/src/test/regress/expected/create_operator.out +++ b/src/test/regress/expected/create_operator.out @@ -15,19 +15,17 @@ CREATE OPERATOR <% ( negator = >=% ); CREATE OPERATOR @#@ ( - rightarg = int4, -- left unary - procedure = int4fac + rightarg = int8, -- left unary + procedure = numeric_fac ); CREATE OPERATOR #@# ( - leftarg = int4, -- right unary - procedure = int4fac + leftarg = int8, -- right unary + procedure = numeric_fac ); CREATE OPERATOR #%# ( - leftarg = int4, -- right unary - procedure = int4fac + leftarg = int8, -- right unary + procedure = numeric_fac ); -- Test comments COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary'; ERROR: operator does not exist: integer ###### -COMMENT ON OPERATOR #%# (int4, NONE) IS 'right unary'; -COMMENT ON OPERATOR #%# (int4, NONE) IS NULL; diff --git a/src/test/regress/sql/create_operator.sql b/src/test/regress/sql/create_operator.sql index 4167bf3ab8..6637629ea4 100644 --- a/src/test/regress/sql/create_operator.sql +++ b/src/test/regress/sql/create_operator.sql @@ -18,23 +18,21 @@ CREATE OPERATOR <% ( ); CREATE OPERATOR @#@ ( - rightarg = int4, -- left unary - procedure = int4fac + rightarg = int8, -- left unary + procedure = numeric_fac ); CREATE OPERATOR #@# ( - leftarg = int4, -- right unary - procedure = int4fac + leftarg = int8, -- right unary + procedure = numeric_fac ); CREATE OPERATOR #%# ( - leftarg = int4, -- right unary - procedure = int4fac + leftarg = int8, -- right unary + procedure = numeric_fac ); -- Test comments COMMENT ON OPERATOR ###### (int4, NONE) IS 'bad right unary'; -COMMENT ON OPERATOR #%# (int4, NONE) IS 'right unary'; -COMMENT ON OPERATOR #%# (int4, NONE) IS NULL; -- 2.40.0