From b163baa89ce0e4385497bc0f38deaf0078074d76 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 17 Jun 2008 19:10:56 +0000 Subject: [PATCH] Clean up some problems with redundant cross-type arithmetic operators. Add int2-and-int8 implementations of the basic arithmetic operators +, -, *, /. This doesn't really add any new functionality, but it avoids "operator is not unique" failures that formerly occurred in these cases because the parser couldn't decide whether to promote the int2 to int4 or int8. We could alternatively have removed the existing cross-type operators, but experimentation shows that the cost of an additional type coercion expression node is noticeable compared to such cheap operators; so let's not give up any performance here. On the other hand, I removed the int2-and-int4 modulo (%) operators since they didn't seem as important from a performance standpoint. Per a complaint last January from ykhuang. --- src/backend/utils/adt/int.c | 32 +------ src/backend/utils/adt/int8.c | 180 +++++++++++++++++++++++++++++++++++++- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_operator.h | 14 ++- src/include/catalog/pg_proc.h | 27 ++++-- src/include/utils/builtins.h | 4 +- src/include/utils/int8.h | 12 ++- 7 files changed, 223 insertions(+), 50 deletions(-) diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index 64ba146d71..c8dfe1cfeb 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.81 2008/01/01 19:45:52 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.82 2008/06/17 19:10:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1085,36 +1085,6 @@ int2mod(PG_FUNCTION_ARGS) PG_RETURN_INT16(arg1 % arg2); } -Datum -int24mod(PG_FUNCTION_ARGS) -{ - int16 arg1 = PG_GETARG_INT16(0); - int32 arg2 = PG_GETARG_INT32(1); - - if (arg2 == 0) - ereport(ERROR, - (errcode(ERRCODE_DIVISION_BY_ZERO), - errmsg("division by zero"))); - /* No overflow is possible */ - - PG_RETURN_INT32(arg1 % arg2); -} - -Datum -int42mod(PG_FUNCTION_ARGS) -{ - int32 arg1 = PG_GETARG_INT32(0); - int16 arg2 = PG_GETARG_INT16(1); - - if (arg2 == 0) - ereport(ERROR, - (errcode(ERRCODE_DIVISION_BY_ZERO), - errmsg("division by zero"))); - /* No overflow is possible */ - - PG_RETURN_INT32(arg1 % arg2); -} - /* int[24]abs() * Absolute value diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 6f3f9e2105..dc56df4d18 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.69 2008/04/21 00:26:45 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.70 2008/06/17 19:10:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -922,6 +922,184 @@ int48div(PG_FUNCTION_ARGS) PG_RETURN_INT64((int64) arg1 / arg2); } +Datum +int82pl(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; + + result = arg1 + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int82mi(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; + + result = arg1 - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int82mul(PG_FUNCTION_ARGS) +{ + int64 arg1 = PG_GETARG_INT64(0); + int16 arg2 = PG_GETARG_INT16(1); + int64 result; + + 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("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int82div(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"))); + + result = arg1 / arg2; + + /* + * Overflow check. The only possible overflow case is for arg1 = + * INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN, which + * can't be represented on a two's-complement machine. + */ + if (arg2 == -1 && arg1 < 0 && result < 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int28pl(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = arg1 + arg2; + + /* + * Overflow check. If the inputs are of different signs then their sum + * cannot overflow. If the inputs are of the same sign, their sum had + * better be that sign too. + */ + if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int28mi(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + result = arg1 - arg2; + + /* + * Overflow check. If the inputs are of the same sign then their + * difference cannot overflow. If they are of different signs then the + * result should be of the same sign as the first input. + */ + if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int28mul(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + int64 result; + + 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("bigint out of range"))); + PG_RETURN_INT64(result); +} + +Datum +int28div(PG_FUNCTION_ARGS) +{ + int16 arg1 = PG_GETARG_INT16(0); + int64 arg2 = PG_GETARG_INT64(1); + + if (arg2 == 0) + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* No overflow is possible */ + PG_RETURN_INT64((int64) arg1 / arg2); +} + /* Binary arithmetics * * int8and - returns arg1 & arg2 diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 31bfd2d747..5b434df515 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.462 2008/05/27 00:13:09 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.463 2008/06/17 19:10:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200805261 +#define CATALOG_VERSION_NO 200806171 #endif diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index c9f05ec964..7bb2035b1b 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.159 2008/05/27 00:13:09 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.160 2008/06/17 19:10:56 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -204,8 +204,6 @@ DATA(insert OID = 544 ( "*" PGNSP PGUID b f f 21 23 23 545 0 int24mul - - ) DATA(insert OID = 545 ( "*" PGNSP PGUID b f f 23 21 23 544 0 int42mul - - )); DATA(insert OID = 546 ( "/" PGNSP PGUID b f f 21 23 23 0 0 int24div - - )); DATA(insert OID = 547 ( "/" PGNSP PGUID b f f 23 21 23 0 0 int42div - - )); -DATA(insert OID = 548 ( "%" PGNSP PGUID b f f 21 23 23 0 0 int24mod - - )); -DATA(insert OID = 549 ( "%" PGNSP PGUID b f f 23 21 23 0 0 int42mod - - )); DATA(insert OID = 550 ( "+" PGNSP PGUID b f f 21 21 21 550 0 int2pl - - )); DATA(insert OID = 551 ( "+" PGNSP PGUID b f f 23 23 23 551 0 int4pl - - )); DATA(insert OID = 552 ( "+" PGNSP PGUID b f f 21 23 23 553 0 int24pl - - )); @@ -321,6 +319,7 @@ DATA(insert OID = 684 ( "+" PGNSP PGUID b f f 20 20 20 684 0 int8pl - - )); DATA(insert OID = 685 ( "-" PGNSP PGUID b f f 20 20 20 0 0 int8mi - - )); DATA(insert OID = 686 ( "*" PGNSP PGUID b f f 20 20 20 686 0 int8mul - - )); DATA(insert OID = 687 ( "/" PGNSP PGUID b f f 20 20 20 0 0 int8div - - )); + DATA(insert OID = 688 ( "+" PGNSP PGUID b f f 20 23 20 692 0 int84pl - - )); DATA(insert OID = 689 ( "-" PGNSP PGUID b f f 20 23 20 0 0 int84mi - - )); DATA(insert OID = 690 ( "*" PGNSP PGUID b f f 20 23 20 694 0 int84mul - - )); @@ -330,6 +329,15 @@ DATA(insert OID = 693 ( "-" PGNSP PGUID b f f 23 20 20 0 0 int48mi - - )); DATA(insert OID = 694 ( "*" PGNSP PGUID b f f 23 20 20 690 0 int48mul - - )); DATA(insert OID = 695 ( "/" PGNSP PGUID b f f 23 20 20 0 0 int48div - - )); +DATA(insert OID = 818 ( "+" PGNSP PGUID b f f 20 21 20 822 0 int82pl - - )); +DATA(insert OID = 819 ( "-" PGNSP PGUID b f f 20 21 20 0 0 int82mi - - )); +DATA(insert OID = 820 ( "*" PGNSP PGUID b f f 20 21 20 824 0 int82mul - - )); +DATA(insert OID = 821 ( "/" PGNSP PGUID b f f 20 21 20 0 0 int82div - - )); +DATA(insert OID = 822 ( "+" PGNSP PGUID b f f 21 20 20 818 0 int28pl - - )); +DATA(insert OID = 823 ( "-" PGNSP PGUID b f f 21 20 20 0 0 int28mi - - )); +DATA(insert OID = 824 ( "*" PGNSP PGUID b f f 21 20 20 820 0 int28mul - - )); +DATA(insert OID = 825 ( "/" PGNSP PGUID b f f 21 20 20 0 0 int28div - - )); + DATA(insert OID = 706 ( "<->" PGNSP PGUID b f f 603 603 701 706 0 box_distance - - )); DATA(insert OID = 707 ( "<->" PGNSP PGUID b f f 602 602 701 707 0 path_distance - - )); DATA(insert OID = 708 ( "<->" PGNSP PGUID b f f 628 628 701 708 0 line_distance - - )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index c4bc9f3e7e..dbe7910282 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.502 2008/05/29 22:48:07 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.503 2008/06/17 19:10:56 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -351,10 +351,6 @@ DATA(insert OID = 172 ( int24div PGNSP PGUID 12 1 0 f f t f i 2 23 "21 23" DESCR("divide"); DATA(insert OID = 173 ( int42div PGNSP PGUID 12 1 0 f f t f i 2 23 "23 21" _null_ _null_ _null_ int42div - _null_ _null_ )); DESCR("divide"); -DATA(insert OID = 174 ( int24mod PGNSP PGUID 12 1 0 f f t f i 2 23 "21 23" _null_ _null_ _null_ int24mod - _null_ _null_ )); -DESCR("modulus"); -DATA(insert OID = 175 ( int42mod PGNSP PGUID 12 1 0 f f t f i 2 23 "23 21" _null_ _null_ _null_ int42mod - _null_ _null_ )); -DESCR("modulus"); DATA(insert OID = 176 ( int2pl PGNSP PGUID 12 1 0 f f t f i 2 21 "21 21" _null_ _null_ _null_ int2pl - _null_ _null_ )); DESCR("add"); DATA(insert OID = 177 ( int4pl PGNSP PGUID 12 1 0 f f t f i 2 23 "23 23" _null_ _null_ _null_ int4pl - _null_ _null_ )); @@ -1177,10 +1173,6 @@ DATA(insert OID = 940 ( mod PGNSP PGUID 12 1 0 f f t f i 2 21 "21 21" _nul DESCR("modulus"); DATA(insert OID = 941 ( mod PGNSP PGUID 12 1 0 f f t f i 2 23 "23 23" _null_ _null_ _null_ int4mod - _null_ _null_ )); DESCR("modulus"); -DATA(insert OID = 942 ( mod PGNSP PGUID 12 1 0 f f t f i 2 23 "21 23" _null_ _null_ _null_ int24mod - _null_ _null_ )); -DESCR("modulus"); -DATA(insert OID = 943 ( mod PGNSP PGUID 12 1 0 f f t f i 2 23 "23 21" _null_ _null_ _null_ int42mod - _null_ _null_ )); -DESCR("modulus"); DATA(insert OID = 945 ( int8mod PGNSP PGUID 12 1 0 f f t f i 2 20 "20 20" _null_ _null_ _null_ int8mod - _null_ _null_ )); DESCR("modulus"); @@ -1570,6 +1562,23 @@ DESCR("multiply"); DATA(insert OID = 1281 ( int48div PGNSP PGUID 12 1 0 f f t f i 2 20 "23 20" _null_ _null_ _null_ int48div - _null_ _null_ )); DESCR("divide"); +DATA(insert OID = 837 ( int82pl PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82pl - _null_ _null_ )); +DESCR("add"); +DATA(insert OID = 838 ( int82mi PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82mi - _null_ _null_ )); +DESCR("subtract"); +DATA(insert OID = 839 ( int82mul PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82mul - _null_ _null_ )); +DESCR("multiply"); +DATA(insert OID = 840 ( int82div PGNSP PGUID 12 1 0 f f t f i 2 20 "20 21" _null_ _null_ _null_ int82div - _null_ _null_ )); +DESCR("divide"); +DATA(insert OID = 841 ( int28pl PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28pl - _null_ _null_ )); +DESCR("add"); +DATA(insert OID = 942 ( int28mi PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28mi - _null_ _null_ )); +DESCR("subtract"); +DATA(insert OID = 943 ( int28mul PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28mul - _null_ _null_ )); +DESCR("multiply"); +DATA(insert OID = 948 ( int28div PGNSP PGUID 12 1 0 f f t f i 2 20 "21 20" _null_ _null_ _null_ int28div - _null_ _null_ )); +DESCR("divide"); + DATA(insert OID = 1287 ( oid PGNSP PGUID 12 1 0 f f t f i 1 26 "20" _null_ _null_ _null_ i8tooid - _null_ _null_ )); DESCR("convert int8 to oid"); DATA(insert OID = 1288 ( int8 PGNSP PGUID 12 1 0 f f t f i 1 20 "26" _null_ _null_ _null_ oidtoi8 - _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index e152fe671a..c34ee7aa90 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.316 2008/05/27 00:13:09 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.317 2008/06/17 19:10:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -190,8 +190,6 @@ extern Datum int42mul(PG_FUNCTION_ARGS); extern Datum int42div(PG_FUNCTION_ARGS); 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 int2larger(PG_FUNCTION_ARGS); extern Datum int2smaller(PG_FUNCTION_ARGS); extern Datum int4larger(PG_FUNCTION_ARGS); diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h index b7b2310056..c19d167464 100644 --- a/src/include/utils/int8.h +++ b/src/include/utils/int8.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.48 2008/01/01 19:45:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.49 2008/06/17 19:10:56 tgl Exp $ * * NOTES * These data types are supported on all 64-bit architectures, and may @@ -96,6 +96,16 @@ extern Datum int48mi(PG_FUNCTION_ARGS); extern Datum int48mul(PG_FUNCTION_ARGS); extern Datum int48div(PG_FUNCTION_ARGS); +extern Datum int82pl(PG_FUNCTION_ARGS); +extern Datum int82mi(PG_FUNCTION_ARGS); +extern Datum int82mul(PG_FUNCTION_ARGS); +extern Datum int82div(PG_FUNCTION_ARGS); + +extern Datum int28pl(PG_FUNCTION_ARGS); +extern Datum int28mi(PG_FUNCTION_ARGS); +extern Datum int28mul(PG_FUNCTION_ARGS); +extern Datum int28div(PG_FUNCTION_ARGS); + extern Datum int48(PG_FUNCTION_ARGS); extern Datum int84(PG_FUNCTION_ARGS); -- 2.11.0